如何使用 AccessibilityService.getWindows() 获取可遍历的 AccessibilityNodeInfo? [英] How can I use AccessibilityService.getWindows() to obtain a traversable AccessibilityNodeInfo?

查看:66
本文介绍了如何使用 AccessibilityService.getWindows() 获取可遍历的 AccessibilityNodeInfo?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing an AccessibilityService for Android and, up to API level 20, I have been using the AccessibilityEvent.getSource() method to obtain a traversable AccessibilityNodeInfo when onAccessibilityEvent(AccessibilityEvent event) is triggered. Although the resulting AccessibilityNodeInfo does not always reflect the content of the screen, it is still possible to work with it.

从 API 级别 21 开始,新的 AccessibilityService.getWindows() 应该不仅能够更好地表示视图层次结构(即尊重 Z 排序),而且应该能够公开包含当前输入法 (IME) 中所有视图的节点.我想利用这一点,但我无法这样做,我不知道我到底做错了什么.顺便说一句,除了极少的 Java 文档之外,我一直无法找到有关如何执行此操作的任何更详细信息.

Starting on API level 21, the new AccessibilityService.getWindows() is supposed to be not only able to better represent the view hierarchy (i.e., Z-ordering is respected), but it is also supposed to be able to expose a node that includes all views in the current input method (IME). I would like to take advantage of this but I have not been able to do so and I do not know what exactly I am doing wrong. Incidentally, I have been unable to find any more detailed information on how to do this, other than the very minimal java docs.

我已经完成了以下工作:

I have already done the following:

  • 配置服务以检索窗口内容 (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() 执行以下操作:

where getNodesFromWindows() does the following:

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 级别 20 及以下使用 AccessibilityEvent.getSource() 时,此数组的大小始终接近屏幕上的视图数,但是当我使用 AccessibilityService.getWindows() 时 大小几乎总是 1(有时是 0),并且列表中唯一的 AccessibilityNodeInfo 的边界总是在屏幕之外.

after this, updateTargetLeafs() collects all clickable, enabled and visible nodes into a separate AccessibilityNodeInfo ArrayList so I can index and access them at will (see below). When using AccessibilityEvent.getSource() on API Level 20 and below, the size of this array is always close to the number of views on the screen, but when I use AccessibilityService.getWindows() the size is almost always 1 (sometimes 0), and the bounds of the only AccessibilityNodeInfo in the list are always outside of the screen.

添加遍历所有节点子节点的代码(其中 mNodesgetNodesFromWindows() 的输出):

Add the code for iterating through all nodes children (where mNodes is the output of 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!");
        ...

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

Odd, I know, but what am I doing wrong?

推荐答案

您可以使用 getChild() 方法访问 Windows 内容.在您的 onAccessibilityEvent(AccessibilityEvent event) 中,您可以执行以下操作.

You can get access of windows content using getChild() method. In your onAccessibilityEvent(AccessibilityEvent event) you can do like below.

@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
          }
}

这篇关于如何使用 AccessibilityService.getWindows() 获取可遍历的 AccessibilityNodeInfo?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆