# 通知体系与后台行为 > DSH Mobile 会在三种场景下发通知:Agent 任务状态、AI 长时间操作设备、局域网 WebUI 开启。 > 另外「退出」会真正结束界面并释放内存。这份文档说明每条通知的来源、频率与关闭方式。 ## 1. 通知通道 | 通道 ID | 名称 | 重要级 | 用途 | |---|---|---|---| | `engine` | 引擎运行状态 | LOW(常驻) | 前台服务通知:引擎就绪/启动中;带「退出」按钮 | | `agent_notify` | Agent 任务通知 | DEFAULT | 任务完成推送;AI 长串无障碍操作的进度 | | `lan_web` | 局域网 WebUI | LOW | 「已开启」常驻提醒,带「关闭」按钮 | Android 13+ 需要通知权限;没有权限时: - 引擎前台服务仍合法(只是通知不可见); - 局域网代理**照常工作**,但不会出现常驻提醒; - Agent 通知(`/notify`)会退化为前台服务的状态小字。 ## 2. AI 长串无障碍操作通知 **目的**:AI 在操作你的手机界面时(点击/输入/滑动/启动应用),你能确认它真的在干活, 而不是界面自己变来变去像 bug。 **规则**(`AgentBridge.noteA11yOperation`): - 只统计**动作类**端点:`/tap`、`/tap-id`、`/gesture`、`/key`、`/input`、 `/scroll-find`、`/scroll-center`、`/scroll-edge`、`/launch`、`/launch-intent`、 `/vision/tap`、`/vision/drag`、`/loop/run`;读屏类不计入(否则看一眼屏幕就算一步); - **连续第 3 步起**出现,之后**原地更新**同一条通知(固定 id,`setOnlyAlertOnce` 不重复响铃); - 正文示例:「第 7 步 · 点击」; - 30 秒没有新动作视为新序列;最后一步后 **10 秒自动撤掉**; - `/loop/run` 是一整段连续操作,**一次即视为达标**(内部步骤不走 HTTP,否则永远凑不够 3 步); - 点通知回到 App。 ## 3. 任务完成通知 Agent 可以主动调用本机桥 `POST /notify`(或 `notify` 命令)推送: `{"title": "...", "body": "..."}`。用于「跑完了」「需要你确认」这类提醒。 无通知权限时自动转成引擎前台服务那行小字,不会静默丢失。 ## 4. 局域网开启提醒 见 [LAN_WEBUI.md](LAN_WEBUI.md):开启成功后出现常驻通知,带「关闭」按钮; 关闭(通知按钮 / 设置开关 / 退出引擎)时同步撤掉。 ## 5. 「退出」到底做了什么 通知栏前台服务通知里的「退出」是**用户显式退出**,与「引擎崩溃/被系统回收」严格区分: 1. 停止引擎(优雅退出,最多等 3 秒); 2. 停止**独立子进程**:局域网代理(node,端口 3090)与本地推理服务(llama-server); 3. 结束主界面任务栈(`finishAndRemoveTask`)→ 触发 `onDestroy` → **销毁 WebView**; 4. 撤掉悬浮窗、停掉周期刷新与定时器; 5. 撤掉前台服务通知。 第 3 步是内存的关键:WebView 与它的渲染进程通常占 300–400MB,只停引擎不销毁它,进程会继续 在后台抱着这部分内存。 **不会误伤**:只有显式退出会结束界面;引擎被系统回收等被动停止不会关闭正在看的界面。 退出后重新打开 App 会正常显示「启动引擎」按钮,不会闪退。 ## 6. 悬浮窗状态提示(不是系统通知) 悬浮球本身也会显示状态:空闲 / 执行中 / 聆听中 / 完成,展开可看最近一次动作。 它由无障碍服务持有,不占通知栏,也不会在「AI 操作设备」时刷屏。 ## 7. 常见问题 | 现象 | 原因 / 处理 | |---|---| | 收不到任何通知 | 检查通知权限(Android 13+);检查系统「勿扰」与通道是否被关闭 | | AI 操作时通知不出现 | 少于 3 步不会提示;读屏类操作不计入;`/loop/run` 一次即算达标 | | 通知一直不消失 | 正常情况停手 10 秒自动撤;常驻类(引擎/局域网)本来就不会自动消失 | | 退出后仍有进程 | 升级到含「同 uid 直杀」的版本;本版本会停掉 LAN 代理与本地推理 |