merge: pause task claiming when accessibility is not ready (#385)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NTDbDcwbDw1TSAcE6wfh2F
This commit is contained in:
@@ -12,11 +12,15 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import cn.ilapage.goauto.agent.service.AgentForegroundService
|
||||
import cn.ilapage.goauto.agent.service.AgentSettingsStore
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityPauseText
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityReadiness
|
||||
import cn.ilapage.goauto.agent.ui.AgentSettingsFragment
|
||||
import cn.ilapage.goauto.agent.ui.AgentUiVisibility
|
||||
import cn.ilapage.goauto.agent.ui.AgentStatusFragment
|
||||
import cn.ilapage.goauto.agent.ui.TaskHistoryFragment
|
||||
import cn.ilapage.goauto.agent.update.AgentAppUpdateManager
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private var selectedTab = TAB_STATUS
|
||||
@@ -30,6 +34,18 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private var accessibilityDialog: androidx.appcompat.app.AlertDialog? = null
|
||||
private val accessibilityReceiver = object : android.content.BroadcastReceiver() {
|
||||
override fun onReceive(context: android.content.Context?, intent: android.content.Intent?) {
|
||||
if (intent?.action != AgentForegroundService.ACTION_ACCESSIBILITY_ALERT) return
|
||||
val readiness = runCatching {
|
||||
AccessibilityReadiness.valueOf(intent.getStringExtra(AgentForegroundService.EXTRA_ACCESSIBILITY_READINESS).orEmpty())
|
||||
}.getOrNull() ?: return
|
||||
showAccessibilityDialog(readiness)
|
||||
}
|
||||
}
|
||||
private var accessibilityReceiverRegistered = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
selectedTab = AgentTabSelectionPolicy.initialTab(
|
||||
@@ -53,9 +69,15 @@ class MainActivity : AppCompatActivity() {
|
||||
cn.ilapage.goauto.agent.automation.GoAutoAccessibilityService.instance?.dismissPurchaseResultBubble()
|
||||
screenPolicyHandler.removeCallbacks(screenPolicyRefresh)
|
||||
screenPolicyHandler.post(screenPolicyRefresh)
|
||||
AgentUiVisibility.resumed = true
|
||||
registerAccessibilityReceiver()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
AgentUiVisibility.resumed = false
|
||||
unregisterAccessibilityReceiver()
|
||||
accessibilityDialog?.dismiss()
|
||||
accessibilityDialog = null
|
||||
screenPolicyHandler.removeCallbacks(screenPolicyRefresh)
|
||||
super.onPause()
|
||||
}
|
||||
@@ -65,6 +87,38 @@ class MainActivity : AppCompatActivity() {
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
private fun showAccessibilityDialog(readiness: AccessibilityReadiness) {
|
||||
accessibilityDialog?.dismiss()
|
||||
accessibilityDialog = null
|
||||
val detail = AccessibilityPauseText.recovery(readiness) ?: return // READY:恢复,仅关闭弹窗
|
||||
accessibilityDialog = MaterialAlertDialogBuilder(this)
|
||||
.setTitle(AccessibilityPauseText.TITLE)
|
||||
.setMessage(detail)
|
||||
.setNegativeButton("稍后", null)
|
||||
.setPositiveButton("去设置") { _, _ ->
|
||||
startActivity(android.content.Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS))
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun registerAccessibilityReceiver() {
|
||||
if (accessibilityReceiverRegistered) return
|
||||
val filter = android.content.IntentFilter(AgentForegroundService.ACTION_ACCESSIBILITY_ALERT)
|
||||
if (Build.VERSION.SDK_INT >= 33) {
|
||||
registerReceiver(accessibilityReceiver, filter, RECEIVER_NOT_EXPORTED)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
registerReceiver(accessibilityReceiver, filter)
|
||||
}
|
||||
accessibilityReceiverRegistered = true
|
||||
}
|
||||
|
||||
private fun unregisterAccessibilityReceiver() {
|
||||
if (!accessibilityReceiverRegistered) return
|
||||
runCatching { unregisterReceiver(accessibilityReceiver) }
|
||||
accessibilityReceiverRegistered = false
|
||||
}
|
||||
|
||||
private fun buildContent(): LinearLayout {
|
||||
val content = LinearLayout(this).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
|
||||
@@ -79,6 +79,13 @@ import cn.ilapage.goauto.agent.diagnostics.AccessibilitySnapshotSource
|
||||
import cn.ilapage.goauto.agent.diagnostics.FailureSnapshotCapture
|
||||
import cn.ilapage.goauto.agent.diagnostics.FailureSnapshotPolicy
|
||||
import cn.ilapage.goauto.agent.diagnostics.SnapshotContext
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityAlertAction
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityAlertTracker
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityDispatchGate
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityPauseText
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityReadiness
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityReadinessDetector
|
||||
import cn.ilapage.goauto.agent.ui.AgentUiVisibility
|
||||
import cn.ilapage.goauto.agent.ui.PurchaseResultBubblePolicy
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
@@ -103,6 +110,7 @@ class AgentForegroundService : Service() {
|
||||
private var repurchaseSession: RepurchaseSession? = null
|
||||
private val repurchaseEvidence = java.util.concurrent.ConcurrentHashMap<Long, java.util.concurrent.ConcurrentHashMap<Long, RepurchaseExecutionEvidence>>()
|
||||
private val taskMutex = TaskExecutionMutex()
|
||||
private val accessibilityAlerts = AccessibilityAlertTracker()
|
||||
private val probeHandoff = PurchaseProbeHandoff()
|
||||
private val backfillGuard = OrderBackfillGuard(taskMutex)
|
||||
private val runningTaskId = AtomicReference<Long?>(null)
|
||||
@@ -443,6 +451,15 @@ class AgentForegroundService : Service() {
|
||||
|
||||
private fun scheduleTask(api: AgentApiClient, token: String): String {
|
||||
if (taskMutex.currentTaskId() != null) return MANUAL_BUSY
|
||||
val readiness = AccessibilityReadinessDetector.current(this)
|
||||
handleAccessibilityAlert(readiness)
|
||||
if (!AccessibilityDispatchGate.allowsClaiming(readiness)) {
|
||||
// 不调用任何领取/查询下一任务接口,任务留在服务端 pending;恢复后下一轮同步自动继续。
|
||||
cancelIdleReturn("无障碍未就绪")
|
||||
stateStore.update("ONLINE", AccessibilityPauseText.TITLE, tokenStored = true)
|
||||
updateNotification(AccessibilityPauseText.TITLE)
|
||||
return MANUAL_ACCESSIBILITY_NOT_READY
|
||||
}
|
||||
val collectionCooldown = activeCollectionCooldown()
|
||||
val purchaseTask = api.nextPurchaseTask(token)
|
||||
when (TaskDispatchPolicy.decide(purchaseTask?.status, collectionCooldown != null)) {
|
||||
@@ -489,6 +506,50 @@ class AgentForegroundService : Service() {
|
||||
return MANUAL_COLLECTION_TASK
|
||||
}
|
||||
|
||||
private fun handleAccessibilityAlert(readiness: AccessibilityReadiness) {
|
||||
val action = accessibilityAlerts.onReadiness(readiness)
|
||||
if (action == AccessibilityAlertAction.NONE) return
|
||||
val manager = getSystemService(NotificationManager::class.java)
|
||||
if (action == AccessibilityAlertAction.CANCEL) {
|
||||
manager.cancel(ACCESSIBILITY_ALERT_NOTIFICATION_ID)
|
||||
} else if (!AgentUiVisibility.resumed) {
|
||||
postAccessibilityAlertNotification(manager, readiness)
|
||||
}
|
||||
// 前台时由 MainActivity 收到广播后弹窗;恢复时同一广播让它关闭弹窗。
|
||||
sendBroadcast(Intent(ACTION_ACCESSIBILITY_ALERT).apply {
|
||||
setPackage(packageName)
|
||||
putExtra(EXTRA_ACCESSIBILITY_READINESS, readiness.name)
|
||||
})
|
||||
}
|
||||
|
||||
private fun postAccessibilityAlertNotification(manager: NotificationManager, readiness: AccessibilityReadiness) {
|
||||
// 通知权限被拒时静默跳过,不新增请求流程。
|
||||
if (!manager.areNotificationsEnabled()) return
|
||||
runCatching {
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
this, 1, Intent(this, MainActivity::class.java),
|
||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
|
||||
)
|
||||
val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
Notification.Builder(this, ACCESSIBILITY_ALERT_CHANNEL_ID)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
Notification.Builder(this).setPriority(Notification.PRIORITY_HIGH)
|
||||
}
|
||||
val detail = AccessibilityPauseText.recovery(readiness)
|
||||
manager.notify(
|
||||
ACCESSIBILITY_ALERT_NOTIFICATION_ID,
|
||||
builder.setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||
.setContentTitle(AccessibilityPauseText.TITLE)
|
||||
.setContentText(detail)
|
||||
.setStyle(Notification.BigTextStyle().bigText(detail))
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun publishManualCheckResult(result: String) {
|
||||
sendBroadcast(Intent(ACTION_CHECK_RESULT).apply {
|
||||
setPackage(packageName)
|
||||
@@ -1760,6 +1821,9 @@ class AgentForegroundService : Service() {
|
||||
manager.createNotificationChannel(
|
||||
NotificationChannel(CHANNEL_ID, "Agent 连接与心跳", NotificationManager.IMPORTANCE_LOW),
|
||||
)
|
||||
manager.createNotificationChannel(
|
||||
NotificationChannel(ACCESSIBILITY_ALERT_CHANNEL_ID, "无障碍未就绪提醒", NotificationManager.IMPORTANCE_HIGH),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1877,6 +1941,9 @@ class AgentForegroundService : Service() {
|
||||
const val EXTRA_CURRENT_PAGE_MESSAGE = "current_page_message"
|
||||
const val EXTRA_REPLACEMENT_ORIGIN_TYPE = "replacement_origin_type"
|
||||
const val EXTRA_REPLACEMENT_ORIGIN_TASK_ID = "replacement_origin_task_id"
|
||||
const val ACTION_ACCESSIBILITY_ALERT = "cn.ilapage.goauto.agent.ACCESSIBILITY_ALERT"
|
||||
const val EXTRA_ACCESSIBILITY_READINESS = "accessibility_readiness"
|
||||
const val MANUAL_ACCESSIBILITY_NOT_READY = "accessibility_not_ready"
|
||||
const val MANUAL_EMPTY = "empty"
|
||||
const val MANUAL_COLLECTION_TASK = "collection_task"
|
||||
const val MANUAL_PURCHASE_TASK = "purchase_task"
|
||||
@@ -1889,6 +1956,8 @@ class AgentForegroundService : Service() {
|
||||
const val MANUAL_COLLECTION_COOLDOWN_PREFIX = "collection_cooldown:"
|
||||
private const val CHANNEL_ID = "agent_connection"
|
||||
private const val NOTIFICATION_ID = 1001
|
||||
private const val ACCESSIBILITY_ALERT_CHANNEL_ID = "agent_accessibility_alert"
|
||||
private const val ACCESSIBILITY_ALERT_NOTIFICATION_ID = 1002
|
||||
private const val HEARTBEAT_SECONDS = 15L
|
||||
private const val TASK_WAKE_LOCK_TIMEOUT_MILLIS = 5 * 60 * 1000L
|
||||
private const val IDLE_RETURN_WAKE_LOCK_TIMEOUT_MILLIS = 30_000L
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.ilapage.goauto.agent.ui
|
||||
|
||||
/** 无障碍未就绪时暂停领取任务(#385)。纯策略,便于单元测试。 */
|
||||
object AccessibilityDispatchGate {
|
||||
fun allowsClaiming(readiness: AccessibilityReadiness): Boolean = readiness == AccessibilityReadiness.READY
|
||||
}
|
||||
|
||||
/** 暂停提示的文案,状态 Tab、手动检查、弹窗和通知共用。 */
|
||||
object AccessibilityPauseText {
|
||||
const val TITLE = "无障碍未就绪,已暂停领取任务"
|
||||
|
||||
fun recovery(readiness: AccessibilityReadiness): String? = when (readiness) {
|
||||
AccessibilityReadiness.READY -> null
|
||||
AccessibilityReadiness.ENABLED_WAITING -> "请到 设置 → 无障碍,把 GoAuto 关闭后重新打开"
|
||||
AccessibilityReadiness.DISABLED -> "请到 设置 → 无障碍 开启 GoAuto"
|
||||
}
|
||||
}
|
||||
|
||||
enum class AccessibilityAlertAction { NONE, PROMPT, CANCEL }
|
||||
|
||||
/**
|
||||
* 只在「就绪 → 未就绪」时提示一次;持续未就绪(含 DISABLED 与 ENABLED_WAITING 互转)不重复;
|
||||
* 恢复就绪时撤销提示,之后再次失效重新提示。进程内状态,不持久化。
|
||||
* 进程启动后的第一次观察视为转变:首次未就绪会提示,首次就绪会撤销可能残留的旧通知。
|
||||
*/
|
||||
class AccessibilityAlertTracker {
|
||||
private var previous: AccessibilityReadiness? = null
|
||||
|
||||
@Synchronized
|
||||
fun onReadiness(current: AccessibilityReadiness): AccessibilityAlertAction {
|
||||
val last = previous
|
||||
previous = current
|
||||
val ready = current == AccessibilityReadiness.READY
|
||||
return when {
|
||||
ready && last != AccessibilityReadiness.READY -> AccessibilityAlertAction.CANCEL
|
||||
!ready && (last == null || last == AccessibilityReadiness.READY) -> AccessibilityAlertAction.PROMPT
|
||||
else -> AccessibilityAlertAction.NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Agent 界面是否在前台(MainActivity onResume/onPause 维护),服务据此选择弹窗或通知。 */
|
||||
object AgentUiVisibility {
|
||||
@Volatile var resumed: Boolean = false
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import java.util.Date
|
||||
internal object ManualTaskCheckPolicy {
|
||||
fun blockedMessage(stateCode: String, currentTaskId: Long?, readiness: AccessibilityReadiness): String? = when {
|
||||
currentTaskId != null || stateCode == "BUSY" -> "当前任务执行中,无需重复检查"
|
||||
readiness != AccessibilityReadiness.READY -> "请先到“设置”开启采集采购助手"
|
||||
readiness != AccessibilityReadiness.READY -> AccessibilityPauseText.recovery(readiness)
|
||||
stateCode == "CONFIG_REQUIRED" -> "请先到“设置”配置服务地址"
|
||||
stateCode == "AUTH_ERROR" -> "设备身份校验失败,请先检查设置"
|
||||
else -> null
|
||||
@@ -38,6 +38,7 @@ internal object ManualTaskCheckPolicy {
|
||||
result == AgentForegroundService.MANUAL_EMPTY -> "暂无新任务,Agent 会继续自动检查"
|
||||
result == AgentForegroundService.MANUAL_COLLECTION_TASK -> "已领取采集任务"
|
||||
result == AgentForegroundService.MANUAL_PURCHASE_TASK -> "已领取采购任务"
|
||||
result == AgentForegroundService.MANUAL_ACCESSIBILITY_NOT_READY -> AccessibilityPauseText.TITLE
|
||||
result == AgentForegroundService.MANUAL_BUSY -> "当前任务执行中,无需重复检查"
|
||||
result == AgentForegroundService.MANUAL_CONFIG_REQUIRED -> "请先到“设置”配置服务地址"
|
||||
result == AgentForegroundService.MANUAL_AUTH_ERROR -> "设备身份校验失败,请先检查设置"
|
||||
@@ -52,10 +53,17 @@ internal object AgentStatusTextPolicy {
|
||||
"最近心跳:$heartbeat",
|
||||
).joinToString("\n")
|
||||
|
||||
fun accessibilityDetail(readiness: AccessibilityReadiness): String? = when (readiness) {
|
||||
AccessibilityReadiness.READY -> null
|
||||
AccessibilityReadiness.ENABLED_WAITING -> "请到“设置”检查无障碍服务"
|
||||
AccessibilityReadiness.DISABLED -> "请到“设置”开启"
|
||||
fun accessibilityDetail(readiness: AccessibilityReadiness): String? = AccessibilityPauseText.recovery(readiness)
|
||||
|
||||
fun accessibilityTitle(readiness: AccessibilityReadiness): String = when (readiness) {
|
||||
AccessibilityReadiness.READY -> "已开启"
|
||||
AccessibilityReadiness.ENABLED_WAITING -> "未连接,任务已暂停"
|
||||
AccessibilityReadiness.DISABLED -> "未开启,任务已暂停"
|
||||
}
|
||||
|
||||
fun accessibilityColor(readiness: AccessibilityReadiness): Int = when (readiness) {
|
||||
AccessibilityReadiness.READY -> R.color.agent_primary_light
|
||||
else -> R.color.agent_error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +117,7 @@ class AgentStatusFragment : Fragment() {
|
||||
AgentForegroundService.MANUAL_CONFIG_REQUIRED,
|
||||
AgentForegroundService.MANUAL_NETWORK_ERROR,
|
||||
AgentForegroundService.MANUAL_ERROR,
|
||||
AgentForegroundService.MANUAL_ACCESSIBILITY_NOT_READY,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -286,20 +295,8 @@ class AgentStatusFragment : Fragment() {
|
||||
"${if (purchase) "采购" else "采集"}任务 ${if (purchase) "CG-" else "#"}$id"
|
||||
} ?: "等待任务"
|
||||
val readiness = AccessibilityReadinessDetector.current(context)
|
||||
when (readiness) {
|
||||
AccessibilityReadiness.READY -> {
|
||||
accessibilityTitle.text = "已开启"
|
||||
accessibilityTitle.setTextColor(context.getColor(R.color.agent_primary_light))
|
||||
}
|
||||
AccessibilityReadiness.ENABLED_WAITING -> {
|
||||
accessibilityTitle.text = "等待连接"
|
||||
accessibilityTitle.setTextColor(context.getColor(R.color.agent_warning))
|
||||
}
|
||||
AccessibilityReadiness.DISABLED -> {
|
||||
accessibilityTitle.text = "未开启"
|
||||
accessibilityTitle.setTextColor(context.getColor(R.color.agent_error))
|
||||
}
|
||||
}
|
||||
accessibilityTitle.text = AgentStatusTextPolicy.accessibilityTitle(readiness)
|
||||
accessibilityTitle.setTextColor(context.getColor(AgentStatusTextPolicy.accessibilityColor(readiness)))
|
||||
accessibilityDetail.text = AgentStatusTextPolicy.accessibilityDetail(readiness).orEmpty()
|
||||
accessibilityDetail.visibility = if (accessibilityDetail.text.isEmpty()) View.GONE else View.VISIBLE
|
||||
val mediaReadiness = MediaPermissionPolicy.current(context)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package cn.ilapage.goauto.agent
|
||||
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityAlertAction
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityAlertTracker
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityDispatchGate
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityReadiness
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class AccessibilityDispatchGateTest {
|
||||
@Test fun pausesClaimingWhenDisabledOrWaiting() {
|
||||
assertFalse(AccessibilityDispatchGate.allowsClaiming(AccessibilityReadiness.DISABLED))
|
||||
assertFalse(AccessibilityDispatchGate.allowsClaiming(AccessibilityReadiness.ENABLED_WAITING))
|
||||
}
|
||||
|
||||
@Test fun allowsClaimingWhenReady() {
|
||||
assertTrue(AccessibilityDispatchGate.allowsClaiming(AccessibilityReadiness.READY))
|
||||
}
|
||||
|
||||
@Test fun promptsOnceWhenReadyBecomesNotReady() {
|
||||
val tracker = AccessibilityAlertTracker()
|
||||
assertEquals(AccessibilityAlertAction.CANCEL, tracker.onReadiness(AccessibilityReadiness.READY))
|
||||
assertEquals(AccessibilityAlertAction.NONE, tracker.onReadiness(AccessibilityReadiness.READY))
|
||||
assertEquals(AccessibilityAlertAction.PROMPT, tracker.onReadiness(AccessibilityReadiness.ENABLED_WAITING))
|
||||
assertEquals(AccessibilityAlertAction.NONE, tracker.onReadiness(AccessibilityReadiness.ENABLED_WAITING))
|
||||
assertEquals(AccessibilityAlertAction.NONE, tracker.onReadiness(AccessibilityReadiness.ENABLED_WAITING))
|
||||
}
|
||||
|
||||
@Test fun switchingBetweenNotReadyStatesDoesNotPromptAgain() {
|
||||
val tracker = AccessibilityAlertTracker()
|
||||
tracker.onReadiness(AccessibilityReadiness.READY)
|
||||
assertEquals(AccessibilityAlertAction.PROMPT, tracker.onReadiness(AccessibilityReadiness.DISABLED))
|
||||
assertEquals(AccessibilityAlertAction.NONE, tracker.onReadiness(AccessibilityReadiness.ENABLED_WAITING))
|
||||
assertEquals(AccessibilityAlertAction.NONE, tracker.onReadiness(AccessibilityReadiness.DISABLED))
|
||||
}
|
||||
|
||||
@Test fun recoveryCancelsAndNextFailurePromptsAgain() {
|
||||
val tracker = AccessibilityAlertTracker()
|
||||
tracker.onReadiness(AccessibilityReadiness.READY)
|
||||
tracker.onReadiness(AccessibilityReadiness.DISABLED)
|
||||
assertEquals(AccessibilityAlertAction.CANCEL, tracker.onReadiness(AccessibilityReadiness.READY))
|
||||
assertEquals(AccessibilityAlertAction.PROMPT, tracker.onReadiness(AccessibilityReadiness.ENABLED_WAITING))
|
||||
}
|
||||
|
||||
@Test fun firstObservationAfterProcessStartPromptsWhenNotReady() {
|
||||
assertEquals(
|
||||
AccessibilityAlertAction.PROMPT,
|
||||
AccessibilityAlertTracker().onReadiness(AccessibilityReadiness.ENABLED_WAITING),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.ilapage.goauto.agent
|
||||
|
||||
import cn.ilapage.goauto.agent.service.AgentForegroundService
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityReadiness
|
||||
import cn.ilapage.goauto.agent.ui.AccessibilityReadinessResolver
|
||||
import cn.ilapage.goauto.agent.ui.ManualTaskCheckPolicy
|
||||
@@ -46,9 +47,13 @@ class AccessibilityReadinessTest {
|
||||
ManualTaskCheckPolicy.blockedMessage("BUSY", 35L, AccessibilityReadiness.READY),
|
||||
)
|
||||
assertEquals(
|
||||
"请先到“设置”开启采集采购助手",
|
||||
"请到 设置 → 无障碍 开启 GoAuto",
|
||||
ManualTaskCheckPolicy.blockedMessage("ONLINE", null, AccessibilityReadiness.DISABLED),
|
||||
)
|
||||
assertEquals(
|
||||
"请到 设置 → 无障碍,把 GoAuto 关闭后重新打开",
|
||||
ManualTaskCheckPolicy.blockedMessage("ONLINE", null, AccessibilityReadiness.ENABLED_WAITING),
|
||||
)
|
||||
assertEquals(null, ManualTaskCheckPolicy.blockedMessage("ONLINE", null, AccessibilityReadiness.READY))
|
||||
}
|
||||
|
||||
@@ -59,5 +64,9 @@ class AccessibilityReadinessTest {
|
||||
assertEquals("已领取采购任务", ManualTaskCheckPolicy.resultMessage("purchase_task"))
|
||||
assertEquals("采集间隔中,还需 12 秒", ManualTaskCheckPolicy.resultMessage("collection_cooldown:12"))
|
||||
assertEquals("检查失败,Agent 将继续自动重试", ManualTaskCheckPolicy.resultMessage("network_error"))
|
||||
assertEquals(
|
||||
"无障碍未就绪,已暂停领取任务",
|
||||
ManualTaskCheckPolicy.resultMessage(AgentForegroundService.MANUAL_ACCESSIBILITY_NOT_READY),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,12 +25,21 @@ class AgentStatusTextPolicyTest {
|
||||
@Test fun hidesReadyDetailButKeepsRecoveryMessages() {
|
||||
assertNull(AgentStatusTextPolicy.accessibilityDetail(AccessibilityReadiness.READY))
|
||||
assertEquals(
|
||||
"请到“设置”检查无障碍服务",
|
||||
"请到 设置 → 无障碍,把 GoAuto 关闭后重新打开",
|
||||
AgentStatusTextPolicy.accessibilityDetail(AccessibilityReadiness.ENABLED_WAITING),
|
||||
)
|
||||
assertEquals(
|
||||
"请到“设置”开启",
|
||||
"请到 设置 → 无障碍 开启 GoAuto",
|
||||
AgentStatusTextPolicy.accessibilityDetail(AccessibilityReadiness.DISABLED),
|
||||
)
|
||||
}
|
||||
|
||||
@Test fun accessibilityCardTitleAndColorFollowReadiness() {
|
||||
assertEquals("已开启", AgentStatusTextPolicy.accessibilityTitle(AccessibilityReadiness.READY))
|
||||
assertEquals("未开启,任务已暂停", AgentStatusTextPolicy.accessibilityTitle(AccessibilityReadiness.DISABLED))
|
||||
assertEquals("未连接,任务已暂停", AgentStatusTextPolicy.accessibilityTitle(AccessibilityReadiness.ENABLED_WAITING))
|
||||
assertEquals(R.color.agent_primary_light, AgentStatusTextPolicy.accessibilityColor(AccessibilityReadiness.READY))
|
||||
assertEquals(R.color.agent_error, AgentStatusTextPolicy.accessibilityColor(AccessibilityReadiness.DISABLED))
|
||||
assertEquals(R.color.agent_error, AgentStatusTextPolicy.accessibilityColor(AccessibilityReadiness.ENABLED_WAITING))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user