java - 遍历AccessibilityNodeInfo时Android辅助功能服务中的无限递归

标签 java android accessibilityservice

几天以来,我的应用程序的用户都遇到了崩溃。我能够在我的设备上收集一个 logcat,并添加了一些调试输出。所以这是正在发生的事情:

在我的 handleAccessibilityEvent() 中,我调用

AccessibilityNodeInfo root = getRootInActiveWindow();
int eventWindowId = event.getWindowId();
if (ExistsNodeOrChildren(root, new WindowIdCondition(eventWindowId)))
{
}

递归遍历节点树:

private boolean ExistsNodeOrChildren(AccessibilityNodeInfo n, NodeCondition condition) 
{
    Log.d(_logTag, "ExistsNodeOrChildren" + n.toString());
    if (n == null) return false;
    if (condition.check(n))
        return true;
    for (int i = 0; i < n.getChildCount(); i++)
    {
        Log.d(_logTag, "ExistsNodeOrChildren child" + i);
        if (ExistsNodeOrChildren(n.getChild(i), condition))
            return true;
    }
    return false;
}

NodeCondition 是一个简单的接口(interface),用于对节点进行类似谓词的检查。

ExistsNodeOrChildren 遇到无限递归。从日志(见下文)来看,在我看来,一个节点正在将自己作为自己的 child 返回。

我的主要问题是:这是否允许并且必须在我的无障碍服务中处理?这似乎是在最近的一些更新中引入的,可能与 WebView 或 Chrome 有关。

如果是:我应该如何比较 AccessibilityNodeInfo 对象以检查它们是否引用同一个节点?

(最新 Activity 在最上面)

02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildrenandroid.view.accessibility.AccessibilityNodeInfo@c723; boundsInParent: Rect(0, 0 - 1080, 1605); boundsInScreen: Rect(0, 210 - 1080, 1668); packageName: com.opera.mini.native; className: android.webkit.WebView; text: null; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: false; longClickable: false; contextClickable: false; enabled: true; password: false; scrollable: false; importantForAccessibility: false; actions: null
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildren child0
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildrenandroid.view.accessibility.AccessibilityNodeInfo@c723; boundsInParent: Rect(0, 0 - 1080, 1605); boundsInScreen: Rect(0, 210 - 1080, 1668); packageName: com.opera.mini.native; className: android.webkit.WebView; text: null; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: false; longClickable: false; contextClickable: false; enabled: true; password: false; scrollable: false; importantForAccessibility: false; actions: null
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildren child0
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildrenandroid.view.accessibility.AccessibilityNodeInfo@c723; boundsInParent: Rect(0, 0 - 1080, 1605); boundsInScreen: Rect(0, 210 - 1080, 1668); packageName: com.opera.mini.native; className: android.webkit.WebView; text: null; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: false; longClickable: false; contextClickable: false; enabled: true; password: false; scrollable: false; importantForAccessibility: false; actions: null
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildren child0
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildren child0
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildren child0
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildrenandroid.view.accessibility.AccessibilityNodeInfo@c723; boundsInParent: Rect(0, 0 - 1080, 1605); boundsInScreen: Rect(0, 210 - 1080, 1668); packageName: com.opera.mini.native; className: android.webkit.WebView; text: null; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: false; longClickable: false; contextClickable: false; enabled: true; password: false; scrollable: false; importantForAccessibility: false; actions: null
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildrenandroid.view.accessibility.AccessibilityNodeInfo@c723; boundsInParent: Rect(0, 0 - 1080, 1605); boundsInScreen: Rect(0, 210 - 1080, 1668); packageName: com.opera.mini.native; className: android.webkit.WebView; text: null; error: null; maxTextLength: -1; contentDescription: null; viewIdResName: null; checkable: false; checked: false; focusable: false; focused: false; selected: false; clickable: false; longClickable: false; contextClickable: false; enabled: true; password: false; scrollable: false; importantForAccessibility: false; actions: null
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildren child0
02-08 10:49:01.074  Google Pixel    Debug   9314    KP2AAF  ExistsNodeOrChildren child0

最佳答案

如果这不是由您的 NodeCondition 函数(您可能应该提供)中的某些其他递归引起的,并且这实际上是 Android 操作系统虚拟 View 层次结构中的错误,您可以尝试通过执行以下操作来修复它这个:

private boolean ExistsNodeOrChildren(AccessibilityNodeInfo n, NodeCondition condition) {

    //For God sake do this first if you think n might actually be null!!!
    //Or just don't do it, and let n.toString() throw a NPE. (BAD IDEA)
    if (n == null) return false; 

    Log.d(_logTag, "ExistsNodeOrChildren" + n.toString());

    //NOTE: This could also cause recursion, you didn't provide this code.
    if (condition.check(n)) return true;

    for (int i = 0; i < n.getChildCount(); i++) {
        AccessibilityNodeInfo child = n.getChild(i);

        //Skip recursion the times n.getChild() returns n.
        //The check really is this simple, because we can only skip this
        //When the child is literally the same object, otherwise it might be
        //a node that has identical properties, which can happen.
        if (child != n) {
            Log.d(_logTag, "ExistsNodeOrChildren child" + i);
            if (ExistsNodeOrChildren(n.getChild(i), condition)) return true;
        } else {
            log.e("We should report this as a bug in the AOSP");
        }
    }

    return false;
}

关于java - 遍历AccessibilityNodeInfo时Android辅助功能服务中的无限递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48682757/

相关文章:

java - AndEngine如何让 Sprite 在调用jump方法时不跳转

android - Android默认开启AccessibilityService的方法

java - 摆脱警告?

java - 如何在 map 上显示不同的标记?

android - 如何在openCV android应用程序中跳过帧?

android - 在 Android 中创建类似网格的布局

android - 在 API 级别 8 上使用 API 级别 18 的 Android AccessabilityService 功能

AccessibilityService 中的 Android onAccessibilityEvent 未被调用

java - 在 struts 2 中上传文件会产生扩展名为 .tmp 的文件

java - 无法解析我的 toString 抛出的 NullPointerException