我想在使用AccessibilityService的android设置中单击按钮,就像greenify一样,但我找不到具体的按钮。请帮帮我。
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);
}
编辑:
只有当type为TYPE_WINDOW_STATE_CHANGED时,我才能得到nodeInfo对象。
答案 0 :(得分:13)
打开一个应用程序的Appinfo,启用强制关闭按钮进行测试:
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
}
}
答案 1 :(得分:3)
所选答案适用于API 18及更高版本,因为它会在API 18中添加的findAccessibilityNodeInfosByViewId中继。 我最后编写了这个类来支持API 17及更低版本。
ResourcesCompat
类找到用给定的activty标识的资源,在我们的例子中应该是Android的Setting活动。在处理辅助功能服务中的辅助功能事件时,可以通过调用此函数来获取设置活动的ComponentName。
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;
}
当您第一次将TYPE_WINDOW_STATE_CHANGED事件视为thecr0w所述时,init(...)
就是onAccessibilityEvent
的好地方。
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);
}
}
有些制造商喜欢移动课程并重命名默认字符串(咳嗽三星咳嗽 Xiomi 咳嗽)所以请确保涵盖所有案例和处理错误和例外。
最后,按名称查找您的视图。在这里,id
可以是'force_stop',例如
private List<AccessibilityNodeInfo> findAccessibilityNodeInfosByName(AccessibilityNodeInfo source, String id) {
String nodeText = mResourcesCompat.getString(id);
if (nodeText != null) {
return source.findAccessibilityNodeInfosByText(nodeText);
}
return null;
}
答案 2 :(得分:0)
这是我用过的:
override fun onAccessibilityEvent(event: AccessibilityEvent) {
val eventPackageName = event.packageName
val className = event.className
val source: AccessibilityNodeInfo? = event.source
val targetAppPackageName=...
val targetViewId=...
val viewsToCheck = rootInActiveWindow?.findAccessibilityNodeInfosByViewId("$targetAppPackageName:id/targetViewId")?.getOrNull(0)
viewsToCheck?.performAction(AccessibilityNodeInfo.ACTION_CLICK)
...