如何使用AccessibilityService.getWindows()获得可遍历的AccessibilityNodeInfo?

J-D*_*Doc 5 java android accessibility accessibilityservice android-5.0-lollipop

我正在AccessibilityService为Android 编写一个,直到API级别20,我一直在使用该AccessibilityEvent.getSource()方法来AccessibilityNodeInfoonAccessibilityEvent(AccessibilityEvent event)触发时获取可遍历的对象。尽管结果AccessibilityNodeInfo并不总是反映屏幕的内容,但是仍然可以使用它。

从API级别21开始,新AccessibilityService.getWindows()功能不仅能够更好地表示视图层次结构(即,遵循Z顺序),而且还应该能够公开包含当前视图中所有视图的节点。输入法(IME)。我想利用这一点,但我却没有这样做,我也不知道我到底在做什么错。顺便说一句,除了极少的Java文档,我无法找到有关该操作的更多详细信息。

我已经做了以下工作:

  • 已配置服务以检索窗口内容(android:canRetrieveWindowContent="true"
  • 添加flagRetrieveInteractiveWindows到服务标志

我的代码如下:

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
            ArrayList<AccessibilityNodeInfo> nodes = getNodesFromWindows();
                switch (event_type) {
                case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
                case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                //case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
                case AccessibilityEvent.TYPE_VIEW_FOCUSED:
                case AccessibilityEvent.TYPE_VIEW_SELECTED:
                case AccessibilityEvent.TYPE_VIEW_SCROLLED:
                //case AccessibilityEvent.TYPE_VIEW_CLICKED:
                    updateTargetLeafs(nodes);
                }
}
Run Code Online (Sandbox Code Playgroud)

其中getNodesFromWindows()执行以下操作:

private ArrayList<AccessibilityNodeInfo> getNodesFromWindows() {
    List<AccessibilityWindowInfo> windows = getWindows();
    ArrayList<AccessibilityNodeInfo> nodes =
            new ArrayList<AccessibilityNodeInfo>();
    if (windows.size() > 0) {
        for (AccessibilityWindowInfo window : windows) {
            nodes.add(window.getRoot());
        }
    }
    return nodes;
}
Run Code Online (Sandbox Code Playgroud)

之后,updateTargetLeafs()将所有可点击,已启用和可见的节点收集到一个单独的节点中,AccessibilityNodeInfo ArrayList以便我可以随意索引和访问它们(请参见下文)。AccessibilityEvent.getSource()在API Level 20及以下级别上使用时,此数组的大小始终接近屏幕上的视图数,但是当我使用时,该数组AccessibilityService.getWindows()的大小几乎始终为1(有时为0),并且AccessibilityNodeInfo列表中唯一的边界总是在屏幕之外。

编辑:添加用于遍历所有节点子节点的代码(mNodes的输出是getNodesFromWindows()):

        ...
        ArrayList<AccessibilityNodeInfo> theseleafs =
                    new ArrayList<AccessibilityNodeInfo>();
        AccessibilityNodeInfo thisnode;
        Queue<AccessibilityNodeInfo> q =
                new LinkedList<AccessibilityNodeInfo>();
        for (AccessibilityNodeInfo n : mNodes) {
            q.add(n);
        }
        while (!q.isEmpty()) {
            thisnode = q.poll();
            if (shouldIncludeNode(thisnode)) {
                //Add only if it fulfills all requirements!
                theseleafs.add(thisnode);
            }
            for (i=0; i<thisnode.getChildCount(); ++i) {
                AccessibilityNodeInfo n = thisnode.getChild(i);
                if (n != null) q.add(n); // Add only if not null!
            }
        };
        LogD("MyTag", theseleafs.size() + " leafs in this node!");
        ...
Run Code Online (Sandbox Code Playgroud)

奇怪,我知道,但是我做错了什么?

Vij*_*ede 5

您可以使用getChild()方法访问 Windows 内容。在onAccessibilityEvent(AccessibilityEvent event)你可以做如下。

@Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
          AccessibilityNodeInfo mSource = event.getSource();
          int child = mSource.getChildCount();
          // iterate through all child of parent view
          for (int i=0; i<child; i++){
            AccessibilityNodeInfo childNodeView = mParent.getChild(i);
            // Do something with this window content
          }
}
Run Code Online (Sandbox Code Playgroud)


小智 0

getNodesFromWindows() 仅返回根节点列表。您需要遍历其子节点以收集窗口中的所有节点。