欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報激活碼778899分享:Android無障礙服務(wù)

柚子快報激活碼778899分享:Android無障礙服務(wù)

http://yzkb.51969.com/

Hi I’m Shendi

Android無障礙服務(wù)

最近想制作一個記錄點(diǎn)擊操作并重復(fù)播放的工具,用以解放雙手,因現(xiàn)在的Android高版本基本上難以Root,所以選擇了使用無障礙來實(shí)現(xiàn),在這里記錄下來。

Android無障礙

可參考文檔:https://informationaccessibilityassociation.github.io/androidAccessibility/services.htm

https://developer.android.google.cn/reference/android/accessibilityservice/AccessibilityService

配置

首先需要在清單文件(AndroidManifest.xml)中進(jìn)行配置

xmlns:tools="http://schemas.android.com/tools">

tools:ignore="ProtectedPermissions,WrongManifestParent" />

android:label="@string/accessibility_service_label"

android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"

android:exported="true">

android:name="android.accessibilityservice"

android:resource="@xml/accessibility_service_config" />

上面首先聲明了權(quán)限,然后在 application 中注冊了服務(wù)。

其中服務(wù)有一個 label,這個label的內(nèi)容與無障礙中應(yīng)用名稱是一致的,例如我的名稱為 AutoImitate - 自動模擬,在手機(jī)的無障礙設(shè)置頁面中,會出現(xiàn)下面這樣的東西

上面還配置了一個配置文件 @xml/accessibility_service_config,資源文件夾xml下的accessibility_service_config.xml

其中內(nèi)容大致如下

android:description="@string/accessibility_service_description"

android:packageNames="com.example.android.apis"

android:accessibilityEventTypes="typeAllMask"

android:accessibilityFlags="flagDefault"

android:accessibilityFeedbackType="feedbackSpoken"

android:notificationTimeout="100"

android:canRetrieveWindowContent="true"

android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity">

上面這種指定文件的方式是從 Android 4.0 開始被支持的。

除了這種指定文件的方式,還可以使用 AccessibilityServiceInfo 來動態(tài)設(shè)置,但這種方法并不能配置所有的配置項(xiàng)。

對于哪些配置可以動態(tài)設(shè)置,參考:https://developer.android.google.cn/reference/android/accessibilityservice/AccessibilityServiceInfo.html

至于上面的配置,功能如下:

android:description

描述信息,會在無障礙頁面點(diǎn)擊本應(yīng)用后的最下方顯示,如下紅色方框部分所示

android:packageNames

接收指定包名的事件,多個用英文逗號分隔,不設(shè)置則接收所有。

android:accessibilityEventTypes

定義服務(wù)接收的事件類型,多個使用|分隔。

類型描述typeViewClicked點(diǎn)擊了某個視圖typeViewFocused某個視圖獲得了焦點(diǎn)typeViewLongClicked用戶長按了某個視圖typeViewSelected某個視圖被選中,例如在列表或網(wǎng)格中選擇了一個項(xiàng)目typeWindowStateChanged一個窗口的狀態(tài)發(fā)生了變化,例如一個新的活動(Activity)被打開或關(guān)閉typeNotificationStateChanged系統(tǒng)的通知狀態(tài)發(fā)生了變化,例如新的通知到達(dá)typeAllMask所有事件

android:accessibilityFlags

定義一些特殊的行為標(biāo)志,多個使用 | 分隔

標(biāo)志描述flagDefault當(dāng)不設(shè)置其他特定標(biāo)志時,使用這個標(biāo)志可以保持輔助功能的默認(rèn)行為。flagIncludeNotImportantViews此標(biāo)志指示輔助功能服務(wù)也應(yīng)接收那些被標(biāo)記為“不重要”的視圖的事件flagRequestTouchExplorationMode請求系統(tǒng)啟用觸摸探索模式,也就是手勢監(jiān)聽。flagRequestEnhancedWebAccessibility請求增強(qiáng)的網(wǎng)頁無障礙功能。這通常意味著在WebView中提供更詳細(xì)和更準(zhǔn)確的無障礙信息flagRequestFilterKeyEvents請求能夠過濾鍵事件,這意味著輔助功能服務(wù)可以捕獲并處理鍵盤輸入事件

android:accessibilityFeedbackType

定義該服務(wù)如何為用戶提供反饋,多個使用|分隔。

名稱描述feedbackSpoken語音反饋,文本轉(zhuǎn)語音(TTS)feedbackHaptic觸覺反饋,通常是通過設(shè)備振動來提供反饋feedbackSound聲音反饋feedbackVisual視覺反饋,在屏幕上顯示額外的視覺元素來提供反饋,如閃爍的邊框或圖標(biāo)。feedbackGeneric一個通用的反饋類型,可能包含上述多種反饋方式的組合。當(dāng)開發(fā)者不確定或想要保持靈活性,不具體到某一種反饋方式時,可以選擇這個選項(xiàng)。這樣,服務(wù)可以根據(jù)實(shí)際情況選擇最合適的反饋方式。feedbackAllMask所有反饋

android:notificationTimeout

定義在連續(xù)接收兩個相同類型的事件之間服務(wù)應(yīng)等待的毫秒數(shù)。這有助于防止服務(wù)被頻繁觸發(fā)。

android:canRetrieveWindowContent

是否允許無障礙服務(wù)訪問活動窗口的內(nèi)容。這對于實(shí)現(xiàn)自動化點(diǎn)擊等功能至關(guān)重要,true或false。

android:settingsActivity

指定一個用于配置無障礙服務(wù)的Activity。

更多的可以在這個頁面查閱:https://developer.android.google.cn/reference/android/R.styleable.html

無障礙服務(wù)

在上面的配置中,注冊了服務(wù),而服務(wù)名稱為 MyAccessibilityService

無障礙服務(wù)必須繼承AccessibilityService 類,重寫該類的函數(shù),有兩個函數(shù)必須重寫。一般重寫下面四個函數(shù)

/**

* 自動模擬服務(wù).

* 創(chuàng)建時間:2024/5/4

* @author 砷碲

*/

public class MyAccessibilityService extends AccessibilityService {

private static SLog log = SLog.getLogger(Application.class.getName());

/** 當(dāng)前服務(wù)的對象,為空代表當(dāng)前服務(wù)未啟動 */

public static MyAccessibilityService instance;

@Override

protected void onServiceConnected() {

super.onServiceConnected();

instance = this;

log.d("accessibility connect");

}

@Override

public void onAccessibilityEvent(AccessibilityEvent event) {

log.d("accessibility event");

}

@Override

public void onInterrupt() {

log.d("accessibility interrupt");

}

@Override

public boolean onUnbind(Intent intent) {

log.d("accessibility unbind");

instance = null;

return super.onUnbind(intent);

}

}

onServiceConnected 在打開當(dāng)前無障礙服務(wù)時執(zhí)行(即手機(jī)的無障礙設(shè)置頁面打開當(dāng)前無障礙)

onUnbind 在關(guān)閉當(dāng)前無障礙服務(wù)時執(zhí)行(即手機(jī)的無障礙設(shè)置頁面關(guān)閉當(dāng)前無障礙)

下圖是打開關(guān)閉當(dāng)前無障礙服務(wù)的輸出信息

onAccessibilityEvent(必選)

當(dāng)系統(tǒng)檢測到一個符合無障礙服務(wù)設(shè)定的無障礙事件過濾參數(shù)的事件時,該方法被系統(tǒng)回調(diào)。例如,當(dāng)用戶在應(yīng)用程序中點(diǎn)擊一個按鈕或聚焦一個用戶界面控件時,你的無障礙服務(wù)會為此應(yīng)用程序提供反饋。此時,系統(tǒng)調(diào)用這個方法,傳遞相關(guān)聯(lián)的無障礙事件,無障礙服務(wù)就可以翻譯和使用該事件為用戶提供反饋。在無障礙服務(wù)的生命周期中,該方法會被調(diào)用多次。

onInterrupt(必選)

當(dāng)系統(tǒng)想要打斷無障礙服務(wù)提供的反饋時該方法被調(diào)用,一般情況下是響應(yīng)用戶操作,如移動焦點(diǎn)到一個不同的控件。在無障礙服務(wù)的生命周期中,該方法會被調(diào)用很多次。

檢測服務(wù)是否打開

通過上面的信息,要檢測當(dāng)前無障礙服務(wù)是否開啟就很簡單了,使用一個全局變量,存儲當(dāng)前對象,在onServiceConnected 時賦值,onUnbind 置空。

接下來,判斷就像下面這樣就可以了,當(dāng)為空代表未開啟,跳轉(zhuǎn)無障礙頁面,跳轉(zhuǎn)失敗就跳設(shè)置頁面

/** 校驗(yàn)無障礙是否開啟,未開啟則跳轉(zhuǎn)開啟頁面. */

public static void checkAccessibility(Context context) {

if (MyAccessibilityService.instance == null) {

try {

context.startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));

} catch (Exception e) {

context.startActivity(new Intent(Settings.ACTION_SETTINGS));

e.printStackTrace();

}

Toast.makeText(context, "請開啟本軟件的無障礙服務(wù):" + context.getString(R.string.accessibility_service_label), Toast.LENGTH_LONG).show();

}

}

獲取事件詳情

當(dāng)監(jiān)聽到事件時(如點(diǎn)擊,滑動等),會觸發(fā) onAccessibilityEvent 函數(shù),函數(shù)接收一個 AccessibilityEvent 對象作為參數(shù)。

Android系統(tǒng)通過AccessibilityEvent對象為無障礙服務(wù)提供用戶界面交互的信息。在Android4.0之前,可從無障礙事件中獲得信息,且無障礙事件能夠提供用戶所選擇的界面控件的大量詳細(xì)信息,但這些信息僅包含有限的上下文信息。在很多情況下,丟失的上下文信息可能是理解已選定控件的意義的關(guān)鍵。

通常,我們需要根據(jù)事件來進(jìn)行后面的操作,例如用戶點(diǎn)擊某按鈕,就自動化做一些操作之類的。

public void onAccessibilityEvent(AccessibilityEvent event) {

if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {

// ...

}

}

上面的 event.getEventType() 是獲取當(dāng)前事件類型,而 AccessibilityEvent.TYPE_VIEW_CLICKED 代表點(diǎn)擊事件,值是1。當(dāng)有任意元素(可以被點(diǎn)擊的)點(diǎn)擊后執(zhí)行(按下+抬起),所以通常需要拿到當(dāng)前事件對應(yīng)的元素,分析是否是我們需要關(guān)注的,根據(jù)這個,再進(jìn)行下一步。

常用的提取元素信息代碼如下

// 獲得事件的資源節(jié)點(diǎn)

AccessibilityNodeInfo nodeInfo = event.getSource();

if (nodeInfo != null) {

// 元素基本信息

System.out.println("元素文本:" + nodeInfo.getText()

+ "\n元素描述:" + nodeInfo.getContentDescription()

+ "\nID資源名稱:" + nodeInfo.getViewIdResourceName()

+ "\n元素類名:" + nodeInfo.getClassName()

+ "\n應(yīng)用包名:" + nodeInfo.getPackageName()

+ "\n是否可點(diǎn)擊:" + nodeInfo.isClickable()

+ "\n是否支持長按:" + nodeInfo.isLongClickable()

+ "\n是否對用戶可見:" + nodeInfo.isVisibleToUser());

// ...

// 位置信息,x,y就是點(diǎn)擊中心

Rect rect = new Rect();

nodeInfo.getBoundsInScreen(rect);

System.out.println("[" + rect.centerX() + "," + rect.centerY() + "], 寬:" + (rect.right - rect.left) + ",高:" + (rect.bottom - rect.top));

// 元素查找操作

// 找到指定id的所有元素

List nodesById = nodeInfo.findAccessibilityNodeInfosByViewId("view id");

// 找到指定文本內(nèi)容的所有元素

List nodesByText = nodeInfo.findAccessibilityNodeInfosByText("砷碲");

// 父元素

AccessibilityNodeInfo parentNode = nodeInfo.getParent();

// 子元素操作

int childCount = nodeInfo.getChildCount();

AccessibilityNodeInfo child = nodeInfo.getChild(0);

// 釋放資源

nodeInfo.recycle();

}

除了上面所說的,還有一些當(dāng)前無障礙服務(wù)對象提供的函數(shù),例如getRootInActiveWindow,獲取當(dāng)前活動窗口的根節(jié)點(diǎn),返回AccessibilityNodeInfo對象

判斷元素類型

可以通過 getClassName 獲取到當(dāng)前元素的全類名,例如判斷是否為按鈕

boolean isBtn = "android.widget.Button".equals(nodeInfo.getClassName());

還可以通過是否可以點(diǎn)擊,是否可輸入等來進(jìn)行判斷。

手勢監(jiān)聽

Android 4.1(API級別16)引入了手勢監(jiān)聽功能,允許無障礙服務(wù)監(jiān)聽特定手勢,并代表用戶響應(yīng)這些手勢。

要使用此功能,無障礙服務(wù)需要請求激活觸摸探索(Explore by Touch)特性,通過在其AccessibilityServiceInfo實(shí)例的flags成員中設(shè)置FLAG_REQUEST_TOUCH_EXPLORATION_MODE來實(shí)現(xiàn)。

激活觸摸探索

需要在配置文件的 accessibilityFlags 增加 flagRequestTouchExplorationMode 或者在服務(wù)中動態(tài)設(shè)置

官方文檔中有描述,當(dāng)版本是Android4.3(API 18)及之后版本,那么還需要配置 canRequestTouchExplorationMode 為 true,否則忽略

配置設(shè)置

android:accessibilityFlags="flagDefault|flagRequestTouchExplorationMode"

android:canRequestTouchExplorationMode="true">

動態(tài)設(shè)置

@Override

protected void onServiceConnected() {

super.onServiceConnected();

instance = this;

log.d("accessibility connect");

// 在 onServiceConnected 中 getServiceInfo 不為null,在onCreate則有可能為null

if (getServiceInfo() != null) {

getServiceInfo().flags = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;

}

}

配置成功的話,在用戶打開無障礙服務(wù)的時候,彈出的對話框會新增一項(xiàng)觸摸探索…

開啟后,交互操作有所改變,比如滑動變成了雙指滑動,點(diǎn)擊變成了雙指點(diǎn)擊等

接收手勢通知

通過重寫 onGesture 函數(shù)來實(shí)現(xiàn)接收。

Android API 31之前,使用 onGesture(int),而31及之后,使用 onGesture(AccessibilityGestureEvent)

需要注意的是,API31后,如果回調(diào)函數(shù)內(nèi)參數(shù)對象的 getDisplayId() == Display.DEFAULT_DISPLAY,那么依然使用onGesture(int)

我使用的是逍遙模擬器,API小于31,所以結(jié)果如下圖所示

這部分是給真正需要使用無障礙的人使用的,包括上面的觸摸探索,所以這里就不深挖了。

操作

從Android4.0(API級別14)開始,無障礙服務(wù)可以代表用戶操作,包含改變輸入焦點(diǎn)和選擇(激活)用戶界面元素。在Android4.1(API級別16),操作的范圍被擴(kuò)展至包含滾動列表和與文本域交互。無障礙服務(wù)也可采取全局操作,如導(dǎo)航到主界面、按返回按鈕、打開屏幕通知和最近應(yīng)用列表。Android4.1也包含新焦點(diǎn)類型,無障礙焦點(diǎn),該焦點(diǎn)類型可讓所有視覺元素能夠被無障礙服務(wù)所選擇。

這些新的能力讓開發(fā)者能夠開發(fā)替代導(dǎo)航模式,如手勢導(dǎo)航,提高殘障用戶對Android設(shè)備的控制。

使用AccessibilityNodeInfo對象你的無障礙服務(wù)可以瀏覽視圖層次來判定采取什么操作并使用performAction()為用戶操作。AccessibilityNodeInfo 對象可以通過 event.getSource() 獲取。

除此之外,還可以通過 AccessibilityService 的 performGlobalAction 進(jìn)行全局操作,示例如下

// 全局操作,以 GLOBAL 開頭的都是全局,例如點(diǎn)擊主頁按鈕,返回按鈕

performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME);

performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);

// 給元素發(fā)送操作,ACTION_之類的,大致操作將后面的翻譯一下就知道了

// 還可以通過元素父級子級等獲取其他元素來操作其他元素

// 例如給當(dāng)前元素的父級元素的第一個子元素發(fā)送點(diǎn)擊事件

AccessibilityNodeInfo nodeInfo = event.getSource();

nodeInfo.getParent().getChild(0).performAction(AccessibilityNodeInfo.ACTION_CLICK);

文本輸入操作,AccessibilityNodeInfo需要是EditText之類的

Bundle textBundle = new Bundle();

textBundle.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "輸入的文本-砷碲");

nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, textBundle);

滾動操作,是滾動一頁,一個往前滾動,一個往后滾動

nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);

nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);

一般這樣夠用了,但是需要精確滾動的話,可以使用模擬手勢

模擬手勢

有的時候有需求,在指定屏幕位置進(jìn)行點(diǎn)擊等各種操作,而不是對組件,這個時候可以使用模擬手勢

模擬手勢是通過編程方式模擬用戶在屏幕上的觸摸和滑動操作

Android API 24及以上可用(即Android 7.0 Nougat)

首先是無障礙中要配置canPerformGestures權(quán)限,這樣在啟動無障礙服務(wù)時會增加一項(xiàng)執(zhí)行手勢,代碼如下

android:canPerformGestures="true">

兩個步驟,構(gòu)建手勢描述(GestureDescription)和發(fā)送手勢(dispatchGesture)

下面列出點(diǎn)擊,長按,滑動的示例

Path path = new Path();

path.moveTo(100, 100);

// 長按位置

Path longPath = new Path();

longPath.moveTo(100, 100);

// 滑動位置, 從100,100到300,300

Path scrollPath = new Path();

scrollPath.moveTo(100, 100);

scrollPath.lineTo(300, 300);

// 可以多次addStroke來實(shí)現(xiàn)組合動作

// * 但實(shí)測,只建議單個addStroke,多個可能會導(dǎo)致APP和系統(tǒng)崩潰...

// StrokeDescription中,第二個參數(shù)是開始時間,第三個參數(shù)是持續(xù)多久,單位毫秒

GestureDescription gd = new GestureDescription.Builder()

// 點(diǎn)擊屏幕,坐標(biāo) x=100, y=100。

.addStroke(new GestureDescription.StrokeDescription(path, 0, 100))

// 點(diǎn)擊完長按屏幕

.addStroke(new GestureDescription.StrokeDescription(longPath, 100, 10000))

// 點(diǎn)擊,長按完,滑動

.addStroke(new GestureDescription.StrokeDescription(scrollPath, 1100, 300))

// 構(gòu)建

.build();

// 發(fā)送手勢,返回手勢是否成功發(fā)送到了系統(tǒng)以進(jìn)行執(zhí)行

// 第二個參數(shù)是GestureResultCallback,可選,用來接收手勢執(zhí)行的結(jié)果,當(dāng)手勢執(zhí)行完成后,系統(tǒng)會調(diào)用這個回調(diào)接口中的方法,并傳遞一個GestureResult對象作為參數(shù),該對象包含了手勢執(zhí)行的結(jié)果信息。通過實(shí)現(xiàn)這個接口,你可以在應(yīng)用程序中處理手勢執(zhí)行的結(jié)果,例如根據(jù)結(jié)果更新UI或執(zhí)行其他操作。

// 第三個參數(shù)Handler,可選,如果你提供了Handler對象,那么GestureResultCallback的回調(diào)方法將在該Handler指定的線程中執(zhí)行。這允許你控制回調(diào)方法在哪個線程中運(yùn)行,以便更好地管理線程和避免潛在的線程沖突問題。如果你沒有提供Handler對象,那么回調(diào)方法將在系統(tǒng)默認(rèn)的UI線程中執(zhí)行。

boolean isRun = dispatchGesture(gd, new GestureResultCallback() {

@Override

public void onCompleted(GestureDescription gestureDescription) {

System.out.println("手勢完成");

super.onCompleted(gestureDescription);

}

@Override

public void onCancelled(GestureDescription gestureDescription) {

System.out.println("手勢取消");

super.onCancelled(gestureDescription);

}

}, null);

System.out.println(isRun);

踩坑

開關(guān)無障礙服務(wù)函數(shù)沒有被調(diào)用

當(dāng)將一切都配置好,本來可以調(diào)用,莫名其妙突然無法調(diào)用。我的問題出現(xiàn)場景大概是我將無障礙服務(wù)的類名修改,然后重新運(yùn)行,發(fā)現(xiàn)再次開啟無障礙服務(wù),沒有任何效果(即不會觸發(fā)服務(wù)的函數(shù))

最后猜到是模擬器問題,將其重啟后就解決了。

END

柚子快報激活碼778899分享:Android無障礙服務(wù)

http://yzkb.51969.com/

相關(guān)文章

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://m.gantiao.com.cn/post/19320680.html

發(fā)布評論

您暫未設(shè)置收款碼

請?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄