xiongzhu 1 年間 前
コミット
bd21fdc0f6

+ 18 - 1
app/build.gradle

@@ -6,6 +6,10 @@ android {
     namespace 'com.example.modifier'
     compileSdk 34
 
+    buildFeatures {
+        buildConfig = true
+    }
+
     defaultConfig {
         applicationId "com.example.modifier"
         minSdk 26
@@ -16,10 +20,23 @@ android {
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
 
+    signingConfigs {
+        release {
+            storeFile file('../release.keystore')
+            storePassword '123456'
+            keyAlias 'key'
+            keyPassword '123456'
+        }
+    }
+
     buildTypes {
         release {
             minifyEnabled false
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.release
+        }
+        debug {
+            signingConfig signingConfigs.release
         }
     }
     compileOptions {
@@ -47,7 +64,7 @@ dependencies {
     implementation(libs.socket.io.client) {
         exclude group: 'org.json', module: 'json'
     }
-    implementation (libs.socket.io.client) {
+    implementation(libs.socket.io.client) {
         exclude group: 'org.json', module: 'json'
     }
 }

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

@@ -3,6 +3,7 @@
     xmlns:tools="http://schemas.android.com/tools">
 
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application
         android:allowBackup="true"
         android:dataExtractionRules="@xml/data_extraction_rules"

+ 22 - 24
app/src/main/java/com/example/modifier/MainActivity.java

@@ -108,32 +108,30 @@ public class MainActivity extends AppCompatActivity {
             sendBroadcast(intent);
         });
 
-        checkRoot();
-        Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        startActivity(intent);
-    }
+        executor.execute(() -> {
+            if (Utils.hasRootAccess()) {
+                if (!Utils.isAccessibilityEnabled()) {
+                    if (!Utils.enableAccessibility()) {
+                        Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
+                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        startActivity(intent);
+                        handler.postDelayed(this::finish, 100);
+                    }
 
-    private void checkRoot() {
-        boolean rootAccess = false;
-        try {
-            String res = runAsRoot("echo 'imrooted'");
-            if (res.contains("imrooted")) {
-                rootAccess = true;
+                }
+            } else {
+                handler.post(() -> {
+                    new AlertDialog.Builder(this)
+                            .setTitle("No Root Access")
+                            .setMessage("Root access is required to run this app")
+                            .setCancelable(false)
+                            .setPositiveButton("Exit", (dialog, which) -> {
+                                finish();
+                            })
+                            .show();
+                });
             }
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        if (!rootAccess) {
-            new AlertDialog.Builder(this)
-                    .setTitle("No Root Access")
-                    .setMessage("Root access is required to run this app")
-                    .setCancelable(false)
-                    .setPositiveButton("Exit", (dialog, which) -> {
-                        finish();
-                    })
-                    .show();
-        }
+        });
     }
 
     private void onSave() {

+ 23 - 5
app/src/main/java/com/example/modifier/ModifierService.java

@@ -3,6 +3,7 @@ package com.example.modifier;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.Rect;
+import android.os.Build;
 import android.util.Log;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -10,7 +11,9 @@ import android.view.accessibility.AccessibilityNodeInfo;
 import org.json.JSONObject;
 
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.net.URISyntaxException;
+import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -26,6 +29,8 @@ public class ModifierService extends android.accessibilityservice.AccessibilityS
 
     private static final String TAG = "ModifierService";
 
+    public static final String NAME = BuildConfig.APPLICATION_ID + ".ModifierService";
+
     private ScheduledExecutorService mExecutor = new ScheduledThreadPoolExecutor(8);
 
     private Socket mSocket;
@@ -33,7 +38,9 @@ public class ModifierService extends android.accessibilityservice.AccessibilityS
     public ModifierService() {
         Log.i(TAG, "Creating ModifierService");
         try {
-            mSocket = IO.socket("http://192.168.6.215:3000");
+            IO.Options opts = new IO.Options();
+            opts.query = "device=" + Build.MANUFACTURER + " " + Build.MODEL;
+            mSocket = IO.socket("http://192.168.50.202:3000", opts);
             mSocket.on("message", this);
             mSocket.on(Socket.EVENT_CONNECT, args -> {
                 Log.i(TAG, "Connected to server");
@@ -48,7 +55,7 @@ public class ModifierService extends android.accessibilityservice.AccessibilityS
                     e.printStackTrace();
                 }
             });
-        } catch (URISyntaxException e) {
+        } catch (Exception e) {
             e.printStackTrace();
         }
     }
@@ -62,7 +69,6 @@ public class ModifierService extends android.accessibilityservice.AccessibilityS
 
     @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
-
     }
 
     @Override
@@ -87,7 +93,9 @@ public class ModifierService extends android.accessibilityservice.AccessibilityS
                         try {
                             Utils.runAsRoot(cmd);
 
+                            Log.i(TAG, "Command executed successfully, waiting for app to open...");
                             mExecutor.schedule(() -> {
+                                Log.i(TAG, "Getting root node...");
                                 AccessibilityNodeInfo root = getRootInActiveWindow();
                                 String packageName = root.getPackageName().toString();
                                 String appName = null;
@@ -96,10 +104,11 @@ public class ModifierService extends android.accessibilityservice.AccessibilityS
                                     ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
                                     appName = packageManager.getApplicationLabel(applicationInfo).toString();
                                 } catch (PackageManager.NameNotFoundException e) {
-                                    throw new RuntimeException(e);
+                                    e.printStackTrace();
                                 }
+                                Log.i(TAG, "App: " + appName + " (" + packageName + ")");
                                 traverseNode(root);
-                            }, 2, java.util.concurrent.TimeUnit.SECONDS);
+                            }, 1, java.util.concurrent.TimeUnit.SECONDS);
 
                         } catch (Exception e) {
                             e.printStackTrace();
@@ -122,6 +131,15 @@ public class ModifierService extends android.accessibilityservice.AccessibilityS
         node.getBoundsInScreen(rect);
         map.put("bounds", rect);
 
+        String name = node.getViewIdResourceName();
+
+        if ("Compose:Draft:Send".equals(name)) {
+            Log.i(TAG, "Found send button Node: class=" + node.getClassName() + ", text=" + node.getText() + ", name=" + name);
+//            node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
+        }
+
+        node.getViewIdResourceName();
+
         if (node.getChildCount() != 0) {
             List<Map<String, Object>> children = new ArrayList<>();
             for (int i = 0; i < node.getChildCount(); i++) {

+ 58 - 0
app/src/main/java/com/example/modifier/Utils.java

@@ -1,7 +1,14 @@
 package com.example.modifier;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.Context;
+import android.content.pm.ServiceInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.Log;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.appcompat.app.AlertDialog;
 
 import org.apache.commons.io.FileUtils;
 
@@ -9,6 +16,8 @@ import java.io.DataOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
 
 public class Utils {
     private static final String TAG = "Modifier";
@@ -53,4 +62,53 @@ public class Utils {
         outputFile.delete();
         return res;
     }
+
+    public static boolean isAccessibilityEnabled() {
+        Context context = getContext();
+        AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        List<AccessibilityServiceInfo> enabledServices = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+
+        for (AccessibilityServiceInfo enabledService : enabledServices) {
+            Log.i(TAG, "Enabled service: " + enabledService.getResolveInfo().serviceInfo.packageName + "/" + enabledService.getResolveInfo().serviceInfo.name);
+            ServiceInfo enabledServiceInfo = enabledService.getResolveInfo().serviceInfo;
+            if (enabledServiceInfo.packageName.equals(context.getPackageName()) && enabledServiceInfo.name.equals(ModifierService.NAME))
+                return true;
+        }
+
+        return false;
+    }
+
+    public static boolean hasRootAccess() {
+        boolean rootAccess = false;
+        try {
+            String res = runAsRoot("echo 'imrooted'");
+            if (res.contains("imrooted")) {
+                rootAccess = true;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return rootAccess;
+    }
+
+    public static boolean enableAccessibility() {
+        Context context = getContext();
+        AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        List<AccessibilityServiceInfo> enabledServices = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+
+        List<String> names = new ArrayList<>();
+        for (AccessibilityServiceInfo enabledService : enabledServices) {
+            names.add(enabledService.getResolveInfo().serviceInfo.packageName + "/" + enabledService.getResolveInfo().serviceInfo.name);
+        }
+        names.add(context.getPackageName() + "/" + ModifierService.NAME);
+
+        try {
+            runAsRoot("settings put secure enabled_accessibility_services " + TextUtils.join(":", names),
+                    "settings put secure accessibility_enabled 1");
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
 }

BIN
release.keystore