遍历AccessibilityService中的AccessibilityNodeInfos

Traverse AccessibilityNodeInfos in AccessibilityService

我目前使用 getRootInActiveWindow() 检索活动 window 的根节点。然后,我执行广度优先搜索以获取所有节点的列表。

我的问题: 如何遍历此节点列表以获得焦点顺序?此列表是否已根据节点的焦点顺序排序?是否有不同的检索焦点顺序的方法?

提前致谢。

最终,没有。你不能,关于这个的可访问性 api 文档非常具有误导性。

有人可能认为 AccessibilityNodeInfo 的 "focusSearch(int direction)" 函数是可行的方法。但是,最终它被打破了,如果你回到 Android 辅助功能 API 的内部,你最终会找到一个这样记录的函数:

Searches for the nearest view in the specified direction that can take the input focus.

COOL,正是我们想要的吧?稍等一下。这个函数调用了一个函数

AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId, mSourceNodeId, direction);

并且此函数记录如下:

Finds the accessibility focused {@link android.view.accessibility.AccessibilityNodeInfo}. The search is performed in the window whose id is specified and starts from the node whose accessibility id is specified.

令人失望的是,您还会发现此功能无法很好地完成这些工作(定向焦点搜索或定向可访问性焦点搜索)。

最终,当 TalkBack 中的某个元素由于元素的焦点而获得辅助功能焦点时,它实际上是在响应来自 OS 的实际焦点事件,而不是 TalkBack 在输入焦点上进行的任何计算订购。

为了做到这一点,您基本上必须自己实现 OS 中用于 Tab 排序的整个逻辑,系统本身必须执行的信息较少,因为系统具有真正的 android.widget.View 对象来处理,而不是伪造 AccessibilityNodeInfo 信息有限的对象。你能想出的任何方法都将非常脆弱,并且不能保证与系统实际做的一致。

您倾向于尝试广度优先遍历 "input focusable"(AccessibilityNodeInfofocusable 属性)是一个非常合理的解决方案。问题是,真正的系统 Tab Ordering 将是它的一个子集,它忽略了存在于不同 windows 等上的元素之类的东西。

说真的,打开 TalkBack 设置屏幕,打开 TalkBack,连接硬件键盘,疯狂使用 tab 和 shift tab 键,惊叹你怎么不能把焦点放在 "Settings"按钮。你的遍历函数会出错,因为 "Settings" 按钮是 focusable 但不知何故,你不能把焦点放在那里。为什么要深入研究一些我将忽略的严肃的 AOSP 废话,不,我不确定 AccessibilityServices 是否可以使用可以防止这种极端情况出现在您的理论算法中的信息。

总而言之,广度优先遍历在理论上是可行的,但是会有大量的极端情况,不,我不确定 AccessibilityServices 是否可以使用正确处理每个极端情况的信息。另外,值得注意的是,由于这个特殊问题,如果您希望解决方案在 4.4、5.0 和 7.0+ 设备上都是正确的,则必须针对不同的 OS 版本进行不同的计算。是的,那些极端情况会有所不同! (排队恶笑)

我诚实的建议...放弃。