1. 程式人生 > >Android輔助功能(無障礙)使用---AccessibilityService

Android輔助功能(無障礙)使用---AccessibilityService

1.Android文件裡AccessibilityService簡介

在這裡插入圖片描述

輔助功能只在幫助殘障人士使用Android裝置和app的時候使用。 服務程序被殺掉後,下次啟動,需再次申請許可權

2.實現輔助功能服務

實現輔助功能,需要實現AccessibilityService類,並重寫onAccessibilityEventonInterrupt方法。

程式碼:

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例項,獲取到需要操作的節點後呼叫模擬方法。