first commit

This commit is contained in:
admin committed 2026-11-05 14:35:04 +08:00
commit 669f49b1d6
342 files changed
+320811

No files matched your search

@@ -0,0 +1,76 @@
# 徐工语音项目总览
## 一句话结论
徐工语音项目的核心是 `YX_Voice` 系统应用,它作为同行者 TXZ 语音助手与车载业务模块之间的桥接层,负责语音指令接收、协议分发、IPC 调用、车辆状态同步和语音相关问题排查。
## 当前定位
| 项目项 | 内容 |
|---|---|
| 项目名称 | 徐工语音项目 |
| 核心模块 | `YX_Voice` |
| 包名 | `com.yaxon.voice` |
| 应用类型 | Android System Application |
| 进程属性 | 系统持久化进程,`persistent=true` |
| 运行身份 | `android.uid.system` |
| 语音方案 | 同行者 TXZ 语音助手 |
| 主要职责 | TXZ 连接、语音指令分发、协议处理、IPC 调用、状态同步 |
## 核心链路
```text
用户语音
-> TXZ 语音助手
-> VoiceService
-> ProtocolManager
-> YxProtocolHandler
-> 具体 Protocol
-> VoiceEventHelper
-> YxIPC / 业务模块
-> 状态同步回 TXZ
```
## 已有资料索引
| 文档 | 用途 |
|---|---|
| [[YX_Voice_架构文档]] | 系统架构、模块分层、核心链路 |
| [[YX_Voice_模块详细文档]] | 应用入口、服务、管理器、Helper、Receiver 等详细说明 |
| [[YX_Voice_协议设计文档]] | 协议接口、命令映射、Bundle 消息格式、状态同步 |
| [[YX_Voice_配置文档]] | Gradle、Manifest、权限、IPC、TXZ 连接配置 |
| [[同行者可见即可说自动注册框架对接方案_快速阅读]] | 可见即可说接入原则、控件要求、AIDL/广播链路 |
| [[../语音.md]] | 调试命令、账号、问题汇总、资源路径 |
| [[../语音_整理.md]] | 原始整理记录 |
| [[../语音唤醒异常问题分析.md]] | AudioFlinger dump 与唤醒异常排查 |
| [[../log 录音分析.md]] | 录音/音频相关原始分析材料 |
## 当前核心难点
| 难点 | 说明 | 风险 |
|---|---|---|
| TXZ 连接与状态同步 | 连接成功后需同步车辆配置、蓝牙、音量、亮度、设置等状态 | 状态不同步会导致语音反馈与车机实际状态不一致 |
| 协议映射完整性 | 语音指令需要映射到正确协议和业务模块 | 漏映射会出现语音识别成功但功能无响应 |
| IPC 可靠性 | VoiceEventHelper 通过 IPC 控制音乐、设置、空调等模块 | 业务模块未绑定或接口变更会导致调用失败 |
| 可见即可说接入 | 控件需要唯一 ID、文本/隐藏标签、状态型描述动态更新 | UI 可见但语音无法命中或命中错误状态 |
| 音频唤醒问题 | 涉及 AudioFlinger、AudioPolicy、录音 dump 和硬件输入链路 | 需要日志、dump 和录音文件联合判断 |
## 近期优先级
1. 固化调试命令和日志过滤方式,减少重复查找。
2. 维护 Bug 记录,区分现象、根因、修复和验证结果。
3. 建立协议/模块变更记录,避免接口变更后文档失真。
4. 用测试验证记录沉淀每次构建、安装、语音唤醒、指令执行、状态同步结果。
5. 后续进入代码修改时,再联动 `F:\ZDCode\xugong` 源码工程。
## Agent 使用入口
每次让 Agent 处理本项目任务,建议先说:
```text
先读取 agent.md 和 项目文档/徐工/语音/00_项目总览.md。
本次目标是:……
涉及日志/代码/文档是:……
先判断风险等级;如果要改文件,先问我要不要备份。
完成后把原因、处理方式、验证结果、遗留问题写入对应记录文档。
```
@@ -0,0 +1,51 @@
# 徐工语音模块清单
## 模块总览
| 模块 | 文件/类 | 职责 | 关联文档 |
|---|---|---|---|
| 应用入口 | `YxApplication` | 初始化车载 SDK、IPC、崩溃处理和语音服务 | [[YX_Voice_模块详细文档]] |
| 语音服务 | `VoiceService` | TXZ 连接、指令接收、状态初始化、Receiver 注册 | [[YX_Voice_模块详细文档]] |
| 协议管理 | `ProtocolManager` | 接收 IPC 消息并分发到协议处理器 | [[YX_Voice_模块详细文档]] |
| 协议处理 | `YxProtocolHandler` | 维护包名到协议逻辑类映射,后台线程分发协议 | [[YX_Voice_模块详细文档]] |
| 状态管理 | `VoiceManager` | 管理 TXZ 绑定、AVM/DVR 状态、车辆状态回调 | [[YX_Voice_模块详细文档]] |
| 事件封装 | `VoiceEventHelper` | 封装语音控制操作,通过 IPC 调业务模块 | [[YX_Voice_模块详细文档]] |
| 协议实现 | `BaseProtocol` 及子类 | 实现车辆、空调、设置、媒体等协议逻辑 | [[YX_Voice_协议设计文档]] |
| TXZ 通信 | `TxzProtocolManager` | 与同行者语音助手建立协议通信 | [[YX_Voice_架构文档]] |
| IPC 通信 | `YxIPC` | 跨进程调用音乐、设置、空调等模块 | [[YX_Voice_架构文档]] |
| 可见即可说 | 无障碍扫描 / AIDL / 广播 | 控件语音热词注册和命中回调 | [[同行者可见即可说自动注册框架对接方案_快速阅读]] |
## 关键依赖
| 依赖 | 用途 |
|---|---|
| `YX_IPC_SDK` | 跨进程通信 |
| `YX_Lib_CommonBase` | 公共基础能力 |
| `YX_AutoMotiveSDK` | 车载 SDK |
| `library-release-0127.aar` | TXZ 协议库 |
| `tools.jar` | 工具库 |
| `framework_classes.jar` | 系统框架编译依赖 |
| `serial-0.1.6_classes.jar` | 串口相关依赖 |
## 协议类别
| 类别 | 示例 | 验证重点 |
|---|---|---|
| 车辆控制 | 巡航、车道偏离、车窗等 | 指令是否映射到正确 CAN/业务接口 |
| 空调控制 | 开关、温度、风速、模式 | 状态反馈是否同步到 TXZ |
| 系统设置 | 语言、单位、亮度、熄屏 | 设置值是否落库并广播 |
| 媒体控制 | 上一首、播放状态、媒体焦点 | 媒体焦点和播放状态是否一致 |
| 蓝牙相关 | 蓝牙状态、电话、连接 | 蓝牙状态同步和权限边界 |
## 模块变更记录模板
| 日期 | 模块 | 变更类型 | 变更内容 | 影响范围 | 验证方式 | 结论 |
|---|---|---|---|---|---|---|
| 待填写 | 待填写 | 新增/修改/删除 | 待填写 | 待填写 | 待填写 | 待验证 |
## 模块验收标准
- 每个语音指令都有明确协议入口、参数格式和目标业务模块。
- 每个状态同步都有触发时机、数据来源和 TXZ 通知路径。
- 每个跨模块调用都有失败处理和日志。
- 每次模块变更都在本文件记录影响范围和验证方式。
+137
View File
@@ -0,0 +1,137 @@
# 徐工语音 Bug 记录
## 使用规则
每个 Bug 都按“现象 -> 证据 -> 根因 -> 修复 -> 验证 -> 遗留风险”记录,避免只留下口头结论。
## Bug 列表
| ID | 日期 | 问题现象 | 模块 | 优先级 | 状态 | 负责人/来源 | 关联记录 |
|---|---|---|---|---|---|---|---|
| VOICE-001 | 2026-06-15 | 语音唤醒异常 | 音频/TXZ/AudioFlinger | P1 | 待复现 | 已有文档沉淀 | [[../语音唤醒异常问题分析]]、[[../log 录音分析]] |
| VOICE-002 | 待填写 | 语音识别成功但功能无响应 | 协议/IPC | P1 | 待分析 | 待填写 | 待补充 |
| VOICE-003 | 待填写 | 状态同步不准确 | 状态同步/TXZ | P2 | 待分析 | 待填写 | 待补充 |
## Bug 详情
### VOICE-001:语音唤醒异常
| 字段 | 内容 |
|---|---|
| 发现日期 | 历史问题,2026-06-15 补充到 Bug 记录 |
| 影响版本 | 待确认 |
| 问题模块 | 音频输入链路、TXZ 唤醒、AudioFlinger/AudioPolicy |
| 触发条件 | 用户尝试语音唤醒同行者时,出现唤醒失败或录音链路异常 |
| 用户影响 | 无法稳定通过语音唤醒进入后续指令流程 |
| 当前状态 | 待复现 / 待根因确认 |
#### 现象
已有资料将该问题归类为音频唤醒异常,排查方向集中在 AudioFlinger dump、AudioPolicy、录音 dump 和硬件输入链路。当前 Bug 记录先沉淀入口,具体现场表现还需要结合最新 logcat、dump 和录音文件补齐。
#### 复现步骤
1. 确认 TXZ/同行者语音助手处于可唤醒状态。
2. 多次使用唤醒词触发语音唤醒。
3. 记录是否出现无法唤醒、唤醒不稳定、录音异常或 TXZ 无响应。
4. 同步抓取 logcat、AudioFlinger、AudioPolicy、audio dumpsys 和 PCM dump。
#### 证据
| 证据类型 | 路径/命令 | 关键内容 |
|---|---|---|
| 分析文档 | [[../语音唤醒异常问题分析]] | 记录 AudioFlinger dump 识别方式、常用 dump 命令和唤醒异常排查步骤 |
| 原始分析材料 | [[../log 录音分析]] | 录音/音频相关原始分析材料 |
| AudioFlinger dump | `adb shell dumpsys media.audio_flinger > audio_flinger.log` | 关注 Input thread、Frames read、采样率、通道、设备和错误统计 |
| AudioPolicy dump | `adb shell dumpsys media.audio_policy > audio_policy.log` | 关注输入设备选择、路由策略和音频源 |
| 完整音频状态 | `adb shell dumpsys audio > audio.log` | 关注音频服务整体状态 |
| PCM dump | `setprop persist.pcm.dump 9` 后复现,再 `adb pull /data/misc/audioserver/dump_audio_9.pcm` | 判断麦克风是否有有效输入音频 |
#### 根因分析
| 候选根因 | 证据 | 可信度 |
|---|---|---|
| 输入链路没有采集到有效音频 | 需要检查 Input thread 状态、Frames read 变化和 PCM dump 内容 | 中 |
| 音频设备或路由选择异常 | 需要对比 AudioPolicy dump 中的 input device / audio source | 中 |
| 采样率、通道或 HAL 格式与 TXZ 期望不一致 | 需要检查 AudioFlinger 中 Sample rate、HAL format、Channel count | 低 |
| TXZ 唤醒侧状态异常 | 需要补充 TXZ/VoiceService 相关 logcat | 低 |
#### 修复方案
暂不直接给代码修复。下一步先按证据清单复现并抓取日志,确认问题落在音频输入链路、AudioPolicy 路由、TXZ 唤醒状态,还是 `YX_Voice` 与 TXZ 的连接/状态同步链路。
#### 验证结果
| 验证项 | 命令/步骤 | 结果 |
|---|---|---|
| 唤醒复现 | 多次触发唤醒词并记录成功率 | 待验证 |
| 输入采集 | 检查 `adb shell dumpsys media.audio_flinger` 中 Input thread 和 Frames read | 待验证 |
| PCM 有效性 | 拉取 `/data/misc/audioserver/dump_audio_9.pcm` 并听取/分析波形 | 待验证 |
| TXZ 状态 | 过滤 TXZ、VoiceService、唤醒相关 logcat | 待验证 |
#### 遗留风险
当前只有历史分析文档和排查方法,还缺少同一现场下的完整 logcat、dump 和 PCM 文件,因此不能直接判定根因。后续每次复现都应把日志、dump、录音文件路径回填到本 Bug。
## Bug 详情模板
### VOICE-XXX:问题标题
| 字段 | 内容 |
|---|---|
| 发现日期 | 待填写 |
| 影响版本 | 待填写 |
| 问题模块 | 待填写 |
| 触发条件 | 待填写 |
| 用户影响 | 待填写 |
| 当前状态 | 待分析 / 修复中 / 待验证 / 已关闭 |
#### 现象
待填写。
#### 复现步骤
1. 待填写。
2. 待填写。
3. 待填写。
#### 证据
| 证据类型 | 路径/命令 | 关键内容 |
|---|---|---|
| logcat | 待填写 | 待填写 |
| dumpsys | 待填写 | 待填写 |
| 截图/录音 | 待填写 | 待填写 |
#### 根因分析
| 候选根因 | 证据 | 可信度 |
|---|---|---|
| 待填写 | 待填写 | 高/中/低 |
#### 修复方案
待填写。
#### 验证结果
| 验证项 | 命令/步骤 | 结果 |
|---|---|---|
| 正常路径 | 待填写 | 待验证 |
| 异常路径 | 待填写 | 待验证 |
| 回归项 | 待填写 | 待验证 |
#### 遗留风险
待填写。
## 常用问题分类
| 分类 | 典型表现 | 优先看 |
|---|---|---|
| TXZ 连接 | 初始化失败、绑定状态异常 | `VoiceService.onConnected()`、TXZ 初始化日志 |
| 协议分发 | 指令收到但无动作 | `ProtocolManager`、`YxProtocolHandler`、协议映射 |
| IPC 调用 | 业务模块无响应 | `VoiceEventHelper`、YxIPC 绑定状态 |
| 状态同步 | TXZ 反馈和车机状态不一致 | 初始化状态同步、通知方法 |
| 音频唤醒 | 唤醒失败、录音异常 | AudioFlinger、AudioPolicy、PCM dump |
@@ -0,0 +1,96 @@
# 徐工语音日志分析记录
## 日志分析流程
```text
确认问题现象
-> 确认时间点
-> 收集 logcat / dumpsys / 录音 / 截图
-> 提取关键字
-> 建立时间线
-> 区分现象、直接原因、根因
-> 给出验证动作
```
## 常用调试命令
### 语音唤醒与调用
```bash
adb shell am broadcast -a android.intent.action.start_txzvoice
adb shell am start com.txzing.voiceassistant/com.txzing.assistant.core.console.ui.ConsoleActivity
adb shell am broadcast -a com.txznet.txz.invoke -d "txznet://com.txznet.txz/comm.asr.startWithRawText?打开空调"
```
### 缓存清理
```bash
adb shell pm clear com.txzing.voiceassistant
adb shell pm clear com.yaxon.voice
```
### 音频排查
```bash
adb shell setprop persist.pcm.dump 9
adb shell dumpsys media.audio_flinger > audio_flinger.log
adb shell dumpsys media.audio_policy > audio_policy.log
adb shell dumpsys audio > audio.log
adb shell setprop persist.pcm.dump 0
adb pull /data/misc/audioserver/dump_audio_9.pcm
```
## 常用过滤关键字
| 场景 | 关键字 |
|---|---|
| 中间件报文 | `processBodyControl` |
| 语音模块 | `package:com.yaxon.voice`、`VoiceEventHelper`、`sendCommandTxz` |
| 协议逻辑 | `VoiceProtocol`、`ProtocolManager`、`YxProtocolHandler` |
| 同行者状态 | `defaultRegisterHandler`、`TxzProtocolManager` |
| 激活状态 | `onActivationSuccess` |
| 初始化 | `initialize: versions` |
| 音频 dump | `AudioFlinger`、`Input thread`、`Output thread`、`Frames read` |
## 分析记录模板
### LOG-YYYYMMDD-XXX:问题标题
| 字段 | 内容 |
|---|---|
| 日期 | 待填写 |
| 关联 Bug | 待填写 |
| 日志来源 | 待填写 |
| 时间范围 | 待填写 |
| 设备/版本 | 待填写 |
| 分析状态 | 待分析 / 已定位 / 待复测 |
#### 问题现象
待填写。
#### 关键时间线
| 时间 | 进程/模块 | 日志摘要 | 判断 |
|---|---|---|---|
| 待填写 | 待填写 | 待填写 | 待填写 |
#### 关键证据
```text
粘贴关键日志片段,避免贴整份日志。
```
#### 初步结论
待填写。
#### 需要补充的证据
- 待填写。
## 已有关联资料
- [[../语音唤醒异常问题分析]]
- [[../log 录音分析]]
- [[../语音]]
@@ -0,0 +1,80 @@
# 徐工语音测试验证记录
## 验证目标
将每次语音模块修改、配置调整、资源替换和问题修复都沉淀为可复用的验证记录,覆盖主流程、异常流程和回归项。
## 基础验证环境
| 项 | 内容 |
|---|---|
| 项目 | 徐工 X9HP / 语音 |
| 语音助手 | 同行者 TXZ |
| 语音包名 | `com.txzing.voiceassistant` |
| 语音模块包名 | `com.yaxon.voice` |
| 测试账号 | `T9999911` / `xgtest010002` |
| 代码工程 | `F:\ZDCode\xugong` |
| 文档工程 | `F:\AI\Obsidian\项目文档\徐工\语音` |
## 通用验证前置
```bash
adb devices
adb shell pm clear com.txzing.voiceassistant
adb shell pm clear com.yaxon.voice
adb shell am start com.txzing.voiceassistant/com.txzing.assistant.core.console.ui.ConsoleActivity
```
## 验证清单
| 验证项 | 操作 | 期望结果 | 状态 |
|---|---|---|---|
| TXZ 初始化 | 启动语音助手 | 初始化成功,有版本和连接日志 | 待验证 |
| 语音服务启动 | 重启设备或启动服务 | `VoiceService` 正常创建并连接 TXZ | 待验证 |
| 方控唤醒 | `adb shell am broadcast -a android.intent.action.start_txzvoice` | 语音界面或唤醒状态正常 | 待验证 |
| 直接语音指令 | 发送 `startWithRawText` 指令 | TXZ 识别并分发到 YX_Voice | 待验证 |
| 协议分发 | 执行车辆/空调/媒体指令 | `ProtocolManager` 和目标 Protocol 有日志 | 待验证 |
| IPC 调用 | 执行业务控制 | 目标业务模块收到并执行 | 待验证 |
| 状态同步 | 连接成功后同步状态 | 蓝牙、音量、亮度、车辆设置状态正确 | 待验证 |
| 可见即可说 | 当前界面说出控件名称 | 控件被命中并触发点击 | 待验证 |
| 异常恢复 | 清缓存后重新初始化 | 能恢复连接和指令处理 | 待验证 |
## 验证记录模板
### TEST-YYYYMMDD-XXX:验证标题
| 字段 | 内容 |
|---|---|
| 日期 | 待填写 |
| 关联 Bug/需求 | 待填写 |
| 版本/构建号 | 待填写 |
| 测试设备 | 待填写 |
| 测试人员 | 待填写 |
| 结论 | 通过 / 不通过 / 部分通过 |
#### 验证步骤
1. 待填写。
2. 待填写。
3. 待填写。
#### 实际结果
待填写。
#### 关键日志
```text
待填写。
```
#### 遗留问题
待填写。
## 回归要求
- 修改协议映射后,至少验证目标协议、相邻协议和未知指令处理。
- 修改 TXZ 连接逻辑后,至少验证清缓存、冷启动、重启后连接。
- 修改状态同步后,至少验证初始同步和状态变化后的再次同步。
- 修改音频/唤醒相关逻辑后,至少保留 AudioFlinger/AudioPolicy dump 和录音文件结论。
@@ -0,0 +1,52 @@
# 徐工语音决策记录
## 使用规则
本文件记录影响项目方向、接口契约、模块边界、测试策略、资源路径和风险取舍的决策。不要删除旧决策;如果结论变化,用“更新标记”追加。
## 决策列表
| ID | 日期 | 决策 | 原因 | 影响范围 | 状态 |
| ------- | ---------- | ---------------------------------------------------- | ---------------------------- | ----------- | --- |
| ADR-001 | 2026-06-15 | 先在 Obsidian 建立语音项目工程化文档骨架,不直接改 `F:\ZDCode\xugong` 源码 | 当前目标是建立长期记忆和协作流程,不是修具体代码 Bug | 文档工程 | 生效 |
| ADR-002 | 2026-06-15 | 语音项目入口文档使用 `00_项目总览.md` | 让 Agent 和人都能先读一个入口文件快速进入上下文 | Obsidian 文档 | 生效 |
| ADR-003 | 2026-06-15 | Bug、日志、测试、决策分文件记录 | 避免问题分析、验证结论和需求设计混在同一文档中 | 项目管理方式 | 生效 |
## 决策模板
### ADR-XXX:标题
| 字段 | 内容 |
|---|---|
| 日期 | 待填写 |
| 背景 | 待填写 |
| 决策 | 待填写 |
| 备选方案 | 待填写 |
| 选择原因 | 待填写 |
| 影响范围 | 待填写 |
| 风险 | 待填写 |
| 验证方式 | 待填写 |
| 状态 | 生效 / 废弃 / 被替代 |
#### 背景
待填写。
#### 决策
待填写。
#### 影响
待填写。
#### 更新记录
- 待填写。
## 当前约束
- 项目文档放在 `F:\AI\Obsidian\项目文档\徐工\语音`。
- 代码工程位于 `F:\ZDCode\xugong`,只有进入具体开发/修复任务时才修改。
- 高风险变更包括协议契约、权限、状态同步、TXZ 连接、IPC 接口、并发/生命周期逻辑。
- 高风险变更必须先给计划并等待确认。
@@ -0,0 +1,91 @@
# 徐工语音 Agent 协作说明
## 目标
让 Agent 在处理徐工语音项目时,固定遵循“读取上下文、判断风险、执行任务、验证结果、记录结论”的工程闭环。
## 默认上下文读取顺序
1. 根目录 `agent.md`
2. [[00_项目总览]]
3. 与任务相关的专项文档:
- 架构/模块:[[YX_Voice_架构文档]]、[[YX_Voice_模块详细文档]]
- 协议:[[YX_Voice_协议设计文档]]
- 配置:[[YX_Voice_配置文档]]
- 可见即可说:[[同行者可见即可说自动注册框架对接方案_快速阅读]]
- Bug:[[02_Bug记录]]
- 日志:[[03_日志分析记录]]
- 测试:[[04_测试验证记录]]
- 决策:[[05_决策记录]]
## 常用任务口令
### 分析日志
```text
先读取 agent.md 和 项目文档/徐工/语音/00_项目总览.md。
按日志分析流程分析以下日志/现象:……
请输出时间线、证据链、根因候选、修复建议和验证方案。
如果需要写入记录,追加到 03_日志分析记录.md。
```
### 记录 Bug
```text
先读取 agent.md、00_项目总览.md 和 02_Bug记录.md。
把下面的问题按 Bug 模板记录:……
区分现象、复现步骤、证据、根因假设、修复方案、验证结果和遗留风险。
```
### 设计模块
```text
先读取 agent.md、00_项目总览.md、YX_Voice_架构文档.md 和 YX_Voice_模块详细文档.md。
围绕以下需求做模块设计:……
请输出模块目标、接口、数据结构、控制流、异常路径、测试用例和 ASPICE 对齐建议。
```
### 准备改代码
```text
先读取 agent.md 和 00_项目总览.md。
本次准备修改 F:\ZDCode\xugong 中的代码,目标是:……
请先判断风险等级,列出涉及文件、备份建议、修改方案和验证命令。
在我确认前不要改代码。
```
### 做验证
```text
先读取 agent.md、00_项目总览.md 和 04_测试验证记录.md。
按测试验证模板验证:……
请输出验证步骤、实际结果、关键日志、结论和遗留问题。
```
## 风险分级
| 等级 | 判定条件 | 处理方式 |
|---|---|---|
| 高风险 | 协议契约、权限、状态同步、TXZ 连接、IPC 接口、并发、生命周期、架构调整 | 先给计划,等待确认 |
| 中风险 | 单模块多点修改、已有逻辑重构、测试影响不明确 | 先给简要计划 |
| 低风险 | 文档整理、命令记录、单处说明补充、非功能性笔记整理 | 可直接执行 |
## 写入规则
- 修改文件前必须确认是否备份。
- 不删除旧结论;结论变化时使用“更新标记”追加。
- Bug 修复后必须记录验证结果。
- 无法验证时必须明确写“未验证”,不能假装通过。
- 涉及真实代码工程 `F:\ZDCode\xugong` 时,必须先确认目标和风险。
## 推荐输出格式
```text
结论
范围
依据
执行/建议
验证
风险
下一步
```
@@ -0,0 +1,136 @@
# YX_Voice 协议设计文档
## 1. 协议接口定义
### 1.1 IProtocolHandler (协议处理接口)
```java
public interface IProtocolHandler {
void onHandleProtocol(long msgSendTime, String remoteName, Bundle data);
}
```
### 1.2 IProtocolLogic (协议逻辑接口)
```java
public interface IProtocolLogic {
void onProtocolLogic(Bundle data);
}
```
## 2. 协议基类 (BaseProtocol)
```java
public abstract class BaseProtocol implements IProtocolLogic {
@Override
public void onProtocolLogic(Bundle data) {
String cmd = data.getString(VoiceConst.PARAMS_CMD_KEY, "");
switch (cmd) {
case CMD_SWITCH_TXZ_WINDOW: // 切换TXZ窗口
case CMD_PLAY_TTS: // 播放TTS
default:
onProtocolParse(data); // 子类实现具体解析
}
}
protected abstract void onProtocolParse(Bundle data);
}
```
## 3. 协议映射表
```java
protocolLogicMap.put(CAR_CAR_CONTROL_PKG, new CarControlProtocol()); // 车辆控制
protocolLogicMap.put(TXZ_PKG_NEW, new VoiceProtocol()); // 语音协议
protocolLogicMap.put(AIR_PKG, new AirProtocol()); // 空调协议
protocolLogicMap.put(BLUETOOTH_PKG, new BluetoothProtocol()); // 蓝牙协议
protocolLogicMap.put(MUSIC_PKG, new MediaProtocol()); // 媒体协议
protocolLogicMap.put(VIDEO_PKG, new MediaProtocol()); // 视频协议
protocolLogicMap.put(PHOTO_PKG, new MediaProtocol()); // 图库协议
protocolLogicMap.put(RADIO_PKG, new MediaProtocol()); // 收音机协议
protocolLogicMap.put(YX_VOICE_PKG, new YxProtocol()); // 内部协议
protocolLogicMap.put(SETTING_PKG, new SettingProtocol()); // 设置协议
protocolLogicMap.put(SYSTEM_UI_PKG, new SystemUIProtocol()); // 系统UI协议
protocolLogicMap.put(FACTORY_PKG, new FactoryProtocol()); // 工厂模式协议
protocolLogicMap.put(AVM_PKG, new AvmProtocol()); // 360环视协议
protocolLogicMap.put(DVR_PKG, new DvrProtocol()); // 行车记录仪协议
```
## 4. 协议命令常量
### 4.1 车辆控制类
| 命令常量 | 命令名称 | 说明 |
|----------|----------|------|
| CMD_OPEN_SUNROOF | openSunroof | 打开天窗 |
| CMD_CLOSE_SUNROOF | closeSunroof | 关闭天窗 |
| CMD_OPEN_WINDOW | openWindow | 打开车窗 |
| CMD_CLOSE_WINDOW | closeWindow | 关闭车窗 |
| CMD_OPEN_MIRROR_HEAT | openMirrorHeat | 打开后视镜加热 |
| CMD_OPEN_AVM | openAvm | 打开360环视 |
### 4.2 空调控制类
| 命令常量 | 命令名称 | 说明 |
|----------|----------|------|
| CMD_OPEN_AC | openAc | 打开空调 |
| CMD_CLOSE_AC | closeAc | 关闭空调 |
| CMD_SET_AC_WIND_SPEED_LEVEL | setAcWindSpeedLevel | 设置风速档位 |
| CMD_SET_AC_TEMP_VALUE | setAcTempValue | 设置温度 |
### 4.3 系统设置类
| 命令常量 | 命令名称 | 说明 |
|----------|----------|------|
| CMD_OPEN_BLUETOOTH | openBluetooth | 打开蓝牙 |
| CMD_OPEN_WIFI | openWifi | 打开WiFi |
| CMD_SET_VOLUME_TO_VALUE | setVolumeToValue | 设置音量 |
| CMD_SET_SCREEN_BRIGHTNESS_VALUE | setScreenBrightnessValue | 设置亮度 |
| CMD_SWITCH_VOICE_WAKEUP | switchVoicewakeup | 语音唤醒开关 |
| CMD_CUSTOM_WAKE_UP_WORD | customWakeupWord | 自定义唤醒词 |
### 4.4 媒体控制类
| 命令常量 | 命令名称 | 说明 |
|----------|----------|------|
| CMD_PLAY_PAUSE | playPause | 暂停播放 |
| CMD_PLAY_RESUME | playResume | 继续播放 |
| CMD_PLAY_PREV | playPrev | 上一首 |
| CMD_PLAY_NEXT | playNext | 下一首 |
| CMD_OPEN_APP | openApp | 打开应用 |
## 5. 消息格式
### 5.1 Bundle格式
```java
Bundle bundle = new Bundle();
bundle.putString(VoiceConst.PARAMS_CMD_KEY, "命令类型");
bundle.putInt(VoiceConst.PARAMS_NUM_KEY, 数值);
bundle.putBoolean(VoiceConst.PARAMS_SWITCH_KEY, 开关状态);
bundle.putString(VoiceConst.PARAMS_TYPE_KEY, "类型");
```
### 5.2 参数说明
| 参数Key | 类型 | 说明 |
|---------|------|------|
| PARAMS_CMD_KEY | String | 命令类型 |
| PARAMS_NUM_KEY | int | 数值参数 |
| PARAMS_SWITCH_KEY | boolean | 开关状态 |
| PARAMS_TYPE_KEY | String | 类型参数 |
## 6. 状态同步命令
| 命令 | 说明 |
|------|------|
| syncAcStatus | 同步空调状态 |
| syncBlueToothStatus | 同步蓝牙状态 |
| syncWiFiStatus | 同步WiFi状态 |
| syncMediaVolume | 同步媒体音量 |
| syncScreenBrightness | 同步屏幕亮度 |
| syncVoiceWakeUpStatus | 同步语音唤醒开关 |
---
*文档整理日期: 2026-05-27*
@@ -0,0 +1,156 @@
# YX_Voice 架构文档
## 1. 概述
YX_Voice 是车载语音助手服务模块,作为第三方语音助手(同行者TXZ)与车载各功能模块之间的桥梁,负责语音指令的分发、处理以及车辆状态的同步。
| 项目信息 | 说明 |
|----------|------|
| 包名 | `com.yaxon.voice` |
| 应用类型 | Android System Application |
| 进程类型 | 系统持久化进程 (`persistent=true`) |
| 共享UID | `android.uid.system` |
## 2. 整体架构
```
┌─────────────────────────────────────────────────────────────────────┐
│ YX_Voice 架构图 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ TXZ协议 ┌──────────────────────────────┐ │
│ │ TXZ语音 │◄────────────►│ VoiceService │ │
│ │ 助手模块 │ │ (服务入口 & TXZ连接管理) │ │
│ └──────────────┘ └──────────────┬───────────────┘ │
│ │ │
│ ┌──────────────────────────┼────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────────┐ ┌──────────────────────┐ ┌──────────┐│
│ │ ProtocolManager │ │ VoiceManager │ │ Helpers ││
│ │ (协议分发管理) │ │ (核心状态管理) │ │ (辅助类) ││
│ └──────────┬───────────┘ └──────────┬───────────┘ └──────────┘│
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Protocol Implementations │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐ │ │
│ │ │ Voice │ │ Air │ │ Setting │ │ Media │ │ Car │ │ │
│ │ │Protocol │ │Protocol │ │Protocol │ │Protocol │ │Control │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ IPC Communication Layer │ │
│ │ YxIPC (跨进程通信框架) │ │
│ └──────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────┼───────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 音乐 │ │ 设置 │ │ 空调 │ │
│ │ 模块 │ │ 模块 │ │ 模块 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
## 3. 模块分层
| 层级 | 模块 | 职责 |
|------|------|------|
| 应用层 | VoiceService | 服务入口、生命周期管理 |
| 核心层 | ProtocolManager, VoiceManager | 协议分发、状态管理 |
| 协议层 | BaseProtocol及子类 | 具体协议解析与执行 |
| 辅助层 | Helpers, Receivers, Observers | 状态监听、辅助功能 |
| 通信层 | YxIPC, TxzProtocolManager | 跨进程通信 |
## 4. 核心模块
| 模块 | 职责 | 设计模式 |
|------|------|----------|
| VoiceService | 与TXZ语音助手建立连接、接收并分发语音指令 | - |
| ProtocolManager | 实现IPC消息监听接口、将消息分发给协议处理器 | 单例模式 |
| YxProtocolHandler | 维护包名到协议逻辑类的映射、在后台线程处理协议分发 | - |
| VoiceManager | 管理TXZ绑定状态、AVM/DVR前台状态、注册车辆状态回调 | 单例模式 |
| VoiceEventHelper | 封装所有语音控制操作、与各模块进行IPC通信 | - |
## 5. 通信架构
### 5.1 协议处理流程
```
TXZ语音指令
│
▼
TxzProtocolManager.setDefaultHandler()
│
├── 解析 commandType (协议名称)
├── 解析 Bundle 参数
├── 转换为JSON格式
│
▼
ProtocolManager.onResponse()
│
▼
YxProtocolHandler.onHandleProtocol()
│
▼
具体Protocol实现类.onProtocolLogic()
```
### 5.2 IPC通信
```
┌─────────────────┐ YxIPC ┌─────────────────┐
│ YX_Voice │◄──────────────►│ YX_Music │
│ (Server) │ │ (Client) │
└────────┬────────┘ └─────────────────┘
│
│ YxIPC
▼
┌─────────────────┐
│ YX_Setting │
└─────────────────┘
```
### 5.3 TXZ协议通信
```
┌─────────────────┐ TxzProtocolManager ┌─────────────────┐
│ YX_Voice │◄─────────────────────►│ TXZ语音助手 │
│ (ConnectionService) │ (AIDL Service) │
└─────────────────┘ └─────────────────┘
```
## 6. 模块依赖
```
YX_Voice
├── YX_IPC_SDK (IPC通信)
├── YX_Lib_CommonBase (公共基础库)
├── YX_AutoMotiveSDK (车载SDK)
├── library-release-0127.aar (TXZ协议库)
├── tools.jar (工具库)
├── framework_classes.jar (系统框架)
└── serial-0.1.6_classes.jar (串口库)
```
## 7. 包名依赖
| 包名 | 说明 |
|------|------|
| com.txzing.voiceassistant | TXZ语音助手 |
| com.yaxon.music | 音乐模块 |
| com.yaxon.radio | 收音机模块 |
| com.yaxon.hvac | 空调模块 |
| com.yaxon.bluetooth | 蓝牙模块 |
| com.yaxon.setting | 设置模块 |
| com.yaxon.carcontrol | 车辆控制模块 |
| com.yaxon.avm | 360环视模块 |
| com.yaxon.dvr | 行车记录仪模块 |
| com.android.systemui | 系统UI |
---
*文档整理日期: 2026-05-27*
@@ -0,0 +1,254 @@
# YX_Voice 模块详细文档
## 1. 应用入口 (YxApplication)
**文件路径**: `com/yaxon/voice/YxApplication.java`
**职责**:
- 继承 `AutoMotiveSDKApplication`,提供车载SDK上下文
- 初始化IPC通信框架
- 初始化崩溃处理机制
- 启动语音服务
**初始化流程**:
```
onCreate()
├── ToolInit.init() // 工具类初始化
├── CrashExceptionHandler // 崩溃处理
├── YxIPC.bind() // IPC绑定
│ └── ProtocolManager // 设置消息监听
├── PackagePermissionManager // 权限管理
└── startVoiceService() // 启动服务
```
---
## 2. 语音服务 (VoiceService)
**文件路径**: `com/yaxon/voice/service/VoiceService.java`
**继承关系**: `VoiceService extends BaseVoiceService implements ConnectionListener`
**职责**:
- 与TXZ语音助手建立连接
- 接收并分发语音指令
- 管理各模块监听器生命周期
**初始化流程**:
```
onCreate()
├── initTxz() // 初始化TXZ连接
│ ├── TxzProtocolManager.initialize()
│ ├── TxzProtocolManager.connect()
│ └── addConnectionListener()
├── registerTxzCommandReceiver() // 注册指令接收器
├── BlueToothHelper.register() // 蓝牙监听
├── VoiceManager.registerCallbacks() // 车辆状态监听
└── 注册各种Receiver和Callback
```
**TXZ连接成功同步**:
```java
public void onConnected() {
VoiceManager.getInstance().setVoiceBind(true);
VoiceManager.VOICE_EVENT_HELPER.sendVoiceBindSuccess(null);
AppHelper.getInstance().startScanApp();
initNotifyCarConfig(); // 车辆配置
initNotifyBluetoothStatus(); // 蓝牙状态
initNotifyVolumeStatus(); // 音量状态
initNotifyCarSettingStatus(); // 车辆设置状态
sendBrightnessStatus(); // 亮度状态
}
```
---
## 3. 协议管理器 (ProtocolManager)
**文件路径**: `com/yaxon/voice/core/ProtocolManager.java`
**设计模式**: 单例模式
**职责**:
- 实现IPC消息监听接口 (`MessageListener`, `RemoteListener`)
- 将消息分发给协议处理器
**类图**:
```
┌─────────────────────────────────┐
│ ProtocolManager │
├─────────────────────────────────┤
│ - sInstance: ProtocolManager │
│ - mProtocolHandler: IProtocolHandler │
├─────────────────────────────────┤
│ + getInstance() │
│ + setProtocolHandler() │
│ + onResponse() │ ← MessageListener
│ + onBindRemote() │ ← RemoteListener
│ + release() │
└─────────────────────────────────┘
```
---
## 4. 协议处理器 (YxProtocolHandler)
**文件路径**: `com/yaxon/voice/core/YxProtocolHandler.java`
**职责**:
- 维护包名到协议逻辑类的映射
- 在后台线程处理协议分发
---
## 5. 语音管理器 (VoiceManager)
**文件路径**: `com/yaxon/voice/core/VoiceManager.java`
**设计模式**: 单例模式
**职责**:
- 管理TXZ绑定状态
- 管理AVM/DVR前台状态
- 注册车辆状态回调(空调、设置、智能驾驶)
- 提供AudioTrackPlayer实例
**状态管理**:
```java
private boolean isVoiceBind; // TXZ绑定状态
private AtomicBoolean isAvm; // AVM前台状态
private AtomicBoolean isDvr; // DVR前台状态
```
---
## 6. 语音事件助手 (VoiceEventHelper)
**文件路径**: `com/yaxon/voice/helper/VoiceEventHelper.java`
**职责**:
- 封装所有语音控制操作
- 与各模块进行IPC通信
- 通知TXZ状态变化
**主要功能分类**:
| 类别 | 方法示例 | 说明 |
|------|----------|------|
| 空调控制 | sendAirSwitch, sendAcSwitch, sendAirTempTo | 温度、风速、模式控制 |
| 音量控制 | sendVolumeTo, sendVolumeMute, sendVolumeElevator | 音量调节、静音 |
| 屏幕控制 | setMpuBrightnessLevel, sendScreenOff, sendScreenClean | 亮度、熄屏、清洁 |
| 系统设置 | switchSystemLanguage, switchDistanceUnit | 语言、单位切换 |
| 车窗控制 | sendWindowSwitch, sendWindowPercent | 开关、百分比控制 |
| 语音设置 | sendSwitchVoiceWakeup, customWakeupWord, switchVoiceMan | 唤醒词、发音人设置 |
---
## 7. 接收器与观察者
### 7.1 BroadcastReceiver
| 类名 | 监听Action | 功能 |
|------|------------|------|
| BootReceiver | ACTION_BOOT_COMPLETED | 开机启动服务 |
| PowerReceiver | ACTION_SCREEN_ON/OFF | 屏幕亮灭监听 |
| NetworkChangedReceiver | WIFI_STATE_CHANGED | WiFi状态变化 |
| BluetoothMonitorReceiver | Bluetooth状态广播 | 蓝牙连接状态 |
| HomeStatusReceiver | ACTION_HOME_STATUS_CHANGED | 主页状态变化 |
| VolumeChangedCallback | 音量变化回调 | 音量变化监听 |
| SettingReceiver | STREAM_MUTE_CHANGED_ACTION | 静音状态变化 |
### 7.2 ContentObserver
| 类名 | 监听URI | 功能 |
|------|---------|------|
| ScreenSaversObserver | STATE_URI + STANDBY_DIALOG_STATE | 屏保状态 |
| MediaObserver | MEDIA_SOURCE_URI, MUSIC_INFO_URI | 媒体信息 |
| ReverseObserver | 倒车相关URI | 倒车状态 |
| BrightnessObserver | MPU_BRIGHTNESS_LEVEL | 亮度变化 |
| SettingCommonObserver | VIDEO_LIMIT_URI等 | 通用设置 |
---
## 8. 文件结构
```
YX_Voice/
├── src/main/java/com/yaxon/voice/
│ ├── YxApplication.java # 应用入口
│ ├── api/ # 接口定义
│ │ ├── IProtocolHandler.java
│ │ └── IProtocolLogic.java
│ ├── constant/ # 常量定义
│ │ ├── PackageConst.java
│ │ ├── VoiceNewProtocolConst.java
│ │ └── VoiceProtocolConst.java
│ ├── core/ # 核心类
│ │ ├── PackagePermissionManager.java
│ │ ├── ProtocolManager.java
│ │ ├── VoiceManager.java
│ │ └── YxProtocolHandler.java
│ ├── crash/ # 崩溃处理
│ │ └── CrashExceptionHandler.java
│ ├── helper/ # 辅助类
│ │ ├── AppHelper.java
│ │ ├── AudioFocusHelper.java
│ │ ├── AudioTrackPlayer.java
│ │ ├── BlueToothHelper.java
│ │ ├── BrightnessHelper.java
│ │ ├── ContactHelper.java
│ │ ├── HandlerHelper.java
│ │ ├── JsonHelper.java
│ │ ├── McuHelper.java
│ │ ├── VoiceEventHelper.java
│ │ ├── VolumeHelper.java
│ │ └── WifiHelper.java
│ ├── impl/ # 回调实现
│ │ ├── CarAirCallback.java
│ │ ├── CarIntelligentDrivingCallBack.java
│ │ └── CarSettingCallback.java
│ ├── protocol/ # 协议实现
│ │ ├── AirProtocol.java
│ │ ├── AvmProtocol.java
│ │ ├── BaseProtocol.java
│ │ ├── BluetoothProtocol.java
│ │ ├── CarControlProtocol.java
│ │ ├── DvrProtocol.java
│ │ ├── FactoryProtocol.java
│ │ ├── MediaProtocol.java
│ │ ├── SettingProtocol.java
│ │ ├── SystemUIProtocol.java
│ │ ├── VoiceProtocol.java
│ │ └── YxProtocol.java
│ ├── provider/ # ContentObserver
│ │ ├── BrightnessObserver.java
│ │ ├── MediaObserver.java
│ │ ├── ReverseObserver.java
│ │ ├── ScreenSaversObserver.java
│ │ └── SettingCommonObserver.java
│ ├── receiver/ # 广播接收器
│ │ ├── BluetoothMonitorReceiver.java
│ │ ├── BootReceiver.java
│ │ ├── HomeStatusReceiver.java
│ │ ├── NetworkChangedReceiver.java
│ │ ├── PowerReceiver.java
│ │ ├── SettingReceiver.java
│ │ ├── TestReceiver.java
│ │ └── VolumeChangedCallback.java
│ ├── service/ # 服务
│ │ ├── BaseVoiceService.java
│ │ └── VoiceService.java
│ └── utils/ # 工具类
│ ├── AppUtils.java
│ ├── BroadcastUtils.java
│ └── DataConvert.java
├── libs/ # 依赖库
│ ├── library-release-0127.aar
│ └── tools.jar
├── assets/tts/ # TTS音频资源
└── build.gradle
```
---
*文档整理日期: 2026-05-27*
@@ -0,0 +1,120 @@
# YX_Voice 配置文档
## 1. Gradle配置
```groovy
android {
defaultConfig {
applicationId "com.yaxon.voice"
}
aaptOptions {
noCompress "pcm" // 不压缩PCM音频文件
}
buildTypes {
release {
outputFileName = "YX_Voice.apk"
}
}
}
```
## 2. Manifest配置
```xml
<application
android:name=".YxApplication"
android:directBootAware="true"
android:persistent="true"
android:sharedUserId="android.uid.system">
```
## 3. 权限声明
```xml
<!-- 系统权限 -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
<uses-permission android:name="android.permission.DEVICE_POWER"/>
<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!-- 蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!-- 存储权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 其他权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
```
## 4. IPC配置
```java
YxIpcConfig yxIpcConfig = new YxIpcConfig();
yxIpcConfig.addRemoteStartService(PackageConst.MUSIC_PKG);
yxIpcConfig.addRemoteStartService(PackageConst.SETTING_PKG);
yxIpcConfig.setRemoteListener(ProtocolManager.getInstance());
YxIPC.getInstance().bind(this, yxIpcConfig);
```
## 5. TXZ连接配置
```java
TxzProtocolManager.initialize(this);
TxzProtocolManager.connect(PackageConst.TXZ_PKG_NEW);
TxzProtocolManager.getConnection(PackageConst.TXZ_PKG_NEW).addConnectionListener(this);
```
## 6. 模块依赖
```
YX_Voice
├── YX_IPC_SDK (IPC通信)
├── YX_Lib_CommonBase (公共基础库)
├── YX_AutoMotiveSDK (车载SDK)
├── library-release-0127.aar (TXZ协议库)
├── tools.jar (工具库)
├── framework_classes.jar (系统框架)
└── serial-0.1.6_classes.jar (串口库)
```
## 7. 包名依赖
| 包名 | 说明 |
|------|------|
| com.txzing.voiceassistant | TXZ语音助手 |
| com.yaxon.music | 音乐模块 |
| com.yaxon.radio | 收音机模块 |
| com.yaxon.hvac | 空调模块 |
| com.yaxon.bluetooth | 蓝牙模块 |
| com.yaxon.setting | 设置模块 |
| com.yaxon.carcontrol | 车辆控制模块 |
| com.yaxon.avm | 360环视模块 |
| com.yaxon.dvr | 行车记录仪模块 |
| com.android.systemui | 系统UI |
## 8. 版本历史
| 版本 | 日期 | 作者 | 说明 |
|------|------|------|------|
| 1.0 | 2024-01-05 | 张博威 | 初始版本 |
| 1.1 | 2024-02-19 | mango | TXZ协议集成 |
| 1.2 | 2024-07-02 | ZhangBoWei | 协议抽象优化 |
| 1.3 | 2025-03-13 | - | 唤醒词修改功能 |
---
*文档整理日期: 2026-05-27*
@@ -0,0 +1,467 @@
# 同行者可见即可说自动注册框架对接方案 - 快速阅读版
> 来源文档:`F:/AI/Obsidian/项目文档/徐工/语音/同行者可见即可说自动注册框架对接方案.docx`
> 整理日期:2026-06-13
> 目标:把原 Word 文档整理成工程接入时能快速查阅的 Markdown 速查文档。
## 1. 一句话结论
“可见即可说”主要依赖 Android 无障碍服务扫描当前界面控件,通过控件的 `android:id`、`android:text`、`android:contentDescription`、`clickable`、`scrollable` 等信息自动注册语音热词。用户说出界面上可见或已通过隐藏标签声明的词后,语音助手命中热词,再回调触发目标控件事件。
如果界面元素无法被无障碍扫描,例如小程序、网页、自绘界面,则需要应用主动通过 AIDL 或广播向语音发送插词列表,语音命中后再把命中的插词回传给应用,由应用自行执行动作。
## 2. 整体链路
### 2.1 普通 Android 控件链路
1. 应用界面展示控件。
2. Android 无障碍服务扫描界面控件。
3. 语音助手读取控件文本或隐藏标签。
4. 语音助手把文本注册为可见即可说热词。
5. 用户说出对应词,例如“每日推荐”或“打开每日推荐”。
6. 热词模块命中控件节点。
7. 无障碍服务触发控件点击或滑动等事件。
8. 应用执行原控件逻辑。
### 2.2 图标控件链路
图标本身不显示文字时,需要通过 `contentDescription` 提供隐藏标签。例如图标按钮没有文字,但设置了 `android:contentDescription="向下滑"`,语音仍可识别“向下滑”并触发该图标。
### 2.3 非常规界面链路
适用于小程序、网页、自绘页面等无障碍拿不到元素的场景。
1. 应用整理当前界面可执行插词列表。
2. 应用通过 AIDL 或广播发送给语音。
3. 语音收到后注册插词。
4. 用户说出插词。
5. 语音识别命中。
6. 语音通过 AIDL 或广播把命中插词回传给应用。
7. 应用根据插词匹配具体控件或业务动作。
## 3. 接入总原则
| 原则 | 说明 |
|---|---|
| 必须有唯一 ID | 所有需要语音响应的控件都应设置唯一 `android:id`。 |
| 文本优先 | 文本控件优先使用 `android:text` 暴露插词。 |
| 图标补标签 | 图标类控件使用 `android:contentDescription` 暴露隐藏插词。 |
| 多说法用 `#` | 多个插词使用 `#` 分隔,例如 `打开#启动`。 |
| 状态要同步 | 播放/暂停、收藏/取消收藏等状态型图标必须动态更新 `contentDescription`。 |
| 点击看 `clickable` | 控件是否响应与 `clickable` 状态有关,`true` 表示可点击。 |
| 滚动看 `scrollable` | 滑动控件本身需要是可滑动节点,即 `Scrollable=true`。 |
| 弹窗用标准 Dialog | 建议使用标准 `Dialog` 或依附 Activity 的自定义 Dialog。 |
## 4. 常见控件接入方式
## 4.1 文本类控件
适用对象:`TextView`、`Button`、带文本的布局项等。
推荐做法:
```xml
<TextView
android:id="@+id/tv_daily_recommend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:text="每日推荐" />
```
支持泛化说法时,可使用 `contentDescription`:
```xml
<TextView
android:id="@+id/tv_daily_recommend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:text="每日推荐"
android:contentDescription="每日推荐#打开每日推荐#我想打开每日推荐" />
```
注意:
- `contentDescription` 中的插词文本必须包含 `text` 中的文本。
- 控件要能响应点击,需确保 `clickable=true` 或实际可点击。
## 4.2 图标类控件
适用对象:只有图片、没有文本的按钮或图标。
```xml
<ImageView
android:id="@+id/iv_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:contentDescription="搜索#查找" />
```
注意:
- 图标没有显示文本时,必须用 `contentDescription` 提供语音插词。
- 多个插词用 `#` 分隔。
- 控件是否响应仍与 `clickable` 状态有关。
## 4.3 同一图标多状态控件
典型场景:播放/暂停、收藏/取消收藏。
错误做法:
```xml
android:contentDescription="播放#暂停"
```
这种做法可能导致当前处于暂停状态时,用户说“暂停”反而触发点击,结果开始播放。
正确做法:根据状态动态更新。
```java
if (isPlaying) {
playButton.setContentDescription("暂停");
} else {
playButton.setContentDescription("播放");
}
```
原则:
- 当前正在播放,插词应是“暂停”。
- 当前已经暂停,插词应是“播放”。
- 当前已收藏,插词应是“取消收藏”。
- 当前未收藏,插词应是“收藏”。
## 4.4 常规滑动控件
适用对象:`ScrollView`、`RecyclerView`、`ListView` 等。
基础要求:
- 控件本身应可滑动,即无障碍节点 `Scrollable=true`。
- 如果每个 item 需要响应语音,item 需要有唯一 ID。
- item 可使用 `contentDescription` 声明插词。
- 如需响应 item 内部 child 控件,child 按文本类或图标类控件处理。
示例:
```xml
<RecyclerView
android:id="@+id/rv_station_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
```
item 示例:
```xml
<TextView
android:id="@+id/tv_station_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:text="88.6MHz"
android:contentDescription="88.6MHz#播放88.6" />
```
## 4.5 翻页控制
文档中特别强调:如果要让可见即可说支持“上一页 / 下一页”这类翻页逻辑,应用需要预留两个大小为 0 的控件。
要求:
- 控件大小为 0。
- 不能设置为 `GONE`。
- 分别添加“上一页”“下一页”等 `contentDescription`。
- 应用自己实现点击事件,点击后控制对应滚动控件翻页。
- 如果页面中有多个同方向滚动控件,只建议配置用户最可能使用的那个。
- 多组 0 大小翻页控件可能导致目标滚动控件不符合预期。
示例:
```xml
<View
android:id="@+id/voice_page_prev"
android:layout_width="0dp"
android:layout_height="0dp"
android:clickable="true"
android:contentDescription="上一页" />
<View
android:id="@+id/voice_page_next"
android:layout_width="0dp"
android:layout_height="0dp"
android:clickable="true"
android:contentDescription="下一页" />
```
```java
voicePagePrev.setOnClickListener(v -> recyclerView.smoothScrollBy(0, -recyclerView.getHeight()));
voicePageNext.setOnClickListener(v -> recyclerView.smoothScrollBy(0, recyclerView.getHeight()));
```
如果不预留翻页控制控件,默认不支持翻页逻辑。
## 4.6 SeekBar 等特殊滑动控件
适用对象:亮度、音量、进度条等 `SeekBar` 控件。
接入目标:支持类似“调高屏幕亮度”“降低音量”“屏幕亮度调大一点”等语音指令。
推荐做法:
```xml
<SeekBar
android:id="@+id/sb_screen_brightness"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="0dp"
android:paddingEnd="0dp"
android:contentDescription="屏幕亮度" />
```
父布局建议:
```xml
android:clipChildren="false"
android:clipToPadding="false"
```
原因:
- 框架根据控件宽高计算百分比拖动距离。
- 无法直接读取控件内部业务值。
- `SeekBar` 默认内边距会造成拖动精度误差。
- 将 `SeekBar` 内边距设为 0,并允许子控件超出父布局边界,可减少误差。
## 4.7 Switch 开关类控件
原生 `Switch`:通常无需额外适配。
自定义开关 View:需要重写 `onInitializeAccessibilityNodeInfo`。
```java
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setCheckable(true);
info.setChecked(isChecked());
}
```
要求:
- 设置 `checkable=true`。
- 根据真实开关状态同步 `checked`。
- 状态变化时及时刷新无障碍信息。
## 5. 非常规界面 AIDL / 广播对接字段
文档流程图给出的字段含义如下。
## 5.1 应用发送给语音:注册或取消注册
| 字段 | 含义 | 示例 |
| ------------- | --------------------- | ------------------------------------------------------ |
| `key_type` | 要处理的类型,`2600` 表示可见即可说 | `2600` |
| `action` | 动作 | `shadow.register` / `shadow.unregister` |
| `packageName` | 应用包名,可不填 | `com.yaxon.carcontrol` |
| `className` | 页面类名,可不填 | `com.yaxon.carcontrol.activity.CarControlMainActivity` |
| `pageName` | 页面名称,可不填 | `voiceSetting` |
| `keywordList` | 插词列表,泛化词用 `#` 分隔 | `打开#启动` |
示例:
```json
{
"key_type": 2600,
"action": "shadow.register",
"packageName": "com.yaxon.carcontrol",
"className": "com.yaxon.carcontrol.activity.CarControlMainActivity",
"pageName": "voiceSetting",
"keywordList": "打开#启动"
}
```
取消注册:
```json
{
"key_type": 2600,
"action": "shadow.unregister",
"packageName": "com.yaxon.carcontrol",
"pageName": "voiceSetting",
"keywordList": "打开#启动"
}
```
## 5.2 语音回传给应用:命中执行
| 字段 | 含义 | 示例 |
| ---------- | --------------------- | ---------------- |
| `key_type` | 回传类型,`1600` 表示可见即可说执行 | `1600` |
| `action` | 动作 | `shadow.execute` |
| `cmd` | 命中的插词原文 | `打开` |
示例:
```json
{
"key_type": 1600,
"action": "shadow.execute",
"cmd": "打开"
}
```
应用收到后,应根据 `cmd` 做业务分发。
## 6. 已知问题与规避方式
## 6.1 `com.android.systemui` 扫描冲突
问题:
- 底部 touch 栏中可能存在很多图标插词。
- 这些插词可能和桌面或其他应用重复,例如“车主手册”。
- `com.android.systemui` 所在 window 可能一直可见,即使视觉上隐藏,也可能被无障碍服务扫描到。
- 用户说“车主手册”时,可能命中 SystemUI 上隐藏的控件,导致结果不符合预期。
建议:
- SystemUI 隐藏时,临时清空相关控件的 `android:text` 和 `android:contentDescription`。
- SystemUI 重新显示时,再恢复文本和隐藏标签。
示例:
```java
if (isSystemUiHidden) {
view.setContentDescription(null);
textView.setText("");
} else {
view.setContentDescription("车主手册");
textView.setText("车主手册");
}
```
## 6.2 同一图片不同插词
问题:
- 同一图片可能对应不同状态,例如播放/暂停。
- 如果同时注册“播放#暂停”,当前状态下可能执行反向动作。
建议:
- 状态变化时动态更新 `contentDescription`。
- 当前能执行什么动作,就只暴露什么插词。
## 6.3 部分弹框扫描不到
问题:
- 一些通过 Window 直接创建的弹框,可能与 Activity 界面不匹配或层级冲突。
- 无障碍服务可能扫描不到弹框里的控件。
建议:
- 优先使用标准 `Dialog`。
- 自定义 Dialog 应依附于 Activity。
- 避免直接用独立 Window 承载需要语音响应的弹框。
## 7. 工程接入检查清单
## 7.1 页面级检查
- [ ] 页面中需要语音响应的控件是否都有唯一 `android:id`。
- [ ] 文本控件是否有明确 `android:text`。
- [ ] 图标控件是否设置了 `android:contentDescription`。
- [ ] 多说法是否使用 `#` 分隔。
- [ ] 控件是否实际可点击或可滑动。
- [ ] 动态状态控件是否会更新 `contentDescription`。
- [ ] 列表 item 是否有唯一 ID 或稳定的可识别标签。
- [ ] 滚动页面是否需要预留上一页/下一页控制控件。
- [ ] 弹框是否使用标准 Dialog 或依附 Activity。
## 7.2 状态型控件检查
- [ ] 播放状态:播放中只暴露“暂停”。
- [ ] 暂停状态:暂停中只暴露“播放”。
- [ ] 已收藏:只暴露“取消收藏”。
- [ ] 未收藏:只暴露“收藏”。
- [ ] 开关类自定义 View 是否正确设置 `checkable` 和 `checked`。
## 7.3 SystemUI 检查
- [ ] 隐藏状态是否仍可能被无障碍扫描。
- [ ] 隐藏时是否清空 `text/contentDescription`。
- [ ] 显示时是否恢复 `text/contentDescription`。
- [ ] 是否存在与 Launcher 或 App 页面重复的插词。
## 7.4 非常规界面检查
- [ ] 是否确认无障碍无法获取页面元素。
- [ ] 是否整理了当前页面插词列表。
- [ ] 是否支持注册和取消注册。
- [ ] 是否能接收语音命中的 `cmd`。
- [ ] `cmd` 到业务动作是否有明确映射表。
- [ ] 页面销毁或切换时是否取消旧插词。
## 8. 当前徐工项目建议落地顺序
1. 先验证 `YX_Voice` 与同行者之间的 `shadow.register` / `shadow.execute` 链路。
2. 在 `YX_CarControl` 做一个测试插词,不绑定真实业务动作,只看日志是否能完整闭环。
3. 链路确认后,再选一个真实页面做最小闭环,例如语音设置页或声音设置页。
4. 对原生 Android 控件,优先走无障碍自动扫描,不额外走 AIDL/广播。
5. 对自绘、网页、小程序、复杂浮窗,走 AIDL/广播注册插词。
6. 对 SystemUI、Launcher、Music、Radio 这类插词多且易冲突的模块,先做页面级插词清单,再逐个治理冲突。
## 9. 日志验证建议
注册阶段重点看:
```text
registerVisibleSpeakKeywords
shadow.register
keywordList
```
命中阶段重点看:
```text
shadow.execute
cmd
handleVisibleSpeakExecute
```
异常排查重点看:
```text
keywordList is empty
TXZ not connected
protocolLogic is null
packageName or cmd is empty
```
## 10. 快速判断表
| 现象 | 优先排查 |
| ------------ | --------------------------------------------- |
| 说了没反应 | 控件是否有 ID、是否 clickable、是否注册成功 |
| 图标不能说 | 是否设置 `contentDescription` |
| 状态动作反了 | 是否动态更新 `contentDescription` |
| 列表不能翻页 | 是否预留 0 大小上一页/下一页控件 |
| SeekBar 拖动不准 | 是否去掉 SeekBar 内边距,父布局是否设置 `clipChildren=false` |
| 弹框扫不到 | 是否用标准 Dialog 或依附 Activity |
| 命中到错误应用 | 是否存在 SystemUI / Launcher / 当前页面插词冲突 |
| 非常规页面无元素 | 改走 AIDL 或广播插词注册 |
## 11. 后续需求明确后需要补充的内容
- 每个模块的可见即可说页面清单。
- 每个页面的控件 ID、显示文本、隐藏标签、状态规则。
- 插词冲突表,尤其是 SystemUI、Launcher、CarControl、Music、Radio。
- 非常规界面的 AIDL / 广播接口定义。
- 命中 `cmd` 到实际业务动作的映射表。
- 现场日志验证结果。
@@ -0,0 +1,84 @@
| 项目 | 值 | 类型 |
| --- | --- | --- |
| 请求名称 | `syncAppList` | String |
| 参数名称 | `appList` | String |
| 参数内容 | 应用列表 JSON 字符串 | String |
```java
BundleMutablePayload params = new BundleMutablePayload();
params.putString("appList", appListJson);
Request request = new Request("syncAppList", params);
sendCommandTxz(request);
```
注意:`appList` 参数本身是一个字符串,字符串内容才是应用列表 JSON,不是直接向参数中放入 JSON 对象。
##应用列表 JSON 格式
```json
{
"list": [
{
"app.name": "空调",
"app.package": "com.yaxon.hvac"
},
{
"app.name": "音乐",
"app.package": "com.yaxon.music"
}
]
}
```
### 3.3 字段定义
| 字段 | 类型 | 是否必填 | 说明 |
| --- | --- | --- | --- |
| `list` | JSON Array | 是 | 应用信息数组 |
| `app.name` | String | 是 | 提供给语音识别使用的应用名称 |
| `app.package` | String | 是 | 应用包名或约定的应用功能标识 |
每个应用元素当前只包含 `app.name` 和 `app.package` 两个字段。
```java
private void scanNativeApp() {
mThreadPoolTool.execute(() -> {
JsonHelper jsonHelper = new JsonHelper();
PackageManager packageManager =
YxApplication.getApplication().getPackageManager();
List<PackageInfo> packageInfoList =
packageManager.getInstalledPackages(0);
JSONArray jsonArray = jsonHelper.createJsonArray();
for (PackageInfo packageInfo : packageInfoList) {
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
String appName = applicationInfo.loadLabel(packageManager).toString();
String packageName = packageInfo.packageName;
if (mAppInfoMap.containsKey(packageName)) {
appName = mAppInfoMap.get(packageName);
}
JSONObject item = jsonHelper.createJsonObject(
new Pair<>("app.name", appName),
new Pair<>("app.package", packageName));
if (item != null) {
jsonArray.put(item);
}
}
for (Map.Entry<String, String> app : mCustomAppMap.entrySet()) {
JSONObject item = jsonHelper.createJsonObject(
new Pair<>("app.name", app.getValue()),
new Pair<>("app.package", app.getKey()));
if (item != null) {
jsonArray.put(item);
}
}
jsonHelper.putJsonArray("list", jsonArray);
VoiceManager.VOICE_EVENT_HELPER
.sendAppListScanComplete(jsonHelper.toJson());
});
}
```
@@ -0,0 +1,114 @@
# 车机系统 CPU / 内存监控问题报告
**日期**: 2026-09-05
**设备**: T9999916 · Android 10 · 6核(600%) · RAM 6.1G + swap 2.4G
**监控窗口**: 10:10 – 11:07(约 57 分钟,10 秒采样,持续报文压测中)
**监控方式**: `top` 10s 轮询 + `dumpsys meminfo` + 线程级 `top -H` + `/proc` 快照
---
## 结论总览
| 等级 | 进程 | 问题 | 证据强度 |
|---|---|---|---|
| 🔴 P0 | `com.txzing.voiceassistant` (PID 4733) | **Native 层内存泄漏 + 持续高 CPU** | 确凿 |
| 🟡 P1 | `com.yaxon.fota` (PID 5037) | 常驻高 CPU(升级服务压测下异常) | 高 |
| 🟡 P2 | `com.yaxon.dms` (PID 5056) | CPU 波动大(可能为正常视觉推理负载) | 中 |
| ⚪ 观察 | system_server / systemui / surfaceflinger / logd / logcollector | 二级负载,随报文流量波动 | 信息 |
---
## 🔴 P0: com.txzing.voiceassistant — Native 内存泄漏(核心发现)
### 内存增长曲线(RSS)
- 10:10 起始 ~562MB → 10:45 ~730MB → 11:00 ~770MB → **11:07 停止监控时 754MB(峰值 793MB)**
- **约 57 分钟增长 ~200MB(+35%)**,锯齿形单调上行,无平台期,无回落,未观察到 GC 释放
- 全局 MemAvailable 同步从 ~1.98G 降至 ~1.70–1.77G,与该进程泄漏吻合
### 泄漏定位在 Native 层(非 Java)
停止监控前最终 `dumpsys meminfo` 快照:
```
Pss Private Heap
Total Dirty Alloc
Native Heap 378885 378784 378358 ← 泄漏主体
Dalvik Heap 113174 113112 100795
TOTAL PSS: 704888 (Views: 9837, ViewRootImpl: 29)
```
- **Native Heap: 378MB**(Heap Alloc 378.4MB / Size 386MB,已接近上限)
- Java Heap: 仅 113MB — 若是 Java 泄漏 GC/lmkd 可回收,Native 才解释 RSS 单调涨
- Views: **9837 个 / ViewRootImpl: 29**(UI 对象也在累积,但量级远小于 native heap)
### CPU 与热点线程(共 104 线程)
```
TID 4942 MDS_SERVER R 94.5% 累计 57:31.58 ← 热点
TID 5018 RenderThread S 2.7% 累计 3:36.31
TID 4962 engine_proc S 2.7% 累计 1:21.77
```
- 进程 CPU 常驻 90–140%,峰值 193%
- **热点线程 TID 4942 = `MDS_SERVER`:单线程 94.5%,57 分钟内累计 57 分 31 秒 CPU 时间** —— 几乎吃满一个核,处于报文/流处理路径;内存与 CPU 异常同源
### 判断
MDS_SERVER(native 报文/数据服务线程)存在分配未释放(缓冲区/会话对象累积),同时该路径处理消耗持续 CPU。按当前 ~3.5MB/min 速率,连续运行数小时将逼近 Native Heap 上限并触发 OOM/崩溃。
### 建议动作
1. `debuggerd -j 4733` 抓 MDS_SERVER 调用栈,确认其在忙什么系统调用/库
2. 对比"停止发报文"前后 RSS 斜率,闭环验证报文触发
3. native 内存定位:`adb shell setprop wrap.com.txzing.voiceassistant "LIBC_MALLOC_DEBUG=1"` 后复测
4. 交 txzing 语音助手团队:重点审 MDS_SERVER 线程的报文缓冲生命周期
---
## 🟡 P1: com.yaxon.fota — 常驻高 CPU
- 全程 40–90% CPU(峰值 100%),RSS 稳定 ~141MB(无内存问题)
- 升级服务在报文压测下持续高 CPU 不正常——怀疑频繁解析/重试报文或轮询过密。建议查其日志与轮询策略
## 🟡 P2: com.yaxon.dms
- CPU 7–91% 波动,RSS 稳定 ~158MB。若 DMS 在做视觉推理属正常负载,峰值偏高,建议确认
---
## ⚪ 二级负载(未见泄漏,供参考)
| 进程 | CPU 范围 | 备注 |
|---|---|---|
| system_server | 20–91% 突发 | 随报文/窗口活动波动 |
| com.android.systemui | 17–64% | 正常偏高 |
| surfaceflinger | 20–47% | 渲染负载 |
| logd | 峰值 77% | 日志量随报文增大 |
| logcollector | 突发 116% | 周期性日志收集 |
| com.yaxon.datacenter_service | 14–57% | 疑似报文接收方,CPU 合理 |
---
## 附录:关键证据命令(可复现)
```bash
adb shell dumpsys meminfo com.txzing.voiceassistant # Native 378MB vs Java 113MB
adb shell top -H -b -n 1 -q -p 4733 # MDS_SERVER 94.5% / 57m31s
adb shell cat /proc/4733/task/4942/comm # → MDS_SERVER
adb shell ls /proc/4733/task | wc -l # → 104 线程
adb shell dumpsys meminfo -c # 全进程 PSS 排名
```
### 全进程 PSS Top(11:07 快照)
| 进程 | PID | PSS (KB) |
|---|---|---|
| com.txzing.voiceassistant | 4733 | 693,609 |
| system | 3288 | 120,731 |
| com.yaxon.dms | 5056 | 90,670 |
| com.yaxon.music | 4806 | 53,318 |
| com.yaxon.factory | 5074 | 38,285 |
| com.yaxon.voice | 4677 | 36,104 |
| com.yaxon.logcat | 5031 | 32,314 |
| com.yaxon.bluetooth | 4721 | 33,078 |