Android輔助功能(無障礙)使用---AccessibilityService
阿新 • • 發佈:2018-12-16
1.Android文件裡AccessibilityService
簡介
輔助功能只在幫助殘障人士使用Android裝置和app的時候使用。 服務程序被殺掉後,下次啟動,需再次申請許可權
2.實現輔助功能服務
實現輔助功能,需要實現AccessibilityService
類,並重寫onAccessibilityEvent
和onInterrupt
方法。
程式碼:
public class AccessibilityTestService extends AccessibilityService {
@Override
public void onAccessibilityEvent (AccessibilityEvent event) {
String packageName = event.getPackageName().toString();
int eventType = event.getEventType();
Log.i("accessibility", "packageName = " + packageName + " eventType = " + eventType);
}
@Override
public void onInterrupt() {
}
}
開啟服務許可權後執行,不同頁面,列印不同的packageName
eventType
結果:
packageName = com.android.mms eventType = 2048
packageName = com.miui.home eventType = 32
packageName = com.miui.home eventType = 1
packageName = com.android.camera eventType = 2048
packageName = com.android.camera eventType = 32
packageName = com.android.camera eventType = 2048
packageName = com.android.camera eventType = 2048
packageName = com.miui.home eventType = 32
packageName = com.miui.securitycenter eventType = 64
packageName = com.android.systemui eventType = 2048
3.註冊服務
在AndroidManifest
中註冊服務完成配置。
程式碼:
<service
android:name=".android.accessibility.AccessibilityTestService"
android:exported="true"
android:label="@string/testAccessibility"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:process=":BackgroundService">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_config" />
</service>
label
標籤是在申請許可權的設定頁面顯示該服務的名字。其中需要的permission
和<intent-filter>
是必須的,缺少任何一個系統個都會無視這個服務。<meta-data>
是該服務的一些配置,在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="flagReportViewIds"
android:canRetrieveWindowContent="true"
android:description="@string/accessibility_desc"
android:notificationTimeout="100" />
4.跳轉設定頁面開啟服務
先判斷是否開啟服務
if (!OpenAccessibilitySettingHelper.isAccessibilitySettingsOn(this,
AccessibilityTestService.class.getName())) {// 判斷服務是否開啟
OpenAccessibilitySettingHelper.jumpToSettingPage(this);// 跳轉到開啟頁面
} else {
ToastUtil.showShortToast(this, "服務已開啟");
//do other things...
}
OpenAccessibilitySettingHelper
類:
public class OpenAccessibilitySettingHelper {
//跳轉到設定頁面無障礙服務開啟自定義輔助功能服務
public static void jumpToSettingPage(Context context) {
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
//判斷自定義輔助功能服務是否開啟
public static boolean isAccessibilitySettingsOn(Context context, String className) {
if (context == null) {
return false;
}
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager != null) {
List<ActivityManager.RunningServiceInfo> runningServices =
activityManager.getRunningServices(100);// 獲取正在執行的服務列表
if (runningServices.size() < 0) {
return false;
}
for (int i = 0; i < runningServices.size(); i++) {
ComponentName service = runningServices.get(i).service;
if (service.getClassName().equals(className)) {
return true;
}
}
return false;
} else {
return false;
}
}
}
5.輔助功能具體實現類
模擬的一些點選,退出,拖動,獲取介面資訊等具體的實現方法,主要是通過節點查詢,找到要操作的控制元件。
首先要在實現的AccessibilityTestService
中重寫的onAccessibilityEvent
方法中和event
繫結。
AccessibilityOperator.getInstance().updateEvent(this, event);
updateEvent方法
public void updateEvent(AccessibilityService service, AccessibilityEvent event) {
if (service != null && mAccessibilityService == null) {
mAccessibilityService = service;
}
if (event != null) {
mAccessibilityEvent = event;
}
}
根據text搜尋所有符合的節點
public List<AccessibilityNodeInfo> findNodesByText(String text) {
AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
if (nodeInfo != null) {
return nodeInfo.findAccessibilityNodeInfosByText(text);
}
return null;
根據ID搜尋所有符合的節點
public List<AccessibilityNodeInfo> findNodesById(String viewId) {
AccessibilityNodeInfo nodeInfo = getRootNodeInfo();
if (nodeInfo != null) {
if (Build.VERSION.SDK_INT >= 18) {
return nodeInfo.findAccessibilityNodeInfosByViewId(viewId);
}
}
return null;
}
獲取跟節點
private AccessibilityNodeInfo getRootNodeInfo() {
AccessibilityEvent curEvent = mAccessibilityEvent;
AccessibilityNodeInfo nodeInfo = null;
if (Build.VERSION.SDK_INT >= 16) {
if (mAccessibilityService != null) {
nodeInfo = mAccessibilityService.getRootInActiveWindow();
}
} else {
nodeInfo = curEvent.getSource();
}
return nodeInfo;
}
模擬點選
private boolean performClick(List<AccessibilityNodeInfo> nodeInfos) {
if (nodeInfos != null && !nodeInfos.isEmpty()) {
AccessibilityNodeInfo node;
for (int i = 0; i < nodeInfos.size(); i++) {
node = nodeInfos.get(i);
// 獲得點選View的型別
Log.i("accessibility", "getClassName:" + node.getClassName());
// 進行模擬點選
if (node.isEnabled()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
}
return false;
}
模擬退出鍵
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public boolean clickBackKey() {
return mAccessibilityService.performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
}
需要呼叫的地方直接獲取AccessibilityOperator
例項,獲取到需要操作的節點後呼叫模擬方法。