1. 程式人生 > >UiAutomator2.0 - 與AccessibilityService的關聯

UiAutomator2.0 - 與AccessibilityService的關聯

目錄

Accessibility:無障礙,又稱輔助性功能.
AccessibilityService:無障礙服務,繼承於 Serveice. 它可以監聽操作、檢索視窗內容、啟用觸控瀏覽等

一、Android中的 Accessibility

在原生android裝置中 Settings 應用程式選單中有一項 Accessibility(無障礙). 該項選單下有項 TallBack功能:它能讀取螢幕上的內容,對於盲人和視力低弱人士而言,這項功能非常實用. 還有不知道大家是否會注意,使用三方app store批量自動安裝app時,此時Accessibility中會出現 "xx自動安裝"功能. 那麼這些功能是怎實現的呢?是如何實現的呢?—— AccessibilityService

二、UiAutomator2.0 與 AccessibilityService

  在《UiAutomator2.0 - 控制元件實現點選操作原理》中已經分析了UiAutomator自動測試點選操作的具體實現過程,最終的操作是由 UiAutomation 這個類實現的.從這個類註釋可以看出:可以將UiAutomation看作特殊AccessibilityService 型別,它不為服務生命週期提供掛鉤,並且公開了對UI測試自動化有用的其他API.也就是說UiAutomator2.0是通過 AccessibilityService來實現的.

三、驗證與 AccessibilityService的關聯

a.為了驗證上面的猜想是否正確,在Android studio中新建app工程->建一個服務類MyAccessibility繼承 AccessibilityService

package com.zzw.barrierfree;

import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;

public class MyAccessibility extends AccessibilityService {
    private static final String TAG = MyAccessibility.class.getSimpleName();

    // 初始化服務操作
    @Override
    protected void onServiceConnected() {
        Log.d(TAG, "onServiceConnected: ------- config accessibility ");
        AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
        // 響應某個應用的事件,包名為應用的包名。設定為null等同於所有包名
        accessibilityServiceInfo.packageNames = new String[]{ "com.android.settings"};
        // 響應時間的型別,事件分很多種:單擊、長按、滑動。 這裡設定為所有事件
        accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
        // 設定回饋給使用者的方式,語音播出還是振動
        accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN;
        // 響應時間的設定
        accessibilityServiceInfo.notificationTimeout = 1000;
        setServiceInfo(accessibilityServiceInfo);
    }

    // 響應AccessibilityEvent的事件
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        int eventTypeId = event.getEventType();
        String eventText = "";
        Log.d(TAG, "onAccessibilityEvent: ----------------Start--------------");
        switch (eventTypeId) {
            case AccessibilityEvent.TYPE_VIEW_CLICKED:
                eventText = "TYPE_VIEW_CLICKED";
                break;
            case AccessibilityEvent.TYPE_VIEW_FOCUSED:
                eventText = "TYPE_VIEW_FOCUSED";
                break;
            case AccessibilityEvent.TYPE_VIEW_LONG_CLICKED:
                eventText = "TYPE_VIEW_LONG_CLICKED";
                break;
            case AccessibilityEvent.TYPE_VIEW_SELECTED:
                eventText = "TYPE_VIEW_SELECTED";
                break;
            case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
                eventText = "TYPE_VIEW_TEXT_CHANGED";
                break;
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                eventText = "TYPE_WINDOW_STATE_CHANGED";
                break;
            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
                eventText = "TYPE_NOTIFICATION_STATE_CHANGED";
                break;
            case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
                eventText = "TYPE_TOUCH_EXPLORATION_GESTURE_END";
                break;
            case AccessibilityEvent.TYPE_ANNOUNCEMENT:
                eventText = "TYPE_ANNOUNCEMENT";
                break;
            case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
                eventText = "TYPE_TOUCH_EXPLORATION_GESTURE_START";
                break;
            case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
                eventText = "TYPE_VIEW_HOVER_ENTER";
                break;
            case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
                eventText = "TYPE_VIEW_HOVER_EXIT";
                break;
            case AccessibilityEvent.TYPE_VIEW_SCROLLED:
                eventText = "TYPE_VIEW_SCROLLED";
                break;
            case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
                eventText = "TYPE_VIEW_TEXT_SELECTION_CHANGED";
                break;
            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
                eventText = "TYPE_WINDOW_CONTENT_CHANGED";
                break;
        }
        eventText = eventText + ":" + eventTypeId;
        Log.e(TAG, "onAccessibilityEvent:"+ eventText);
        Log.d(TAG, "onAccessibilityEvent: -------------------End----------------");
    }

    // 打斷獲取事件的過程
    @Override
    public void onInterrupt() {

    }
}

b.在AndroidManifest.xml中配置服務

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zzw.barrierfree">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/AppTheme.NoActionBar">
        <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=".MyAccessibility"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
        </service>
    </application>
</manifest>

c.執行該app,此時在設定->無障礙中會出現配置的服務, 但是該服務處於關閉狀態

d.手動開啟該服務,開啟android studio中的logcat. 操作(點選/滑動等)設定應用程式,會出現相應的響應事件

e.結合上篇的點選時監聽的相應事件,與log中列印的事件是一致的. 那就說明:點選/滑動等操作是通過 AccessibilityService 監聽對應的檢視或視窗狀態來判斷操作是否成功執行.