浅谈辅助功能 AccessibilityService

转自子云心的博客 


辅助功能定义

对于那些由于视力、听力或其它身体原因导致不能方便使用Android智能手机的用户,Android提供了Accessibility功能和服务帮助这些用户更加简单地操作设备,包括文字转语音(不支持中文)、触觉反馈、手势操作、轨迹球和手柄操作。开发者可以搭建自己的Accessibility服务,这可以加强可用性,例如声音提示,物理反馈,和其他可选的操作模式。

随着Android版本的不断升级,AndroidAccessibility功能也越来越强大,Android 4.0版本以前,系统辅助服务功能比较单一,仅仅能过单向获取窗口元素信息,比如获取输入框用户输入内容。到Android 4.1版本以后,系统辅助服务增加了与窗口元素的双向交互,此时可以通过辅助功能服务操作窗口元素,比如点击按钮等。

现实辅助功能准备工作

1、新建自己的AccessibilityService类

想要让自己程序实辅助功能,首先第一步就是要新建类并继承AccessibilityService类。继承自AccessibilityService的子类里实现几个重要的重载方法:

方法

描述

onAccessibilityEvent()

必须。通过这个函数可以接收系统发送来的AccessibilityEvent,接收来的AccessibilityEvent是经过过滤的,过滤是在配置工作时设置的。

onInterrupt()

必须。这个在系统想要中断AccessibilityService返给的响应时会调用。在整个生命周期里会被调用多次。

onServiceConnected()

可选。在系统成功连接上这个AccessibilityService会调用。在这个方法里你可以做一下初始化工作。

onUnbind()

可选。在系统将要关闭这个AccessibilityService会被调用。在这个方法中进行一些释放资源的工作。

2、新建AccessibilityService配置文件

?
1
2
<!--?xml version= "1.0" encoding= "utf-8" ?-->
</accessibility-service>

 

属性分别代表意义:

属性

描述

description

就是设置里辅助功能项的备注说明(不可在运行时修改)。

accessibilityEventTypes

设置响应事件的类型,typeAllMask当然就是响应所有类型的事件了。当然还有单击、长按、滑动等(多个值由“|”分隔)(可在运行时修改)。

值有:

说明

typeViewClicked

Receives TYPE_VIEW_CLICKED events.

typeViewLongClicked

Receives TYPE_VIEW_LONG_CLICKED events.

typeViewSelected

Receives TYPE_VIEW_SELECTED events.

typeViewFocused

Receives TYPE_VIEW_FOCUSED events.

typeViewTextChanged

Receives TYPE_VIEW_TEXT_CHANGED events.

typeWindowStateChanged

Receives TYPE_WINDOW_STATE_CHANGED events.

typeNotificationStateChanged

Receives TYPE_NOTIFICATION_STATE_CHANGED events.

typeViewHoverEnter

Receives TYPE_VIEW_HOVER_ENTER events.

typeViewHoverExit

Receives TYPE_VIEW_HOVER_EXIT events.

typeTouchExplorationGestureStart

Receives TYPE_TOUCH_EXPLORATION_GESTURE_START events.

typeTouchExplorationGestureEnd

Receives TYPE_TOUCH_EXPLORATION_GESTURE_END events.

typeWindowContentChanged

Receives TYPE_WINDOW_CONTENT_CHANGED events.

typeViewScrolled

Receives TYPE_VIEW_SCROLLED events.

typeViewTextSelectionChanged

Receives TYPE_VIEW_TEXT_SELECTION_CHANGED events.

typeAnnouncement

Receives TYPE_ANNOUNCEMENT events.

typeViewAccessibilityFocused

Receives TYPE_VIEW_ACCESSIBILITY_FOCUSED events.

typeViewAccessibilityFocusCleared

Receives TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED events.

typeViewTextTraversedAtMovementGranularity

Receives TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITYevents.

typeGestureDetectionStart

Receives TYPE_GESTURE_DETECTION_START events.

typeGestureDetectionEnd

Receives TYPE_GESTURE_DETECTION_END events.

typeTouchInteractionStart

Receives TYPE_TOUCH_INTERACTION_START events.

typeTouchInteractionEnd

Receives TYPE_TOUCH_INTERACTION_END events.

typeWindowsChanged

Receives TYPE_WINDOWS_CHANGED events.

typeContextClicked

Receives TYPE_VIEW_CONTEXT_CLICKED events.

typeAssistReadingContext

Receives TYPE_ASSIST_READING_CONTEXT events.

typeAllMask

Receives TYPES_ALL_MASK i.e. all events.

 

accessibilityFeedbackType

设置回馈给用户的方式,有语音播出和振动(多个值由“|”分隔)(可在运行时修改)。

值有:

说明

feedbackSpoken

Provides FEEDBACK_SPOKEN feedback.

feedbackHaptic

Provides FEEDBACK_HAPTIC feedback.

feedbackAudible

Provides FEEDBACK_AUDIBLE feedback.

feedbackVisual

Provides FEEDBACK_VISUAL feedback.

feedbackGeneric

Provides FEEDBACK_GENERIC feedback.

feedbackAllMask

Provides FEEDBACK_ALL_MASK feedback.

 

notificationTimeout

相同类型的两个事件之间的最小时间发送到该服务(可在运行时修改)。

accessibilityFlags

可访问性(多个值由“|”分隔)(可在运行时修改)。

值有:

说明

flagDefault

Has flag DEFAULT

flagIncludeNotImportantViews

Has flag FLAG_INCLUDE_NOT_IMPORTANT_VIEWS

flagRequestTouchExplorationMode

Has flag FLAG_REQUEST_TOUCH_EXPLORATION_MODE

flagRequestEnhancedWebAccessibility

Has flag FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY

flagReportViewIds

Has flag FLAG_REPORT_VIEW_IDS

flagRequestFilterKeyEvents

Has flag FLAG_REQUEST_FILTER_KEY_EVENTS

flagRetrieveInteractiveWindows

Has flag FLAG_RETRIEVE_INTERACTIVE_WINDOWS

 

packageNames

响应的程序的包名(多个值由“,”分隔)(可在运行时修改)。

canRetrieveWindowContent

是否能够检索活动窗口的内容(不可在运行时修改)。

settingsActivity

允许用户修改此服务的设置的活动组件名称,(如果不需要在运行时修改设置,可忽略该项)(不可在运行时修改)。

修改设置,可使用:android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo).

3、AndroidManifest里注册服务

 

 

 

 

 

AndroidManifest.XML文件添加以下配置

?
1
2
3
4
5
6
<service android:label= "@string/XXXXX" android:name= ".XXXXX" android:permission= "android.permission.BIND_ACCESSIBILITY_SERVICE" >                // 系统权限
     <intent-filter>
         
     </action></intent-filter>
     <meta-data android:name= "android.accessibilityservice" android:resource= "@xml/XXXXX" >   // XXXXX为上面新建的配置XML文件
</meta-data></service>

获取UI元素

在onAccessibilityEvent中,使用参数event的getSource方法获取到的AccessibilityNodeInfo实例,即为触发这次事件的UI节点。获取到当前界面UITree的根节点可以使用findAccessibilityNodeInfosByText或者findAccessibilityNodeInfosByViewId方法。需要注意findAccessibilityNodeInfosByText在获取UI元素时的判断逻辑是包含而非等于。

示例代码如:

 

?
1
2
Listnodes = event.getSource().findAccessibilityNodeInfosByText( "立即安装" );
Listnodes = event.getSource().findAccessibilityNodeInfosByViewId( "txt_1" );</accessibilitynodeinfo></accessibilitynodeinfo>

 

模拟用户操作

模拟点击

获取界面上UI元素之后,可根据元素是否可响应操作进行相应的处理。例如,如果UI元素是一个有效的按钮,则可以使用下面的代码来进行模拟点击:

?
1
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);

 

同理,如果UI元素是一个有效的列表,则可以使用下面的代码进行模拟滑动:

?
1
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);

 

模拟物理键

也可以模拟物理键的操作,例如模拟按下返回键的代码是:

?
1
AccessibilityService.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);

 

模拟打开消息通知栏

在上面介绍accessibilityEventTypes中提到有一个事件: typeNotificationStateChanged,它便是消息通知栏状态发生改变变触发。一些红包外挂工具里头,一有红包就提醒的原理便是在onAccessibilityEvent中监听该事件,然后判断关键字并打开通知,示例关键代码如:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if (event.getEventType() != AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED){
        return ;
}
List<charsequence>texts = event.getText();
if (texts.size() <= 0 || !mAutoTrack) {
     return ;
}
for (CharSequence text : texts) {
     String content = text.toString();
     if (!content.contains( "[微信红包]" )){
         continue ;
     }
     if (event.getParcelableData() == null || !(event.getParcelableData() instanceofNotification)) {
         continue ;
     }
     Notification notification = (Notification)event.getParcelableData();
     PendingIntent pendingIntent =notification.contentIntent;
     try {
         pendingIntent.send();
     } catch (PendingIntent.CanceledException e) {
         e.printStackTrace();
     }
}</charsequence>

 

语音播放

首先,定义一个TextToSpeech对象,并在服务连上后进行初始化,示例代码如:

 

?
1
2
3
4
5
6
7
8
9
10
private TextToSpeech mTts;
     ……
mTts = newTextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
     @Override
     public void onInit( int status) {
         if (status == TextToSpeech.SUCCESS) {
             mTts.setLanguage(Locale.US);
         }
     }
});

 

执行语音播放代码:

?
1
mTts.speak( "hello" ,TextToSpeech.QUEUE_FLUSH, null );

最后别忘记释放资源:

?
1
mTts.shutdown();

 

建议:

在开发APP想支持语音播功能时,建议在用户界面控件中,通过使用android:contentDescription属性来描控件特性。

对于EditText控件,提供了一个android:hint属性代替了contentDescription属性

判断是否开启辅助功能

 

?
1
2
3
4
intaccessibilityEnabled =Settings.Secure.getInt(context.getApplicationContext().getContentResolver(),android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
if (accessibilityEnabled == 1 ) {
     String settingValue =Settings.Secure.getString(context.getApplicationContext().getContentResolver(),Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
}

 

如果手机中开启了一些APP的辅助功能,settingValue的值为:APP1包名/APP1继承AccessibilityService类全名: APP2包名/APP2继承AccessibilityService类全名

使用Dump View Hierarchy for UI Automator解析UI界面视图帮助查找节点对象

一、

加载中...\

 

二、

\加载中...

 

三、

加载中...

\

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值