我正在编写适用于Android的AccessibilityService,并且在API级别达到20之前,我一直在使用AccessibilityEvent.getSource()方法来触发onAccessibilityEvent(AccessibilityEvent event)时获得可遍历的AccessibilityNodeInfo.尽管生成的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);
}
}
其中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()时,此数组的大小始终接近屏幕上的视图数,但是当我使用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!");
...
奇怪,我知道,但是我做错了什么?
解决方法:
您可以使用getChild()方法访问Windows内容.
在您的onAccessibilityEvent(AccessibilityEvent事件)中,您可以执行以下操作.
@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
}
}