fix(#128): preserve tab from accessibility button
This commit is contained in:
@@ -11,8 +11,8 @@ android {
|
|||||||
applicationId = "cn.ilapage.goauto.agent"
|
applicationId = "cn.ilapage.goauto.agent"
|
||||||
minSdk = 23
|
minSdk = 23
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 29
|
versionCode = 30
|
||||||
versionName = "0.9.16"
|
versionName = "0.9.17"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,11 @@ internal object AgentTabSelectionPolicy {
|
|||||||
|
|
||||||
private val validTabs = setOf(TAB_STATUS, TAB_COLLECTION, TAB_PURCHASE, TAB_SETTINGS)
|
private val validTabs = setOf(TAB_STATUS, TAB_COLLECTION, TAB_PURCHASE, TAB_SETTINGS)
|
||||||
|
|
||||||
fun initialTab(showStatus: Boolean, savedTab: Int?, persistedTab: Int?): Int = when {
|
fun initialTab(savedTab: Int?, persistedTab: Int?): Int = when {
|
||||||
showStatus -> TAB_STATUS
|
|
||||||
savedTab in validTabs -> requireNotNull(savedTab)
|
savedTab in validTabs -> requireNotNull(savedTab)
|
||||||
persistedTab in validTabs -> requireNotNull(persistedTab)
|
persistedTab in validTabs -> requireNotNull(persistedTab)
|
||||||
else -> TAB_STATUS
|
else -> TAB_STATUS
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tabForNewIntent(currentTab: Int, showStatus: Boolean): Int =
|
|
||||||
if (showStatus) TAB_STATUS else normalize(currentTab)
|
|
||||||
|
|
||||||
fun normalize(tab: Int): Int = tab.takeIf(validTabs::contains) ?: TAB_STATUS
|
fun normalize(tab: Int): Int = tab.takeIf(validTabs::contains) ?: TAB_STATUS
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
selectedTab = AgentTabSelectionPolicy.initialTab(
|
selectedTab = AgentTabSelectionPolicy.initialTab(
|
||||||
showStatus = intent.getBooleanExtra(EXTRA_SHOW_STATUS, false),
|
|
||||||
savedTab = savedInstanceState?.getInt(STATE_SELECTED_TAB),
|
savedTab = savedInstanceState?.getInt(STATE_SELECTED_TAB),
|
||||||
persistedTab = tabPreferences.getInt(LAST_SELECTED_TAB, TAB_STATUS),
|
persistedTab = tabPreferences.getInt(LAST_SELECTED_TAB, TAB_STATUS),
|
||||||
)
|
)
|
||||||
@@ -44,11 +43,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
override fun onNewIntent(intent: android.content.Intent) {
|
override fun onNewIntent(intent: android.content.Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
setIntent(intent)
|
setIntent(intent)
|
||||||
val targetTab = AgentTabSelectionPolicy.tabForNewIntent(
|
|
||||||
selectedTab,
|
|
||||||
intent.getBooleanExtra(EXTRA_SHOW_STATUS, false),
|
|
||||||
)
|
|
||||||
if (targetTab != selectedTab) navigation.selectedItemId = targetTab
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@@ -140,7 +134,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val EXTRA_SHOW_STATUS = "cn.ilapage.goauto.agent.SHOW_STATUS"
|
|
||||||
private const val SCREEN_POLICY_REFRESH_MILLIS = 1_000L
|
private const val SCREEN_POLICY_REFRESH_MILLIS = 1_000L
|
||||||
const val TAB_STATUS = AgentTabSelectionPolicy.TAB_STATUS
|
const val TAB_STATUS = AgentTabSelectionPolicy.TAB_STATUS
|
||||||
private const val TAB_COLLECTION = AgentTabSelectionPolicy.TAB_COLLECTION
|
private const val TAB_COLLECTION = AgentTabSelectionPolicy.TAB_COLLECTION
|
||||||
|
|||||||
+1
-1
@@ -5,5 +5,5 @@ internal object AccessibilityButtonPolicy {
|
|||||||
|
|
||||||
fun isSupported(sdkInt: Int): Boolean = sdkInt >= MIN_SUPPORTED_SDK
|
fun isSupported(sdkInt: Int): Boolean = sdkInt >= MIN_SUPPORTED_SDK
|
||||||
|
|
||||||
fun handleClick(openAgentStatus: () -> Boolean): Boolean = openAgentStatus()
|
fun handleClick(openAgentPreservingTab: () -> Boolean): Boolean = openAgentPreservingTab()
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-7
@@ -68,7 +68,7 @@ class GoAutoAccessibilityService : AccessibilityService(), UiDriver, PddCollecto
|
|||||||
runCatching {
|
runCatching {
|
||||||
val callback = object : AccessibilityButtonController.AccessibilityButtonCallback() {
|
val callback = object : AccessibilityButtonController.AccessibilityButtonCallback() {
|
||||||
override fun onClicked(controller: AccessibilityButtonController) {
|
override fun onClicked(controller: AccessibilityButtonController) {
|
||||||
AccessibilityButtonPolicy.handleClick(::openAgentStatus)
|
AccessibilityButtonPolicy.handleClick(::openAgentPreservingTab)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
accessibilityButtonController.registerAccessibilityButtonCallback(callback)
|
accessibilityButtonController.registerAccessibilityButtonCallback(callback)
|
||||||
@@ -111,15 +111,10 @@ class GoAutoAccessibilityService : AccessibilityService(), UiDriver, PddCollecto
|
|||||||
pause = Thread::sleep,
|
pause = Thread::sleep,
|
||||||
).restore(packageName, timeoutMillis)
|
).restore(packageName, timeoutMillis)
|
||||||
|
|
||||||
fun openAgentStatus(): Boolean = openAgent(showStatus = true)
|
fun openAgentPreservingTab(): Boolean = runCatching {
|
||||||
|
|
||||||
fun openAgentPreservingTab(): Boolean = openAgent(showStatus = false)
|
|
||||||
|
|
||||||
private fun openAgent(showStatus: Boolean): Boolean = runCatching {
|
|
||||||
startActivity(
|
startActivity(
|
||||||
android.content.Intent(this, cn.ilapage.goauto.agent.MainActivity::class.java).apply {
|
android.content.Intent(this, cn.ilapage.goauto.agent.MainActivity::class.java).apply {
|
||||||
addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK or android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP or android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK or android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP or android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
if (showStatus) putExtra(cn.ilapage.goauto.agent.MainActivity.EXTRA_SHOW_STATUS, true)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class AccessibilityButtonPolicyTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `one button click opens agent status exactly once`() {
|
fun `one button click opens agent without changing its selected tab`() {
|
||||||
var calls = 0
|
var calls = 0
|
||||||
val opened = AccessibilityButtonPolicy.handleClick {
|
val opened = AccessibilityButtonPolicy.handleClick {
|
||||||
calls++
|
calls++
|
||||||
|
|||||||
@@ -4,24 +4,11 @@ import org.junit.Assert.assertEquals
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class AgentTabSelectionPolicyTest {
|
class AgentTabSelectionPolicyTest {
|
||||||
@Test
|
|
||||||
fun `explicit status target overrides saved and persisted tabs`() {
|
|
||||||
assertEquals(
|
|
||||||
AgentTabSelectionPolicy.TAB_STATUS,
|
|
||||||
AgentTabSelectionPolicy.initialTab(
|
|
||||||
showStatus = true,
|
|
||||||
savedTab = AgentTabSelectionPolicy.TAB_COLLECTION,
|
|
||||||
persistedTab = AgentTabSelectionPolicy.TAB_PURCHASE,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `saved tab wins when activity is recreated`() {
|
fun `saved tab wins when activity is recreated`() {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
AgentTabSelectionPolicy.TAB_SETTINGS,
|
AgentTabSelectionPolicy.TAB_SETTINGS,
|
||||||
AgentTabSelectionPolicy.initialTab(
|
AgentTabSelectionPolicy.initialTab(
|
||||||
showStatus = false,
|
|
||||||
savedTab = AgentTabSelectionPolicy.TAB_SETTINGS,
|
savedTab = AgentTabSelectionPolicy.TAB_SETTINGS,
|
||||||
persistedTab = AgentTabSelectionPolicy.TAB_COLLECTION,
|
persistedTab = AgentTabSelectionPolicy.TAB_COLLECTION,
|
||||||
),
|
),
|
||||||
@@ -33,7 +20,6 @@ class AgentTabSelectionPolicyTest {
|
|||||||
assertEquals(
|
assertEquals(
|
||||||
AgentTabSelectionPolicy.TAB_COLLECTION,
|
AgentTabSelectionPolicy.TAB_COLLECTION,
|
||||||
AgentTabSelectionPolicy.initialTab(
|
AgentTabSelectionPolicy.initialTab(
|
||||||
showStatus = false,
|
|
||||||
savedTab = null,
|
savedTab = null,
|
||||||
persistedTab = AgentTabSelectionPolicy.TAB_COLLECTION,
|
persistedTab = AgentTabSelectionPolicy.TAB_COLLECTION,
|
||||||
),
|
),
|
||||||
@@ -44,20 +30,20 @@ class AgentTabSelectionPolicyTest {
|
|||||||
fun `missing or invalid history falls back to status`() {
|
fun `missing or invalid history falls back to status`() {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
AgentTabSelectionPolicy.TAB_STATUS,
|
AgentTabSelectionPolicy.TAB_STATUS,
|
||||||
AgentTabSelectionPolicy.initialTab(false, null, 999),
|
AgentTabSelectionPolicy.initialTab(null, 999),
|
||||||
)
|
)
|
||||||
assertEquals(AgentTabSelectionPolicy.TAB_STATUS, AgentTabSelectionPolicy.normalize(999))
|
assertEquals(AgentTabSelectionPolicy.TAB_STATUS, AgentTabSelectionPolicy.normalize(999))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `automatic return keeps current tab while explicit intent opens status`() {
|
fun `collection and purchase tabs are valid return targets`() {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
AgentTabSelectionPolicy.TAB_COLLECTION,
|
AgentTabSelectionPolicy.TAB_COLLECTION,
|
||||||
AgentTabSelectionPolicy.tabForNewIntent(AgentTabSelectionPolicy.TAB_COLLECTION, false),
|
AgentTabSelectionPolicy.normalize(AgentTabSelectionPolicy.TAB_COLLECTION),
|
||||||
)
|
)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
AgentTabSelectionPolicy.TAB_STATUS,
|
AgentTabSelectionPolicy.TAB_PURCHASE,
|
||||||
AgentTabSelectionPolicy.tabForNewIntent(AgentTabSelectionPolicy.TAB_COLLECTION, true),
|
AgentTabSelectionPolicy.normalize(AgentTabSelectionPolicy.TAB_PURCHASE),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
||||||
wiki_page: Architecture-and-Code-Map
|
wiki_page: Architecture-and-Code-Map
|
||||||
wiki_url: https://git.ilapage.cn/OPC/goauto/wiki/Architecture-and-Code-Map.-
|
wiki_url: https://git.ilapage.cn/OPC/goauto/wiki/Architecture-and-Code-Map.-
|
||||||
wiki_revision: 5039f107d1f61cf5290eae38719a305b41fb35cc
|
wiki_revision: f82f510e47cf3e74a3510a859ca17bddd2833362
|
||||||
synchronized_at: 2026-08-28T06:34:33Z
|
synchronized_at: 2026-08-28T06:51:01Z
|
||||||
<!-- gitea-wiki-mirror:end -->
|
<!-- gitea-wiki-mirror:end -->
|
||||||
|
|
||||||
# 架构与代码地图
|
# 架构与代码地图
|
||||||
@@ -189,7 +189,7 @@ Android Portal/Agent
|
|||||||
## Android 系统辅助功能按钮(#97)
|
## Android 系统辅助功能按钮(#97)
|
||||||
|
|
||||||
- Android 8.0 及以上的 `GoAutoAccessibilityService` 请求系统 `flagRequestAccessibilityButton`,服务连接后向 `AccessibilityButtonController` 注册单一回调,销毁时注销;服务重连不会叠加回调。
|
- Android 8.0 及以上的 `GoAutoAccessibilityService` 请求系统 `flagRequestAccessibilityButton`,服务连接后向 `AccessibilityButtonController` 注册单一回调,销毁时注销;服务重连不会叠加回调。
|
||||||
- 单击由系统分配给 GoAuto 的辅助功能按钮时,只调用既有 `openAgentStatus()`,以前台 `MainActivity` 打开“状态”Tab;不领取、创建、重置或重试任务,不打开 PDD,也不改变 5 秒空闲返回规则。
|
- 单击由系统分配给 GoAuto 的辅助功能按钮时,只调用 `openAgentPreservingTab()`,以前台 `MainActivity` 打开 Agent 并保持最近一次有效 Tab;不领取、创建、重置或重试任务,不打开 PDD,也不改变 5 秒空闲返回规则。
|
||||||
- 不支持或未分配系统辅助功能按钮的 ROM 保持安全降级;项目不创建自定义悬浮窗。
|
- 不支持或未分配系统辅助功能按钮的 ROM 保持安全降级;项目不创建自定义悬浮窗。
|
||||||
|
|
||||||
## Android Agent 状态页手动检查(#98)
|
## Android Agent 状态页手动检查(#98)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
||||||
wiki_page: Local-Development-and-Verification
|
wiki_page: Local-Development-and-Verification
|
||||||
wiki_url: https://git.ilapage.cn/OPC/goauto/wiki/Local-Development-and-Verification.-
|
wiki_url: https://git.ilapage.cn/OPC/goauto/wiki/Local-Development-and-Verification.-
|
||||||
wiki_revision: 85b880bba09a4276321cd4eb4eb64d07d6f64ec9
|
wiki_revision: 652e61e73cbd8b78cb7d2d7b011c4790693ab9d9
|
||||||
synchronized_at: 2026-08-28T06:34:38Z
|
synchronized_at: 2026-08-28T06:51:06Z
|
||||||
<!-- gitea-wiki-mirror:end -->
|
<!-- gitea-wiki-mirror:end -->
|
||||||
|
|
||||||
# 本地开发与验证
|
# 本地开发与验证
|
||||||
@@ -254,7 +254,7 @@ adb shell am start -n cn.ilapage.goauto.agent/.MainActivity
|
|||||||
真机验证应至少覆盖:
|
真机验证应至少覆盖:
|
||||||
|
|
||||||
- 分别在采集、采购和设置 Tab 离开 Agent,完成一个不会支付的采集或演练任务,确认结果已提交后约 5 秒返回 Agent,并保持离开前 Tab;记录 ROM 是否限制后台 Activity 启动。
|
- 分别在采集、采购和设置 Tab 离开 Agent,完成一个不会支付的采集或演练任务,确认结果已提交后约 5 秒返回 Agent,并保持离开前 Tab;记录 ROM 是否限制后台 Activity 启动。
|
||||||
- 在最近 Tab 不是状态页时重建 MainActivity 或 Agent 进程,确认恢复最近有效 Tab;无历史或无效值回退状态页,系统辅助功能按钮仍显式打开状态页。
|
- 在最近 Tab 不是状态页时重建 MainActivity 或 Agent 进程,确认恢复最近有效 Tab;无历史或无效值回退状态页,系统辅助功能按钮同样恢复最近一次有效 Tab。
|
||||||
- 冷却 5 秒内创建任一类型新任务,确认 Agent 取消返回并继续按采购优先、采集其次执行。
|
- 冷却 5 秒内创建任一类型新任务,确认 Agent 取消返回并继续按采购优先、采集其次执行。
|
||||||
- 冷却期间断网,确认不会把网络失败当成空队列,也不会返回。
|
- 冷却期间断网,确认不会把网络失败当成空队列,也不会返回。
|
||||||
- 冷却期间人工切换到其他 App,确认 Agent 不会强拉回;即使再切回 PDD,前台切换序号变化也会取消本次返回。
|
- 冷却期间人工切换到其他 App,确认 Agent 不会强拉回;即使再切回 PDD,前台切换序号变化也会取消本次返回。
|
||||||
|
|||||||
Reference in New Issue
Block a user