From ac74b52aed935a6220b08eb05fd15f48e6a5e42f Mon Sep 17 00:00:00 2001 From: Jens Date: Thu, 14 Dec 2023 00:15:59 +0100 Subject: [PATCH] Accessibility API --- app/src/apkFlavor/AndroidManifest.xml | 7 ++ app/src/fdroidFlavor/AndroidManifest.xml | 7 ++ app/src/googlePlayFlavor/AndroidManifest.xml | 7 ++ .../java/com/jens/automation2/Action.java | 8 ++ .../java/com/jens/automation2/Actions.java | 9 +++ .../jens/automation2/ActivityManageRule.java | 8 ++ .../jens/automation2/ActivityPermissions.java | 76 +++++++++++++++++++ .../automation2/MyAccessibilityService.java | 29 +++++++ app/src/main/res/values/strings.xml | 3 + 9 files changed, 154 insertions(+) create mode 100644 app/src/main/java/com/jens/automation2/MyAccessibilityService.java diff --git a/app/src/apkFlavor/AndroidManifest.xml b/app/src/apkFlavor/AndroidManifest.xml index 0188eca..6f843ef 100644 --- a/app/src/apkFlavor/AndroidManifest.xml +++ b/app/src/apkFlavor/AndroidManifest.xml @@ -261,6 +261,13 @@ android:exported="true" /> + + + + + + \ No newline at end of file diff --git a/app/src/fdroidFlavor/AndroidManifest.xml b/app/src/fdroidFlavor/AndroidManifest.xml index 1a7d25e..af39e62 100644 --- a/app/src/fdroidFlavor/AndroidManifest.xml +++ b/app/src/fdroidFlavor/AndroidManifest.xml @@ -246,6 +246,13 @@ android:exported="true" /> + + + + + + \ No newline at end of file diff --git a/app/src/googlePlayFlavor/AndroidManifest.xml b/app/src/googlePlayFlavor/AndroidManifest.xml index b4426bc..1c67849 100644 --- a/app/src/googlePlayFlavor/AndroidManifest.xml +++ b/app/src/googlePlayFlavor/AndroidManifest.xml @@ -245,6 +245,13 @@ android:exported="true" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/jens/automation2/Action.java b/app/src/main/java/com/jens/automation2/Action.java index d2694ae..2c3c359 100644 --- a/app/src/main/java/com/jens/automation2/Action.java +++ b/app/src/main/java/com/jens/automation2/Action.java @@ -56,6 +56,7 @@ public class Action startPhoneCall, stopPhoneCall, copyToClipboard, + takeScreenshot, sendTextMessage; public String getFullName(Context context) @@ -140,6 +141,9 @@ public class Action return context.getResources().getString(R.string.endPhoneCall); case copyToClipboard: return context.getResources().getString(R.string.copyTextToClipboard); + case takeScreenshot: + return context.getResources().getString(R.string.takeScreenshot); + default: return "Unknown"; } @@ -307,6 +311,10 @@ public class Action break; case copyToClipboard: returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.copyTextToClipboard)); + break; + case takeScreenshot: + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.takeScreenshot)); + break; default: returnString.append(action.toString()); } diff --git a/app/src/main/java/com/jens/automation2/Actions.java b/app/src/main/java/com/jens/automation2/Actions.java index 1603725..3021ce0 100644 --- a/app/src/main/java/com/jens/automation2/Actions.java +++ b/app/src/main/java/com/jens/automation2/Actions.java @@ -1,6 +1,7 @@ package com.jens.automation2; import android.Manifest; +import android.accessibilityservice.AccessibilityService; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.NotificationManager; @@ -2339,4 +2340,12 @@ public class Actions clipboard.setPrimaryClip(clip); } } + + public static void takeScreenshot() + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + { + MyAccessibilityService.getInstance().performGlobalAction(AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/jens/automation2/ActivityManageRule.java b/app/src/main/java/com/jens/automation2/ActivityManageRule.java index 32fda94..b012e1a 100644 --- a/app/src/main/java/com/jens/automation2/ActivityManageRule.java +++ b/app/src/main/java/com/jens/automation2/ActivityManageRule.java @@ -2126,6 +2126,8 @@ public class ActivityManageRule extends Activity } else if(types[i].toString().equals(Action_Enum.copyToClipboard.toString())) items.add(new Item(typesLong[i].toString(), R.drawable.clipboard)); + else if(types[i].toString().equals(Action_Enum.takeScreenshot.toString())) + items.add(new Item(typesLong[i].toString(), R.drawable.clipboard)); else items.add(new Item(typesLong[i].toString(), R.drawable.placeholder)); } @@ -2352,6 +2354,12 @@ public class ActivityManageRule extends Activity Intent intent = new Intent(ActivityManageRule.this, ActivityManageActionCopyToClipboard.class); startActivityForResult(intent, requestCodeActionCopyTextToClipboardAdd); } + else if(Action.getActionTypesAsArray()[which].toString().equals(Action_Enum.takeScreenshot.toString())) + { + newAction.setAction(Action_Enum.takeScreenshot); + ruleToEdit.getActionSet().add(newAction); + refreshActionList(); + } } }); diff --git a/app/src/main/java/com/jens/automation2/ActivityPermissions.java b/app/src/main/java/com/jens/automation2/ActivityPermissions.java index f18c223..43a9c2d 100644 --- a/app/src/main/java/com/jens/automation2/ActivityPermissions.java +++ b/app/src/main/java/com/jens/automation2/ActivityPermissions.java @@ -18,6 +18,7 @@ import android.os.Bundle; import android.os.PowerManager; import android.provider.Settings; import android.text.Html; +import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; @@ -51,6 +52,7 @@ public class ActivityPermissions extends Activity private static final int requestCodeForPermissionsBatteryOptimization = 12048; private static final int requestCodeForPermissionNotificationAccessAndroid13 = 12049; private static final int requestCodeForPermissionsManageOverlay = 12050; + private static final int requestCodeForPermissionsAccessibility = 12051; protected String[] specificPermissionsToRequest = null; public static String intentExtraName = "permissionsToBeRequested"; @@ -305,6 +307,10 @@ public class ActivityPermissions extends Activity { return android.provider.Settings.canDrawOverlays(Miscellaneous.getAnyContext()); } + else if(s.equals(Manifest.permission.BIND_ACCESSIBILITY_SERVICE)) + { + return haveAccessibilityAccess(Miscellaneous.getAnyContext()); + } else { int res = context.checkCallingOrSelfPermission(s); @@ -323,11 +329,57 @@ public class ActivityPermissions extends Activity return active; } + public static boolean haveAccessibilityAccess(Context mContext) + { + int accessibilityEnabled = 0; + + final String service = mContext.getPackageName() + "/com.mytest.accessibility.MyAccessibilityService"; + + boolean accessibilityFound = false; + try + { + accessibilityEnabled = Settings.Secure.getInt(mContext.getApplicationContext().getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED); + Log.v(TAG, "accessibilityEnabled = " + accessibilityEnabled); + } + catch (Settings.SettingNotFoundException e) + { + Log.e(TAG, "Error finding setting, default accessibility to not found: " + e.getMessage()); + } + TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':'); + + if (accessibilityEnabled == 1) { + String settingValue = Settings.Secure.getString(mContext + .getApplicationContext().getContentResolver(), + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); + if (settingValue != null) { + TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; + splitter.setString(settingValue); + while (splitter.hasNext()) { + String accessabilityService = splitter.next(); + + if (accessabilityService.equalsIgnoreCase(service)) { + return true; + } + } + } + } + + return accessibilityFound; + } + public static void requestOverlay() { Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION); ActivityPermissions.getInstance().startActivityForResult(intent, requestCodeForPermissionsManageOverlay); } + + public static void requestBindAccessibilityService() + { + Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + ActivityPermissions.getInstance().startActivityForResult(intent, requestCodeForPermissionsAccessibility); + } + public static void requestDeviceAdmin() { if(!haveDeviceAdmin()) @@ -722,6 +774,8 @@ public class ActivityPermissions extends Activity case stopPhoneCall: addToArrayListUnique(Manifest.permission.ANSWER_PHONE_CALLS, requiredPermissions); break; + case takeScreenshot: + addToArrayListUnique(Manifest.permission.BIND_ACCESSIBILITY_SERVICE, requiredPermissions); default: break; } @@ -971,6 +1025,8 @@ public class ActivityPermissions extends Activity case Manifest.permission.QUERY_ALL_PACKAGES: usingElements.add(getResources().getString(R.string.queryAllPackages)); break; + case Manifest.permission.BIND_ACCESSIBILITY_SERVICE: + usingElements.add(getResources().getString(R.string.bindAccessibilityService)); } return usingElements; @@ -1026,6 +1082,10 @@ public class ActivityPermissions extends Activity if (requestCode == requestCodeForPermissionsManageOverlay) if(havePermission(Manifest.permission.SYSTEM_ALERT_WINDOW, ActivityPermissions.this)) requestPermissions(cachedPermissionsToRequest, true); + + if (requestCode == requestCodeForPermissionsAccessibility) + if(havePermission(Manifest.permission.BIND_ACCESSIBILITY_SERVICE, ActivityPermissions.this)) + requestPermissions(cachedPermissionsToRequest, true); } } @@ -1107,6 +1167,22 @@ public class ActivityPermissions extends Activity diag.show(); return; } + else if (s.equalsIgnoreCase(Manifest.permission.BIND_ACCESSIBILITY_SERVICE)) + { + AlertDialog diag = Miscellaneous.messageBox(getResources().getString(R.string.info), getResources().getString(R.string.accessibilityApiPermissionHint), ActivityPermissions.this); + diag.setOnDismissListener(new DialogInterface.OnDismissListener() + { + @Override + public void onDismiss(DialogInterface dialogInterface) + { + requiredPermissions.remove(s); + cachedPermissionsToRequest = requiredPermissions; + requestBindAccessibilityService(); + } + }); + diag.show(); + return; + } else if (s.equalsIgnoreCase(Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE)) { if(Build.VERSION.SDK_INT >= 33) diff --git a/app/src/main/java/com/jens/automation2/MyAccessibilityService.java b/app/src/main/java/com/jens/automation2/MyAccessibilityService.java new file mode 100644 index 0000000..922c91f --- /dev/null +++ b/app/src/main/java/com/jens/automation2/MyAccessibilityService.java @@ -0,0 +1,29 @@ +package com.jens.automation2; + +import android.accessibilityservice.AccessibilityService; +import android.view.accessibility.AccessibilityEvent; + +public class MyAccessibilityService extends AccessibilityService +{ + static MyAccessibilityService instance; + + public static MyAccessibilityService getInstance() + { + if(instance == null) + instance = new MyAccessibilityService(); + + return instance; + } + + @Override + public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) + { + + } + + @Override + public void onInterrupt() + { + + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c71f261..bfaa942 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -892,4 +892,7 @@ Method GET POST + Take screenshot + Bind to accessibility service + After clicking OK you\'ll be sent to a system dialog. Please select Automation there and allow "Allow accessibility API". \ No newline at end of file