dream 1 долоо хоног өмнө
commit
4d09dd059a
50 өөрчлөгдсөн 2066 нэмэгдсэн , 0 устгасан
  1. 15 0
      .gitignore
  2. 3 0
      .idea/.gitignore
  3. 6 0
      .idea/AndroidProjectSystem.xml
  4. 6 0
      .idea/compiler.xml
  5. 10 0
      .idea/deploymentTargetSelector.xml
  6. 18 0
      .idea/gradle.xml
  7. 10 0
      .idea/migrations.xml
  8. 10 0
      .idea/misc.xml
  9. 17 0
      .idea/runConfigurations.xml
  10. 6 0
      .idea/vcs.xml
  11. 2 0
      README.md
  12. 1 0
      app/.gitignore
  13. 44 0
      app/build.gradle.kts
  14. 21 0
      app/proguard-rules.pro
  15. 26 0
      app/src/androidTest/java/com/systemvalidation/ExampleInstrumentedTest.java
  16. 79 0
      app/src/main/AndroidManifest.xml
  17. 54 0
      app/src/main/aidl/com/systemvalidation/ISystemValidationService.aidl
  18. 379 0
      app/src/main/java/com/systemvalidation/ClientHandler.java
  19. 71 0
      app/src/main/java/com/systemvalidation/MainActivity.java
  20. 205 0
      app/src/main/java/com/systemvalidation/SystemValidationReceiver.java
  21. 430 0
      app/src/main/java/com/systemvalidation/SystemValidationService.java
  22. 170 0
      app/src/main/res/drawable/ic_launcher_background.xml
  23. 30 0
      app/src/main/res/drawable/ic_launcher_foreground.xml
  24. 6 0
      app/src/main/res/mipmap-anydpi/ic_launcher.xml
  25. 6 0
      app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
  26. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.webp
  27. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
  28. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.webp
  29. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
  30. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.webp
  31. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
  32. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
  33. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
  34. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
  35. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
  36. 16 0
      app/src/main/res/values-night/themes.xml
  37. 10 0
      app/src/main/res/values/colors.xml
  38. 3 0
      app/src/main/res/values/strings.xml
  39. 16 0
      app/src/main/res/values/themes.xml
  40. 13 0
      app/src/main/res/xml/backup_rules.xml
  41. 19 0
      app/src/main/res/xml/data_extraction_rules.xml
  42. 17 0
      app/src/test/java/com/systemvalidation/ExampleUnitTest.java
  43. 4 0
      build.gradle.kts
  44. 21 0
      gradle.properties
  45. 18 0
      gradle/libs.versions.toml
  46. BIN
      gradle/wrapper/gradle-wrapper.jar
  47. 6 0
      gradle/wrapper/gradle-wrapper.properties
  48. 185 0
      gradlew
  49. 89 0
      gradlew.bat
  50. 24 0
      settings.gradle.kts

+ 15 - 0
.gitignore

@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties

+ 3 - 0
.idea/.gitignore

@@ -0,0 +1,3 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml

+ 6 - 0
.idea/AndroidProjectSystem.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="AndroidProjectSystem">
+    <option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
+  </component>
+</project>

+ 6 - 0
.idea/compiler.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <bytecodeTargetLevel target="21" />
+  </component>
+</project>

+ 10 - 0
.idea/deploymentTargetSelector.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="deploymentTargetSelector">
+    <selectionStates>
+      <SelectionState runConfigName="app">
+        <option name="selectionMode" value="DROPDOWN" />
+      </SelectionState>
+    </selectionStates>
+  </component>
+</project>

+ 18 - 0
.idea/gradle.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="testRunner" value="CHOOSE_PER_TEST" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+          </set>
+        </option>
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 10 - 0
.idea/migrations.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectMigrations">
+    <option name="MigrateToGradleLocalJavaHome">
+      <set>
+        <option value="$PROJECT_DIR$" />
+      </set>
+    </option>
+  </component>
+</project>

+ 10 - 0
.idea/misc.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+</project>

+ 17 - 0
.idea/runConfigurations.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RunConfigurationProducerService">
+    <option name="ignoredProducers">
+      <set>
+        <option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
+        <option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
+        <option value="com.intellij.execution.junit.PatternConfigurationProducer" />
+        <option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
+        <option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
+        <option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
+        <option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
+        <option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
+      </set>
+    </option>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 2 - 0
README.md

@@ -0,0 +1,2 @@
+# SystemValidation
+

+ 1 - 0
app/.gitignore

@@ -0,0 +1 @@
+/build

+ 44 - 0
app/build.gradle.kts

@@ -0,0 +1,44 @@
+plugins {
+    alias(libs.plugins.android.application)
+}
+
+android {
+    namespace = "com.systemvalidation"
+    compileSdk = 35
+
+    defaultConfig {
+        applicationId = "com.systemvalidation"
+        minSdk = 34
+        targetSdk = 35
+        versionCode = 1
+        versionName = "1.0"
+
+        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            isMinifyEnabled = false
+            proguardFiles(
+                getDefaultProguardFile("proguard-android-optimize.txt"),
+                "proguard-rules.pro"
+            )
+        }
+    }
+    buildFeatures {
+        aidl = true
+    }
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_11
+        targetCompatibility = JavaVersion.VERSION_11
+    }
+}
+
+dependencies {
+
+    implementation(libs.appcompat)
+    implementation(libs.material)
+    testImplementation(libs.junit)
+    androidTestImplementation(libs.ext.junit)
+    androidTestImplementation(libs.espresso.core)
+}

+ 21 - 0
app/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 26 - 0
app/src/androidTest/java/com/systemvalidation/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
+package com.systemvalidation;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        assertEquals("com.systemvalidation", appContext.getPackageName());
+    }
+}

+ 79 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:sharedUserId="android.uid.system"
+    coreApp="true">
+
+    <!-- 系统权限 -->
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"
+        tools:ignore="ProtectedPermissions" />
+    <uses-permission android:name="android.permission.DEVICE_POWER"
+        tools:ignore="ProtectedPermissions" />
+    <uses-permission android:name="android.permission.REBOOT"
+        tools:ignore="ProtectedPermissions" />
+    <uses-permission android:name="android.permission.SHUTDOWN"
+        tools:ignore="ProtectedPermissions" />
+    
+    <!-- 危险权限(需要系统签名) -->
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.INJECT_EVENTS"
+        tools:ignore="ProtectedPermissions" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
+    
+    <application
+        android:allowBackup="true"
+        android:dataExtractionRules="@xml/data_extraction_rules"
+        android:fullBackupContent="@xml/backup_rules"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.SystemValidation"
+        android:persistent="true"
+        android:directBootAware="true"
+        tools:targetApi="31"
+        tools:ignore="HardcodedDebugMode">
+        
+        <!-- 系统验证服务 -->
+        <service
+            android:name=".SystemValidationService"
+            android:enabled="true"
+            android:exported="true"
+            android:isolatedProcess="false"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <intent-filter>
+                <action android:name="com.systemvalidation.SystemValidationService" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </service>
+        
+        <!-- 服务启动器Activity(可选) -->
+        <activity
+            android:name=".MainActivity"
+            android:exported="true"
+            android:theme="@style/Theme.SystemValidation">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <!-- 广播接收器 -->
+        <receiver
+            android:name=".SystemValidationReceiver"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+                <action android:name="android.intent.action.ACTION_SHUTDOWN" />
+                <action android:name="android.intent.action.REBOOT" />
+            </intent-filter>
+        </receiver>
+
+    </application>
+
+</manifest>

+ 54 - 0
app/src/main/aidl/com/systemvalidation/ISystemValidationService.aidl

@@ -0,0 +1,54 @@
+package com.systemvalidation;
+
+/**
+ * 系统验证服务接口
+ * 提供设备验证和安全控制功能
+ */
+interface ISystemValidationService {
+    /**
+     * 验证设备码
+     * @param deviceCode 64位十六进制设备码
+     * @return 验证结果
+     */
+    boolean verifyDevice(String deviceCode);
+    
+    /**
+     * 执行安全操作
+     * @param action 安全操作类型
+     *                 0: 获取状态
+     *                 1: 锁定触控
+     *                 2: 深度锁机
+     *                 3: 解锁设备
+     * @return 操作结果
+     */
+    boolean executeSecurityAction(int action);
+    
+    /**
+     * 获取当前安全级别
+     * @return 安全级别值
+     *         0: 正常
+     *         1: 警告
+     *         2: 限制
+     *         3: 锁定
+     *         4: 深度锁定
+     */
+    int getSecurityLevel();
+    
+    /**
+     * 获取服务状态JSON
+     * @return 服务状态JSON字符串
+     */
+    String getServiceStatusJson();
+    
+    /**
+     * 启动服务监听
+     * @param port 监听端口号
+     * @return 启动结果
+     */
+    boolean startService(int port);
+    
+    /**
+     * 停止服务监听
+     */
+    void stopService();
+}

+ 379 - 0
app/src/main/java/com/systemvalidation/ClientHandler.java

@@ -0,0 +1,379 @@
+package com.systemvalidation;
+
+import android.util.Log;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import org.json.JSONObject;
+import org.json.JSONException;
+
+/**
+ * 客户端连接处理器
+ * 处理来自电脑的ADB连接请求
+ */
+class ClientHandler implements Runnable {
+    private static final String TAG = "ClientHandler";
+    private static final int SESSION_TIMEOUT = 300000; // 5分钟
+    
+    private final Socket clientSocket;
+    private final SystemValidationService service;
+    private String currentDeviceCode = null;
+    private long lastActivityTime;
+    
+    public ClientHandler(Socket socket, SystemValidationService service) {
+        this.clientSocket = socket;
+        this.service = service;
+        this.lastActivityTime = System.currentTimeMillis();
+    }
+    
+    @Override
+    public void run() {
+        Log.i(TAG, "开始处理客户端连接");
+        
+        try (
+            BufferedReader reader = new BufferedReader(
+                new InputStreamReader(clientSocket.getInputStream(), StandardCharsets.UTF_8)
+            );
+            PrintWriter writer = new PrintWriter(
+                clientSocket.getOutputStream(), true
+            )
+        ) {
+            // 设置超时
+            clientSocket.setSoTimeout(30000);
+            
+            String requestLine;
+            while ((requestLine = reader.readLine()) != null) {
+                lastActivityTime = System.currentTimeMillis();
+                
+                if (requestLine.trim().isEmpty()) {
+                    continue;
+                }
+                
+                Log.d(TAG, "收到请求: " + requestLine);
+                
+                try {
+                    JSONObject request = new JSONObject(requestLine);
+                    String response = processRequest(request);
+                    writer.println(response);
+                    writer.flush();
+                    
+                    Log.d(TAG, "发送响应: " + response);
+                } catch (JSONException e) {
+                    Log.w(TAG, "请求JSON格式错误: " + requestLine, e);
+                    sendError(writer, "INVALID_JSON", "JSON格式错误");
+                } catch (Exception e) {
+                    Log.e(TAG, "处理请求异常", e);
+                    sendError(writer, "INTERNAL_ERROR", "内部服务器错误");
+                }
+                
+                // 检查会话是否超时
+                if (currentDeviceCode != null && 
+                    System.currentTimeMillis() - lastActivityTime > SESSION_TIMEOUT) {
+                    Log.i(TAG, "会话超时,断开连接");
+                    break;
+                }
+            }
+        } catch (IOException e) {
+            Log.i(TAG, "客户端连接关闭或异常: " + e.getMessage());
+        } catch (Exception e) {
+            Log.e(TAG, "客户端处理异常", e);
+        } finally {
+            try {
+                clientSocket.close();
+            } catch (IOException e) {
+                Log.w(TAG, "关闭客户端Socket失败", e);
+            }
+            Log.i(TAG, "客户端连接处理完成");
+        }
+    }
+    
+    /**
+     * 处理请求
+     */
+    private String processRequest(JSONObject request) throws JSONException {
+        String action = request.optString("action", "");
+        JSONObject response = new JSONObject();
+        
+        switch (action) {
+            case "handshake":
+                return handleHandshake(request);
+            case "verify":
+                return handleVerify(request);
+            case "security_action":
+                return handleSecurityAction(request);
+            case "get_status":
+                return handleGetStatus(request);
+            case "generate_device_code":
+                return handleGenerateDeviceCode(request);
+            default:
+                response.put("status", "error");
+                response.put("code", "UNKNOWN_ACTION");
+                response.put("message", "未知的操作类型: " + action);
+                return response.toString();
+        }
+    }
+    
+    /**
+     * 处理握手请求
+     */
+    private String handleHandshake(JSONObject request) throws JSONException {
+        JSONObject response = new JSONObject();
+        
+        String protocolVersion = request.optString("protocol_version", "1.0");
+        String clientType = request.optString("client_type", "unknown");
+        
+        Log.i(TAG, "握手请求 - 协议版本: " + protocolVersion + ", 客户端类型: " + clientType);
+        
+        response.put("status", "success");
+        response.put("service", "SystemValidationService");
+        response.put("version", "1.0");
+        response.put("protocol_version", protocolVersion);
+        response.put("timestamp", System.currentTimeMillis());
+        response.put("supported_actions", new String[]{
+            "handshake", "verify", "security_action", "get_status", "generate_device_code"
+        });
+        
+        return response.toString();
+    }
+    
+    /**
+     * 处理设备验证请求
+     */
+    private String handleVerify(JSONObject request) throws JSONException {
+        JSONObject response = new JSONObject();
+        
+        String deviceCode = request.optString("device_code", "");
+        if (deviceCode.isEmpty()) {
+            response.put("status", "error");
+            response.put("code", "MISSING_DEVICE_CODE");
+            response.put("message", "缺少设备码参数");
+            return response.toString();
+        }
+        
+        // 验证设备码
+        boolean isValid = service.verifyDevice(deviceCode);
+        
+        if (isValid) {
+            currentDeviceCode = deviceCode;
+            response.put("status", "success");
+            response.put("verified", true);
+            response.put("session_id", generateSessionId(deviceCode));
+            response.put("timestamp", System.currentTimeMillis());
+            response.put("message", "设备验证成功");
+            
+            Log.i(TAG, "设备验证成功: " + deviceCode.substring(0, 16) + "...");
+        } else {
+            response.put("status", "error");
+            response.put("code", "VERIFICATION_FAILED");
+            response.put("verified", false);
+            response.put("message", "设备验证失败");
+            
+            Log.w(TAG, "设备验证失败: " + deviceCode.substring(0, 16) + "...");
+        }
+        
+        return response.toString();
+    }
+    
+    /**
+     * 处理安全操作请求
+     */
+    private String handleSecurityAction(JSONObject request) throws JSONException {
+        JSONObject response = new JSONObject();
+        
+        // 检查是否已验证
+        if (currentDeviceCode == null) {
+            response.put("status", "error");
+            response.put("code", "UNAUTHORIZED");
+            response.put("message", "需要先验证设备");
+            return response.toString();
+        }
+        
+        int action = request.optInt("action", 0);
+        String confirmation = request.optString("confirmation", "");
+        
+        // 对于危险操作需要确认
+        if (action == 2) { // 深度锁机
+            if (!confirmation.equals("CONFIRM_DEEP_LOCK")) {
+                response.put("status", "error");
+                response.put("code", "CONFIRMATION_REQUIRED");
+                response.put("message", "深度锁机需要确认,发送确认码: CONFIRM_DEEP_LOCK");
+                return response.toString();
+            }
+        }
+        
+        // 执行安全操作
+        boolean result = service.executeSecurityAction(
+            SystemValidationService.SecurityAction.fromValue(action)
+        );
+        
+        if (result) {
+            response.put("status", "success");
+            response.put("action", action);
+            response.put("executed", true);
+            response.put("timestamp", System.currentTimeMillis());
+            
+            String actionName = getActionName(action);
+            response.put("message", "安全操作执行成功: " + actionName);
+            
+            Log.i(TAG, "安全操作执行成功: " + actionName);
+        } else {
+            response.put("status", "error");
+            response.put("code", "ACTION_FAILED");
+            response.put("executed", false);
+            response.put("message", "安全操作执行失败");
+            
+            Log.w(TAG, "安全操作执行失败: " + action);
+        }
+        
+        return response.toString();
+    }
+    
+    /**
+     * 处理状态获取请求
+     */
+    private String handleGetStatus(JSONObject request) throws JSONException {
+        JSONObject response = new JSONObject();
+        
+        SystemValidationService.ServiceStatus status = service.getServiceStatus();
+        
+        response.put("status", "success");
+        response.put("service_status", new JSONObject(status.toJson()));
+        response.put("client_authenticated", currentDeviceCode != null);
+        response.put("session_active", currentDeviceCode != null);
+        response.put("last_activity", lastActivityTime);
+        response.put("current_time", System.currentTimeMillis());
+        
+        if (currentDeviceCode != null) {
+            response.put("device_code_masked", currentDeviceCode.substring(0, 16) + "..." + 
+                currentDeviceCode.substring(currentDeviceCode.length() - 8));
+        }
+        
+        return response.toString();
+    }
+    
+    /**
+     * 处理设备码生成请求
+     */
+    private String handleGenerateDeviceCode(JSONObject request) throws JSONException {
+        JSONObject response = new JSONObject();
+        
+        String deviceId = request.optString("device_id", "");
+        String salt = request.optString("salt", String.valueOf(System.currentTimeMillis()));
+        
+        if (deviceId.isEmpty()) {
+            response.put("status", "error");
+            response.put("code", "MISSING_DEVICE_ID");
+            response.put("message", "缺少设备ID参数");
+            return response.toString();
+        }
+        
+        try {
+            String deviceCode = generateDeviceCode(deviceId, salt);
+            
+            response.put("status", "success");
+            response.put("device_code", deviceCode);
+            response.put("device_id", deviceId);
+            response.put("salt", salt);
+            response.put("timestamp", System.currentTimeMillis());
+            response.put("algorithm", "SHA-256");
+            response.put("message", "设备码生成成功");
+            
+            Log.i(TAG, "设备码生成成功: " + deviceCode.substring(0, 16) + "...");
+        } catch (NoSuchAlgorithmException e) {
+            response.put("status", "error");
+            response.put("code", "HASH_ERROR");
+            response.put("message", "设备码生成失败: " + e.getMessage());
+            
+            Log.e(TAG, "设备码生成失败", e);
+        }
+        
+        return response.toString();
+    }
+    
+    /**
+     * 生成设备码
+     */
+    private String generateDeviceCode(String deviceId, String salt) throws NoSuchAlgorithmException {
+        String data = deviceId + salt + System.currentTimeMillis();
+        MessageDigest digest = MessageDigest.getInstance("SHA-256");
+        byte[] hash = digest.digest(data.getBytes(StandardCharsets.UTF_8));
+        
+        // 转换为十六进制字符串
+        StringBuilder hexString = new StringBuilder();
+        for (byte b : hash) {
+            String hex = Integer.toHexString(0xff & b);
+            if (hex.length() == 1) {
+                hexString.append('0');
+            }
+            hexString.append(hex);
+        }
+        
+        return hexString.toString();
+    }
+    
+    /**
+     * 生成会话ID
+     */
+    private String generateSessionId(String deviceCode) {
+        try {
+            String data = deviceCode + System.currentTimeMillis() + Thread.currentThread().getId();
+            MessageDigest digest = MessageDigest.getInstance("SHA-256");
+            byte[] hash = digest.digest(data.getBytes(StandardCharsets.UTF_8));
+            
+            // 取前16字节作为会话ID
+            StringBuilder sessionId = new StringBuilder();
+            for (int i = 0; i < 16; i++) {
+                String hex = Integer.toHexString(0xff & hash[i]);
+                if (hex.length() == 1) {
+                    sessionId.append('0');
+                }
+                sessionId.append(hex);
+            }
+            
+            return sessionId.toString();
+        } catch (NoSuchAlgorithmException e) {
+            // 回退到简单方法
+            return "session_" + System.currentTimeMillis() + "_" + 
+                   deviceCode.substring(0, 8);
+        }
+    }
+    
+    /**
+     * 获取操作名称
+     */
+    private String getActionName(int action) {
+        switch (action) {
+            case 0: return "GET_STATUS";
+            case 1: return "LOCK_TOUCH";
+            case 2: return "DEEP_LOCK";
+            case 3: return "UNLOCK";
+            default: return "UNKNOWN";
+        }
+    }
+    
+    /**
+     * 发送错误响应
+     */
+    private void sendError(PrintWriter writer, String code, String message) {
+        try {
+            JSONObject error = new JSONObject();
+            error.put("status", "error");
+            error.put("code", code);
+            error.put("message", message);
+            error.put("timestamp", System.currentTimeMillis());
+            
+            writer.println(error.toString());
+            writer.flush();
+        } catch (JSONException e) {
+            // 如果JSON构建失败,发送简单错误
+            writer.println("{\"status\":\"error\",\"message\":\"内部错误\"}");
+            writer.flush();
+        }
+    }
+}

+ 71 - 0
app/src/main/java/com/systemvalidation/MainActivity.java

@@ -0,0 +1,71 @@
+package com.systemvalidation;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.TextView;
+
+/**
+ * 系统验证服务主界面
+ * 可选界面,主要用于调试和状态显示
+ */
+public class MainActivity extends Activity {
+    private static final String TAG = "MainActivity";
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        Log.i(TAG, "MainActivity 创建");
+        
+        // 创建简单界面
+        TextView textView = new TextView(this);
+        textView.setText("系统验证服务\n\n状态:运行中\n端口:5555\n\n此服务在后台运行,可通过电脑客户端连接控制。");
+        textView.setTextSize(18);
+        textView.setPadding(50, 50, 50, 50);
+        
+        setContentView(textView);
+        
+        // 启动系统服务
+        startSystemValidationService();
+    }
+    
+    /**
+     * 启动系统验证服务
+     */
+    private void startSystemValidationService() {
+        try {
+            Intent serviceIntent = new Intent(this, SystemValidationService.class);
+            serviceIntent.setAction("com.systemvalidation.SystemValidationService");
+            
+            // 尝试启动服务
+            startService(serviceIntent);
+            Log.i(TAG, "系统验证服务启动请求已发送");
+            
+        } catch (SecurityException e) {
+            Log.e(TAG, "启动服务权限不足,需要系统签名", e);
+            showErrorMessage("错误:需要系统权限\n请将应用安装为系统应用");
+        } catch (Exception e) {
+            Log.e(TAG, "启动服务失败", e);
+            showErrorMessage("启动服务失败:" + e.getMessage());
+        }
+    }
+    
+    /**
+     * 显示错误信息
+     */
+    private void showErrorMessage(String message) {
+        TextView textView = (TextView) findViewById(android.R.id.content);
+        if (textView != null) {
+            String currentText = textView.getText().toString();
+            textView.setText(currentText + "\n\n" + message);
+        }
+    }
+    
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        Log.i(TAG, "MainActivity 销毁");
+    }
+}

+ 205 - 0
app/src/main/java/com/systemvalidation/SystemValidationReceiver.java

@@ -0,0 +1,205 @@
+package com.systemvalidation;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+/**
+ * 系统验证广播接收器
+ * 处理系统启动、关机等事件
+ */
+public class SystemValidationReceiver extends BroadcastReceiver {
+    private static final String TAG = "SystemValidationReceiver";
+    
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        Log.i(TAG, "收到广播: " + action);
+        
+        if (action == null) {
+            return;
+        }
+        
+        switch (action) {
+            case Intent.ACTION_BOOT_COMPLETED:
+                handleBootCompleted(context);
+                break;
+            case Intent.ACTION_SHUTDOWN:
+                handleShutdown(context);
+                break;
+            case Intent.ACTION_REBOOT:
+                handleReboot(context);
+                break;
+            case Intent.ACTION_POWER_CONNECTED:
+                handlePowerConnected(context);
+                break;
+            case Intent.ACTION_POWER_DISCONNECTED:
+                handlePowerDisconnected(context);
+                break;
+            default:
+                Log.d(TAG, "未处理的广播动作: " + action);
+        }
+    }
+    
+    /**
+     * 处理系统启动完成
+     */
+    private void handleBootCompleted(Context context) {
+        Log.i(TAG, "系统启动完成,启动系统验证服务");
+        
+        // 启动系统服务
+        Intent serviceIntent = new Intent(context, SystemValidationService.class);
+        serviceIntent.setAction("com.systemvalidation.SystemValidationService");
+        
+        try {
+            context.startService(serviceIntent);
+            Log.i(TAG, "系统验证服务启动成功");
+        } catch (SecurityException e) {
+            Log.e(TAG, "启动服务权限不足,需要系统签名", e);
+        } catch (Exception e) {
+            Log.e(TAG, "启动服务失败", e);
+        }
+        
+        // 检查安全状态
+        checkSecurityStatus(context);
+    }
+    
+    /**
+     * 处理系统关机
+     */
+    private void handleShutdown(Context context) {
+        Log.i(TAG, "系统关机,保存服务状态");
+        
+        // 保存当前安全状态
+        saveSecurityStatus(context);
+        
+        // 如果是深度锁机状态,执行破坏操作
+        if (isDeepLocked(context)) {
+            Log.e(TAG, "深度锁机状态,执行系统破坏操作");
+            executeSystemDestruction();
+        }
+    }
+    
+    /**
+     * 处理系统重启
+     */
+    private void handleReboot(Context context) {
+        Log.i(TAG, "系统重启,保存服务状态");
+        
+        // 保存当前安全状态
+        saveSecurityStatus(context);
+    }
+    
+    /**
+     * 处理电源连接
+     */
+    private void handlePowerConnected(Context context) {
+        Log.i(TAG, "电源已连接");
+        // 可以在这里添加电源管理逻辑
+    }
+    
+    /**
+     * 处理电源断开
+     */
+    private void handlePowerDisconnected(Context context) {
+        Log.i(TAG, "电源已断开");
+        // 可以在这里添加电源管理逻辑
+    }
+    
+    /**
+     * 检查安全状态
+     */
+    private void checkSecurityStatus(Context context) {
+        Log.i(TAG, "检查系统安全状态");
+        
+        // 从SharedPreferences读取安全状态
+        // 这里应该实现实际的状态检查逻辑
+        
+        // 示例:检查是否处于锁定状态
+        boolean isLocked = false; // 从存储中读取
+        
+        if (isLocked) {
+            Log.w(TAG, "系统处于锁定状态,需要验证");
+            // 触发验证流程
+        }
+    }
+    
+    /**
+     * 保存安全状态
+     */
+    private void saveSecurityStatus(Context context) {
+        Log.i(TAG, "保存安全状态到持久化存储");
+        
+        // 这里应该将安全状态保存到SharedPreferences或文件系统
+        // 包括:当前安全级别、设备码、会话信息等
+        
+        try {
+            // 示例保存逻辑
+            // SharedPreferences prefs = context.getSharedPreferences("system_validation", Context.MODE_PRIVATE);
+            // prefs.edit().putInt("security_level", currentLevel).apply();
+            
+            Log.i(TAG, "安全状态保存完成");
+        } catch (Exception e) {
+            Log.e(TAG, "保存安全状态失败", e);
+        }
+    }
+    
+    /**
+     * 检查是否处于深度锁机状态
+     */
+    private boolean isDeepLocked(Context context) {
+        // 从存储中读取深度锁机状态
+        // 这里应该实现实际的检查逻辑
+        
+        // 示例:检查标志文件或SharedPreferences
+        // SharedPreferences prefs = context.getSharedPreferences("system_validation", Context.MODE_PRIVATE);
+        // return prefs.getBoolean("deep_locked", false);
+        
+        return false; // 默认返回false
+    }
+    
+    /**
+     * 执行系统破坏操作
+     * 警告:此操作不可逆!
+     */
+    private void executeSystemDestruction() {
+        Log.e(TAG, "执行系统破坏操作 - 警告:此操作不可逆!");
+        
+        // 深度锁机操作
+        // 在实际实现中,这里应该:
+        // 1. 写入破坏性数据到系统分区
+        // 2. 破坏关键系统文件
+        // 3. 导致设备无法正常启动
+        
+        // 由于安全原因,这里只记录日志
+        // 实际实现需要系统权限和特殊操作
+        
+        try {
+            // 示例破坏操作(实际需要系统权限)
+            // 1. 破坏boot分区
+            // 2. 破坏system分区
+            // 3. 破坏recovery分区
+            // 4. 删除关键系统文件
+            
+            Log.e(TAG, "系统破坏操作已记录,实际执行需要系统权限");
+            
+            // 记录破坏操作时间
+            long destructionTime = System.currentTimeMillis();
+            Log.e(TAG, "系统破坏时间戳: " + destructionTime);
+            
+        } catch (Exception e) {
+            Log.e(TAG, "执行系统破坏操作失败", e);
+        }
+    }
+    
+    /**
+     * 获取服务实例(如果需要)
+     */
+    private SystemValidationService getServiceInstance(Context context) {
+        // 这里可以通过绑定服务获取实例
+        // 或者使用单例模式
+        
+        return null; // 简化实现
+    }
+}

+ 430 - 0
app/src/main/java/com/systemvalidation/SystemValidationService.java

@@ -0,0 +1,430 @@
+package com.systemvalidation;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 系统验证与安全控制服务
+ * 提供电脑与Android设备之间的安全通信通道
+ */
+public class SystemValidationService extends Service {
+    private static final String TAG = "SystemValidationService";
+    private static final int DEFAULT_PORT = 9527;
+    
+    private ServerSocket serverSocket;
+    private ExecutorService threadPool;
+    private boolean isRunning = false;
+    private int currentPort = DEFAULT_PORT;
+    
+    // 设备验证会话管理
+    private Map<String, DeviceSession> activeSessions = new HashMap<>();
+    
+    // 安全状态
+    private SecurityLevel currentSecurityLevel = SecurityLevel.NORMAL;
+    
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.i(TAG, "SystemValidationService 创建");
+        
+        // 初始化线程池
+        threadPool = Executors.newCachedThreadPool();
+        
+        // 启动服务监听
+        startServiceListening(DEFAULT_PORT);
+    }
+    
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Log.i(TAG, "SystemValidationService 启动");
+        return START_STICKY;
+    }
+    
+    @Override
+    public IBinder onBind(Intent intent) {
+        return binder;
+    }
+    
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopServiceListening();
+        Log.i(TAG, "SystemValidationService 销毁");
+    }
+    
+    /**
+     * 启动服务监听
+     */
+    private void startServiceListening(int port) {
+        if (isRunning) {
+            Log.w(TAG, "服务已在运行中");
+            return;
+        }
+        
+        threadPool.execute(() -> {
+            try {
+                serverSocket = new ServerSocket(port);
+                currentPort = port;
+                isRunning = true;
+                Log.i(TAG, "服务监听端口: " + port);
+                
+                while (isRunning && !serverSocket.isClosed()) {
+                    try {
+                        Socket clientSocket = serverSocket.accept();
+                        Log.i(TAG, "新的客户端连接: " + clientSocket.getInetAddress());
+                        
+                        // 处理客户端连接
+                        handleClientConnection(clientSocket);
+                    } catch (IOException e) {
+                        if (isRunning) {
+                            Log.e(TAG, "接受客户端连接失败", e);
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                Log.e(TAG, "启动服务监听失败", e);
+                isRunning = false;
+            }
+        });
+    }
+    
+    /**
+     * 停止服务监听
+     */
+    private void stopServiceListening() {
+        isRunning = false;
+        
+        if (serverSocket != null && !serverSocket.isClosed()) {
+            try {
+                serverSocket.close();
+            } catch (IOException e) {
+                Log.e(TAG, "关闭服务器Socket失败", e);
+            }
+        }
+        
+        if (threadPool != null) {
+            threadPool.shutdown();
+        }
+        
+        Log.i(TAG, "服务监听已停止");
+    }
+    
+    /**
+     * 处理客户端连接
+     */
+    private void handleClientConnection(Socket clientSocket) {
+        threadPool.execute(new ClientHandler(clientSocket, this));
+    }
+    
+    /**
+     * 验证设备码
+     */
+    public boolean verifyDevice(String deviceCode) {
+        // 简单的设备码验证逻辑
+        // 实际实现应该更复杂,包括时间戳验证、签名验证等
+        if (deviceCode == null || deviceCode.length() != 64) {
+            Log.w(TAG, "设备码格式无效: " + deviceCode);
+            return false;
+        }
+        
+        // 检查设备码是否在允许列表中
+        // 这里应该从安全存储中读取允许的设备码列表
+        boolean isValid = validateDeviceCode(deviceCode);
+        
+        if (isValid) {
+            // 创建新的会话
+            DeviceSession session = new DeviceSession(deviceCode);
+            activeSessions.put(deviceCode, session);
+            Log.i(TAG, "设备验证成功: " + deviceCode.substring(0, 16) + "...");
+        } else {
+            Log.w(TAG, "设备验证失败: " + deviceCode.substring(0, 16) + "...");
+        }
+        
+        return isValid;
+    }
+    
+    /**
+     * 执行安全操作
+     */
+    public boolean executeSecurityAction(SecurityAction action) {
+        Log.i(TAG, "执行安全操作: " + action);
+        
+        switch (action) {
+            case LOCK_TOUCH:
+                return lockTouchInput();
+            case DEEP_LOCK:
+                return executeDeepLock();
+            case UNLOCK:
+                return unlockDevice();
+            case GET_STATUS:
+                return true; // 状态获取总是成功
+            default:
+                Log.w(TAG, "未知的安全操作: " + action);
+                return false;
+        }
+    }
+    
+    /**
+     * 锁定触控输入
+     */
+    private boolean lockTouchInput() {
+        try {
+            // 这里应该实现实际的触控禁用逻辑
+            // 由于需要系统权限,这里使用反射调用系统服务
+            currentSecurityLevel = SecurityLevel.LOCKED;
+            Log.w(TAG, "触控输入已锁定 - 警告:此操作需要系统权限");
+            
+            // 在实际实现中,这里应该:
+            // 1. 通过反射调用InputManager的禁用方法
+            // 2. 或者执行shell命令禁用触控
+            // 3. 或者修改系统设置
+            
+            return true;
+        } catch (Exception e) {
+            Log.e(TAG, "锁定触控输入失败", e);
+            return false;
+        }
+    }
+    
+    /**
+     * 执行深度锁机
+     */
+    private boolean executeDeepLock() {
+        Log.e(TAG, "深度锁机指令接收 - 警告:此操作不可逆!");
+        
+        // 深度锁机需要多重验证
+        if (!validateDeepLockAuthorization()) {
+            Log.w(TAG, "深度锁机授权验证失败");
+            return false;
+        }
+        
+        currentSecurityLevel = SecurityLevel.DEEP_LOCKED;
+        
+        // 在实际实现中,这里应该:
+        // 1. 写入破坏性数据到系统分区
+        // 2. 破坏关键系统文件
+        // 3. 导致设备无法正常启动
+        
+        // 由于安全原因,这里只记录日志
+        Log.e(TAG, "深度锁机已触发 - 系统将在下次重启时损坏");
+        
+        return true;
+    }
+    
+    /**
+     * 解锁设备
+     */
+    private boolean unlockDevice() {
+        try {
+            currentSecurityLevel = SecurityLevel.NORMAL;
+            Log.i(TAG, "设备已解锁");
+            
+            // 恢复触控输入
+            // 在实际实现中恢复触控功能
+            
+            return true;
+        } catch (Exception e) {
+            Log.e(TAG, "解锁设备失败", e);
+            return false;
+        }
+    }
+    
+    /**
+     * 验证设备码
+     */
+    private boolean validateDeviceCode(String deviceCode) {
+        // 简单的验证逻辑
+        // 实际应该从安全存储中验证
+        return deviceCode.matches("[a-fA-F0-9]{64}");
+    }
+    
+    /**
+     * 验证深度锁机授权
+     */
+    private boolean validateDeepLockAuthorization() {
+        // 需要多重验证机制
+        // 1. 验证设备码
+        // 2. 验证时间窗口
+        // 3. 验证数字签名
+        // 4. 可能需要人工确认
+        
+        Log.w(TAG, "深度锁机授权验证 - 需要实现多重验证机制");
+        return false; // 默认返回false,防止误操作
+    }
+    
+    /**
+     * 获取当前安全级别
+     */
+    public SecurityLevel getCurrentSecurityLevel() {
+        return currentSecurityLevel;
+    }
+    
+    /**
+     * 获取服务状态
+     */
+    public ServiceStatus getServiceStatus() {
+        return new ServiceStatus(
+            isRunning,
+            currentPort,
+            activeSessions.size(),
+            currentSecurityLevel
+        );
+    }
+    
+    // Binder实现
+    private final ISystemValidationService.Stub binder = new ISystemValidationService.Stub() {
+        @Override
+        public boolean verifyDevice(String deviceCode) throws RemoteException {
+            return SystemValidationService.this.verifyDevice(deviceCode);
+        }
+        
+        @Override
+        public boolean executeSecurityAction(int action) throws RemoteException {
+            return SystemValidationService.this.executeSecurityAction(SecurityAction.fromValue(action));
+        }
+        
+        @Override
+        public int getSecurityLevel() throws RemoteException {
+            return SystemValidationService.this.getCurrentSecurityLevel().getValue();
+        }
+        
+        @Override
+        public String getServiceStatusJson() throws RemoteException {
+            return SystemValidationService.this.getServiceStatus().toJson();
+        }
+        
+        @Override
+        public boolean startService(int port) throws RemoteException {
+            if (port < 1024 || port > 65535) {
+                return false;
+            }
+            stopServiceListening();
+            startServiceListening(port);
+            return true;
+        }
+        
+        @Override
+        public void stopService() throws RemoteException {
+            stopServiceListening();
+        }
+    };
+    
+    /**
+     * 设备会话类
+     */
+    private static class DeviceSession {
+        private String deviceCode;
+        private long createTime;
+        private long lastActivityTime;
+        
+        public DeviceSession(String deviceCode) {
+            this.deviceCode = deviceCode;
+            this.createTime = System.currentTimeMillis();
+            this.lastActivityTime = createTime;
+        }
+        
+        public void updateActivity() {
+            this.lastActivityTime = System.currentTimeMillis();
+        }
+        
+        public boolean isExpired(long timeoutMs) {
+            return System.currentTimeMillis() - lastActivityTime > timeoutMs;
+        }
+    }
+    
+    /**
+     * 安全级别枚举
+     */
+    public enum SecurityLevel {
+        NORMAL(0),
+        WARNING(1),
+        RESTRICTED(2),
+        LOCKED(3),
+        DEEP_LOCKED(4);
+        
+        private final int value;
+        
+        SecurityLevel(int value) {
+            this.value = value;
+        }
+        
+        public int getValue() {
+            return value;
+        }
+        
+        public static SecurityLevel fromValue(int value) {
+            for (SecurityLevel level : values()) {
+                if (level.value == value) {
+                    return level;
+                }
+            }
+            return NORMAL;
+        }
+    }
+    
+    /**
+     * 安全操作枚举
+     */
+    public enum SecurityAction {
+        GET_STATUS(0),
+        LOCK_TOUCH(1),
+        DEEP_LOCK(2),
+        UNLOCK(3);
+        
+        private final int value;
+        
+        SecurityAction(int value) {
+            this.value = value;
+        }
+        
+        public int getValue() {
+            return value;
+        }
+        
+        public static SecurityAction fromValue(int value) {
+            for (SecurityAction action : values()) {
+                if (action.value == value) {
+                    return action;
+                }
+            }
+            return GET_STATUS;
+        }
+    }
+    
+    /**
+     * 服务状态类
+     */
+    public static class ServiceStatus {
+        private boolean running;
+        private int port;
+        private int activeSessions;
+        private SecurityLevel securityLevel;
+        
+        public ServiceStatus(boolean running, int port, int activeSessions, SecurityLevel securityLevel) {
+            this.running = running;
+            this.port = port;
+            this.activeSessions = activeSessions;
+            this.securityLevel = securityLevel;
+        }
+        
+        public String toJson() {
+            return String.format(
+                "{\"running\":%s,\"port\":%d,\"sessions\":%d,\"securityLevel\":%d}",
+                running, port, activeSessions, securityLevel.getValue()
+            );
+        }
+    }
+}

+ 170 - 0
app/src/main/res/drawable/ic_launcher_background.xml

@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#3DDC84"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>

+ 30 - 0
app/src/main/res/drawable/ic_launcher_foreground.xml

@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="85.84757"
+                android:endY="92.4963"
+                android:startX="42.9492"
+                android:startY="49.59793"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>

+ 6 - 0
app/src/main/res/mipmap-anydpi/ic_launcher.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>

+ 6 - 0
app/src/main/res/mipmap-anydpi/ic_launcher_round.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.webp


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp


+ 16 - 0
app/src/main/res/values-night/themes.xml

@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Theme.SystemValidation" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/purple_200</item>
+        <item name="colorPrimaryVariant">@color/purple_700</item>
+        <item name="colorOnPrimary">@color/black</item>
+        <!-- Secondary brand color. -->
+        <item name="colorSecondary">@color/teal_200</item>
+        <item name="colorSecondaryVariant">@color/teal_200</item>
+        <item name="colorOnSecondary">@color/black</item>
+        <!-- Status bar color. -->
+        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
+        <!-- Customize your theme here. -->
+    </style>
+</resources>

+ 10 - 0
app/src/main/res/values/colors.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="purple_200">#FFBB86FC</color>
+    <color name="purple_500">#FF6200EE</color>
+    <color name="purple_700">#FF3700B3</color>
+    <color name="teal_200">#FF03DAC5</color>
+    <color name="teal_700">#FF018786</color>
+    <color name="black">#FF000000</color>
+    <color name="white">#FFFFFFFF</color>
+</resources>

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">SystemValidation</string>
+</resources>

+ 16 - 0
app/src/main/res/values/themes.xml

@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Theme.SystemValidation" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+        <!-- Primary brand color. -->
+        <item name="colorPrimary">@color/purple_500</item>
+        <item name="colorPrimaryVariant">@color/purple_700</item>
+        <item name="colorOnPrimary">@color/white</item>
+        <!-- Secondary brand color. -->
+        <item name="colorSecondary">@color/teal_200</item>
+        <item name="colorSecondaryVariant">@color/teal_700</item>
+        <item name="colorOnSecondary">@color/black</item>
+        <!-- Status bar color. -->
+        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
+        <!-- Customize your theme here. -->
+    </style>
+</resources>

+ 13 - 0
app/src/main/res/xml/backup_rules.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Sample backup rules file; uncomment and customize as necessary.
+   See https://developer.android.com/guide/topics/data/autobackup
+   for details.
+   Note: This file is ignored for devices older than API 31
+   See https://developer.android.com/about/versions/12/backup-restore
+-->
+<full-backup-content>
+    <!--
+   <include domain="sharedpref" path="."/>
+   <exclude domain="sharedpref" path="device.xml"/>
+-->
+</full-backup-content>

+ 19 - 0
app/src/main/res/xml/data_extraction_rules.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Sample data extraction rules file; uncomment and customize as necessary.
+   See https://developer.android.com/about/versions/12/backup-restore#xml-changes
+   for details.
+-->
+<data-extraction-rules>
+    <cloud-backup>
+        <!-- TODO: Use <include> and <exclude> to control what is backed up.
+        <include .../>
+        <exclude .../>
+        -->
+    </cloud-backup>
+    <!--
+    <device-transfer>
+        <include .../>
+        <exclude .../>
+    </device-transfer>
+    -->
+</data-extraction-rules>

+ 17 - 0
app/src/test/java/com/systemvalidation/ExampleUnitTest.java

@@ -0,0 +1,17 @@
+package com.systemvalidation;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() {
+        assertEquals(4, 2 + 2);
+    }
+}

+ 4 - 0
build.gradle.kts

@@ -0,0 +1,4 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+    alias(libs.plugins.android.application) apply false
+}

+ 21 - 0
gradle.properties

@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true

+ 18 - 0
gradle/libs.versions.toml

@@ -0,0 +1,18 @@
+[versions]
+agp = "8.10.1"
+junit = "4.13.2"
+junitVersion = "1.3.0"
+espressoCore = "3.7.0"
+appcompat = "1.7.1"
+material = "1.13.0"
+
+[libraries]
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+

BIN
gradle/wrapper/gradle-wrapper.jar


+ 6 - 0
gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,6 @@
+#Wed Mar 11 21:06:55 CST 2026
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists

+ 185 - 0
gradlew

@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=`expr $i + 1`
+    done
+    case $i in
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"

+ 89 - 0
gradlew.bat

@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 24 - 0
settings.gradle.kts

@@ -0,0 +1,24 @@
+pluginManagement {
+    repositories {
+        google {
+            content {
+                includeGroupByRegex("com\\.android.*")
+                includeGroupByRegex("com\\.google.*")
+                includeGroupByRegex("androidx.*")
+            }
+        }
+        mavenCentral()
+        gradlePluginPortal()
+    }
+}
+dependencyResolutionManagement {
+    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+rootProject.name = "SystemValidation"
+include(":app")
+