How to click a button in settings using AccessibilityService?

I want to press a button in Android settings using AccessibilityService, like greenify, but I can not find a specific button. please help me.

MyAccessibilityService.java:

public class MyAccessibilityService extends AccessibilityService { private static final String TAG = MyAccessibilityService.class .getSimpleName(); @Override public void onAccessibilityEvent(AccessibilityEvent event) { Log.i(TAG, "ACC::onAccessibilityEvent: " + event.getEventType()); //TYPE_WINDOW_STATE_CHANGED = 32, if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event.getEventType()) { AccessibilityNodeInfo nodeInfo = event.getSource(); Log.i(TAG, "ACC::onAccessibilityEvent: nodeInfo=" + nodeInfo.getText()); List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId("com.android.settings:id/left_button"); for (AccessibilityNodeInfo node : list) { Log.i(TAG, "ACC::onAccessibilityEvent: " + event.getEventType() + " " + node); } 

EDIT:

Only when the type is TYPE_WINDOW_STATE_CHANGED, could I get a nodeInfo object.

+5
source share
2 answers

Open one Appinfo application with a force check close button:

 public class MyAccessibilityService extends AccessibilityService { private static final String TAG = MyAccessibilityService.class .getSimpleName(); @Override public void onAccessibilityEvent(AccessibilityEvent event) { Log.i(TAG, "ACC::onAccessibilityEvent: " + event.getEventType()); //TYPE_WINDOW_STATE_CHANGED == 32 if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event .getEventType()) { AccessibilityNodeInfo nodeInfo = event.getSource(); Log.i(TAG, "ACC::onAccessibilityEvent: nodeInfo=" + nodeInfo); if (nodeInfo == null) { return; } List<AccessibilityNodeInfo> list = nodeInfo .findAccessibilityNodeInfosByViewId("com.android.settings:id/left_button"); for (AccessibilityNodeInfo node : list) { Log.i(TAG, "ACC::onAccessibilityEvent: left_button " + node); node.performAction(AccessibilityNodeInfo.ACTION_CLICK); } list = nodeInfo .findAccessibilityNodeInfosByViewId("android:id/button1"); for (AccessibilityNodeInfo node : list) { Log.i(TAG, "ACC::onAccessibilityEvent: button1 " + node); node.performAction(AccessibilityNodeInfo.ACTION_CLICK); } } } @Override public void onServiceConnected() { Log.i(TAG, "ACC::onServiceConnected: "); } @Override public void onInterrupt() { // TODO Auto-generated method stub } } 
+12
source

The selected answer works on API 18 and above, because it passes to findAccessibilityNodeInfosByViewId, which was added to API 18. I ended up writing this class to support API 17 and below.

ResourcesCompat class finds resources identified with this activity, which in our case should be active in the Android settings. You can get the ComponentName property from the settings by calling this function when processing an accessibility event in the accessibility service.

  public static ComponentName getForegroundActivity(Context context) { ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1); ComponentName topActivity = taskInfo.get(0).topActivity; return topActivity; } 

A good place to call init(...) is in onAccessibilityEvent when you first handle the TYPE_WINDOW_STATE_CHANGED event like thecr0w .

 public class ResourcesCompat { private final static String RESOURCE_TYPE = "string"; private String mResourcesPackageName; private Resources mResources; /** * Find the resource file for a specific activity * * @param context * @param settingsPackageName * @param settingsClassName */ public void init(Context context, String settingsPackageName, String settingsClassName) { try { mResourcesPackageName = settingsPackageName; ComponentName settingsComponentName = new ComponentName(settingsPackageName, settingsPackageName + settingsClassName); mResources = context.getPackageManager().getResourcesForActivity(settingsComponentName); } catch (PackageManager.NameNotFoundException e) { } } /** * Return the localised string for the given resource name. * @param resourceName The name of the resource definition in strings.xml */ public String getString(String resourceName) { int resourceId = getIdentifier(resourceName); return resourceId > 0 ? mResources.getString(resourceId) : null; } /** * Return a resource identifier for the given resource name. * @param resourceName The name of the desired resource. * @return int The associated resource identifier. Returns 0 if no such resource was found. (0 is not a valid resource ID.) */ private int getIdentifier(String resourceName) { return mResources.getIdentifier(resourceName, RESOURCE_TYPE, mResourcesPackageName); } } 

Some manufacturers like to move classes and rename default lines (cough Samsung cough Xiomi cough). Therefore, make sure that you cover all cases and handle errors and exceptions.

Finally, find your opinion by name. here id can be "force_stop", for example

 private List<AccessibilityNodeInfo> findAccessibilityNodeInfosByName(AccessibilityNodeInfo source, String id) { String nodeText = mResourcesCompat.getString(id); if (nodeText != null) { return source.findAccessibilityNodeInfosByText(nodeText); } return null; } 
+2
source

Source: https://habr.com/ru/post/1205771/


All Articles