1. <div id="f8mbs"></div>
        当前位置:首页 > 安卓源码 > 技术博客 >

        Android 辅助功能服务AccessibilityService使用

        时间:2019-02-13 17:16 来源:互联网 作者:源码搜藏 浏览: 收藏 挑错 推荐 打印

        Android提供辅助功能服务的目的在于帮助那些具有视觉、身体或年龄相关限制的用户更轻松的使用Android设备和应用,例如当用户悬停在屏幕的重要区域上时将文本转换为语音或触觉反馈,从而使一些有视力缺陷的用户也能够使用。除此之外,我们还可以使用Accessibi

        Android提供辅助功能服务的目的在于帮助那些具有视觉、身体或年龄相关限制的用户更轻松的使用Android设备和应用,例如当用户悬停在屏幕的重要区域上时将文本转换为语音或触觉反馈,从而使一些有视力缺陷的用户也能够使用。除此之外,我们还可以使用AccessibilityService将一些人工操作进行自动化处理,从而将人从这些无聊繁琐的重复操作中解放出来。

        1、首先需要定义一个继承自AccessibilityService的服务(这里命名为MyAccessibilityService),并在AndroidManifest中声明:

        <service
            android:name=".MyAccessibilityService"
            android:description="@string/accessibility_service_description"
            android:label="@string/accessibility_service_label"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService"/>
            </intent-filter>
        
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_service_config"/>
        </service>

        其中accessibility_service_description是有关这个服务的功能?#24471;鰨?code style="overflow-wrap: break-word; box-sizing: border-box; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 13.6px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.04); border-radius: 3px;">accessibility_service_label是服务的名称,这些会在设置里面的辅助服务中显示出来,用户需要在里面开启服务才能使用。permissionintent-filter是固定写法。meta-data主要用于对服务进行一些配置,配置的具体内容在 res/xml/accessibility_service_config.xml 文件里面:

        <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
            android:description="@string/accessibility_service_description"
            android:packageNames="com.example.android.apis"
            android:accessibilityEventTypes="typeAllMask"
            android:accessibilityFlags="flagDefault"
            android:accessibilityFeedbackType="feedbackSpoken"
            android:notificationTimeout="100"
            android:canRetrieveWindowContent="true"
            android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"/>

        服务的配置选项具体可参考 https://developer.android.com/reference/android/accessibilityservice/AccessibilityServiceInfo.html 这里仅解释一下几个比较重要的配置属性:
        android:packageNames服务要监控的应用的包名,如果有多个则用逗号连起来,空着表示监听所有的应用。
        android:accessibilityEventTypes服务要监控的事件类?#20572;?#22914;通知、窗口改变、点击、焦点改变等等,如果有多个可以用 | 连起来,typeAllMask代表所有类型。
        android:accessibilityFeedbackType服务反馈的方式,如语音、震动等等,feedbackAllMask代表所有类型。
        android:notificationTimeout 接受事件的时间间隔(毫秒)
        android:canRetrieveWindowContent 服务能否获取窗口里面的内容
        这些配置除了在xml里面写之外,还可以在代码中建立一个AccessibilityServiceInfo对象,然后通过setServiceInfo()来设置。

        2、辅助服务继承AccessibilityService类并覆盖该类中的以下方法:
        onServiceConnected 系统成功连接到辅助功能服务时调用,可以执行执行任何一次性设置步骤,包括连接到用户反馈系统服务,如音频管理器或设备振动器。还可以在此调用setServiceInfo()设置服务配置。
        onAccessibilityEvent 当系统检测?#25509;階ccessibility服务指定的事件过滤参数匹配的AccessibilityEvent时调用。这是必须实现的方法,通常需要在该方法中根据AccessibilityEvent作出判断并执行一些处理。
        onInterrupt 当系统想要中断服务提供的反馈时调用,通常是响应用户操作,如将焦点移动到其他控件。
        onUnbindonDestroy 当系统即将关闭辅助功能服务时调用,可以执行任何一次性关机程序,包括取消分配用户反馈系统服务,例如音频管理器或设备振动器。

        3、AccessibilityEvent 是辅助功能服务中一个非常重要的类,它主要用于提供有关用户界面?#25442;?#30340;信息。当用户界面中发生了服务需要关注的事件时系统就会发送AccessibilityEvent事件,并传递到onAccessibilityEvent方法。通常,用得比较多的是event.getEventType()event.getClassName(),分别用于获取当前事件的类型和发生该事件的类名,通过这两个的判断可以过滤想要处理的事件,并进行操作。例如,当点击一个按钮时,会发送一个type为TYPE_VIEW_CLICKED,className为android.widget.Button的事件,如果我们需要在某个按钮被点击时做一些操作,就可以在onAccessibilityEvent中对event进?#20449;?#26029;。
        AccessibilityEvent 的Type包括:

        TYPE_VIEW_CLICKED
        TYPE_VIEW_LONG_CLICKED
        TYPE_VIEW_FOCUSED
        TYPE_VIEW_SELECTED
        TYPE_VIEW_TEXT_CHANGED
        TYPE_WINDOW_STATE_CHANGED
        TYPE_NOTIFICATION_STATE_CHANGED
        TYPE_TOUCH_EXPLORATION_GESTURE_START
        TYPE_TOUCH_EXPLORATION_GESTURE_END
        TYPE_VIEW_HOVER_ENTER
        TYPE_VIEW_HOVER_EXIT
        TYPE_VIEW_SCROLLED
        TYPE_VIEW_TEXT_SELECTION_CHANGED
        TYPE_WINDOW_CONTENT_CHANGED
        TYPE_ANNOUNCEMENT
        TYPE_GESTURE_DETECTION_START
        TYPE_GESTURE_DETECTION_END
        TYPE_TOUCH_INTERACTION_START
        TYPE_TOUCH_INTERACTION_END
        TYPE_VIEW_ACCESSIBILITY_FOCUSED
        TYPE_WINDOWS_CHANGED
        TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED

        4、AccessibilityNodeInfo 同样是辅助功能服务中一个非常重要的类,它代表了一个View的状态信息。我们可以通过event.getSource()获取发生事件的控件的信息,也可以通过getRootInActiveWindow()获取当前窗口中的根节点的信息。前提是服务配置中android:canRetrieveWindowContenttrue,并且发生事件的窗口为当前窗口,否则这两个方法返回的值都为null
        那么,我们得到了AccessibilityNodeInfo能做什么呢?AccessibilityNodeInfo和View一样,也是一个具有层级关系的节点树,一个AccessibilityNodeInfo里面可以有多个AccessibilityNodeInfo的子节点,当我们想要获取一个目标节点时,可以先获取根节点,然后再通过递归遍历其子节点去寻找,也可以通过findAccessibilityNodeInfosByViewId()findAccessibilityNodeInfosByText()方法去寻找。当找到目标节点后,可以对其执行想要的操作,比如点击,滚动,填入文?#20540;?#31561;。
        举个例子,当我们想要在当前界面点击第一个文字为“确定”的按钮时:

        AccessibilityNodeInfo rootNode = getRootInActiveWindow();
        if (rootNode != null) {
            List<AccessibilityNodeInfo> nodes = rootNode.findAccessibilityNodeInfosByText("确定");
            for (AccessibilityNodeInfo node : nodes) {
                if (TextUtils.equals(node.getText(), "确定") &amp;&amp; TextUtils.equals(node.getClassName(), "android.widget.Button")) {
                    node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                }
            }
        }

        首先调用getRootInActiveWindow()获取当前界面的根节点,然后再通过findAccessibilityNodeInfosByText()找到所有包含目标文字的节点(注意,这里?#21069;?#21547;目标文字,而非完全与目标文字相同),之后再遍历这个列表,找到第一个Text完全等于目标文字,且控件类型为Button的节点,最后再调用performAction(AccessibilityNodeInfo.ACTION_CLICK)执行点击事件。
        AccessibilityNodeInfo 中的Action包括:

        ACTION_ACCESSIBILITY_FOCUS
        ACTION_ARGUMENT_COLUMN_INT
        ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
        ACTION_ARGUMENT_HTML_ELEMENT_STRING
        ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
        ACTION_ARGUMENT_PROGRESS_VALUE
        ACTION_ARGUMENT_ROW_INT
        ACTION_ARGUMENT_SELECTION_END_INT
        ACTION_ARGUMENT_SELECTION_START_INT
        ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
        ACTION_CLEAR_ACCESSIBILITY_FOCUS
        ACTION_CLEAR_FOCUS
        ACTION_CLEAR_SELECTION
        ACTION_CLICK
        ACTION_COLLAPSE
        ACTION_COPY
        ACTION_CUT
        ACTION_DISMISS
        ACTION_EXPAND
        ACTION_FOCUS
        ACTION_LONG_CLICK
        ACTION_NEXT_AT_MOVEMENT_GRANULARITY
        ACTION_NEXT_HTML_ELEMENT
        ACTION_PASTE
        ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
        ACTION_PREVIOUS_HTML_ELEMENT
        ACTION_SCROLL_BACKWARD
        ACTION_SCROLL_FORWARD
        ACTION_SELECT
        ACTION_SET_SELECTION
        ACTION_SET_TEXT
        FOCUS_ACCESSIBILITY
        FOCUS_INPUT
        MOVEMENT_GRANULARITY_CHARACTER
        MOVEMENT_GRANULARITY_LINE
        MOVEMENT_GRANULARITY_PAGE
        MOVEMENT_GRANULARITY_PARAGRAPH
        MOVEMENT_GRANULARITY_WORD

        其中用的比较多的有点击、长按、滚动等等,如果想为EditText设置文字可以用:

        Bundle arguments = new Bundle();
        arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
        inputNode.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);

        另外,AccessibilityService中还有一个performGlobalAction()方法,用于执行一些通用的事件,主要包括:

        GLOBAL_ACTION_BACK    点击返回按钮
        GLOBAL_ACTION_HOME    点击home
        GLOBAL_ACTION_NOTIFICATIONS    打开通知
        GLOBAL_ACTION_RECENTS    打开最近应用
        GLOBAL_ACTION_QUICK_SETTINGS    打开快速设置
        GLOBAL_ACTION_POWER_DIALOG    打开长按电源键的弹框
        Android 辅助功能服务AccessibilityService使用转载<\/script>');
        辽宁十一选五单双