我试图通过Accessibility服务在我的屏幕上获取TextView的X和Y位置来查找TextView,这可能吗?我发现的一切都需要您先触摸屏幕。以下是我获取节点信息的方法。
public class MyAccessibilityService extends AccessibilityService {
@TargetApi(16)
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
}
}
答案 0 :(得分:8)
您可以随时从辅助功能服务中随意搜索辅助功能视图层次结构!虽然我建议在某种类型的辅助功能事件的上下文中这样做,然后确保有遍历的屏幕内容!在随机回调中这样做充其量是挑剔的。以下是用于此目的的合理的辅助功能配置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"
/>
以下是对其中一些领域的一些评论。
机器人:notificationTimeout =&#34; 1000&#34;
每秒只检索一次给定类型的辅助功能事件!对于列出的事件,任何较低的设置都将是QUITE verbose。我们只依靠它来调用我们的回调并确保我们有节点。为了这些目的,每秒一次就是DAND DANDY。必要时调整。
机器人:accessibilityEventTypes =&#34; typeWindowContentChanged | typeWindowsChanged | typeWindowStateChanged&#34;
粗略地说,这是允许您捕获所有屏幕更改事件的事件子集。打开一个新窗口...扫描视图层次结构!
机器人:accessibilityFlags =&#34; flagReportViewIds | flagIncludeNotImportantViews&#34;
标记包括不重要的视图将在AccessibilityNodeInfo层次结构中包含更多视图。特别是许多布局视图,并且Android OS通常不会认为是可访问性目的所必需的。我喜欢将此选中,因为这也是开发人员可调整属性,而Android开发人员在可访问性方面是出了名的愚蠢。最好只取一切并自己整理!
好的,那么您的服务配置就是这样!现在,其余的很容易。您要做的是通过子节点子节点向下递归,直到找到TextView节点。我在下面设置了一个愚蠢的服务,它会在每个屏幕上发现第一个TextView节点更新(除非它们在给定上面的服务配置XML的情况下每秒多于一次),然后记录它的屏幕坐标。
class MyAccessibilityService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent e) {
//You can actually call getRootInActiveWindow() any time!
//Doing so here ensures that the screen is in a reasonable state
//and not in the middle of rendering or something else silly.
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) {
//I highly recommend leaving this line in! You never know when the screen content will
//invalidate a node you're about to work on, or when a parents child will suddenly be gone!
//Not doing this safety check is very dangerous!
if (nodeInfo == null) return null;
Log.v(A11yService.class.getSimpleName(), nodeInfo.toString());
//Notice that we're searching for the TextView's simple name!
//This allows us to find AppCompat versions of TextView as well
//as 3rd party devs well names subclasses... though with perhaps
//a few poorly named unintended stragglers!
if (nodeInfo.getClassName().toString().contains(TextView.class.getSimpleName())) {
return nodeInfo;
}
//Do other work!
for (int i = 0; i < nodeInfo.getChildCount(); i++) {
AccessibilityNodeInfo result = findTextViewNode(nodeInfo.getChild(i));
if (result != null) return result;
}
return null;
}
//Required for a valid Accessibility Service.
@Override
public void onInterrupt() {}
}
您还可以找到我使用Accessibility Service Utilities构建的开源库,这使得所有这些内容变得更加容易! A11yNodeInfoMatcher类是您想要的。