我正在为Android编写AccessibilityService,在API级别达到20之前,我一直在使用AccessibilityEvent.getSource()方法来触发AccessibilityNodeInfo时获得可遍历的onAccessibilityEvent(AccessibilityEvent event)。尽管生成的AccessibilityNodeInfo并不总是反射(reflect)屏幕的内容,但是仍然可以使用它。

从API级别21开始,新的AccessibilityService.getWindows()不仅能够更好地表示 View 层次结构(即,遵循Z顺序),而且还应该能够公开包含所有 View 的节点。当前输入法(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);
                    }
    }
    

    其中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;
    }
    

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

    编辑:添加用于遍历所有节点子代的代码(其中mNodesgetNodesFromWindows()的输出):
            ...
            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!");
            ...
    

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

    最佳答案

    您可以使用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
              }
    }
    

    10-08 06:22