GIT 提交信息:

改善无障碍服务应用的跟踪和反馈

- 实现通过应用程序包名跟踪当前活动应用的支持。
- 引入重试机制,提高检测并返回目标应用的可靠性。
- 通过吐司消息增强用户体验,以反馈应用启动问题。
This commit is contained in:
lvlisong 2025-02-14 13:11:36 +08:00
parent 56c14fe3ca
commit 77579d2b5f

View File

@ -4,10 +4,14 @@ import android.accessibilityservice.AccessibilityService
import android.content.Intent
import android.graphics.Rect
import android.os.Binder
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.Toast
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import kotlinx.coroutines.delay
import java.util.LinkedList
class MyAccessibilityService : AccessibilityService() {
@ -22,6 +26,7 @@ class MyAccessibilityService : AccessibilityService() {
}
private val binder = MyBinder()
private var targetAppPackageName: String? = null // 目标应用的包名
inner class MyBinder : Binder() {
fun getService(): MyAccessibilityService = this@MyAccessibilityService
@ -136,6 +141,10 @@ class MyAccessibilityService : AccessibilityService() {
return result
}
/**
* 查找并启动指定应用
* @param appName 应用名称
*/
/**
* 查找并启动指定应用
* @param appName 应用名称
@ -160,6 +169,16 @@ class MyAccessibilityService : AccessibilityService() {
matchingNodes.firstOrNull()?.let { targetNode ->
if (targetNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)) {
Log.d(TAG, "Successfully launched: $appName")
// 启动重试机制
retryToDetectTargetApp(10, 3000) { success ->
if (success) {
Log.d(TAG, "Target app package name detected: $targetAppPackageName")
} else {
Log.e(TAG, "Failed to detect target app after 10 retries")
showToast("Failed to launch $appName")
}
}
} else {
Log.w(TAG, "Failed to click app: $appName")
}
@ -174,6 +193,49 @@ class MyAccessibilityService : AccessibilityService() {
}
}
/**
* 重试检测目标应用
* @param maxRetries 最大重试次数
* @param delayMillis 每次重试的延时毫秒
* @param onResult 结果回调true 表示成功false 表示失败
*/
private fun retryToDetectTargetApp(maxRetries: Int, delayMillis: Long, onResult: (Boolean) -> Unit) {
var retryCount = 0
val retryRunnable = object : Runnable {
override fun run() {
rootInActiveWindow?.let { currentRoot ->
val packageName = currentRoot.packageName?.toString()
if (packageName != null && packageName != targetAppPackageName) {
targetAppPackageName = packageName
onResult(true) // 成功检测到目标应用
return
}
}
retryCount++
if (retryCount < maxRetries) {
Handler(Looper.getMainLooper()).postDelayed(this, delayMillis) // 继续重试
} else {
onResult(false) // 重试次数用尽,失败
}
}
}
// 启动第一次重试
Handler(Looper.getMainLooper()).postDelayed(retryRunnable, delayMillis)
}
/**
* 显示 Toast 消息
* @param message 要显示的消息
*/
private fun showToast(message: String) {
Handler(Looper.getMainLooper()).post {
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
}
/**
* 处理无障碍事件
* @param event 无障碍事件
@ -183,10 +245,63 @@ class MyAccessibilityService : AccessibilityService() {
when (event.eventType) {
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> {
Log.d(TAG, "Window state changed: ${event.packageName}")
Log.d(TAG, "target app package name: $targetAppPackageName")
// 检测当前活动的应用是否发生了变化
event.packageName?.let { currentPackageName ->
if (targetAppPackageName != null && currentPackageName != targetAppPackageName) {
Log.d(TAG, "Detected app switch from $targetAppPackageName to $currentPackageName")
retryBackToTargetApp(10, 1000) { success ->
if (success) {
Log.d(TAG, "Successfully returned to $targetAppPackageName")
} else {
Log.e(TAG, "Failed to return to $targetAppPackageName after 10 retries")
showToast("Failed to return to target app")
}
}
}
}
}
}
}
/**
* 重试返回目标应用
* @param maxRetries 最大重试次数
* @param delayMillis 每次重试的延时毫秒
* @param onResult 结果回调true 表示成功false 表示失败
*/
private fun retryBackToTargetApp(maxRetries: Int, delayMillis: Long, onResult: (Boolean) -> Unit) {
var retryCount = 0
val retryRunnable = object : Runnable {
override fun run() {
// 检测当前窗口是否已经返回到目标应用
rootInActiveWindow?.let { currentRoot ->
val packageName = currentRoot.packageName?.toString()
if (packageName == targetAppPackageName) {
onResult(true) // 成功返回到目标应用
return
}
}
// 尝试点击返回按钮
performGlobalAction(GLOBAL_ACTION_BACK)
Log.d(TAG, "Performed back action, retry count: $retryCount")
retryCount++
if (retryCount < maxRetries) {
Handler(Looper.getMainLooper()).postDelayed(this, delayMillis) // 继续重试
} else {
onResult(false) // 重试次数用尽,失败
}
}
}
// 启动第一次重试
Handler(Looper.getMainLooper()).postDelayed(retryRunnable, delayMillis)
}
/**
* 安全启动主Activity
*/
@ -206,6 +321,7 @@ class MyAccessibilityService : AccessibilityService() {
*/
private fun cleanUpResources() {
instance = null
targetAppPackageName = null
}
/**