最近收到一个需求,需要监控用户的按键行为来启动应用。类似与快捷键启动应用的方式。
方案
使用AccessibilityService来监听用户行为。
AccessibilityService是什么
Google为了让Android系统更实用,为用户提供了无障碍辅助服务(
AccessibilityService
).
AccessibilityService
运行在后台,并且能够收到由系统发出的一些事件(AccessibilityEvent
,这些事件表示用户界面一系列的状态变化),比如焦点改变,输入内容变化,按钮被点击了等等,该种服务能够请求获取当前活动窗口并查找其中的内容.换言之,界面中产生的任何变化都会产生一个时间,并由系统通知给AccessibilityService
.这就像监视器监视着界面的一举一动,一旦界面发生变化,立刻发出警报.更多详情,请阅读官方文档:官方文档。或查阅其他相关资料。
实例
MyKeyService.java
public class MyKeyService extends AccessibilityService {
private AccessibilityServiceInfo mAccessibilityServiceInfo;
protected static final String TAG = "tangtangAccessibilityService";
@SuppressLint("LongLogTag")
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: MyKeyService isStart !");
}
@SuppressLint("LongLogTag")
@Override
protected boolean onKeyEvent(KeyEvent paramKeyEvent) {
Log.d(TAG, "onKeyEvent " + paramKeyEvent);
return false;//如果返回true,就会导致其他应用接收不到事件了,但是对KeyEvent的修改是不会分发到其他应用中的!
}
@SuppressLint("LongLogTag")
@Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
System.out.println("KEYCODE_onAccessibilityEvent");
Log.i(TAG, "KEYCODE_onAccessibilityEvent");
}
@Override
public void onInterrupt() {
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.showimage.start.myapplication"
android:sharedUserId="android.uid.system">
<!---android:sharedUserId="android.uid.system" 系统权限-->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!---监听服务-->
<service
android:name=".AccessibilityService.MyKeyService"
android:enabled="true"
android:exported="true"
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/accessibilityservice" />
</service>
</application>
</manifest>
accessibilityservice.xml
在工程res目录下创建xml目录,同时在xml目录下创建accessibilityservice.xml文件
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagRequestFilterKeyEvents"
android:canRetrieveWindowContent="true"
android:canRequestFilterKeyEvents="true"
android:description="@string/app_name">
</accessibility-service>
无障碍辅助功能开启方式
简介
开启方式将就是enabled_accessibility_services和accessibility_enabled值写入到settings的secure相关文件中去。
//android 5.1以下平台
/data/user/0/com.android.settings/databases/search_index.db
//android 6.0以上平台
/data/system/users/0/
//无障碍辅助功能相关值
INSERT INTO "secure" VALUES(86,'enabled_accessibility_services','com.showimage.start.myapplication/com.showimage.start.myapplication.AccessibilityService.MyKeyService');
INSERT INTO "secure" VALUES(87,'accessibility_enabled','1');
手动开启
设置--->无障碍--->你的服务--->打开。
跳转到无障碍服务设置页
程序员的打开方式。
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
代码开启
需要注意的是这个需要系统权限。
//关闭无障碍服务
private void autoCloseAccessibilityService(Context context){
if (isStartAccessibilityServiceEnable(context)) {
String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
ComponentName selfComponentName = new ComponentName(context.getPackageName(), KeyInterceptService.class.getCanonicalName());
String flattenToString = selfComponentName.flattenToString();
enabledServicesSetting=enabledServicesSetting.replace(":"+flattenToString , "");
Settings.Secure.putString(context.getContentResolver(),Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,enabledServicesSetting);
//Settings.Secure.putInt(context.getContentResolver(),Settings.Secure.ACCESSIBILITY_ENABLED, 0);
Log.d(TAG, "autoCloseAccessibilityService: SETTING ACCESSIBILITY SUCCESS!");
}
return;
}
//开启无障碍服务
private void autoOpenAccessibilityService(Context context){
if (!isStartAccessibilityServiceEnable(context)) {
String enabledServicesSetting = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
ComponentName selfComponentName = new ComponentName(context.getPackageName(), KeyInterceptService.class.getCanonicalName());
String flattenToString = selfComponentName.flattenToString();
if (enabledServicesSetting==null||
!enabledServicesSetting.contains(flattenToString)) {
enabledServicesSetting += ":"+flattenToString;
}
Settings.Secure.putString(context.getContentResolver(),Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,enabledServicesSetting);
Settings.Secure.putInt(context.getContentResolver(),Settings.Secure.ACCESSIBILITY_ENABLED, 1);
Log.d(TAG, "autoOpenAccessibilityService: SETTING ACCESSIBILITY SUCCESS!");
}
return;
}
/**
* 判断无障碍服务是否开启
*
* @param context
* @return
*/
private boolean isStartAccessibilityServiceEnable(Context context) {
AccessibilityManager accessibilityManager = (AccessibilityManager)context.getSystemService(Context.ACCESSIBILITY_SERVICE);
assert accessibilityManager != null;
List<AccessibilityServiceInfo> accessibilityServices = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
for (AccessibilityServiceInfo info : accessibilityServices) {
if (info.getId().contains(context.getPackageName())) {
return true;
}
}
return false;
}
命令开启
也需要系统权限。
settings put secure enabled_accessibility_services com.showimage.start.myapplication/com.showimage.start.myapplication.AccessibilityService.MyKeyService
settings put secure accessibility_enabled 1
结束语
以上就是本次分享的辅助服务监听系统按键(AccessibilityService)相关知识以及实例。