AccessibilityService是什么
某些用户由于视力、身体、年龄等问题致使他们不能使用触摸屏幕,为这些用户提供无障碍服务时应该更多的提供语音、触摸反馈、手势操作、模拟点击等。
为此android官方推出了AccessibilityService方便开发者为特殊用户服务。
更详细资料可以看android官方文档
AccessibilityService能做什么
AccessibilityService是一个辅助类,可以监听我们手机的焦点,窗口变化,按钮点击等,同时它还可以模拟点击。基本上等同于可以监听一切你想监听的内容。
如何使用AccessibilityService
AccessibilityService使用很简单:
1. 新建一个类继承AccessibilityService,并实现几个重要的重载方法;
2.在AndroidManifest中注册服务
3.配置AceessibilityService
通过这三步就可以创建自己的辅助类了,在 系统设置-》辅助功能中开启我们的服务就实现我们想要的功能了。
我们以利用系统自带语音助手打开第三方应用为例来实现。
1.新建MyAccessibilityService类并继承AccessibilityService
利用getRootInActivityWindow()方法可以获得当前界面的根节点node
然后通过findAccessibilityNodeInfosByText() 获取到我们想要的节点
public class MyAccessbilityService extends AccessibilityService {
private static final String TAG = "MyAccessbilityService";
//记录上一次识别结果,防止死循环
private String lastText = "";
/**
* 连接服务成功后调用
* 可选
*/
protected void onServiceConnected() {
Log.d(TAG, "onServiceConnected: success");
super.onServiceConnected();
}
/**
* 接受系统发来的accessibilityEvent
* 必须实现
*/
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo nodes = getRootInActiveWindow();
if (nodes == null){
return;
}
// List nodeList =
// nodes.findAccessibilityNodeInfosByViewId(Config.viewId);
// 也可通过findAccessibilityNodeInfosByViewId 方式解决
List nodeInfoList =
nodes.findAccessibilityNodeInfosByText("芝麻开门");
for (int i = 0; i < nodeInfoList.size(); i++){
String text = nodeInfoList.get(i).getText().toString();
Log.d(TAG, "onAccessibilityEvent: result" + i +" = " + text);
if (!text.equals(lastText)){
dealText(text);
}
}
nodes.recycle();
Log.d(TAG, "onAccessibilityEvent: packageName = " + event.getPackageName());
Log.d(TAG, "onAccessibilityEvent: eventType = " + event.getEventType());
Log.d(TAG, "onAccessibilityEvent: windowId = " + event.getWindowId());
Log.d(TAG, "onAccessibilityEvent: -------------");
}
/**
* 中断服务
* 必须实现
*/
@Override
public void onInterrupt() {
}
/**
* 系统关闭服务时调用
* 可选
* @param intent
* @return
*/
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
/**
* 打开第三方应用,这里以打开我们自己的Activity为例
* @param text 打开应用附带的消息
*/
private void openApp(String text){
Log.d(TAG, "open some app");
lastText = text;
Intent intent = new Intent(MyAccessbilityService.this, MainActivity.class);
intent.putExtra("str",text);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
/**
* 处理语音识别结果
* @param str
*/
private void dealText(String str){
if (str.contains(Config.mark)){
openApp(str);
}
}
}
AccessibilityService中的重要方法
onServiceConnected() - 可选。系统会在成功连接上你的服务的时候调用这个方法,在这个方法里你可以做一下初始化工作,例如设备的声音震动管理,也可以调用setServiceInfo()进行配置工作。
onAccessibilityEvent() - 必须。通过这个函数可以接收系统发送来的AccessibilityEvent,接收来的AccessibilityEvent是经过过滤的,过滤是在配置工作时设置的。
onInterrupt() - 必须。这个在系统想要中断AccessibilityService返给的响应时会调用。在整个生命周期里会被调用多次。
onUnbind() - 可选。在系统将要关闭这个AccessibilityService会被调用。在这个方法中进行一些释放资源的工作。
2.在AndroidManifest中注册服务
在AndroidManifest下application标签中加入如下代码
label 为服务的名字
description 为服务的描述 这样我们的服务就成功注册了 3.配置AceessibilityService 有两种配置方式,一种是java代码配置,一种是使用xml文件配置。xml配置方式支持更多的参数,推荐使用这种方式配置。 xml文件配置方式 在res文件夹下新建一个xml文件夹 在xml文件夹中新建一个xml文件,取名跟meta-data中的name一致 xml文件代码 java代码配置方式 需要new一个AccessibilityServiceInfo对象并设置相关参数 最后在MyaccessibilityService类中的onServiceConnected方法中配置参数。 在MyaccessibilityService中添加方法 经过以上三步我们的服务就编写完成了 编译运行就可以在 系统设置->辅助功能 中看到我们 的服务 打开服务,启动系统自带的语音助手,说出密令词 “芝麻开门” 就可以打开MainActivity了。 利用系统自带语音助手打开第三方应用就实现了。
packageNames中填入想要监听的包名,我的测试机是魅族MX3,语音助手的包名是com.meizu.voiceassistant ,可以替换成你需要的包名
在onServiceConnect中调用该方法
private void setServiceInfo(int feedbackType) {
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
// We are interested in all types of accessibility events.
info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
// We want to provide specific type of feedback.
info.feedbackType = feedbackType;
// We want to receive events in a certain interval.
info.notificationTimeout = EVENT_NOTIFICATION_TIMEOUT_MILLIS;
// We want to receive accessibility events only from certain packages.
info.packageNames = PACKAGE_NAMES;
setServiceInfo(info);
}
protected void onServiceConnected() {
super.onServiceConnected();
setServiceInfo(AccessibilityServiceInfo.FEEDBACK_GENERIC);
}