Android onAccessibilityEvent获取TextView的X和Y位置

时间:2017-07-31 19:20:41

标签: android accessibilityservice

我试图通过Accessibility服务在我的屏幕上获取TextView的X和Y位置来查找TextView,这可能吗?我发现的一切都需要您先触摸屏幕。以下是我获取节点信息的方法。

public class MyAccessibilityService extends AccessibilityService {

    @TargetApi(16)
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        AccessibilityNodeInfo source = event.getSource();
    }
}

1 个答案:

答案 0 :(得分:8)

您可以随时从辅助功能服务中随意搜索辅助功能视图层次结构!虽然我建议在某种类型的辅助功能事件的上下文中这样做,然后确保有遍历的屏幕内容!在随机回调中这样做充其量是挑剔的。以下是用于此目的的合理的辅助功能配置XML文件:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:accessibilityEventTypes="typeWindowContentChanged|typeWindowsChanged|typeWindowStateChanged"
    android:accessibilityFlags="flagReportViewIds|flagIncludeNotImportantViews"
    android:canRetrieveWindowContent="true"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:notificationTimeout="1000" 
    android:settingsActivity=".SettingsActivity"
    />

以下是对其中一些领域的一些评论。

  

机器人:notificationTimeout =&#34; 1000&#34;

每秒只检索一次给定类型的辅助功能事件!对于列出的事件,任何较低的设置都将是QUITE verbose。我们只依靠它来调用我们的回调并确保我们有节点。为了这些目的,每秒一次就是DAND DANDY。必要时调整。

  

机器人:accessibilityEventTypes =&#34; typeWindowContentChanged | typeWindowsChanged | typeWindowStateChanged&#34;

粗略地说,这是允许您捕获所有屏幕更改事件的事件子集。打开一个新窗口...扫描视图层次结构!

  

机器人:accessibilityFlags =&#34; flagReportViewIds | flagIncludeNotImportantViews&#34;

标记包括不重要的视图将在AccessibilityNodeInfo层次结构中包含更多视图。特别是许多布局视图,并且Android OS通常不会认为是可访问性目的所必需的。我喜欢将此选中,因为这也是开发人员可调整属性,而Android开发人员在可访问性方面是出了名的愚蠢。最好只取一切并自己整理!

好的,那么您的服务配置就是这样!现在,其余的很容易。您要做的是通过子节点子节点向下递归,直到找到TextView节点。我在下面设置了一个愚蠢的服务,它会在每个屏幕上发现第一个TextView节点更新(除非它们在给定上面的服务配置XML的情况下每秒多于一次),然后记录它的屏幕坐标。

class MyAccessibilityService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent e) {

        //You can actually call getRootInActiveWindow() any time!
        //Doing so here ensures that the screen is in a reasonable state
        //and not in the middle of rendering or something else silly.
        final AccessibilityNodeInfo textNodeInfo = findTextViewNode(getRootInActiveWindow());

        if (textNodeInfo == null) return;

        Rect rect = new Rect();

        textNodeInfo.getBoundsInScreen(rect);

        Log.i(A11yService.class.getSimpleName(), "The TextView Node: " + rect.toString());

    }


    public AccessibilityNodeInfo findTextViewNode(AccessibilityNodeInfo nodeInfo) {

        //I highly recommend leaving this line in! You never know when the screen content will
        //invalidate a node you're about to work on, or when a parents child will suddenly be gone!
        //Not doing this safety check is very dangerous!
        if (nodeInfo == null) return null;

        Log.v(A11yService.class.getSimpleName(), nodeInfo.toString());

        //Notice that we're searching for the TextView's simple name!
        //This allows us to find AppCompat versions of TextView as well
        //as 3rd party devs well names subclasses... though with perhaps
        //a few poorly named unintended stragglers!
        if (nodeInfo.getClassName().toString().contains(TextView.class.getSimpleName())) {
            return nodeInfo;
        }

        //Do other work!

        for (int i = 0; i < nodeInfo.getChildCount(); i++) {
            AccessibilityNodeInfo result = findTextViewNode(nodeInfo.getChild(i));

            if (result != null) return result;
        }

        return null;
    }

    //Required for a valid Accessibility Service.
    @Override
    public void onInterrupt() {}
}

您还可以找到我使用Accessibility Service Utilities构建的开源库,这使得所有这些内容变得更加容易! A11yNodeInfoMatcher类是您想要的。