Как я могу использовать AccessibilityService.getWindows() для получения проходимой AccessibilityNodeInfo?

Я пишу AccessibilityService для Android, и до уровня API 20 я использовал метод AccessibilityEvent.getSource() для получения проходного AccessibilityNodeInfo при срабатывании onAccessibilityEvent(AccessibilityEvent event). Хотя полученный AccessibilityNodeInfo не всегда отражает содержимое экрана, с ним все же можно работать.

Начиная с уровня API 21, новый AccessibilityService.getWindows() должен не только лучше представлять иерархию представлений (т. текущий метод ввода (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, чтобы я мог индексировать и получать к ним доступ по своему желанию (см. ниже). При использовании AccessibilityEvent.getSource() на уровне API 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!");
        ...

Странно, я знаю, но что я делаю не так?


person J-Doc    schedule 23.02.2015    source источник


Ответы (2)


Вы можете получить доступ к содержимому Windows, используя метод getChild(). В вашем 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
          }
}
person Vijay Vankhede    schedule 05.05.2015
comment
у меня есть одно сомнение. мы получаем все дочерние узлы, это нормально, но как получить источник всех дочерних узлов? Это возможно? через событие мы можем получить источник узла, который запускается каким-то событием. для дочерних узлов, как мы можем получить источник? @vsvankahede - person Vji; 18.06.2015
comment
Сначала получите родителя исходного узла с помощью getParent(). Затем найдите номер дочернего элемента родителя с помощью getChildCount(). Используйте цикл for и выполните итерацию по всем дочерним элементам и сохраните там ссылку на ArrayList‹AccessibilityNodeInfo›. Теперь вы можете делать с этим узлом специальных возможностей все, что захотите. - person Vijay Vankhede; 18.06.2015
comment
да, но как получить источник дочерних узлов? - person Vji; 18.06.2015
comment
Прочтите этот developer.android.com/reference/android /просмотр/доступность/ - person Vijay Vankhede; 24.06.2015
comment
что вы подразумеваете под «источником» дочерних узлов? В AccessibilityService вы получаете AccessibilityEvent, а когда вы вызываете getSource() для одного события, вы получаете AccessibilityNodeInfo объект. Итак, узел является источником, то есть источником события. - person Prasad Pawar; 14.12.2015
comment
@vsvankhede Я специально упомянул, что в настоящее время использую event.getSource() и что он работает. Это вообще не отвечает на вопрос, а именно... как получить информацию о доступности с помощью нового метода getWindows(), доступного в API уровня 21 и выше. - person J-Doc; 23.03.2016

getNodesFromWindows() возвращает только список корневых узлов. Вам нужно перебрать его дочерние элементы, чтобы собрать все узлы в окне.

person Phil Weaver    schedule 23.02.2015
comment
да, это именно то, что делает updateTargetLeafs(). Я обновил вопрос, чтобы показать это. - person J-Doc; 23.02.2015