feat(android): 状态 Tab 新增设备连接卡片,显示 Wi-Fi IP 与无线调试状态 #380

Open
opened 2026-10-12 14:55:18 +08:00 by ila · 6 comments
Owner

基本信息

  • 类型:新功能(Android Agent「状态」Tab 新增「设备连接」卡片:显示 Wi-Fi IP 与无线调试开关状态)。
  • 状态:已建单,待实施;本次只建单。
  • 来源:2026-10-12 用户:「如果要在agent的状态tab显示当前设备ip和无线调试状态已经端口.是加载#375还是新建工单呢」。Claude Code 建议新建工单;用户要求「在测试机上只读验证端口能不能读到」,验证后问「可以简单判断wifi调试有没有开启吗」,并确认「不用上报admin」;草稿经用户确认「建」。Gitea MCP 不可用,回退 REST 建单。
  • 关联:#375(同为 Agent 界面改动,范围独立,可并行)。

已核验事实(origin/main 23dafcf,2026-10-12)

测试机只读验证(3B668T01GF400000,PLY110,Android 16,SDK 36;Agent targetSdk 34)

项目 shell 身份 App 身份(run-as cn.ilapage.goauto.agent) 结论
Wi-Fi IPv4 可读 App 可用 ConnectivityManager.getLinkProperties(已有 ACCESS_NETWORK_STATE 权限) 可显示
service.adb.tls.port 属性 空 空 Android 16 不可见,端口不可读
/proc/net/tcp*、ss(netlink) 可见监听端口 Permission denied App 不可读,且无法区分 adbd
dumpsys adb 无端口信息 无权限 不可用
mDNS _adb-tls-connect._tcp 电脑端 adb mdns services 与自发查询均无回应 — 未能证实,不纳入
Settings.Global.adb_wifi_enabled 值为 1(与实际开启一致) settings/content 命令行工具因其自身所需系统权限被拒,不代表 API 读取结果 见下
  • AOSP Android 16 Settings.java:Settings.Global.ADB_WIFI_ENABLED = "adb_wifi_enabled" 标注 @Readable(无 maxTargetSdk),targetSdk ≥ 31 的 App 可通过 Settings.Global.getInt 读取。尚未在 App 内真机实测;OEM 改动可能性低但未排除。

代码

  • 「状态」Tab:android/app/src/main/java/cn/ilapage/goauto/agent/ui/AgentStatusFragment.kt;onCreateView 依次添加连接、当前任务、无障碍、相册权限卡片(:132–170);refreshStatus()(:245)在 onResume 后每 REFRESH_MILLIS = 1_000L 刷新一次。
  • 卡片样式复用 AgentUiKit.kt 的 card/cardColumn/label。
  • Manifest 已有 ACCESS_NETWORK_STATE,无需新增权限。

目标

在「状态」Tab 显示本机 Wi-Fi IP 和无线调试是否开启,方便用户用 adb 连接设备时核对。

非目标

  • 不读取、不推测无线调试端口(不扫描端口、不读 /proc、不用 mDNS);只显示到系统设置查看的提示。
  • 不上报服务端、不在 Admin 显示(用户:「不用上报admin」);不改 API、数据库、Web、心跳。
  • 不写日志、不写诊断记录;不提供开关或跳转去改变调试设置。
  • 不改其他卡片。

方案

  1. 新增「设备连接」卡片,放在「相册权限」卡片之后(不挤占连接/任务等主要信息)。
  2. Wi-Fi IP:取当前活动网络中传输类型为 Wi-Fi 的 LinkProperties 的 IPv4 地址;不是 Wi-Fi 或无 IPv4 时显示「未连接 Wi-Fi」。
  3. 无线调试:Settings.Global.getInt(resolver, "adb_wifi_enabled", 0):1 →「已开启」(主色),0 →「未开启」(警告色);抛 SecurityException 或其他异常 →「无法读取」(灰色),不崩溃、不重试刷屏。
  4. 端口:固定提示「端口请在 开发者选项 → 无线调试 中查看」。
  5. 随现有 refreshStatus() 每秒刷新;读取放在独立的小工具类/策略对象中便于单测。
  6. 读取结果只在界面显示,不持久化、不上报、不进日志。

设计证据(低保真,2026-10-12)

┌──────────────────────────────────┐
│ 设备连接                          │  ← 标题 14sp 灰
│ Wi-Fi IP:192.168.0.93            │  ← 18sp
│ 无线调试:已开启                  │  ← 已开启 主色 / 未开启 警告色 / 无法读取 灰
│ 端口请在 开发者选项 → 无线调试 中查看 │  ← 14sp 灰
└──────────────────────────────────┘

状态:正常(有 IP、已开启);未连接 Wi-Fi;未开启;无法读取。无加载态(同步读取)。无权限边界(能看到 Agent 的人都能看到)。现有页面的小范围新增卡片,复用现有卡片样式,不需要 QuantUX 原型。

子项目影响、依赖与并行

  • 仅 Android:AgentStatusFragment.kt、新增读取工具类及其单元测试。
  • 无前置依赖;与 #370/#379(采集器)、#375(详情页/服务)文件不重叠,可并行。

验收标准

  • 单元测试:IP 选择(Wi-Fi IPv4 / 非 Wi-Fi / 无 IPv4)、开关值 1/0/异常 → 对应文案与颜色。
  • Android 单元测试与 Debug 构建通过。
  • 真机(测试机,装机需用户授权):无线调试开着 → 显示「已开启」及正确 IP;在系统设置中关闭无线调试 → 1 秒内变为「未开启」(由用户手动操作);切换/断开 Wi-Fi → IP 变化或显示「未连接 Wi-Fi」。
  • 若真机上读取开关抛异常,记录结果并显示「无法读取」,由用户决定是否保留该行。

风险与回退

  • OEM 若限制 adb_wifi_enabled 读取,只能显示「无法读取」;不寻找绕过方式。
  • 在屏幕上显示 IP:只在本机界面,无新增暴露;连接仍需已配对的电脑或配对码。
  • 回退:移除卡片;无数据变化。

文档影响

无长期文档影响:仅新增界面只读信息,不改变入口、配置、接口、数据或业务规则。(如用户希望把「状态 Tab 可查看 IP/无线调试」写进运维说明,可另行更新 Deployment-and-Operations。)

## 基本信息 - 类型:新功能(Android Agent「状态」Tab 新增「设备连接」卡片:显示 Wi-Fi IP 与无线调试开关状态)。 - 状态:**已建单,待实施**;本次只建单。 - 来源:2026-10-12 用户:「如果要在agent的状态tab显示当前设备ip和无线调试状态已经端口.是加载#375还是新建工单呢」。Claude Code 建议新建工单;用户要求「在测试机上只读验证端口能不能读到」,验证后问「可以简单判断wifi调试有没有开启吗」,并确认「不用上报admin」;草稿经用户确认「建」。Gitea MCP 不可用,回退 REST 建单。 - 关联:#375(同为 Agent 界面改动,范围独立,可并行)。 ## 已核验事实(`origin/main` `23dafcf`,2026-10-12) ### 测试机只读验证(`3B668T01GF400000`,PLY110,Android 16,SDK 36;Agent targetSdk 34) | 项目 | shell 身份 | App 身份(`run-as cn.ilapage.goauto.agent`) | 结论 | |---|---|---|---| | Wi-Fi IPv4 | 可读 | App 可用 `ConnectivityManager.getLinkProperties`(已有 `ACCESS_NETWORK_STATE` 权限) | 可显示 | | `service.adb.tls.port` 属性 | 空 | 空 | Android 16 不可见,**端口不可读** | | `/proc/net/tcp*`、`ss`(netlink) | 可见监听端口 | Permission denied | App 不可读,且无法区分 adbd | | `dumpsys adb` | 无端口信息 | 无权限 | 不可用 | | mDNS `_adb-tls-connect._tcp` | 电脑端 `adb mdns services` 与自发查询均无回应 | — | 未能证实,不纳入 | | `Settings.Global.adb_wifi_enabled` | 值为 `1`(与实际开启一致) | `settings`/`content` 命令行工具因其自身所需系统权限被拒,不代表 API 读取结果 | 见下 | - AOSP Android 16 `Settings.java`:`Settings.Global.ADB_WIFI_ENABLED = "adb_wifi_enabled"` 标注 `@Readable`(无 maxTargetSdk),targetSdk ≥ 31 的 App 可通过 `Settings.Global.getInt` 读取。尚未在 App 内真机实测;OEM 改动可能性低但未排除。 ### 代码 - 「状态」Tab:`android/app/src/main/java/cn/ilapage/goauto/agent/ui/AgentStatusFragment.kt`;`onCreateView` 依次添加连接、当前任务、无障碍、相册权限卡片(:132–170);`refreshStatus()`(:245)在 `onResume` 后每 `REFRESH_MILLIS = 1_000L` 刷新一次。 - 卡片样式复用 `AgentUiKit.kt` 的 `card/cardColumn/label`。 - Manifest 已有 `ACCESS_NETWORK_STATE`,无需新增权限。 ## 目标 在「状态」Tab 显示本机 Wi-Fi IP 和无线调试是否开启,方便用户用 adb 连接设备时核对。 ## 非目标 - 不读取、不推测无线调试端口(不扫描端口、不读 `/proc`、不用 mDNS);只显示到系统设置查看的提示。 - 不上报服务端、不在 Admin 显示(用户:「不用上报admin」);不改 API、数据库、Web、心跳。 - 不写日志、不写诊断记录;不提供开关或跳转去改变调试设置。 - 不改其他卡片。 ## 方案 1. 新增「设备连接」卡片,放在「相册权限」卡片之后(不挤占连接/任务等主要信息)。 2. **Wi-Fi IP**:取当前活动网络中传输类型为 Wi-Fi 的 `LinkProperties` 的 IPv4 地址;不是 Wi-Fi 或无 IPv4 时显示「未连接 Wi-Fi」。 3. **无线调试**:`Settings.Global.getInt(resolver, "adb_wifi_enabled", 0)`:1 →「已开启」(主色),0 →「未开启」(警告色);抛 `SecurityException` 或其他异常 →「无法读取」(灰色),不崩溃、不重试刷屏。 4. **端口**:固定提示「端口请在 开发者选项 → 无线调试 中查看」。 5. 随现有 `refreshStatus()` 每秒刷新;读取放在独立的小工具类/策略对象中便于单测。 6. 读取结果只在界面显示,不持久化、不上报、不进日志。 ## 设计证据(低保真,2026-10-12) ``` ┌──────────────────────────────────┐ │ 设备连接 │ ← 标题 14sp 灰 │ Wi-Fi IP:192.168.0.93 │ ← 18sp │ 无线调试:已开启 │ ← 已开启 主色 / 未开启 警告色 / 无法读取 灰 │ 端口请在 开发者选项 → 无线调试 中查看 │ ← 14sp 灰 └──────────────────────────────────┘ ``` 状态:正常(有 IP、已开启);未连接 Wi-Fi;未开启;无法读取。无加载态(同步读取)。无权限边界(能看到 Agent 的人都能看到)。现有页面的小范围新增卡片,复用现有卡片样式,不需要 QuantUX 原型。 ## 子项目影响、依赖与并行 - 仅 Android:`AgentStatusFragment.kt`、新增读取工具类及其单元测试。 - 无前置依赖;与 #370/#379(采集器)、#375(详情页/服务)文件不重叠,可并行。 ## 验收标准 - [ ] 单元测试:IP 选择(Wi-Fi IPv4 / 非 Wi-Fi / 无 IPv4)、开关值 1/0/异常 → 对应文案与颜色。 - [ ] Android 单元测试与 Debug 构建通过。 - [ ] 真机(测试机,装机需用户授权):无线调试开着 → 显示「已开启」及正确 IP;在系统设置中关闭无线调试 → 1 秒内变为「未开启」(由用户手动操作);切换/断开 Wi-Fi → IP 变化或显示「未连接 Wi-Fi」。 - [ ] 若真机上读取开关抛异常,记录结果并显示「无法读取」,由用户决定是否保留该行。 ## 风险与回退 - OEM 若限制 `adb_wifi_enabled` 读取,只能显示「无法读取」;不寻找绕过方式。 - 在屏幕上显示 IP:只在本机界面,无新增暴露;连接仍需已配对的电脑或配对码。 - 回退:移除卡片;无数据变化。 ## 文档影响 无长期文档影响:仅新增界面只读信息,不改变入口、配置、接口、数据或业务规则。(如用户希望把「状态 Tab 可查看 IP/无线调试」写进运维说明,可另行更新 Deployment-and-Operations。)
Author
Owner

开始实施(2026-10-12,Claude Code)

用户:「按照subagent用sonnet做#380」。

  • worktree D:/OPC/goauto-worktrees/issue-380,分支 feat/380-status-device-connection,基线 origin/main 23dafcf。
  • 由 Sonnet 子 Agent 按正文方案实施,Claude Code 审查并复跑测试。
  • 推送、装机(仅测试机)、合并需用户逐次授权;用户要求暂不操作采购1、采购2。
  • Gitea MCP 不可用,回退 REST。
## 开始实施(2026-10-12,Claude Code) 用户:「按照subagent用sonnet做#380」。 - worktree `D:/OPC/goauto-worktrees/issue-380`,分支 `feat/380-status-device-connection`,基线 `origin/main` `23dafcf`。 - 由 Sonnet 子 Agent 按正文方案实施,Claude Code 审查并复跑测试。 - 推送、装机(仅测试机)、合并需用户逐次授权;用户要求暂不操作采购1、采购2。 - Gitea MCP 不可用,回退 REST。
Author
Owner

实现回写(2026-10-12,Claude Code)

用户授权:「推送分支,并在 #380 回写实现证据.装包到测试机」。实现由 Sonnet 子 Agent 完成,Claude Code 审查并复跑。Gitea MCP 不可用,回退 REST。

提交

  • 分支 feat/380-status-device-connection,ff8c536(基线 origin/main 23dafcf),已推送。
  • ui/AgentStatusFragment.kt(+20):「相册权限」后新增「设备连接」卡片,随 refreshStatus() 每秒刷新。
  • 新增 ui/DeviceConnectionInfo.kt(+85):DeviceConnectionPolicy(纯函数:选 Wi-Fi 非回环 IPv4、adb_wifi_enabled 原始值 → 状态、状态 → 文案/颜色);DeviceConnectionReader(ConnectivityManager 活动网络 + TRANSPORT_WIFI + LinkProperties;Settings.Global.getInt(…, "adb_wifi_enabled", 0);任何异常 → 未知),不写日志、不持久化、不上报。
  • 新增 DeviceConnectionPolicyTest.kt(9 项):Wi-Fi 有 IPv4、非 Wi-Fi、仅 IPv6、多地址取 IPv4、跳过回环、开关 1/0/其他/异常、三种显示颜色。
  • 未改 Manifest 权限、服务端、Web、文档。

自定处(审查认可)

  • 开关值非 0/1 → 「无法读取」;地址选择跳过回环 IPv4。
  • 局限:开 VPN 时活动网络为 VPN,显示「未连接 Wi-Fi」(采购机一般不开 VPN,暂不处理)。

测试

  • Claude Code 复跑:testDebugUnitTest 762 项 0 失败 0 跳过;assembleDebug 成功;LF 换行。

装机与真机(测试机 3B668T01GF400000,Android 16)

  • debug.keystore 改签包 sha256 d1896670…1fc7,覆盖安装成功,装后回读哈希一致(替换 #370/#379 分支改签包 2469b2db…8f86)。
  • 只读 uiautomator 导出状态页:「设备连接」/「Wi-Fi IP:192.168.0.93」/「无线调试:已开启」/端口提示,均正确。确认 App 内可读取 adb_wifi_enabled(此前仅依据 AOSP @Readable 推断)。

待验收

  • 用户在系统设置关闭无线调试 → 1 秒内变为「未开启」;重新开启 → 恢复「已开启」。
  • 切换/断开 Wi-Fi → IP 变化或「未连接 Wi-Fi」。
  • 合并 main、装采购机:待授权(用户要求暂不操作采购1/2)。
  • 文档影响:无(见正文)。
## 实现回写(2026-10-12,Claude Code) 用户授权:「推送分支,并在 #380 回写实现证据.装包到测试机」。实现由 Sonnet 子 Agent 完成,Claude Code 审查并复跑。Gitea MCP 不可用,回退 REST。 ### 提交 - 分支 `feat/380-status-device-connection`,`ff8c536`(基线 `origin/main` `23dafcf`),已推送。 - `ui/AgentStatusFragment.kt`(+20):「相册权限」后新增「设备连接」卡片,随 `refreshStatus()` 每秒刷新。 - 新增 `ui/DeviceConnectionInfo.kt`(+85):`DeviceConnectionPolicy`(纯函数:选 Wi-Fi 非回环 IPv4、`adb_wifi_enabled` 原始值 → 状态、状态 → 文案/颜色);`DeviceConnectionReader`(`ConnectivityManager` 活动网络 + `TRANSPORT_WIFI` + `LinkProperties`;`Settings.Global.getInt(…, "adb_wifi_enabled", 0)`;任何异常 → 未知),不写日志、不持久化、不上报。 - 新增 `DeviceConnectionPolicyTest.kt`(9 项):Wi-Fi 有 IPv4、非 Wi-Fi、仅 IPv6、多地址取 IPv4、跳过回环、开关 1/0/其他/异常、三种显示颜色。 - 未改 Manifest 权限、服务端、Web、文档。 ### 自定处(审查认可) - 开关值非 0/1 → 「无法读取」;地址选择跳过回环 IPv4。 - 局限:开 VPN 时活动网络为 VPN,显示「未连接 Wi-Fi」(采购机一般不开 VPN,暂不处理)。 ### 测试 - Claude Code 复跑:`testDebugUnitTest` 762 项 0 失败 0 跳过;`assembleDebug` 成功;LF 换行。 ### 装机与真机(测试机 `3B668T01GF400000`,Android 16) - debug.keystore 改签包 sha256 `d1896670…1fc7`,覆盖安装成功,装后回读哈希一致(替换 #370/#379 分支改签包 `2469b2db…8f86`)。 - 只读 uiautomator 导出状态页:「设备连接」/「Wi-Fi IP:192.168.0.93」/「无线调试:已开启」/端口提示,均正确。**确认 App 内可读取 `adb_wifi_enabled`**(此前仅依据 AOSP `@Readable` 推断)。 ### 待验收 - [ ] 用户在系统设置关闭无线调试 → 1 秒内变为「未开启」;重新开启 → 恢复「已开启」。 - [ ] 切换/断开 Wi-Fi → IP 变化或「未连接 Wi-Fi」。 - [ ] 合并 main、装采购机:待授权(用户要求暂不操作采购1/2)。 - 文档影响:无(见正文)。
Author
Owner

真机人工验证通过(2026-10-12)

用户:「#380人工验证通过」。测试机 3B668T01GF400000(Android 16)装 ff8c536 改签包,用户手动完成无线调试开关与 Wi-Fi 变化检查。

  • 待办:合并 main(需授权)、删除 worktree issue-380;装采购1/2 待授权(用户要求暂不操作);正式验收关闭待用户「#380 验收通过」。
## 真机人工验证通过(2026-10-12) 用户:「#380人工验证通过」。测试机 `3B668T01GF400000`(Android 16)装 `ff8c536` 改签包,用户手动完成无线调试开关与 Wi-Fi 变化检查。 - 待办:合并 main(需授权)、删除 worktree `issue-380`;装采购1/2 待授权(用户要求暂不操作);正式验收关闭待用户「#380 验收通过」。
Author
Owner

合并 main(2026-10-12,Claude Code)

  • 合并提交 f334c1d(merge: device connection card on status tab (#380))。
  • 合并方式:在干净 worktree(D:/OPC/goauto-worktrees/merge-370-380,基于 origin/main 23dafcf)依次 --no-ff 合并 #370 2ae3e81 → #379 d45a9b9 → #380 ff8c536 → #375 d3d3837,无冲突;推送 23dafcf..82ed666。
  • 合并结果验证:testDebugUnitTest 815 项 0 失败 0 跳过;assembleDebug 成功(未改签、未安装)。
  • 未发布:未安装采购1/采购2(用户要求暂不操作);工单 worktree 待装机发布后按规则清理。
  • 文档影响:无(见正文)。待用户「#380 验收通过」后关闭。
## 合并 main(2026-10-12,Claude Code) - 合并提交 `f334c1d`(merge: device connection card on status tab (#380))。 - 合并方式:在干净 worktree(`D:/OPC/goauto-worktrees/merge-370-380`,基于 `origin/main` `23dafcf`)依次 `--no-ff` 合并 #370 `2ae3e81` → #379 `d45a9b9` → #380 `ff8c536` → #375 `d3d3837`,无冲突;推送 `23dafcf..82ed666`。 - 合并结果验证:`testDebugUnitTest` **815 项 0 失败 0 跳过**;`assembleDebug` 成功(未改签、未安装)。 - 未发布:未安装采购1/采购2(用户要求暂不操作);工单 worktree 待装机发布后按规则清理。 - 文档影响:无(见正文)。待用户「#380 验收通过」后关闭。
Author
Owner

Agent 版本号升级(2026-10-12,Claude Code)

用户问「为什么测试机agent显示的版本没有改变呢」:合并后的 APK 仍沿用 build.gradle.kts 中 #373 设定的 0.9.69 / 82 与 Debug 后缀 -373-fix1。用户确认后提交 main 3495de9:versionCode 83、versionName 0.9.70,去掉 Debug 后缀,不改功能。

  • 验证:Android testDebugUnitTest 815 项 0 失败;assembleDebug 成功,aapt 读取 versionCode=83 versionName=0.9.70,Debug APK SHA256 72129515c078f8d7632144ca55311d610b0e60f2c079732e1a54c9bb7d97450f(未改签、未安装)。
  • 之后装测试机/采购机以此版本为准;采购机装包仍需授权。
## Agent 版本号升级(2026-10-12,Claude Code) 用户问「为什么测试机agent显示的版本没有改变呢」:合并后的 APK 仍沿用 `build.gradle.kts` 中 #373 设定的 `0.9.69` / 82 与 Debug 后缀 `-373-fix1`。用户确认后提交 main `3495de9`:versionCode 83、versionName 0.9.70,去掉 Debug 后缀,不改功能。 - 验证:Android `testDebugUnitTest` 815 项 0 失败;`assembleDebug` 成功,aapt 读取 `versionCode=83 versionName=0.9.70`,Debug APK SHA256 `72129515c078f8d7632144ca55311d610b0e60f2c079732e1a54c9bb7d97450f`(未改签、未安装)。 - 之后装测试机/采购机以此版本为准;采购机装包仍需授权。
Author
Owner

测试机安装 0.9.70(2026-10-12,Claude Code)

用户:「装到测试机」。main 3495de9 的 Debug APK 经 debug.keystore 改签,SHA256 7b562de2813fb7534a71f09178eefff85400b768422abd33aa474144de8d3fdb,覆盖安装测试机 3B668T01GF400000(192.168.0.93:36847)成功;装后回读哈希一致,系统显示 versionCode 83 / versionName 0.9.70。安装前本地无 pending/running 采集任务。采购机未操作。

## 测试机安装 0.9.70(2026-10-12,Claude Code) 用户:「装到测试机」。main `3495de9` 的 Debug APK 经 debug.keystore 改签,SHA256 `7b562de2813fb7534a71f09178eefff85400b768422abd33aa474144de8d3fdb`,覆盖安装测试机 `3B668T01GF400000`(`192.168.0.93:36847`)成功;装后回读哈希一致,系统显示 versionCode 83 / versionName 0.9.70。安装前本地无 pending/running 采集任务。采购机未操作。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#380