你可以随时从无障碍服务中任意搜索可访问性视图层次结构!不过,我建议在某种类型的可访问性事件的上下文中进行搜索,这样可以确保有屏幕内容可遍历!在随机回调中这样做可能会出现问题。以下是一个合理的可访问性配置 XML 文件,可用于此类目的:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/accessibility_service_description"
android:accessibilityEventTypes="typeWindowContentChanged|typeWindowsChanged|typeWindowStateChanged"
android:accessibilityFlags="flagReportViewIds|flagIncludeNotImportantViews"
android:canRetrieveWindowContent="true"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="1000"
android:settingsActivity=".SettingsActivity"
/>
以下是针对其中一些字段的注释。
android:notificationTimeout="1000"
每秒只检索一次特定类型的辅助功能事件!对于所列出的事件,更低的设置会非常冗长。我们仅依赖此来调用回调并确保我们有节点。每秒一次针对这些目的是可以接受的。根据需要进行微调。
android:accessibilityEventTypes="typeWindowContentChanged|typeWindowsChanged|typeWindowStateChanged"
粗略地说,这是允许您捕获所有屏幕更改事件的事件子集。打开新窗口...扫描视图层次结构!
android:accessibilityFlags="flagReportViewIds|flagIncludeNotImportantViews"
标记包括不重要的视图会在AccessibilityNodeInfo层次结构中包含更多的视图。具体而言,许多布局视图等Android操作系统通常认为对辅助功能目的不必要。我喜欢包括这个,因为这也是一个可以由开发人员调整的属性,而Android开发人员在辅助功能方面常常无知。最好获取所有内容并自行排序!
好了,那么这就是您的服务配置!现在,其余部分相当容易。你要做的是递归遍历根节点的子节点,直到找到TextView节点。我下面设置了一个愚蠢的服务,它会在每次屏幕更新时找到第一个TextView节点(除非根据上述服务配置XML它们每秒出现超过一次),然后记录其屏幕坐标。
class MyAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent e) {
final AccessibilityNodeInfo textNodeInfo = findTextViewNode(getRootInActiveWindow());
if (textNodeInfo == null) return;
Rect rect = new Rect();
textNodeInfo.getBoundsInScreen(rect);
Log.i(A11yService.class.getSimpleName(), "The TextView Node: " + rect.toString());
}
public AccessibilityNodeInfo findTextViewNode(AccessibilityNodeInfo nodeInfo) {
if (nodeInfo == null) return null;
Log.v(A11yService.class.getSimpleName(), nodeInfo.toString());
if (nodeInfo.getClassName().toString().contains(TextView.class.getSimpleName())) {
return nodeInfo;
}
for (int i = 0; i < nodeInfo.getChildCount(); i++) {
AccessibilityNodeInfo result = findTextViewNode(nodeInfo.getChild(i));
if (result != null) return result;
}
return null;
}
@Override
public void onInterrupt() {}
}
你还可以寻找我构建的开源库
Accessibility Service Utilities,它可以让所有这些东西变得更加容易!
A11yNodeInfoMatcher
类是你想要的。