Я пишу 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!");
...
Странно, я знаю, но что я делаю не так?