first commit
No files matched your search
@@ -0,0 +1,3 @@
|
||||
This directory contains plugin interfaces that launcher listens for and plugins implement. In other words, these are the hooks that specify what plugins launcher currently supports.
|
||||
|
||||
Details about how to create a new plugin interface, or to use existing interfaces to write a plugin can be found at go/gnl/plugins.
|
||||
@@ -0,0 +1,419 @@
|
||||
# X9HP 开机时间优化分析报告
|
||||
|
||||
**日期**: 2026-06-04
|
||||
**平台**: Semidrive X9HP (Android 10 + FreeRTOS SafetyOS on R5)
|
||||
**对比仓库**: 徐工 (x9hp_xcmg) vs A6
|
||||
|
||||
---
|
||||
|
||||
## 一、概述
|
||||
|
||||
徐工仓库 (`/users/lintenglong/x9hp/androd10_x9hp_ptg4.3p3`) 的开机时间比 A6 仓库 (`/users/lintenglong/x9hp/androd10_x9hp_ptg4.3`) 慢约 **3.5 秒**。
|
||||
|
||||
经过两板 dmesg + logcat 逐段对比,定位到根因为**徐工定制的 Launcher (`com.yaxon.launcher`) 第一帧绘制过慢**。
|
||||
|
||||
---
|
||||
|
||||
## 二、原始数据
|
||||
|
||||
以下为两个板子上直接抓取的全部原始日志(按采集命令组织)。
|
||||
|
||||
### 2.1 dmesg 全日志
|
||||
|
||||
#### A6 dmesg
|
||||
|
||||
```console
|
||||
console:/ $ dmesg
|
||||
[ 2.113762] init: init first stage started!
|
||||
[ 2.543083] init: init second stage started!
|
||||
[ 2.840928] ueventd: Coldboot took 0.132 seconds
|
||||
[ 3.266118] start to do gpu hw reset !
|
||||
[ 3.282734] [drm] Initialized pvr ... on minor 1
|
||||
[ 3.319165] PVR_K: RGX Firmware image loaded
|
||||
[ 3.819167] e2fsck: Pass 1: Checking inodes, blocks, and sizes
|
||||
[ 4.024370] mkswap: Swapspace size: 2369596k
|
||||
[ 4.154427] apexd: Marking APEXd as starting
|
||||
[ 7.498030] === Current system mem: ...
|
||||
[ 7.540411] bcm89883_config_init: start...
|
||||
[ 7.863817] [A6]=== CPU_info: ...
|
||||
[ 8.039518] ---------- Current system time: 08:00:09 CST boot_completed checking ----------
|
||||
[ 9.708556] sdcardfs version 2.0
|
||||
[ 14.191638] [boot_completed] ANDROID_BOOT_STATUS set: id=16, val=0x10000
|
||||
```
|
||||
|
||||
#### 徐工 dmesg
|
||||
|
||||
```console
|
||||
console:/ $ dmesg
|
||||
[ 2.269841] init: init first stage started!
|
||||
[ 2.697998] init: init second stage started!
|
||||
[ 3.025057] ueventd: Coldboot took 0.194 seconds
|
||||
[ 3.457942] start to do gpu hw reset !
|
||||
[ 3.475247] [drm] Initialized pvr ... on minor 1
|
||||
[ 3.797422] PVR_K: RGX Firmware image loaded
|
||||
[ 4.010759] e2fsck: Pass 1: Checking inodes, blocks, and sizes
|
||||
[ 4.148274] Adding 2579104k swap ...
|
||||
[ 5.136792] update_verifier: Booting slot 0 ...
|
||||
[ 7.548430] ---------- Current system time: 08:00:08 CST boot_completed checking ----------
|
||||
[ 9.039796] sdcardfs version 2.0
|
||||
[ 17.333482] init: Received control message 'stop' for 'bootanim' from pid: 3300
|
||||
[ 17.521355] [boot_completed] ANDROID_BOOT_STATUS set: id=16, val=0x10000
|
||||
[ 18.350758] ---------- Current system time: 10:24:17 CST boot_completed done ----------
|
||||
```
|
||||
|
||||
### 2.2 boot_progress 全日志
|
||||
|
||||
#### A6 boot_progress
|
||||
|
||||
```console
|
||||
console:/ $ logcat -b events -d | grep boot
|
||||
01-01 08:00:06.641 2925 2925 I boot_progress_start: 5202
|
||||
01-01 08:00:07.142 2925 2925 I boot_progress_preload_start: 5703
|
||||
01-01 08:00:08.328 2925 2925 I boot_progress_preload_end: 6889
|
||||
01-01 08:00:08.514 3276 3276 I boot_progress_system_run: 7075
|
||||
01-01 08:00:08.779 3276 3276 I boot_progress_pms_start: 7339
|
||||
01-01 08:00:09.068 3276 3276 I boot_progress_pms_system_scan_start: 7629
|
||||
01-01 08:00:09.482 3276 3276 I boot_progress_pms_data_scan_start: 8043
|
||||
01-01 08:00:09.485 3276 3276 I boot_progress_pms_scan_end: 8046
|
||||
01-01 08:00:09.703 3276 3276 I boot_progress_pms_ready: 8264
|
||||
05-25 21:49:45.099 3276 3276 I boot_progress_ams_ready: 9548
|
||||
05-25 21:49:49.547 2753 2870 I sf_stop_bootanim: 13996
|
||||
```
|
||||
|
||||
#### 徐工 boot_progress
|
||||
|
||||
```console
|
||||
console:/ $ logcat -b events -d | grep boot
|
||||
01-01 08:00:06.677 2913 2913 I boot_progress_start: 5238
|
||||
01-01 08:00:07.183 2913 2913 I boot_progress_preload_start: 5744
|
||||
01-01 08:00:08.196 2913 2913 I boot_progress_preload_end: 6757
|
||||
01-01 08:00:08.391 3296 3296 I boot_progress_system_run: 6952
|
||||
01-01 08:00:08.667 3296 3296 I boot_progress_pms_start: 7228
|
||||
01-01 08:00:08.862 3296 3296 I boot_progress_pms_system_scan_start: 7423
|
||||
01-01 08:00:09.158 3296 3296 I boot_progress_pms_data_scan_start: 7719
|
||||
01-01 08:00:09.161 3296 3296 I boot_progress_pms_scan_end: 7722
|
||||
01-01 08:00:09.354 3296 3296 I boot_progress_pms_ready: 7915
|
||||
05-30 10:05:07.567 3296 3296 I boot_progress_ams_ready: 8645
|
||||
05-30 10:05:10.701 3296 3322 I boot_progress_enable_screen: 11779
|
||||
05-30 10:05:15.944 2734 3343 I sf_stop_bootanim: 17022
|
||||
05-30 10:05:16.042 2736 4831 I sf_stop_bootanim: 17264
|
||||
05-30 10:05:16.047 3299 3326 I wm_boot_animation_done: 17268
|
||||
```
|
||||
|
||||
### 2.3 Launcher 启动日志
|
||||
|
||||
#### A6 Launcher
|
||||
|
||||
未抓取到特定日志(SDDemo 启动快)。
|
||||
|
||||
#### 徐工 Launcher
|
||||
|
||||
```console
|
||||
console:/ $ logcat -d | grep "com.yaxon.launcher"
|
||||
01-01 08:00:09.034 3299 3357 E PackageParser: wangsl find an home app,app is ApplicationInfo{... com.yaxon.launcher}
|
||||
05-30 10:05:07.916 3299 3331 I ActivityManager: Start proc 3536:com.yaxon.launcher/1000
|
||||
05-30 10:05:07.980 3299 3299 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.yaxon.launcher/.main.LauncherActivity}
|
||||
05-30 10:05:08.409 3536 3536 D IocContainer: inject key:...LauncherApplication
|
||||
05-30 10:05:08.413 3536 3536 D UserCenterControllerImp: send broadcast
|
||||
05-30 10:05:08.624 3589 3589 I CAR.AM : Updating top task to: LauncherActivity
|
||||
05-30 10:05:08.849 3536 3536 D IocContainer: inject key:...SoundSourceViewModel
|
||||
05-30 10:05:08.897 3536 3536 D IocContainer: inject key:...SoundSourceViewModel
|
||||
05-30 10:05:08.924 3536 3536 D IocContainer: inject key:...IntelligentDrivingCardViewModel
|
||||
05-30 10:05:09.037 3536 3536 D IocContainer: inject key:...DisplayShareViewModel
|
||||
05-30 10:05:09.058 3536 3536 D IocContainer: inject key:...DisplayShareViewModel
|
||||
05-30 10:05:09.068 3536 3536 D DisplayShareBusyness: resolveDisplayShareViewModel3
|
||||
05-30 10:05:09.117 3536 3536 D IocContainer: inject key:...IntelligentDrivingCardViewModel
|
||||
05-30 10:05:09.300 3536 3536 D IocContainer: inject key:...IntelligentDrivingCardViewModel
|
||||
05-30 10:05:09.862 3536 3536 W ContextImpl: ...LauncherActivity.sendHomeStatusBroadcast ...LauncherActivity.onResume
|
||||
05-30 10:05:12.540 3892 3892 I ForegroundAppMonitor: Foreground app changed: -> com.yaxon.launcher
|
||||
05-30 10:05:19.087 3536 3536 D DisplayShareBusyness: resolveDisplayShareViewModel3
|
||||
05-30 10:05:28.038 3299 3332 I ActivityTaskManager: Displayed com.yaxon.launcher/.main.LauncherActivity: +2s598ms
|
||||
```
|
||||
|
||||
### 2.4 init 服务列表
|
||||
|
||||
#### A6 running services
|
||||
|
||||
```console
|
||||
console:/ $ getprop | grep "init.svc" | grep running
|
||||
[init.svc.adbd]: [running]
|
||||
[init.svc.apexd]: [running]
|
||||
...共 75 个服务...
|
||||
[init.svc.zygote_secondary]: [running]
|
||||
```
|
||||
|
||||
#### 徐工 running services
|
||||
|
||||
```console
|
||||
console:/ $ getprop | grep "init.svc" | grep running
|
||||
[init.svc.adbd]: [running]
|
||||
[init.svc.apexd]: [running]
|
||||
...共 74 个服务...
|
||||
[init.svc.zygote_secondary]: [running]
|
||||
|
||||
# 特有的服务:
|
||||
[init.svc.check_data_partition]: [running]
|
||||
[init.svc.logcollector]: [running]
|
||||
[init.svc.ut-service]: [running]
|
||||
[init.svc.yx_tbox]: [running]
|
||||
|
||||
# A6 有但徐工没有的服务:
|
||||
# - [init.svc.evs_driver]: [running]
|
||||
# - [init.svc.evs_manager]: [running]
|
||||
# - [init.svc.gocsdk_auth]: [running]
|
||||
# - [init.svc.vendor.sensors-hal-1-0]: [running]
|
||||
```
|
||||
|
||||
### 2.5 进程数量
|
||||
|
||||
```console
|
||||
# A6
|
||||
console:/ $ ps -A | wc -l
|
||||
278
|
||||
|
||||
# 徐工
|
||||
console:/ $ ps -A | wc -l
|
||||
259
|
||||
```
|
||||
|
||||
### 2.6 bootanim 状态
|
||||
|
||||
```console
|
||||
# 两个仓库
|
||||
console:/ $ getprop init.svc.bootanim
|
||||
stopped
|
||||
```
|
||||
|
||||
### 2.7 数据分区大小
|
||||
|
||||
```console
|
||||
# A6
|
||||
console:/ $ df -h /data
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
/dev/block/mmcblk1p26 44G 438M 43G 1% /data
|
||||
|
||||
# 徐工
|
||||
console:/ $ df -h /data
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
/dev/block/mmcblk1p25 44G 438M 43G 1% /data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、对比分析
|
||||
|
||||
### 3.1 内核时间戳对比 (dmesg)
|
||||
|
||||
| 事件 | A6 | 徐工 | 差 |
|
||||
|------|------|------|------|
|
||||
| init first stage | 2.11s | 2.27s | +0.16s |
|
||||
| init second stage | 2.54s | 2.70s | +0.16s |
|
||||
| ueventd coldboot | 0.132s (2.84s) | 0.194s (3.03s) | +0.06s |
|
||||
| GPU 驱动初始化 | 3.28s | 3.48s | +0.20s |
|
||||
| GPU 固件加载 | 3.32s | 3.80s | +0.48s |
|
||||
| GPU 完成 | 3.28s→3.32s (0.04s) | 3.48s→3.80s (0.32s) | +0.28s |
|
||||
| e2fsck data 分区 | 3.82s→3.83s | 4.01s→4.13s | +0.30s |
|
||||
| swap 开启 | 4.02s | 4.15s | +0.13s |
|
||||
| update_verifier 完成 | ~5.14s | 5.14s | 持平 |
|
||||
| sdcardfs 挂载 | 9.71s | 9.04s | **-0.67s ✅** |
|
||||
| boot_completed checking | 7.50s | 7.55s | +0.05s |
|
||||
| **boot_completed 到达** | **14.19s** | **17.52s** | **+3.33s ❌** |
|
||||
|
||||
### 3.2 Boot Progress 对比
|
||||
|
||||
将 logcat 时间戳转为开机后秒数:
|
||||
|
||||
| 阶段 | A6 (ms) | A6 (s) | 徐工 (ms) | 徐工 (s) | 差(s) |
|
||||
|------|---------|--------|-----------|---------|-------|
|
||||
| boot_progress_start | 5202 | 5.20 | 5238/5385 | 5.39 | +0.19 |
|
||||
| preload_start | 5703 | 5.70 | 5744/5854 | 5.85 | +0.15 |
|
||||
| preload_end | 6889 | 6.89 | 6757/6886 | 6.89 | 0.00 |
|
||||
| system_run | 7075 | 7.08 | 6952/7089 | 7.09 | +0.01 |
|
||||
| pms_start | 7339 | 7.34 | 7228/7338 | 7.34 | 0.00 |
|
||||
| pms_system_scan_start | 7629 | 7.63 | 7423/7522 | 7.52 | -0.11 |
|
||||
| pms_data_scan_start | 8043 | 8.04 | 7719/7850 | 7.85 | -0.19 |
|
||||
| pms_scan_end | 8046 | 8.05 | 7722/7853 | 7.85 | -0.20 |
|
||||
| pms_ready | 8264 | 8.26 | 7915/8048 | 8.05 | -0.21 |
|
||||
| ams_ready | 9548 | **9.55** | 8645/8791 | **8.79** | **-0.76 ✅** |
|
||||
| enable_screen | - | - | 11779/11813 | **11.81** | - |
|
||||
| sf_stop_bootanim | 13996 | **14.00** | 17022/17264 | **17.26** | **+3.26 ❌** |
|
||||
| wm_boot_animation_done | - | - | 17268 | 17.27 | - |
|
||||
|
||||
> 注:徐工 boot_progress 有两组时间戳(logcat 时间±开机时间),这里取开机时间换算值。
|
||||
|
||||
### 3.3 各阶段耗时对比
|
||||
|
||||
| 阶段 | A6 耗时 | 徐工耗时 | 差 | 结论 |
|
||||
|------|---------|---------|------|------|
|
||||
| start→preload_start | 0.50s | 0.46s | -0.04s | ✅ 正常 |
|
||||
| preload_start→end (Zygote预加载) | 1.19s | 1.04s | -0.15s | ✅ 正常 |
|
||||
| preload_end→system_run | 0.19s | 0.20s | +0.01s | ✅ 正常 |
|
||||
| system_run→pms_start | 0.26s | 0.25s | -0.01s | ✅ 正常 |
|
||||
| pms_start→pms_ready (PMS扫描) | 0.93s | 0.69s | -0.24s | ✅ 徐工略快 |
|
||||
| pms_ready→ams_ready | 1.28s | 0.73s | -0.55s | ✅ 徐工快 |
|
||||
| **ams_ready→sf_stop (总耗时)** | **4.45s** | **8.47s** | **+4.02s ❌** | **问题区间** |
|
||||
| ams_ready→enable_screen | - | 3.02s | - | 正常范围 |
|
||||
| **enable_screen→sf_stop** | - | **5.45s** | - | **等待Launcher** |
|
||||
| **总 (start→sf_stop)** | **8.80s** | **11.87s** | **+3.07s ❌** | |
|
||||
|
||||
### 3.4 init 服务差异
|
||||
|
||||
| 差异项 | A6 | 徐工 | 影响 |
|
||||
|--------|----|------|------|
|
||||
| 总进程数 | 278 | 259 | −19(正常) |
|
||||
| running services | 75 | 74 | 基本相同 |
|
||||
| **特有服务** | evs_driver, evs_manager, gocsdk_auth, sensors-hal | check_data_partition, logcollector, ut-service, yx_tbox, StrLink | 差异微小,非导致3.5s的原因 |
|
||||
| bootanim 状态 | stopped | stopped | 一致 |
|
||||
|
||||
### 3.5 Launcher 启动耗时(根因)
|
||||
|
||||
**徐工 `com.yaxon.launcher` 启动时间线:**
|
||||
|
||||
| 时间 | 事件 | 距开机(s) |
|
||||
|------|------|----------|
|
||||
| 10:05:07.916 | 进程启动 | ~9s |
|
||||
| 10:05:07.980 | START LauncherActivity | ~9s |
|
||||
| 10:05:08.409 | IocContainer 注入开始 | ~9.5s |
|
||||
| 10:05:08.413 | UserCenterController | ~9.5s |
|
||||
| 10:05:08.624 | CAR.AM 更新前台任务 | ~9.5s |
|
||||
| 10:05:08.892 | SoundSourceViewModel ×2 | ~10s |
|
||||
| 10:05:08.924 | IntelligentDrivingCardViewModel | ~10s |
|
||||
| 10:05:09.037 | DisplayShareViewModel ×N | ~10s |
|
||||
| 10:05:09.862 | onResume | ~10.5s |
|
||||
| 10:05:12.540 | ForegroundAppMonitor 确认前台 | ~13.5s |
|
||||
| 10:05:19.087 | DisplayShareBusyness resolve | ~20s |
|
||||
| **10:05:28.038** | **Displayed: +2s598ms** | **~29s** |
|
||||
|
||||
A6 用的是 `SDDemo MainActivity`(简单 Demo 列表),没有复杂的依赖注入开销,启动极快,不影响 bootanim 停止时间。
|
||||
|
||||
---
|
||||
|
||||
## 四、根因结论
|
||||
|
||||
**前 9.5 秒两个仓库几乎一致,甚至徐工还快 1 秒。3.5 秒的差距全部集中在 `ams_ready` (8.79s) 到 `sf_stop_bootanim` (17.26s) 之间。**
|
||||
|
||||
具体链路:
|
||||
|
||||
```
|
||||
ams_ready (8.79s)
|
||||
→ system_server 启动各种服务
|
||||
→ Launcher 启动 (9s)
|
||||
→ enable_screen (11.81s) → 屏幕亮起(R5 彩条/动画)
|
||||
→ WindowManager 等待 Launcher 绘制第一帧
|
||||
→ Launcher 还在 IocContainer 注入中...
|
||||
→ LauncherActivity onResume (10.5s)
|
||||
→ Displayed (29s) ← 绘制完成!
|
||||
→ sf_stop_bootanim (17.26s) ← WMS 等不及了,超时停止
|
||||
→ boot_completed (17.52s)
|
||||
```
|
||||
|
||||
**根本原因:`com.yaxon.launcher` 的 IocContainer 依赖注入太重**,大量 ViewModel 同步初始化(SoundSourceViewModel ×2、IntelligentDrivingCardViewModel ×2、DisplayShareViewModel ×N),拖慢了首帧绘制,导致 WindowManager 等待超时。
|
||||
|
||||
---
|
||||
|
||||
## 五、优化建议
|
||||
|
||||
### 5.1 治本:优化 Launcher 启动(推荐,预期收益 2-3s)
|
||||
|
||||
| 优化项 | 说明 | 预期收益 | 难度 |
|
||||
|--------|------|---------|------|
|
||||
| 非首屏 ViewModel 懒加载 | DisplayShareViewModel 等延后到主界面显示后注入 | ~1-2s | 中 |
|
||||
| 减少同步 IocContainer DI 注入 | 改为异步/懒加载 | ~0.5-1s | 中 |
|
||||
| 移除不必要的 broadcast | sendHomeStatusBroadcast 等 | ~0.1s | 低 |
|
||||
|
||||
### 5.2 治标:提前停 bootanim(预期收益 3-4s)
|
||||
|
||||
在 `enable_screen` 后就 `stopBootAnim()`,不等 Launcher 绘制。但 `boot_completed` 会在桌面未完全渲染时发出。
|
||||
|
||||
### 5.3 其他优化(组合使用可达 1-2s)
|
||||
|
||||
| 优化项 | 路径 | 说明 | 预期 |
|
||||
|--------|------|------|------|
|
||||
| bootlogo 4s hardcode | `bootlogo.c` `thread_sleep(4000)` | 改 500ms | ~3.5s |
|
||||
| R5 动画提前结束 | 已实现彩条测试 | 收到 boot_completed 立即清屏 | 视觉改善 |
|
||||
|
||||
---
|
||||
|
||||
## 六、验证方式
|
||||
|
||||
```bash
|
||||
# 1. boot_completed 内核时间戳
|
||||
dmesg | grep "boot_completed"
|
||||
|
||||
# 2. Launcher 第一帧绘制时间
|
||||
logcat -d | grep "Displayed.*launcher"
|
||||
|
||||
# 3. boot_progress 全链路
|
||||
logcat -b events -d | grep "boot_progress\|sf_stop"
|
||||
```
|
||||
|
||||
**目标:将 `sf_stop_bootanim` 从 17.26s 降低到 14s 以内。**
|
||||
|
||||
---
|
||||
|
||||
## 七、附录
|
||||
|
||||
### 7.1 R5 开机动画流程
|
||||
|
||||
```
|
||||
LK Boot → FreeRTOS SafetyOS (lk_main)
|
||||
→ apps_init() 启动 APP_START
|
||||
├── bootlogo → 显示 YUV 图片, thread_sleep(4000)
|
||||
├── USM → Unified Service Manager
|
||||
│ ├── SplashScreen → 显示 RGB 品牌图
|
||||
│ └── Animation → 播放 MJPEG 动画
|
||||
│ ├── 新路径: ani_app_5.c (ANI_APP_MODE==5)
|
||||
│ └── 通过 DCF property 监听 Android 启动状态
|
||||
│ - DMP_ID_ANDROID_BOOT_STATUS (ID=16)
|
||||
│ - 收到 boot_completed → 结束动画 → 清屏
|
||||
```
|
||||
|
||||
### 7.2 Android Boot Completed 信号链路
|
||||
|
||||
```
|
||||
sys.boot_completed=1
|
||||
→ bootnotify.rc: start bootnotify
|
||||
→ BootNotifyMain.cpp: setAndroidBootStatus(1)
|
||||
→ ioctl(/dev/property, DCF_IOC_SET_PROPERTY, id=16)
|
||||
→ 内核 DCF 驱动 (sdrv_property_client.c)
|
||||
→ rpmsg 跨核通信
|
||||
→ R5 property 回调 (android_changed_cb)
|
||||
→ 结束动画 / 刷彩条
|
||||
```
|
||||
|
||||
### 7.3 涉及源码路径
|
||||
|
||||
| 路径 | 说明 |
|
||||
|------|------|
|
||||
| `android10/vendor/semidrive/tools/BootNotify/` | Boot Completed 通知 |
|
||||
| `android10/vendor/semidrive/tools/ScreenTrigger/` | 屏幕触发通知 |
|
||||
| `android10/vendor/semidrive/tools/SDDemo/` | 测试 Demo / A6 Launcher |
|
||||
| `rtos/freertos_safetyos/application/early_app/Animation/` | R5 动画服务 |
|
||||
| `rtos/freertos_safetyos/application/early_app/bootlogo/` | Bootlogo 显示 |
|
||||
| `rtos/freertos_safetyos/application/early_app/SplashScreen/` | 品牌图显示 |
|
||||
| `rtos/freertos_safetyos/top/main.c` | R5 主入口 |
|
||||
|
||||
### 7.4 抓取数据所用命令
|
||||
|
||||
```bash
|
||||
# 内核日志
|
||||
dmesg
|
||||
|
||||
# Android boot stages
|
||||
logcat -b events -d | grep -E "boot_progress|sf_stop|wm_boot"
|
||||
|
||||
# Launcher 日志
|
||||
logcat -d | grep "com.yaxon.launcher"
|
||||
|
||||
# init 服务列表
|
||||
getprop | grep "init.svc" | grep running
|
||||
|
||||
# bootanim 状态
|
||||
getprop init.svc.bootanim
|
||||
|
||||
# 进程数
|
||||
ps -A | wc -l
|
||||
|
||||
# 磁盘
|
||||
df -h /data
|
||||
```
|
||||
@@ -0,0 +1,181 @@
|
||||
# YX_Voice 架构设计
|
||||
|
||||
## 整体架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 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 (跨进程通信框架) │ │
|
||||
│ └──────────────────────────┬───────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────────┼───────────────────────┐ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ 音乐 │ │ 设置 │ │ 空调 │ │
|
||||
│ │ 模块 │ │ 模块 │ │ 模块 │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 模块分层
|
||||
|
||||
| 层级 | 模块 | 职责 |
|
||||
|------|------|------|
|
||||
| 应用层 | VoiceService | 服务入口、生命周期管理 |
|
||||
| 核心层 | ProtocolManager, VoiceManager | 协议分发、状态管理 |
|
||||
| 协议层 | BaseProtocol及子类 | 具体协议解析与执行 |
|
||||
| 辅助层 | Helpers, Receivers, Observers | 状态监听、辅助功能 |
|
||||
| 通信层 | YxIPC, TxzProtocolManager | 跨进程通信 |
|
||||
|
||||
---
|
||||
|
||||
## 协议处理流程
|
||||
|
||||
```
|
||||
TXZ语音指令
|
||||
│
|
||||
▼
|
||||
TxzProtocolManager.setDefaultHandler()
|
||||
│
|
||||
├── 解析 commandType (协议名称)
|
||||
├── 解析 Bundle 参数
|
||||
├── 转换为JSON格式
|
||||
│
|
||||
▼
|
||||
ProtocolManager.onResponse()
|
||||
│
|
||||
▼
|
||||
YxProtocolHandler.onHandleProtocol()
|
||||
│
|
||||
▼
|
||||
具体Protocol实现类.onProtocolLogic()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## IPC通信架构
|
||||
|
||||
```
|
||||
┌─────────────────┐ YxIPC ┌─────────────────┐
|
||||
│ YX_Voice │◄──────────────►│ YX_Music │
|
||||
│ (Server) │ │ (Client) │
|
||||
└────────┬────────┘ └─────────────────┘
|
||||
│
|
||||
│ YxIPC
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ YX_Setting │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
**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);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TXZ协议通信
|
||||
|
||||
```
|
||||
┌─────────────────┐ TxzProtocolManager ┌─────────────────┐
|
||||
│ YX_Voice │◄─────────────────────►│ TXZ语音助手 │
|
||||
│ (ConnectionService) │ (AIDL Service) │
|
||||
└─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
**连接流程**:
|
||||
```java
|
||||
TxzProtocolManager.initialize(this);
|
||||
TxzProtocolManager.connect(PackageConst.TXZ_PKG_NEW);
|
||||
TxzProtocolManager.getConnection(PackageConst.TXZ_PKG_NEW).addConnectionListener(this);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 模块依赖关系
|
||||
|
||||
```
|
||||
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 (串口库)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 包名依赖
|
||||
|
||||
| 包名 | 说明 |
|
||||
|------|------|
|
||||
| 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 |
|
||||
|
||||
---
|
||||
|
||||
## 核心模块
|
||||
|
||||
### VoiceService
|
||||
- **继承关系**: `VoiceService extends BaseVoiceService implements ConnectionListener`
|
||||
- **职责**: 与TXZ语音助手建立连接、接收并分发语音指令
|
||||
|
||||
### ProtocolManager
|
||||
- **设计模式**: 单例模式
|
||||
- **职责**: 实现IPC消息监听接口、将消息分发给协议处理器
|
||||
|
||||
### YxProtocolHandler
|
||||
- **职责**: 维护包名到协议逻辑类的映射、在后台线程处理协议分发
|
||||
|
||||
### VoiceManager
|
||||
- **设计模式**: 单例模式
|
||||
- **职责**: 管理TXZ绑定状态、AVM/DVR前台状态、注册车辆状态回调
|
||||
|
||||
### VoiceEventHelper
|
||||
- **职责**: 封装所有语音控制操作、与各模块进行IPC通信
|
||||
|
||||
---
|
||||
|
||||
*文档生成日期: 2026-03-19*
|
||||
@@ -0,0 +1,655 @@
|
||||
# YX_Voice 详细设计文档
|
||||
|
||||
## 1. 概述
|
||||
|
||||
### 1.1 项目简介
|
||||
YX_Voice 是车载语音助手服务模块,作为第三方语音助手(同行者TXZ)与车载各功能模块之间的桥梁,负责语音指令的分发、处理以及车辆状态的同步。
|
||||
|
||||
### 1.2 项目信息
|
||||
- **包名**: `com.yaxon.voice`
|
||||
- **应用类型**: Android System Application
|
||||
- **进程类型**: 系统持久化进程 (`persistent=true`)
|
||||
- **共享UID**: `android.uid.system`
|
||||
|
||||
### 1.3 主要功能
|
||||
1. 语音指令接收与分发
|
||||
2. 车辆控制(空调、车窗、灯光等)
|
||||
3. 媒体播放控制
|
||||
4. 系统设置控制
|
||||
5. 蓝牙电话控制
|
||||
6. 车辆状态同步
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构设计
|
||||
|
||||
### 2.1 整体架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ 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 (跨进程通信框架) │ │
|
||||
│ └──────────────────────────┬───────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────────┼───────────────────────┐ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ 音乐 │ │ 设置 │ │ 空调 │ │
|
||||
│ │ 模块 │ │ 模块 │ │ 模块 │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 模块分层
|
||||
|
||||
| 层级 | 模块 | 职责 |
|
||||
|------|------|------|
|
||||
| 应用层 | VoiceService | 服务入口、生命周期管理 |
|
||||
| 核心层 | ProtocolManager, VoiceManager | 协议分发、状态管理 |
|
||||
| 协议层 | BaseProtocol及子类 | 具体协议解析与执行 |
|
||||
| 辅助层 | Helpers, Receivers, Observers | 状态监听、辅助功能 |
|
||||
| 通信层 | YxIPC, TxzProtocolManager | 跨进程通信 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心模块详细设计
|
||||
|
||||
### 3.1 应用入口 (YxApplication)
|
||||
|
||||
**文件路径**: `com/yaxon/voice/YxApplication.java`
|
||||
|
||||
**职责**:
|
||||
- 继承 `AutoMotiveSDKApplication`,提供车载SDK上下文
|
||||
- 初始化IPC通信框架
|
||||
- 初始化崩溃处理机制
|
||||
- 启动语音服务
|
||||
|
||||
**关键代码流程**:
|
||||
```
|
||||
onCreate()
|
||||
├── ToolInit.init() // 工具类初始化
|
||||
├── CrashExceptionHandler // 崩溃处理
|
||||
├── YxIPC.bind() // IPC绑定
|
||||
│ └── ProtocolManager // 设置消息监听
|
||||
├── PackagePermissionManager // 权限管理
|
||||
└── startVoiceService() // 启动服务
|
||||
```
|
||||
|
||||
### 3.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指令处理流程**:
|
||||
```
|
||||
TXZ语音指令
|
||||
│
|
||||
▼
|
||||
TxzProtocolManager.setDefaultHandler()
|
||||
│
|
||||
├── 解析 commandType (协议名称)
|
||||
├── 解析 Bundle 参数
|
||||
├── 转换为JSON格式
|
||||
│
|
||||
▼
|
||||
ProtocolManager.onResponse()
|
||||
│
|
||||
▼
|
||||
YxProtocolHandler.onHandleProtocol()
|
||||
│
|
||||
▼
|
||||
具体Protocol实现类.onProtocolLogic()
|
||||
```
|
||||
|
||||
### 3.3 协议管理器 (ProtocolManager)
|
||||
|
||||
**文件路径**: `com/yaxon/voice/core/ProtocolManager.java`
|
||||
|
||||
**设计模式**: 单例模式
|
||||
|
||||
**职责**:
|
||||
- 实现IPC消息监听接口 (`MessageListener`, `RemoteListener`)
|
||||
- 将消息分发给协议处理器
|
||||
|
||||
**类图**:
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ ProtocolManager │
|
||||
├─────────────────────────────────┤
|
||||
│ - sInstance: ProtocolManager │
|
||||
│ - mProtocolHandler: IProtocolHandler │
|
||||
├─────────────────────────────────┤
|
||||
│ + getInstance() │
|
||||
│ + setProtocolHandler() │
|
||||
│ + onResponse() │ ← MessageListener
|
||||
│ + onBindRemote() │ ← RemoteListener
|
||||
│ + release() │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.4 协议处理器 (YxProtocolHandler)
|
||||
|
||||
**文件路径**: `com/yaxon/voice/core/YxProtocolHandler.java`
|
||||
|
||||
**职责**:
|
||||
- 维护包名到协议逻辑类的映射
|
||||
- 在后台线程处理协议分发
|
||||
|
||||
**协议映射表**:
|
||||
```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()); // 行车记录仪协议
|
||||
```
|
||||
|
||||
### 3.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前台状态
|
||||
```
|
||||
|
||||
### 3.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 | 唤醒词、发音人设置 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 协议设计
|
||||
|
||||
### 4.1 协议接口定义
|
||||
|
||||
**IProtocolHandler (协议处理接口)**:
|
||||
```java
|
||||
public interface IProtocolHandler {
|
||||
void onHandleProtocol(long msgSendTime, String remoteName, Bundle data);
|
||||
}
|
||||
```
|
||||
|
||||
**IProtocolLogic (协议逻辑接口)**:
|
||||
```java
|
||||
public interface IProtocolLogic {
|
||||
void onProtocolLogic(Bundle data);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.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);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 TXZ协议常量定义
|
||||
|
||||
协议命令类型(部分):
|
||||
|
||||
#### 车辆控制类
|
||||
| 命令常量 | 命令名称 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 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环视 |
|
||||
|
||||
#### 空调控制类
|
||||
| 命令常量 | 命令名称 | 说明 |
|
||||
|----------|----------|------|
|
||||
| CMD_OPEN_AC | openAc | 打开空调 |
|
||||
| CMD_CLOSE_AC | closeAc | 关闭空调 |
|
||||
| CMD_SET_AC_WIND_SPEED_LEVEL | setAcWindSpeedLevel | 设置风速档位 |
|
||||
| CMD_SET_AC_TEMP_VALUE | setAcTempValue | 设置温度 |
|
||||
|
||||
#### 系统设置类
|
||||
| 命令常量 | 命令名称 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 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 | 自定义唤醒词 |
|
||||
|
||||
#### 媒体控制类
|
||||
| 命令常量 | 命令名称 | 说明 |
|
||||
|----------|----------|------|
|
||||
| CMD_PLAY_PAUSE | playPause | 暂停播放 |
|
||||
| CMD_PLAY_RESUME | playResume | 继续播放 |
|
||||
| CMD_PLAY_PREV | playPrev | 上一首 |
|
||||
| CMD_PLAY_NEXT | playNext | 下一首 |
|
||||
| CMD_OPEN_APP | openApp | 打开应用 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 模块间通信设计
|
||||
|
||||
### 5.1 IPC通信架构
|
||||
|
||||
YX_Voice 使用 `YxIPC` 框架进行跨进程通信:
|
||||
|
||||
```
|
||||
┌─────────────────┐ YxIPC ┌─────────────────┐
|
||||
│ YX_Voice │◄──────────────►│ YX_Music │
|
||||
│ (Server) │ │ (Client) │
|
||||
└────────┬────────┘ └─────────────────┘
|
||||
│
|
||||
│ YxIPC
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ YX_Setting │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
**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.2 TXZ协议通信
|
||||
|
||||
TXZ语音助手使用自定义协议框架:
|
||||
|
||||
```
|
||||
┌─────────────────┐ TxzProtocolManager ┌─────────────────┐
|
||||
│ YX_Voice │◄─────────────────────►│ TXZ语音助手 │
|
||||
│ (ConnectionService) │ (AIDL Service) │
|
||||
└─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
**连接流程**:
|
||||
```java
|
||||
TxzProtocolManager.initialize(this);
|
||||
TxzProtocolManager.connect(PackageConst.TXZ_PKG_NEW);
|
||||
TxzProtocolManager.getConnection(PackageConst.TXZ_PKG_NEW).addConnectionListener(this);
|
||||
```
|
||||
|
||||
### 5.3 消息格式
|
||||
|
||||
**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, "类型");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 接收器与观察者
|
||||
|
||||
### 6.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 | 静音状态变化 |
|
||||
| TestReceiver | 测试相关Action | 测试功能 |
|
||||
|
||||
### 6.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等 | 通用设置 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 状态同步机制
|
||||
|
||||
### 7.1 初始化同步
|
||||
|
||||
当TXZ连接成功时,同步所有状态:
|
||||
```java
|
||||
public void onConnected() {
|
||||
VoiceManager.getInstance().setVoiceBind(true);
|
||||
VoiceManager.VOICE_EVENT_HELPER.sendVoiceBindSuccess(null);
|
||||
AppHelper.getInstance().startScanApp();
|
||||
initNotifyCarConfig(); // 车辆配置
|
||||
initNotifyBluetoothStatus(); // 蓝牙状态
|
||||
initNotifyVolumeStatus(); // 音量状态
|
||||
initNotifyCarSettingStatus(); // 车辆设置状态
|
||||
sendBrightnessStatus(); // 亮度状态
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 状态同步命令
|
||||
|
||||
同步类命令(部分):
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| syncAcStatus | 同步空调状态 |
|
||||
| syncBlueToothStatus | 同步蓝牙状态 |
|
||||
| syncWiFiStatus | 同步WiFi状态 |
|
||||
| syncMediaVolume | 同步媒体音量 |
|
||||
| syncScreenBrightness | 同步屏幕亮度 |
|
||||
| syncVoiceWakeUpStatus | 同步语音唤醒开关 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 依赖关系
|
||||
|
||||
### 8.1 模块依赖
|
||||
|
||||
```
|
||||
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 (串口库)
|
||||
```
|
||||
|
||||
### 8.2 包名依赖
|
||||
|
||||
| 包名 | 说明 |
|
||||
|------|------|
|
||||
| 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 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 权限声明
|
||||
|
||||
```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"/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 部署配置
|
||||
|
||||
### 10.1 Gradle配置
|
||||
|
||||
```groovy
|
||||
android {
|
||||
defaultConfig {
|
||||
applicationId "com.yaxon.voice"
|
||||
}
|
||||
|
||||
aaptOptions {
|
||||
noCompress "pcm" // 不压缩PCM音频文件
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
outputFileName = "YX_Voice.apk"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 10.2 Manifest配置
|
||||
|
||||
```xml
|
||||
<application
|
||||
android:name=".YxApplication"
|
||||
android:directBootAware="true"
|
||||
android:persistent="true"
|
||||
android:sharedUserId="android.uid.system">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 附录
|
||||
|
||||
### 11.1 文件结构
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
### 11.2 语音唤醒词设置流程
|
||||
|
||||
```
|
||||
用户语音输入唤醒词
|
||||
│
|
||||
▼
|
||||
TXZ解析并发送协议: customWakeupWord
|
||||
│
|
||||
▼
|
||||
VoiceProtocol.onProtocolLogic()
|
||||
│
|
||||
▼
|
||||
VoiceEventHelper.customWakeupWord()
|
||||
│
|
||||
├── 检查当前值是否相同
|
||||
├── 保存到Settings.System
|
||||
└── 通过IPC发送到CAR_CAR_CONTROL_PKG
|
||||
│
|
||||
▼
|
||||
车辆控制模块更新唤醒词
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 版本历史
|
||||
|
||||
| 版本 | 日期 | 作者 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 1.0 | 2024-01-05 | 张博威 | 初始版本 |
|
||||
| 1.1 | 2024-02-19 | mango | TXZ协议集成 |
|
||||
| 1.2 | 2024-07-02 | ZhangBoWei | 协议抽象优化 |
|
||||
| 1.3 | 2025-03-13 | - | 唤醒词修改功能 |
|
||||
|
||||
---
|
||||
|
||||
*文档生成日期: 2026-03-18*
|
||||
@@ -0,0 +1,338 @@
|
||||
# 蓝牙模块 Git 提交记录汇总
|
||||
|
||||
> 统计时间: 2024-01-01 ~ 2026-05-06
|
||||
> 提交总数: 230条
|
||||
> 涉及模块: YX_BlueTooth, YX_BluetoothSDK
|
||||
|
||||
---
|
||||
|
||||
## 一、语音与蓝牙交互 (35条)
|
||||
|
||||
### 1.1 语音控制蓝牙功能
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2026-03-27 | 7e9d994a8 | 修改语音蓝牙拒接逻辑 |
|
||||
| 2026-03-27 | c0dc00a8b | 蓝牙来电,语音拒接不了问题 |
|
||||
| 2026-03-24 | 0c7512035 | 新增蓝牙通讯录共享功能 |
|
||||
| 2026-03-11 | e362ac75d | 同步给语音蓝牙通讯录和通话记录页面打开和关闭状态 |
|
||||
| 2026-02-11 | 5fc8c14cb | 新增语音蓝牙查看通讯录和通话记录跳转 |
|
||||
| 2024-03-11 | 8faaffd29 | 增加通过语音控制蓝牙相关功能 |
|
||||
| 2024-03-08 | ac659eabb | 实现语音对蓝牙音乐的控制 |
|
||||
| 2024-04-07 | 7cead2675 | 增加语音对蓝牙通讯录同步开关进行控制 |
|
||||
|
||||
### 1.2 语音与蓝牙音乐交互
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2026-03-23 | 22b19dc21 | 修改蓝牙音乐播放没响应问题 |
|
||||
| 2026-03-17 | ac6575de4 | 新增亿连播放音乐的时候请求蓝牙音频焦点 |
|
||||
| 2024-10-22 | c258164fd | 修复蓝牙音乐播放过程中,唤醒语音,播放按钮多跳变 |
|
||||
| 2024-05-08 | d93dd2ede | 修复接听电话挂断后语音唤醒不了 |
|
||||
| 2024-05-07 | 0a54a8f97 | 修复语音与蓝牙音乐混响的问题 |
|
||||
| 2024-04-24 | 8b0aa26ba | 修复蓝牙音乐被语音连续打断两次后,停止播放 |
|
||||
| 2024-08-30 | 2b0735476 | 修改USB音乐和蓝牙音乐传给同行者播放状态有误 |
|
||||
| 2024-05-21 | 05136e9c3 | 提交语音音乐指令常量修改 |
|
||||
| 2024-05-21 | c0a852f9a | 去掉无用的媒体指令常量 |
|
||||
| 2024-04-24 | fd83a2721 | 去掉废弃的语音函数 |
|
||||
|
||||
### 1.3 电话状态同步给语音
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-09-25 | 9625bff28 | 拨打电话的状态同步给语音 |
|
||||
| 2024-03-11 | d7cfc38a6 | 增加电话信息同步给语音 |
|
||||
| 2024-03-11 | f8317495b | 同步电话拒接信息给语音 |
|
||||
| 2024-03-11 | 4eed44177 | 蓝牙连接状态通知给语音 |
|
||||
|
||||
---
|
||||
|
||||
## 二、蓝牙音乐功能 (25条)
|
||||
|
||||
### 2.1 音乐播放状态
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2026-03-25 | 0290c5a84 | 蓝牙音乐新增倒车暂停播放 |
|
||||
| 2025-12-16 | 916e700c1 | 修复强制杀死蓝牙音乐应用后,launcher播放中状态没改变 |
|
||||
| 2025-12-24 | 6a3d81c06 | 优化蓝牙音乐逻辑 |
|
||||
| 2025-03-21 | 3135c7b4d | 重启车机后自动连接,蓝牙音乐界面显示播放状态,实际没播放 |
|
||||
| 2025-02-24 | 15ba71006 | 播放蓝牙音乐中,电源OFF→ON后,界面显示播放但实际没播放 |
|
||||
| 2025-02-14 | fb76ce90e | 电源OFF→ON后,再次播放音乐,声音变小 |
|
||||
| 2025-02-05 | ae6337f0c | 车辆下电再上电后,音乐卡片播放按钮无法操作 |
|
||||
| 2024-04-15 | ccf44711b | 修复视频播放被蓝牙音乐暂停,点击未恢复播放 |
|
||||
| 2024-04-08 | 9bcd8929d | 修复手机播放音乐时连接蓝牙蓝牙音乐无声 |
|
||||
| 2024-03-19 | 82572176f | 重启自动连接后,手机播放,车机显示播放然后暂停 |
|
||||
|
||||
### 2.2 音乐投屏与仪表
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-02-20 | e45e30069 | 修复切换蓝牙音乐和USB音乐时,仪表投屏闪烁 |
|
||||
| 2023-10-08 | 8a749b570 | 修改专辑图片不为空时才传数据给投屏 |
|
||||
| 2023-08-11 | 99f9fd96a | 数据中心添加蓝牙专辑图片及歌曲进度,供投屏使用 |
|
||||
|
||||
### 2.3 音乐焦点与控制
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2023-09-27 | daa5146ff | 修改蓝牙音乐不申请焦点前,小控件不显示播放信息 |
|
||||
| 2023-08-25 | 58a661adb | 蓝牙音乐添加静音设置功能 |
|
||||
| 2023-08-17 | b42455a51 | 蓝牙音乐添加方控控制 |
|
||||
| 2023-08-11 | 6c58e6ed3 | 添加蓝牙音频流接口 |
|
||||
| 2024-05-24 | 39dbd133c | 过滤掉蓝牙音乐 Not Provided |
|
||||
|
||||
---
|
||||
|
||||
## 三、蓝牙电话功能 (40条)
|
||||
|
||||
### 3.1 来电/去电显示
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-05 | 0fb28752a | 优化网络电话功能 |
|
||||
| 2025-11-05 | 6af47aa37 | 优化网络电话判断逻辑 |
|
||||
| 2025-10-17 | 184c93201 | 更新蓝牙电话应用外float显示功能 |
|
||||
| 2025-10-16 | 0fd9c73ec | 优化电话来电不可以切换音频通道 |
|
||||
| 2025-10-09 | 5a4a9e6c0 | 更新电话拨打页面缩小UI及通讯录点击拨打逻辑 |
|
||||
| 2025-09-30 | c4018d7e9 | 优化更新应用外电话弹出框功能 |
|
||||
| 2024-05-21 | 4974f4cb1 | 修复蓝牙去电流程,功能示意图标处没显示当前连接蓝牙名称 |
|
||||
| 2024-04-20 | 231ae2bb6 | 修复拨打微信电话时提示语显示不完整 |
|
||||
| 2024-03-25 | 649577900 | 修复语音未及时同步通讯录的问题 |
|
||||
| 2023-12-23 | d9cd419e2 | 修复第三方来电时,不显示通话时间(全屏) |
|
||||
| 2023-12-23 | 29ac3327e | 修复来电时,左侧图不显示当前连接蓝牙名称 |
|
||||
| 2023-12-19 | 55862fb86 | 修复蓝牙电话去电未接通UI错误 |
|
||||
|
||||
### 3.2 电话通话状态
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-09-05 | b4452bb57 | 修复蓝牙电话搜索名字结果,点击后应先显示号码 |
|
||||
| 2024-03-15 | 8d6b61675 | 解决导航过程中方向盘按键暂停蓝牙音乐,导航播完后自动继续播放 |
|
||||
| 2024-03-19 | 810509299 | 修复蓝牙通话记录同步时,圈圈一卡一卡的问题 |
|
||||
| 2024-02-23 | ee6f6780c | 修复蓝牙通话时点击非通话悬浮框区域也跳转到通话页面 |
|
||||
| 2024-01-25 | a5fc79803 | 修复连接蓝牙,呼出电话,方控ok按键没有挂断电话 |
|
||||
| 2024-01-17 | b9f71dc21 | 修复通话记录中不应该记录网络通话记录的问题 |
|
||||
| 2023-12-13 | 18a297d93 | 修复蓝牙电话通话中,acc off,手机还显示蓝牙连接状态 |
|
||||
| 2023-11-11 | 4d72baadb | 修复蓝牙电话去电仪表没有投屏效果 |
|
||||
| 2023-11-07 | 96a1efe59 | 修复蓝牙电话挂断后挂断键没有置灰 |
|
||||
| 2023-10-08 | 0e6124187 | 传输蓝牙电话结束的状态给投屏 |
|
||||
| 2023-10-08 | 753ff3f7f | 把电话投屏数据通过json格式进行传输 |
|
||||
|
||||
### 3.3 电话投屏接口
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2023-08-22 | fc81093dd | 蓝牙电话投屏接口添加号码归属地及通话时长功能 |
|
||||
| 2023-08-11 | 803a170df | 添加蓝牙电话各状态至数据中心供投屏使用 |
|
||||
| 2023-08-14 | d19784227 | 联调蓝牙电话投屏状态错误问题 |
|
||||
|
||||
---
|
||||
|
||||
## 四、通讯录同步 (30条)
|
||||
|
||||
### 4.1 同步流程优化
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-07-21 | 6421f38b7 | 联系人和通话记录同步完成后,修正isPhoneBookPulling为false |
|
||||
| 2024-04-10 | 9deeb99c4 | 修复提示同步失败后,蓝牙通话记录一直在加载同步 |
|
||||
| 2024-04-04 | faaa29039 | 修复同步通讯录完成后,再次点击同步,界面卡在正在同步界面 |
|
||||
| 2024-03-30 | 271a40273 | 修复点击拨号键,界面闪现同步通讯录画面的问题 |
|
||||
| 2024-03-25 | 649577900 | 修复语音未及时同步通讯录的问题 |
|
||||
| 2024-03-12 | a731df32b | 修复系统设置界面开启自动同步通讯录开关后,蓝牙电话记录自动同步太慢 |
|
||||
| 2024-01-29 | 2b2f2e130 | 修复手机通话记录为空时,中控显示通话记录未同步的问题 |
|
||||
| 2024-01-25 | 8d541765c | 修复偶现同步联系人和通话记录后缺少一个通话记录的问题 |
|
||||
| 2024-01-22 | 6155a30fc | 修复联系人没有存电话号码,车机端不能同步该联系人 |
|
||||
| 2024-01-04 | 2c95dca9c | 修复在同步联系人过程中,同步时间很久的问题 |
|
||||
| 2024-01-03 | 0354c65d3 | 修复连接蓝牙后未同步通话记录下用车机拨号,通话记录消失 |
|
||||
| 2023-12-20 | 9dcbac50b | 修复蓝牙关闭自动同步,还能同步成功的问题 |
|
||||
| 2023-08-22 | a7e216453 | 通讯录盖尾限制2000条 |
|
||||
| 2023-08-17 | c02339467 | 通讯录限制在2500条,超出部分去除 |
|
||||
|
||||
### 4.2 通讯录UI与交互
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-03-21 | d2309fb29 | 修复配对完蓝牙,切换到通讯录界面,界面显示异常有重叠 |
|
||||
| 2025-10-13 | 0680db5b1 | 优化通讯录个数UI显示 |
|
||||
| 2025-10-16 | 0b947f3a4 | 更新蓝牙通讯录默认选中第一个 |
|
||||
| 2025-10-08 | 00415fb2d | 优化蓝牙通讯录页面连接断开逻辑 |
|
||||
| 2024-06-11 | 4c4092983 | 修复点击刷新按钮右侧会闪过联系人详情页 |
|
||||
| 2024-05-21 | 5b73c1cd0 | 修复多次点击通讯录刷新按钮,会跳出通讯录未同步 |
|
||||
| 2024-04-22 | 4e4c7d2f6 | 修复蓝牙电话滑动联系人列表,联系人详情页依然显示 |
|
||||
| 2024-04-19 | a7fb60fe3 | 修复蓝牙电话通讯录显示有中文 |
|
||||
| 2023-12-25 | 159ed069b | 修复连接蓝牙,点击最近使用的电话进入通讯录页面,加载不出来 |
|
||||
| 2023-12-15 | 3304c57a5 | 修复未连接蓝牙时,无法切换到通讯录页面 |
|
||||
| 2023-12-14 | 3f389a05b | 修复蓝牙电话-通讯录-字母查询-通讯录中没有的字母,无反应 |
|
||||
| 2023-08-11 | 409bc14f6 | 按照新的设计要求修改通讯录列表及添加通讯录搜索功能 |
|
||||
| 2023-07-26 | 991c8eea3 | 蓝牙添加通讯录和通话记录功能 |
|
||||
|
||||
---
|
||||
|
||||
## 五、蓝牙连接状态管理 (20条)
|
||||
|
||||
### 5.1 ACC电源状态处理
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-20 | 295607af2 | 修改acc开关,蓝牙不做断开或重连操作,保持原状态 |
|
||||
| 2024-01-15 | 3ee792ae9 | 修复负一屏点击整车下电后,踩刹车上电,蓝牙没有自动连接 |
|
||||
| 2024-01-09 | dd6d12c31 | 修复蓝牙上电后第一次进入蓝牙音乐界面时,蓝牙音乐会暂停一下 |
|
||||
| 2024-01-02 | 9258088f0 | 修复上电后,手机端播放蓝牙音乐,从主界面进入后蓝牙音乐暂停 |
|
||||
| 2023-12-07 | fdfe2c820 | 修复播放蓝牙音乐过程中断开ACC再重新连接,进度条显示00:00 |
|
||||
| 2023-12-13 | 18a297d93 | 修复蓝牙电话通话中,acc off,手机还显示蓝牙连接状态 |
|
||||
|
||||
### 5.2 蓝牙可见性与配对
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2026-01-28 | a0e15fe92 | 进入蓝牙设置页面,手机就搜不到车机的蓝牙问题 |
|
||||
| 2026-01-28 | c1a490f80 | 修改蓝牙可见性 |
|
||||
| 2025-12-29 | 6d491ec73 | 新增蓝牙配对设备最大数量限制为10;配对请求5s未响应自动拒绝 |
|
||||
| 2024-01-12 | d89e68cd7 | 修复连接一个蓝牙后,另一个手机配对成功,通讯录界面蓝牙名称没更新 |
|
||||
| 2023-12-21 | fbf1637bb | 修复打开蓝牙然后关闭开放蓝牙监测,手机还能搜索到车机 |
|
||||
| 2023-12-08 | a815b4bef | 修复车机连接手机的话,蓝牙连接和手机配对成功,连接失败 |
|
||||
| 2023-10-19 | 60c5779cd | 修复蓝牙可见性不可见性修改 |
|
||||
|
||||
### 5.3 蓝牙名称管理
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-09-05 | e238b8d4c | 修改默认蓝牙和WiFi名称 |
|
||||
| 2024-01-05 | 6a75240d7 | 连接时实时刷新蓝牙名称 |
|
||||
| 2023-12-21 | 42b72c8f2 | 修复写入新的vin码,蓝牙名称还显示原来的 |
|
||||
| 2023-11-14 | 5f3d5e800 | 修复蓝牙名称恢复出厂设置显示错误问题 |
|
||||
| 2023-09-27 | 538f326a6 | 蓝牙名称修改成vin后6位 |
|
||||
| 2023-08-17 | a5d1f78d2 | 修复蓝牙名称加vin码默认名称 |
|
||||
|
||||
---
|
||||
|
||||
## 六、UI适配与优化 (35条)
|
||||
|
||||
### 6.1 深色模式适配
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-21 | 49a6ca185 | 修改深色模式状态监听模式 |
|
||||
| 2025-11-14 | 2175a4bd8 | 修改联系人字母显示dark模式颜色 |
|
||||
| 2025-11-14 | f7999efe6 | 添加深色模式适配功能 |
|
||||
|
||||
### 6.2 右舵/国际化适配
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2026-01-17 | 9c43ac6ad | 添加适配12.3寸屏幕功能 |
|
||||
| 2025-02-26 | 83fb691b6 | 修改蓝牙电话右舵UI效果 |
|
||||
| 2025-02-25 | 8ef5fb690 | 蓝牙新增右舵项目布局资源 |
|
||||
| 2024-03-11 | 1b292b8ed | 新增阿拉伯语 |
|
||||
| 2023-08-15 | afb4eb70a | 修改通话记录两天以上,一周以内显示星期 |
|
||||
|
||||
### 6.3 界面UI更新
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-17 | 6c6a39f36 | 优化蓝牙电话背景图片以及搜索功能 |
|
||||
| 2025-11-04 | e3413202b | 修改蓝牙连接按键跳转到最新的页面 |
|
||||
| 2025-11-04 | 6b0c946ad | 更新通讯录文案为联系人 |
|
||||
| 2025-10-16 | 449e78098 | 修改拨号按键不可用时,透明度为0.6 |
|
||||
| 2025-10-16 | 5f97d7f07 | 根据最新UE调整蓝牙电话页面显示 |
|
||||
| 2025-10-15 | 8eb033ea3 | 优化拨号按键板功能 |
|
||||
| 2025-10-15 | 118b7c74c | 优化按键板搜索同时搜索通话记录和通讯录 |
|
||||
| 2025-10-08 | 85b3fc57e | 修改通话记录时间显示格式 |
|
||||
| 2025-09-28 | be6c7aa5e | 更新蓝牙UI |
|
||||
| 2025-09-26 | 5fedd8aea | 更新蓝牙UI相关功能 |
|
||||
| 2025-07-21 | 3ff34003d | 修改空联系人提示UI位置错误 |
|
||||
| 2024-05-24 | 738188f67 | 修复蓝牙来电显示界面,文言重叠 |
|
||||
| 2024-03-21 | 13bc1ecdf | 修复了蓝牙文字重叠的问题 |
|
||||
| 2023-12-21 | a3b1ba89f | 修复未连接蓝牙时通话界面和UI不一致 |
|
||||
| 2023-12-04 | dea35c78f | 修复蓝牙通话记录没有滚动条,与UI设计不符 |
|
||||
| 2023-10-31 | 5e6a03a0b | 蓝牙电话通话页面V1.3UI适配修改 |
|
||||
| 2023-10-27 | d9acac409 | 蓝牙通话记录和通讯录V1.3UI修改适配 |
|
||||
| 2023-08-31 | d893ecdf4 | 修复蓝牙相关的走查UI问题 |
|
||||
|
||||
---
|
||||
|
||||
## 七、国际化/翻译 (15条)
|
||||
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-07-11 | 07d05e2c0 | 修复蓝牙电话翻译显示格式错误 |
|
||||
| 2024-07-05 | a418fc475 | 修复未找到"%s"的相关结果的英文和需求对应不上 |
|
||||
| 2024-05-13 | b1d5b4b3b | 蓝牙翻译文本更新 |
|
||||
| 2024-04-18 | 67c6c9aa6 | 修复蓝牙(未找到"%s"的相关结果)的英文和需求对应不上 |
|
||||
| 2024-03-28 | 9dfce2f80 | 修复通话名称Dial和Deepway多语言翻译不一致 |
|
||||
| 2023-11-22 | c2d68a84d | 蓝牙数字统一设置DINGPRO格式 |
|
||||
| 2023-07-19 | da0d81c9f | 参照UE调整通讯录和通话记录 |
|
||||
|
||||
---
|
||||
|
||||
## 八、代码优化与重构 (15条)
|
||||
|
||||
### 8.1 工具类统一
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-12-24 | 653c4b6b3 | 统一使用YX_log工具打印 |
|
||||
| 2025-12-17 | 48c6f2d2d | 修改toast调用,统一调用自定义toast |
|
||||
| 2025-12-17 | 0f688b8fc | 不用系统toast,添加自定义toast |
|
||||
| 2024-03-25 | b232e10ad | 优化日志打印 |
|
||||
|
||||
### 8.2 构建优化
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-05 | 7ebb3b171 | 优化sdk build.gradle |
|
||||
| 2025-11-05 | b5b840b98 | 添加SharedPrefsManager.init |
|
||||
| 2024-12-24 | abf1034fd | 删除无效资源,png图片转webp,优化apk体积 |
|
||||
| 2024-12-25 | e39ee2e1e | 修改打包资源错误导致没有打包到中文资源 |
|
||||
| 2023-12-12 | 18a297d93 | 去掉依赖库,可以通过脚本编译release的apk |
|
||||
| 2024-03-05 | 6447ff187 | 优化代码,去掉无用的资源引用 |
|
||||
|
||||
---
|
||||
|
||||
## 九、Bug修复 (杂项) (15条)
|
||||
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-04-18 | 2ffb50935 | 修复出现蓝牙ANR |
|
||||
| 2024-01-18 | e948b2e69 | 修复麦克风禁用问题 |
|
||||
| 2024-01-08 | 4e5eb00d7 | 修复monkey crash问题 |
|
||||
| 2023-11-02 | f5ef447c6 | 修复SQLiteCursor未关闭引起的异常 |
|
||||
| 2023-11-23 | 0bc5caee4 | 修复跑monkey时出现蓝牙ANR问题 |
|
||||
| 2023-10-13 | b61120c85 | 处理专辑封面闪烁问题 |
|
||||
| 2023-10-14 | b7cc4717a | 修复蓝牙电话切换音源,仪表会出现消失一下 |
|
||||
| 2023-10-20 | 8040146aa | 解决偶现断连后,状态栏不显示蓝牙图标 |
|
||||
| 2023-09-21 | ebf265af1 | 处理蓝牙电话和蓝牙音乐方向盘控制功能 |
|
||||
| 2023-09-21 | c6784f0ef | 处理空指针报错 |
|
||||
| 2023-09-06 | d2fd3d9be | 修复蓝牙跑monkey崩溃问题 |
|
||||
| 2023-08-24 | 6c58e6ed3 | 添加蓝牙音频流接口 |
|
||||
|
||||
---
|
||||
|
||||
## 十、关键修改点总结 (便于下次修改)
|
||||
|
||||
### 10.1 语音交互入口类
|
||||
- `VoiceEventHelper.java` - 语音事件处理,所有语音蓝牙操作入口
|
||||
- `MediaProtocol.java` - 媒体协议,蓝牙音乐状态同步
|
||||
- `VoiceNewProtocolConst.java` - TXZ语音协议常量
|
||||
|
||||
### 10.2 蓝牙音乐核心类
|
||||
- `BluetoothHfpClient.java` - HFP协议,电话状态
|
||||
- 音频焦点管理 - 与语音、导航、视频的焦点竞争
|
||||
- 投屏数据格式 - JSON格式传输给仪表
|
||||
|
||||
### 10.3 通讯录同步核心类
|
||||
- `BluetoothPbapClient.java` - PBAP协议入口
|
||||
- `BtContactsManager.java` - 通讯录管理
|
||||
- `isPhoneBookPulling` - 同步状态标志,需在完成后置false
|
||||
- 同步限制: 通讯录2500条/2000条盖尾,通话记录50条
|
||||
|
||||
### 10.4 ACC电源处理要点
|
||||
- ACC OFF时不主动断开蓝牙,保持原状态
|
||||
- ACC ON后恢复播放状态需校验实际播放状态
|
||||
- 下电再上电后播放按钮状态同步
|
||||
|
||||
### 10.5 UI适配要点
|
||||
- 深色模式: 联系人字母颜色、监听模式
|
||||
- 右舵项目: 需要单独布局资源
|
||||
- 12.3寸屏幕适配
|
||||
|
||||
### 10.6 国际化要点
|
||||
- 阿拉伯语已支持
|
||||
- 通话记录时间格式: "昨天"根据语言切换
|
||||
- 数字格式统一DINGPRO格式
|
||||
|
||||
---
|
||||
|
||||
## 十一、常见问题快速定位
|
||||
|
||||
| 问题类型 | 关键类/方法 | 日志关键字 |
|
||||
|---------|------------|-----------|
|
||||
| 通讯录不同步 | BluetoothPbapClient.phoneBookPullRequest() | BtContactsManager, onContactsPullCompleted |
|
||||
| 音乐状态异常 | 音频焦点处理 | AudioManager, onFocusChange |
|
||||
| 语音拒接失败 | VoiceEventHelper拒接逻辑 | 蓝牙拒接, HFP |
|
||||
| ACC状态处理 | 电源状态监听 | ACC_OFF, ACC_ON |
|
||||
| 投屏数据 | JSON数据传输 | 投屏, DataCenter |
|
||||
| ANR问题 | 主线程阻塞 | ANR, SQLiteCursor |
|
||||
@@ -0,0 +1,204 @@
|
||||
# 三方应用对接授权文档
|
||||
|
||||
一、概述
|
||||
|
||||
徐工车机项目的隐私授权系统通过 Android Settings.System 存储授权状态(0/1值),第三方应用通过读取这些
|
||||
Key 的值来判断用户是否已授权,进而决定是否允许对应功能的访问。
|
||||
|
||||
二、读取授权状态
|
||||
|
||||
2.1 权限授权状态
|
||||
|
||||
全局开关和有效期
|
||||
|
||||
┌────────────────────────────────────────┬──────┬──────────────────────┐
|
||||
│ Key │ 类型 │ 说明 │
|
||||
├────────────────────────────────────────┼──────┼──────────────────────┤
|
||||
│ xcmg_permission_global_switch │ int │ 0 = 关闭,1 = 开启 │
|
||||
├────────────────────────────────────────┼──────┼──────────────────────┤
|
||||
│ xcmg_permission_authorization_duration │ int │ 1 = 180天,2 = 360天 │
|
||||
├────────────────────────────────────────┼──────┼──────────────────────┤
|
||||
│ xcmg_permission_authorization_date │ long │ 授权开始时间戳(毫秒) │
|
||||
└────────────────────────────────────────┴──────┴──────────────────────┘
|
||||
|
||||
具体权限Key及使用场景
|
||||
|
||||
┌────────────────────────────────────────────┬──────────────────────────────────────┐
|
||||
│ Key │ 使用场景 │
|
||||
├────────────────────────────────────────────┼──────────────────────────────────────┤
|
||||
│ xcmg_permission_contacts_bluetooth_phone │ 联系人权限 - 蓝牙电话读取联系人 │
|
||||
├────────────────────────────────────────────┼──────────────────────────────────────┤
|
||||
│ xcmg_permission_microphone_voice_assistant │ 麦克风权限 - 语音助手录音 │
|
||||
├────────────────────────────────────────────┼──────────────────────────────────────┤
|
||||
│ xcmg_permission_microphone_bluetooth_phone │ 麦克风权限 - 蓝牙电话通话 │
|
||||
├────────────────────────────────────────────┼──────────────────────────────────────┤
|
||||
│ xcmg_permission_location_voice_assistant │ 位置权限 - 语音助手获取位置 │
|
||||
├────────────────────────────────────────────┼──────────────────────────────────────┤
|
||||
│ xcmg_permission_location_map │ 位置权限 - 地图/导航获取位置 │
|
||||
├────────────────────────────────────────────┼──────────────────────────────────────┤
|
||||
│ xcmg_permission_location_carlink │ 位置权限 - 亿连手机互联获取位置 │
|
||||
├────────────────────────────────────────────┼──────────────────────────────────────┤
|
||||
│ xcmg_permission_camera_dvr │ 摄像头权限 - 行车记录仪录像 │
|
||||
└────────────────────────────────────────────┴──────────────────────────────────────┘
|
||||
|
||||
读取示例(Java):
|
||||
|
||||
// 读取某个具体权限状态
|
||||
int locationMapPermission = Settings.System.getInt(
|
||||
context.getContentResolver(), "xcmg_permission_location_map", 0);
|
||||
// 1 = 已授权, 0 = 未授权
|
||||
|
||||
// 判断授权是否有效(完整判断逻辑)
|
||||
boolean isAuthorized = false;
|
||||
int globalSwitch = Settings.System.getInt(
|
||||
context.getContentResolver(), "xcmg_permission_global_switch", 0);
|
||||
if (globalSwitch == 1) {
|
||||
long authDate = Settings.System.getLong(
|
||||
context.getContentResolver(), "xcmg_permission_authorization_date", 0);
|
||||
int duration = Settings.System.getInt(
|
||||
context.getContentResolver(), "xcmg_permission_authorization_duration", 0);
|
||||
int totalDays = (duration == 1) ? 180 : 360;
|
||||
long daysPassed = (System.currentTimeMillis() - authDate) / (1000 * 60 * 60 * 24);
|
||||
if (daysPassed < totalDays) {
|
||||
// 有效期未过,读取具体权限
|
||||
int permission = Settings.System.getInt(
|
||||
context.getContentResolver(), "xcmg_permission_location_map", 0);
|
||||
isAuthorized = (permission == 1);
|
||||
}
|
||||
}
|
||||
|
||||
三、判断逻辑
|
||||
|
||||
流程图:
|
||||
|
||||
┌─────────────┐ 否 ┌──────────┐
|
||||
│ 隐私已授权? ├────────────►│ 未授权 │
|
||||
└──────┬──────┘ └──────────┘
|
||||
│是
|
||||
▼
|
||||
┌─────────────┐ 否 ┌──────────┐
|
||||
│ 全局开关开启?├────────────►│ 未授权 │
|
||||
└──────┬──────┘ └──────────┘
|
||||
│是
|
||||
▼
|
||||
┌─────────────┐ 是 ┌──────────┐
|
||||
│ 授权已过期? ├────────────►│ 未授权 │
|
||||
└──────┬──────┘ └──────────┘
|
||||
│否
|
||||
▼
|
||||
┌─────────────┐ 否 ┌──────────┐
|
||||
│ 具体权限=1? ├────────────►│ 未授权 │
|
||||
└──────┬──────┘ └──────────┘
|
||||
│是
|
||||
▼
|
||||
┌──────────┐
|
||||
│ 已授权 │
|
||||
└──────────┘
|
||||
|
||||
四、具体弹窗代码
|
||||
|
||||
三方应用在读取权限Key为0(未授权)后,需弹出"允许/不允许"授权提示框。推荐通过广播触发系统弹窗(方式1),
|
||||
系统已内置对话框和处理逻辑;
|
||||
|
||||
方式1:广播触发系统弹窗(推荐)
|
||||
|
||||
发送广播后,系统 PrivacyPolicyMonitorService 会自动弹出权限授权请求对话框,包含"允许"和"不允许"按钮,
|
||||
用户点击"允许"后系统自动将对应 Settings.System Key 设为1,并继续检查下一个未授权权限。
|
||||
|
||||
/**
|
||||
* 请求权限授权,触发系统弹出"允许/不允许"对话框
|
||||
* @param context 上下文
|
||||
* @param targetPackageName 目标应用包名(用于系统判断所需权限列表)
|
||||
* @param permissionKey 具体的权限Key
|
||||
*/
|
||||
public static void requestPermission(Context context, String targetPackageName, String permissionKey) {
|
||||
Intent intent = new Intent("com.yaxon.carcontrol.ACTION_OPEN_PERMISSION_UI");
|
||||
intent.putExtra("package_name", targetPackageName);
|
||||
intent.putExtra("permission_key", permissionKey);
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
// 使用示例:百度地图检测到位置权限未授权
|
||||
if (locationPermission == 0) {
|
||||
requestPermission(context, "com.title.mapautosdk", "xcmg_permission_location_map");
|
||||
}
|
||||
|
||||
系统弹窗样式:
|
||||
┌─────────────────────────────────────┐
|
||||
│ 提示 │
|
||||
│ │
|
||||
│ 位置权限-地图:是否允许开启 │
|
||||
│ 位置权限? │
|
||||
│ │
|
||||
│ 开启后,地图将被授权可获取位置信息 │
|
||||
│ │
|
||||
│ [允许] [不允许] │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
用户操作结果:
|
||||
- 点击"允许" → Settings.System 写入该 Key=1 → 继续检查下一个未授权权限 → 全部授权后自动启动目标应用
|
||||
- 点击"不允许" → Settings.System 写入该 Key=0 → 流程结束
|
||||
|
||||
五、应用包名与权限Key对照表
|
||||
|
||||
┌──────────────────────────────┬──────────────────────────────────────────────────────────┐
|
||||
│ 应用包名 │ 权限Key │
|
||||
├──────────────────────────────┼──────────────────────────────────────────────────────────┤
|
||||
│ com.yaxon.bluetooth │ xcmg_permission_contacts_bluetooth_phone │
|
||||
│ │ xcmg_permission_microphone_bluetooth_phone │
|
||||
├──────────────────────────────┼──────────────────────────────────────────────────────────┤
|
||||
│ com.txznet.txz │ xcmg_permission_microphone_voice_assistant │
|
||||
│ (同行者语音助手) │ xcmg_permission_location_voice_assistant │
|
||||
├──────────────────────────────┼──────────────────────────────────────────────────────────┤
|
||||
│ com.txznet.adapter │ xcmg_permission_microphone_voice_assistant │
|
||||
│ (同行者语音适配) │ xcmg_permission_location_voice_assistant │
|
||||
├──────────────────────────────┼──────────────────────────────────────────────────────────┤
|
||||
│ com.txzing.voiceassistant │ xcmg_permission_microphone_voice_assistant │
|
||||
│ (语音助手) │ xcmg_permission_location_voice_assistant │
|
||||
├──────────────────────────────┼──────────────────────────────────────────────────────────┤
|
||||
│ com.title.mapautosdk │ xcmg_permission_location_map │
|
||||
│ (百度地图) │ │
|
||||
├──────────────────────────────┼──────────────────────────────────────────────────────────┤
|
||||
│ net.easyconn │ xcmg_permission_location_carlink │
|
||||
│ (亿连手机互联) │ │
|
||||
├──────────────────────────────┼──────────────────────────────────────────────────────────┤
|
||||
│ com.yaxon.dvr │ xcmg_permission_camera_dvr │
|
||||
│ (行车记录仪) │ │
|
||||
└──────────────────────────────┴──────────────────────────────────────────────────────────┘
|
||||
|
||||
---
|
||||
|
||||
六、Key 速查(可直接复制)
|
||||
|
||||
**全局控制:**
|
||||
|
||||
```
|
||||
xcmg_permission_global_switch // 全局开关 0=关闭 1=开启
|
||||
xcmg_permission_authorization_duration // 有效期 1=180天 2=360天
|
||||
xcmg_permission_authorization_date // 授权开始时间戳(毫秒)
|
||||
```
|
||||
|
||||
**权限 Key:**
|
||||
|
||||
```
|
||||
xcmg_permission_contacts_bluetooth_phone // 联系人权限 - 蓝牙电话读取联系人
|
||||
xcmg_permission_microphone_voice_assistant // 麦克风权限 - 语音助手录音
|
||||
xcmg_permission_microphone_bluetooth_phone // 麦克风权限 - 蓝牙电话通话
|
||||
xcmg_permission_location_voice_assistant // 位置权限 - 语音助手获取位置
|
||||
xcmg_permission_location_map // 位置权限 - 地图/导航获取位置
|
||||
xcmg_permission_location_carlink // 位置权限 - 亿连手机互联获取位置
|
||||
xcmg_permission_camera_dvr // 摄像头权限 - 行车记录仪录像
|
||||
```
|
||||
|
||||
**应用包名:**
|
||||
|
||||
```
|
||||
com.yaxon.bluetooth // 蓝牙
|
||||
com.txznet.txz // 同行者语音助手
|
||||
com.txznet.adapter // 同行者语音适配
|
||||
com.txzing.voiceassistant // 语音助手
|
||||
com.title.mapautosdk // 百度地图
|
||||
net.easyconn // 亿连手机互联
|
||||
com.yaxon.dvr // 行车记录仪
|
||||
```
|
||||
@@ -0,0 +1 @@
|
||||
日志分析开机时间: logcat -b events | grep "boot_progress"
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
@@ -0,0 +1,115 @@
|
||||
# 徐工项目相关文档
|
||||
|
||||
> 整理自腾讯文档/WPS云文档
|
||||
|
||||
---
|
||||
|
||||
## 参考文档
|
||||
|
||||
- [腾讯文档:徐工项目(软件)](https://docs.qq.com/sheet/DZHNRTm1rQ29OTlpa?tab=BB08J2)
|
||||
- [金山文档:徐工项目车辆设置需要的CAN信号2-周帅](https://www.kdocs.cn/l/ctqaRN8zXfeR)
|
||||
|
||||
---
|
||||
|
||||
## 一、新版刷机软件
|
||||
|
||||
![[徐工相关_图片/image_1.png]]
|
||||
|
||||
---
|
||||
|
||||
## 二、源码编译
|
||||
|
||||
### 2.1 编译步骤
|
||||
|
||||
| 步骤 | 命令 | 说明 |
|
||||
| --- | ----------------- | ----------- |
|
||||
| 1 | `./build_apk.sh` | 先编译APK |
|
||||
| 2 | `./build.sh all` | 生成线刷包 |
|
||||
| 3 | `./build.sh ota2` | 生成U盘升级包和线刷包 |
|
||||
编译前先clean下:
|
||||
|
||||
![[徐工相关_图片/image_2.png]]
|
||||
|
||||
![[徐工相关_图片/image_3.png]]
|
||||
|
||||
![[徐工相关_图片/image_4.png]]
|
||||
|
||||
![[徐工相关_图片/image_5.png]]
|
||||
|
||||
---
|
||||
|
||||
## 三、系统属性配置
|
||||
|
||||
### 3.1 ro.product.xg.hardware
|
||||
|
||||
| 值 | 说明 |
|
||||
|----|------|
|
||||
| 1 | 高配 |
|
||||
| 2 | 低配 |
|
||||
|
||||
![[徐工相关_图片/image_6.png]]
|
||||
|
||||
![[徐工相关_图片/image_7.png]]
|
||||
|
||||
![[徐工相关_图片/image_8.png]]
|
||||
|
||||
---
|
||||
|
||||
### 3.2 ro.product.xg.device.type
|
||||
|
||||
为上层应用获取简便,新增属性:
|
||||
|
||||
| 值 | 说明 |
|
||||
|----|------|
|
||||
| 1 | 低配123 |
|
||||
| 2 | 低配156 |
|
||||
| 3 | 高配123 |
|
||||
| 4 | 高配156 |
|
||||
|
||||
![[徐工相关_图片/image_9.png]]
|
||||
|
||||
|
||||
|
||||
固件路径:
|
||||
|
||||
高配路径:Z:\znzc\034_xcmg\x9hp_xcmg\androd10_x9hp_ptg4.3p3\android10\device\semidrive\x9hp\x9hp_ms\rg440_sdk
|
||||
|
||||
Y:\xugong_high\androd10_x9hp_ptg4.3p3\android10\device\semidrive\x9hp\x9hp_ms\rg440_sdk
|
||||
|
||||
低配路径:Z:\znzc\034_xcmg\x9m_xcmg\androd10_x9hp_ptg4.3p3\android10\device\semidrive\x9hp\x9hp_ms\rg440_sdk
|
||||
|
||||
Y:\xugong_low\androd10_x9hp_ptg4.3p3\android10\device\semidrive\x9hp\x9hp_ms\rg440_sdk
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
语音替换路径: Z:\znzc\034_xcmg\x9hp_xcmg\androd10_x9hp_ptg4.3p3\android10\vendor\yaxon
|
||||
|
||||
高配路径:Z:\znzc\034_xcmg\x9hp_xcmg\androd10_x9hp_ptg4.3p3\android10\vendor\yaxon\realtek_rn440\bluetooth
|
||||
|
||||
Y:\xugong_high\androd10_x9hp_ptg4.3p3\android10\vendor\yaxon\realtek_rn440\bluetooth
|
||||
|
||||
低配路径:Z:\znzc\034_xcmg\x9m_xcmg\androd10_x9hp_ptg4.3p3\android10\vendor\yaxon\realtek_rn440\bluetooth
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
# 蓝牙模块 Git 提交记录汇总
|
||||
|
||||
> 统计时间: 2024-01-01 ~ 2026-05-06
|
||||
> 提交总数: 230条
|
||||
> 涉及模块: YX_BlueTooth, YX_BluetoothSDK
|
||||
|
||||
---
|
||||
|
||||
## 一、语音与蓝牙交互 (35条)
|
||||
|
||||
### 1.1 语音控制蓝牙功能
|
||||
| 日期 | Commit | 描述 |
|
||||
| ---------- | --------- | ------------------------ |
|
||||
| 2026-03-27 | 7e9d994a8 | 修改语音蓝牙拒接逻辑 |
|
||||
| 2026-03-27 | c0dc00a8b | 蓝牙来电,语音拒接不了问题 |
|
||||
| 2026-03-24 | 0c7512035 | 新增蓝牙通讯录共享功能 |
|
||||
| 2026-03-11 | e362ac75d | 同步给语音蓝牙通讯录和通话记录页面打开和关闭状态 |
|
||||
| 2026-02-11 | 5fc8c14cb | 新增语音蓝牙查看通讯录和通话记录跳转 |
|
||||
| 2024-03-11 | 8faaffd29 | 增加通过语音控制蓝牙相关功能 |
|
||||
| 2024-03-08 | ac659eabb | 实现语音对蓝牙音乐的控制 |
|
||||
| 2024-04-07 | 7cead2675 | 增加语音对蓝牙通讯录同步开关进行控制 |
|
||||
|
||||
### 1.2 语音与蓝牙音乐交互
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2026-03-23 | 22b19dc21 | 修改蓝牙音乐播放没响应问题 |
|
||||
| 2026-03-17 | ac6575de4 | 新增亿连播放音乐的时候请求蓝牙音频焦点 |
|
||||
| 2024-10-22 | c258164fd | 修复蓝牙音乐播放过程中,唤醒语音,播放按钮多跳变 |
|
||||
| 2024-05-08 | d93dd2ede | 修复接听电话挂断后语音唤醒不了 |
|
||||
| 2024-05-07 | 0a54a8f97 | 修复语音与蓝牙音乐混响的问题 |
|
||||
| 2024-04-24 | 8b0aa26ba | 修复蓝牙音乐被语音连续打断两次后,停止播放 |
|
||||
| 2024-08-30 | 2b0735476 | 修改USB音乐和蓝牙音乐传给同行者播放状态有误 |
|
||||
| 2024-05-21 | 05136e9c3 | 提交语音音乐指令常量修改 |
|
||||
| 2024-05-21 | c0a852f9a | 去掉无用的媒体指令常量 |
|
||||
| 2024-04-24 | fd83a2721 | 去掉废弃的语音函数 |
|
||||
|
||||
### 1.3 电话状态同步给语音
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-09-25 | 9625bff28 | 拨打电话的状态同步给语音 |
|
||||
| 2024-03-11 | d7cfc38a6 | 增加电话信息同步给语音 |
|
||||
| 2024-03-11 | f8317495b | 同步电话拒接信息给语音 |
|
||||
| 2024-03-11 | 4eed44177 | 蓝牙连接状态通知给语音 |
|
||||
|
||||
---
|
||||
|
||||
## 二、蓝牙音乐功能 (25条)
|
||||
|
||||
### 2.1 音乐播放状态
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2026-03-25 | 0290c5a84 | 蓝牙音乐新增倒车暂停播放 |
|
||||
| 2025-12-16 | 916e700c1 | 修复强制杀死蓝牙音乐应用后,launcher播放中状态没改变 |
|
||||
| 2025-12-24 | 6a3d81c06 | 优化蓝牙音乐逻辑 |
|
||||
| 2025-03-21 | 3135c7b4d | 重启车机后自动连接,蓝牙音乐界面显示播放状态,实际没播放 |
|
||||
| 2025-02-24 | 15ba71006 | 播放蓝牙音乐中,电源OFF→ON后,界面显示播放但实际没播放 |
|
||||
| 2025-02-14 | fb76ce90e | 电源OFF→ON后,再次播放音乐,声音变小 |
|
||||
| 2025-02-05 | ae6337f0c | 车辆下电再上电后,音乐卡片播放按钮无法操作 |
|
||||
| 2024-04-15 | ccf44711b | 修复视频播放被蓝牙音乐暂停,点击未恢复播放 |
|
||||
| 2024-04-08 | 9bcd8929d | 修复手机播放音乐时连接蓝牙蓝牙音乐无声 |
|
||||
| 2024-03-19 | 82572176f | 重启自动连接后,手机播放,车机显示播放然后暂停 |
|
||||
|
||||
### 2.2 音乐投屏与仪表
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-02-20 | e45e30069 | 修复切换蓝牙音乐和USB音乐时,仪表投屏闪烁 |
|
||||
| 2023-10-08 | 8a749b570 | 修改专辑图片不为空时才传数据给投屏 |
|
||||
| 2023-08-11 | 99f9fd96a | 数据中心添加蓝牙专辑图片及歌曲进度,供投屏使用 |
|
||||
|
||||
### 2.3 音乐焦点与控制
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2023-09-27 | daa5146ff | 修改蓝牙音乐不申请焦点前,小控件不显示播放信息 |
|
||||
| 2023-08-25 | 58a661adb | 蓝牙音乐添加静音设置功能 |
|
||||
| 2023-08-17 | b42455a51 | 蓝牙音乐添加方控控制 |
|
||||
| 2023-08-11 | 6c58e6ed3 | 添加蓝牙音频流接口 |
|
||||
| 2024-05-24 | 39dbd133c | 过滤掉蓝牙音乐 Not Provided |
|
||||
|
||||
---
|
||||
|
||||
## 三、蓝牙电话功能 (40条)
|
||||
|
||||
### 3.1 来电/去电显示
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-05 | 0fb28752a | 优化网络电话功能 |
|
||||
| 2025-11-05 | 6af47aa37 | 优化网络电话判断逻辑 |
|
||||
| 2025-10-17 | 184c93201 | 更新蓝牙电话应用外float显示功能 |
|
||||
| 2025-10-16 | 0fd9c73ec | 优化电话来电不可以切换音频通道 |
|
||||
| 2025-10-09 | 5a4a9e6c0 | 更新电话拨打页面缩小UI及通讯录点击拨打逻辑 |
|
||||
| 2025-09-30 | c4018d7e9 | 优化更新应用外电话弹出框功能 |
|
||||
| 2024-05-21 | 4974f4cb1 | 修复蓝牙去电流程,功能示意图标处没显示当前连接蓝牙名称 |
|
||||
| 2024-04-20 | 231ae2bb6 | 修复拨打微信电话时提示语显示不完整 |
|
||||
| 2024-03-25 | 649577900 | 修复语音未及时同步通讯录的问题 |
|
||||
| 2023-12-23 | d9cd419e2 | 修复第三方来电时,不显示通话时间(全屏) |
|
||||
| 2023-12-23 | 29ac3327e | 修复来电时,左侧图不显示当前连接蓝牙名称 |
|
||||
| 2023-12-19 | 55862fb86 | 修复蓝牙电话去电未接通UI错误 |
|
||||
|
||||
### 3.2 电话通话状态
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-09-05 | b4452bb57 | 修复蓝牙电话搜索名字结果,点击后应先显示号码 |
|
||||
| 2024-03-15 | 8d6b61675 | 解决导航过程中方向盘按键暂停蓝牙音乐,导航播完后自动继续播放 |
|
||||
| 2024-03-19 | 810509299 | 修复蓝牙通话记录同步时,圈圈一卡一卡的问题 |
|
||||
| 2024-02-23 | ee6f6780c | 修复蓝牙通话时点击非通话悬浮框区域也跳转到通话页面 |
|
||||
| 2024-01-25 | a5fc79803 | 修复连接蓝牙,呼出电话,方控ok按键没有挂断电话 |
|
||||
| 2024-01-17 | b9f71dc21 | 修复通话记录中不应该记录网络通话记录的问题 |
|
||||
| 2023-12-13 | 18a297d93 | 修复蓝牙电话通话中,acc off,手机还显示蓝牙连接状态 |
|
||||
| 2023-11-11 | 4d72baadb | 修复蓝牙电话去电仪表没有投屏效果 |
|
||||
| 2023-11-07 | 96a1efe59 | 修复蓝牙电话挂断后挂断键没有置灰 |
|
||||
| 2023-10-08 | 0e6124187 | 传输蓝牙电话结束的状态给投屏 |
|
||||
| 2023-10-08 | 753ff3f7f | 把电话投屏数据通过json格式进行传输 |
|
||||
|
||||
### 3.3 电话投屏接口
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2023-08-22 | fc81093dd | 蓝牙电话投屏接口添加号码归属地及通话时长功能 |
|
||||
| 2023-08-11 | 803a170df | 添加蓝牙电话各状态至数据中心供投屏使用 |
|
||||
| 2023-08-14 | d19784227 | 联调蓝牙电话投屏状态错误问题 |
|
||||
|
||||
---
|
||||
|
||||
## 四、通讯录同步 (30条)
|
||||
|
||||
### 4.1 同步流程优化
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-07-21 | 6421f38b7 | 联系人和通话记录同步完成后,修正isPhoneBookPulling为false |
|
||||
| 2024-04-10 | 9deeb99c4 | 修复提示同步失败后,蓝牙通话记录一直在加载同步 |
|
||||
| 2024-04-04 | faaa29039 | 修复同步通讯录完成后,再次点击同步,界面卡在正在同步界面 |
|
||||
| 2024-03-30 | 271a40273 | 修复点击拨号键,界面闪现同步通讯录画面的问题 |
|
||||
| 2024-03-25 | 649577900 | 修复语音未及时同步通讯录的问题 |
|
||||
| 2024-03-12 | a731df32b | 修复系统设置界面开启自动同步通讯录开关后,蓝牙电话记录自动同步太慢 |
|
||||
| 2024-01-29 | 2b2f2e130 | 修复手机通话记录为空时,中控显示通话记录未同步的问题 |
|
||||
| 2024-01-25 | 8d541765c | 修复偶现同步联系人和通话记录后缺少一个通话记录的问题 |
|
||||
| 2024-01-22 | 6155a30fc | 修复联系人没有存电话号码,车机端不能同步该联系人 |
|
||||
| 2024-01-04 | 2c95dca9c | 修复在同步联系人过程中,同步时间很久的问题 |
|
||||
| 2024-01-03 | 0354c65d3 | 修复连接蓝牙后未同步通话记录下用车机拨号,通话记录消失 |
|
||||
| 2023-12-20 | 9dcbac50b | 修复蓝牙关闭自动同步,还能同步成功的问题 |
|
||||
| 2023-08-22 | a7e216453 | 通讯录盖尾限制2000条 |
|
||||
| 2023-08-17 | c02339467 | 通讯录限制在2500条,超出部分去除 |
|
||||
|
||||
### 4.2 通讯录UI与交互
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-03-21 | d2309fb29 | 修复配对完蓝牙,切换到通讯录界面,界面显示异常有重叠 |
|
||||
| 2025-10-13 | 0680db5b1 | 优化通讯录个数UI显示 |
|
||||
| 2025-10-16 | 0b947f3a4 | 更新蓝牙通讯录默认选中第一个 |
|
||||
| 2025-10-08 | 00415fb2d | 优化蓝牙通讯录页面连接断开逻辑 |
|
||||
| 2024-06-11 | 4c4092983 | 修复点击刷新按钮右侧会闪过联系人详情页 |
|
||||
| 2024-05-21 | 5b73c1cd0 | 修复多次点击通讯录刷新按钮,会跳出通讯录未同步 |
|
||||
| 2024-04-22 | 4e4c7d2f6 | 修复蓝牙电话滑动联系人列表,联系人详情页依然显示 |
|
||||
| 2024-04-19 | a7fb60fe3 | 修复蓝牙电话通讯录显示有中文 |
|
||||
| 2023-12-25 | 159ed069b | 修复连接蓝牙,点击最近使用的电话进入通讯录页面,加载不出来 |
|
||||
| 2023-12-15 | 3304c57a5 | 修复未连接蓝牙时,无法切换到通讯录页面 |
|
||||
| 2023-12-14 | 3f389a05b | 修复蓝牙电话-通讯录-字母查询-通讯录中没有的字母,无反应 |
|
||||
| 2023-08-11 | 409bc14f6 | 按照新的设计要求修改通讯录列表及添加通讯录搜索功能 |
|
||||
| 2023-07-26 | 991c8eea3 | 蓝牙添加通讯录和通话记录功能 |
|
||||
|
||||
---
|
||||
|
||||
## 五、蓝牙连接状态管理 (20条)
|
||||
|
||||
### 5.1 ACC电源状态处理
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-20 | 295607af2 | 修改acc开关,蓝牙不做断开或重连操作,保持原状态 |
|
||||
| 2024-01-15 | 3ee792ae9 | 修复负一屏点击整车下电后,踩刹车上电,蓝牙没有自动连接 |
|
||||
| 2024-01-09 | dd6d12c31 | 修复蓝牙上电后第一次进入蓝牙音乐界面时,蓝牙音乐会暂停一下 |
|
||||
| 2024-01-02 | 9258088f0 | 修复上电后,手机端播放蓝牙音乐,从主界面进入后蓝牙音乐暂停 |
|
||||
| 2023-12-07 | fdfe2c820 | 修复播放蓝牙音乐过程中断开ACC再重新连接,进度条显示00:00 |
|
||||
| 2023-12-13 | 18a297d93 | 修复蓝牙电话通话中,acc off,手机还显示蓝牙连接状态 |
|
||||
|
||||
### 5.2 蓝牙可见性与配对
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2026-01-28 | a0e15fe92 | 进入蓝牙设置页面,手机就搜不到车机的蓝牙问题 |
|
||||
| 2026-01-28 | c1a490f80 | 修改蓝牙可见性 |
|
||||
| 2025-12-29 | 6d491ec73 | 新增蓝牙配对设备最大数量限制为10;配对请求5s未响应自动拒绝 |
|
||||
| 2024-01-12 | d89e68cd7 | 修复连接一个蓝牙后,另一个手机配对成功,通讯录界面蓝牙名称没更新 |
|
||||
| 2023-12-21 | fbf1637bb | 修复打开蓝牙然后关闭开放蓝牙监测,手机还能搜索到车机 |
|
||||
| 2023-12-08 | a815b4bef | 修复车机连接手机的话,蓝牙连接和手机配对成功,连接失败 |
|
||||
| 2023-10-19 | 60c5779cd | 修复蓝牙可见性不可见性修改 |
|
||||
|
||||
### 5.3 蓝牙名称管理
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-09-05 | e238b8d4c | 修改默认蓝牙和WiFi名称 |
|
||||
| 2024-01-05 | 6a75240d7 | 连接时实时刷新蓝牙名称 |
|
||||
| 2023-12-21 | 42b72c8f2 | 修复写入新的vin码,蓝牙名称还显示原来的 |
|
||||
| 2023-11-14 | 5f3d5e800 | 修复蓝牙名称恢复出厂设置显示错误问题 |
|
||||
| 2023-09-27 | 538f326a6 | 蓝牙名称修改成vin后6位 |
|
||||
| 2023-08-17 | a5d1f78d2 | 修复蓝牙名称加vin码默认名称 |
|
||||
|
||||
---
|
||||
|
||||
## 六、UI适配与优化 (35条)
|
||||
|
||||
### 6.1 深色模式适配
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-21 | 49a6ca185 | 修改深色模式状态监听模式 |
|
||||
| 2025-11-14 | 2175a4bd8 | 修改联系人字母显示dark模式颜色 |
|
||||
| 2025-11-14 | f7999efe6 | 添加深色模式适配功能 |
|
||||
|
||||
### 6.2 右舵/国际化适配
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2026-01-17 | 9c43ac6ad | 添加适配12.3寸屏幕功能 |
|
||||
| 2025-02-26 | 83fb691b6 | 修改蓝牙电话右舵UI效果 |
|
||||
| 2025-02-25 | 8ef5fb690 | 蓝牙新增右舵项目布局资源 |
|
||||
| 2024-03-11 | 1b292b8ed | 新增阿拉伯语 |
|
||||
| 2023-08-15 | afb4eb70a | 修改通话记录两天以上,一周以内显示星期 |
|
||||
|
||||
### 6.3 界面UI更新
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-17 | 6c6a39f36 | 优化蓝牙电话背景图片以及搜索功能 |
|
||||
| 2025-11-04 | e3413202b | 修改蓝牙连接按键跳转到最新的页面 |
|
||||
| 2025-11-04 | 6b0c946ad | 更新通讯录文案为联系人 |
|
||||
| 2025-10-16 | 449e78098 | 修改拨号按键不可用时,透明度为0.6 |
|
||||
| 2025-10-16 | 5f97d7f07 | 根据最新UE调整蓝牙电话页面显示 |
|
||||
| 2025-10-15 | 8eb033ea3 | 优化拨号按键板功能 |
|
||||
| 2025-10-15 | 118b7c74c | 优化按键板搜索同时搜索通话记录和通讯录 |
|
||||
| 2025-10-08 | 85b3fc57e | 修改通话记录时间显示格式 |
|
||||
| 2025-09-28 | be6c7aa5e | 更新蓝牙UI |
|
||||
| 2025-09-26 | 5fedd8aea | 更新蓝牙UI相关功能 |
|
||||
| 2025-07-21 | 3ff34003d | 修改空联系人提示UI位置错误 |
|
||||
| 2024-05-24 | 738188f67 | 修复蓝牙来电显示界面,文言重叠 |
|
||||
| 2024-03-21 | 13bc1ecdf | 修复了蓝牙文字重叠的问题 |
|
||||
| 2023-12-21 | a3b1ba89f | 修复未连接蓝牙时通话界面和UI不一致 |
|
||||
| 2023-12-04 | dea35c78f | 修复蓝牙通话记录没有滚动条,与UI设计不符 |
|
||||
| 2023-10-31 | 5e6a03a0b | 蓝牙电话通话页面V1.3UI适配修改 |
|
||||
| 2023-10-27 | d9acac409 | 蓝牙通话记录和通讯录V1.3UI修改适配 |
|
||||
| 2023-08-31 | d893ecdf4 | 修复蓝牙相关的走查UI问题 |
|
||||
|
||||
---
|
||||
|
||||
## 七、国际化/翻译 (15条)
|
||||
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-07-11 | 07d05e2c0 | 修复蓝牙电话翻译显示格式错误 |
|
||||
| 2024-07-05 | a418fc475 | 修复未找到"%s"的相关结果的英文和需求对应不上 |
|
||||
| 2024-05-13 | b1d5b4b3b | 蓝牙翻译文本更新 |
|
||||
| 2024-04-18 | 67c6c9aa6 | 修复蓝牙(未找到"%s"的相关结果)的英文和需求对应不上 |
|
||||
| 2024-03-28 | 9dfce2f80 | 修复通话名称Dial和Deepway多语言翻译不一致 |
|
||||
| 2023-11-22 | c2d68a84d | 蓝牙数字统一设置DINGPRO格式 |
|
||||
| 2023-07-19 | da0d81c9f | 参照UE调整通讯录和通话记录 |
|
||||
|
||||
---
|
||||
|
||||
## 八、代码优化与重构 (15条)
|
||||
|
||||
### 8.1 工具类统一
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-12-24 | 653c4b6b3 | 统一使用YX_log工具打印 |
|
||||
| 2025-12-17 | 48c6f2d2d | 修改toast调用,统一调用自定义toast |
|
||||
| 2025-12-17 | 0f688b8fc | 不用系统toast,添加自定义toast |
|
||||
| 2024-03-25 | b232e10ad | 优化日志打印 |
|
||||
|
||||
### 8.2 构建优化
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2025-11-05 | 7ebb3b171 | 优化sdk build.gradle |
|
||||
| 2025-11-05 | b5b840b98 | 添加SharedPrefsManager.init |
|
||||
| 2024-12-24 | abf1034fd | 删除无效资源,png图片转webp,优化apk体积 |
|
||||
| 2024-12-25 | e39ee2e1e | 修改打包资源错误导致没有打包到中文资源 |
|
||||
| 2023-12-12 | 18a297d93 | 去掉依赖库,可以通过脚本编译release的apk |
|
||||
| 2024-03-05 | 6447ff187 | 优化代码,去掉无用的资源引用 |
|
||||
|
||||
---
|
||||
|
||||
## 九、Bug修复 (杂项) (15条)
|
||||
|
||||
| 日期 | Commit | 描述 |
|
||||
|------|--------|------|
|
||||
| 2024-04-18 | 2ffb50935 | 修复出现蓝牙ANR |
|
||||
| 2024-01-18 | e948b2e69 | 修复麦克风禁用问题 |
|
||||
| 2024-01-08 | 4e5eb00d7 | 修复monkey crash问题 |
|
||||
| 2023-11-02 | f5ef447c6 | 修复SQLiteCursor未关闭引起的异常 |
|
||||
| 2023-11-23 | 0bc5caee4 | 修复跑monkey时出现蓝牙ANR问题 |
|
||||
| 2023-10-13 | b61120c85 | 处理专辑封面闪烁问题 |
|
||||
| 2023-10-14 | b7cc4717a | 修复蓝牙电话切换音源,仪表会出现消失一下 |
|
||||
| 2023-10-20 | 8040146aa | 解决偶现断连后,状态栏不显示蓝牙图标 |
|
||||
| 2023-09-21 | ebf265af1 | 处理蓝牙电话和蓝牙音乐方向盘控制功能 |
|
||||
| 2023-09-21 | c6784f0ef | 处理空指针报错 |
|
||||
| 2023-09-06 | d2fd3d9be | 修复蓝牙跑monkey崩溃问题 |
|
||||
| 2023-08-24 | 6c58e6ed3 | 添加蓝牙音频流接口 |
|
||||
|
||||
---
|
||||
|
||||
## 十、关键修改点总结 (便于下次修改)
|
||||
|
||||
### 10.1 语音交互入口类
|
||||
- `VoiceEventHelper.java` - 语音事件处理,所有语音蓝牙操作入口
|
||||
- `MediaProtocol.java` - 媒体协议,蓝牙音乐状态同步
|
||||
- `VoiceNewProtocolConst.java` - TXZ语音协议常量
|
||||
|
||||
### 10.2 蓝牙音乐核心类
|
||||
- `BluetoothHfpClient.java` - HFP协议,电话状态
|
||||
- 音频焦点管理 - 与语音、导航、视频的焦点竞争
|
||||
- 投屏数据格式 - JSON格式传输给仪表
|
||||
|
||||
### 10.3 通讯录同步核心类
|
||||
- `BluetoothPbapClient.java` - PBAP协议入口
|
||||
- `BtContactsManager.java` - 通讯录管理
|
||||
- `isPhoneBookPulling` - 同步状态标志,需在完成后置false
|
||||
- 同步限制: 通讯录2500条/2000条盖尾,通话记录50条
|
||||
|
||||
### 10.4 ACC电源处理要点
|
||||
- ACC OFF时不主动断开蓝牙,保持原状态
|
||||
- ACC ON后恢复播放状态需校验实际播放状态
|
||||
- 下电再上电后播放按钮状态同步
|
||||
|
||||
### 10.5 UI适配要点
|
||||
- 深色模式: 联系人字母颜色、监听模式
|
||||
- 右舵项目: 需要单独布局资源
|
||||
- 12.3寸屏幕适配
|
||||
|
||||
### 10.6 国际化要点
|
||||
- 阿拉伯语已支持
|
||||
- 通话记录时间格式: "昨天"根据语言切换
|
||||
- 数字格式统一DINGPRO格式
|
||||
|
||||
---
|
||||
|
||||
## 十一、常见问题快速定位
|
||||
|
||||
| 问题类型 | 关键类/方法 | 日志关键字 |
|
||||
| ------- | ------------------------------------------ | ------------------------------------------ |
|
||||
| 通讯录不同步 | BluetoothPbapClient.phoneBookPullRequest() | BtContactsManager, onContactsPullCompleted |
|
||||
| 音乐状态异常 | 音频焦点处理 | AudioManager, onFocusChange |
|
||||
| 语音拒接失败 | VoiceEventHelper拒接逻辑 | 蓝牙拒接, HFP |
|
||||
| ACC状态处理 | 电源状态监听 | ACC_OFF, ACC_ON |
|
||||
| 投屏数据 | JSON数据传输 | 投屏, DataCenter |
|
||||
| ANR问题 | 主线程阻塞 | ANR, SQLiteCursor |
|
||||
@@ -0,0 +1,544 @@
|
||||
# 蓝牙模块开发熟悉手册
|
||||
|
||||
> 整理日期:2026-07-06
|
||||
> 整理范围:`F:\zdCode\xugong` 当前代码、`agent.md` 历史线索、蓝牙目录现有 Markdown、docx、xlsx、PDF 可抽取文本。
|
||||
> 目的:帮助新接手开发者快速理解徐工项目蓝牙模块的架构、主流程、代码入口、日志排查路径和历史高风险点。
|
||||
|
||||
## 一句话结论
|
||||
|
||||
徐工蓝牙不是单一 APK 功能,而是一条跨 `YX_BlueTooth`、`YX_BluetoothSDK`、`YX_Music`、`YX_Voice`、`YX_Launcher`、`YX_SystemUI`、Android Frameworks、系统 Bluetooth 应用、顾凯 SDK/芯片的链路。开发时优先从 `YX_BluetoothSDK` 看协议封装,再看上层应用如何订阅 SDK 回调和 `DataManager` 数据。
|
||||
|
||||
## 1. 模块地图
|
||||
|
||||
| 模块 | 定位 | 重点入口 |
|
||||
| ------------------------------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| `YX_BluetoothSDK` | 蓝牙核心 SDK,封装 HFP/A2DP/AVRCP/PBAP/MAP、数据库、状态推送、语音同步 | `manager`、`modules`、`platform`、`audio`、`database` |
|
||||
| `YX_BlueTooth` | 蓝牙电话主业务应用,联系人、通话记录、拨号、通话页、常驻服务、widget | `MainActivity`、`ContactsFragment`、`CallLogsFragment`、`BluetoothPhoneActivity`、`BluetoothService` |
|
||||
| `YX_Music` | 蓝牙音乐页面所在应用,负责蓝牙音乐页面 UI、播放控制、封面显示 | `BluetoothMusicFragment`、`BluetoothMusicViewModel` |
|
||||
| `YX_Voice` | 语音控制蓝牙开关、电话、音乐、通讯录/通话记录状态同步 | `VoiceProtocol`、`BlueToothHelper`、`BluetoothMonitorReceiver`、`VoiceEventHelper` |
|
||||
| `YX_Launcher` | 首页音乐卡片、蓝牙音乐信息展示和媒体按键入口 | `WidgetsMedia`、`DisplayShareViewModel`、`Id3Info` |
|
||||
| `YX_SystemUI` | 状态栏/导航媒体区、通话状态显示、系统级入口 | `MediaControlView`、`VirtualManager`、SystemUI 蓝牙封装类 |
|
||||
| `YX_CarControl` | 配对弹窗、自动同步开关等外围联动 | 注意不要重复初始化 PBAP 联系人同步 |
|
||||
| Frameworks / Bluetooth Process | Android 蓝牙 API、Binder、系统 Bluetooth app、JNI、协议栈 | `android.bluetooth.*`、`packages/apps/Bluetooth` |
|
||||
| 顾凯 SDK/芯片 | 蓝牙协议栈供应商实现和 HCI 交互 | 底层联调、btsnoop/顾凯日志 |
|
||||
|
||||
## 2. 总体分层
|
||||
|
||||
PDF《蓝牙框架原理以及通讯数据交互流程》给出的系统层级可落到项目代码中:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["上层应用<br/>YX_BlueTooth / YX_Music / YX_Voice / Launcher / SystemUI"] --> B["YX_BluetoothSDK<br/>ControlManager / Manager / Platform Client"]
|
||||
B --> C["Frameworks API<br/>android.bluetooth.*"]
|
||||
C --> D["Bluetooth Process<br/>packages/apps/Bluetooth"]
|
||||
D --> E["JNI<br/>packages/apps/Bluetooth/jni"]
|
||||
E --> F["AOSP 蓝牙协议栈<br/>system/bt"]
|
||||
F --> G["顾凯 SDK / HAL / HIDL"]
|
||||
G --> H["蓝牙芯片"]
|
||||
```
|
||||
|
||||
反向回调通常是:芯片/协议栈事件 -> JNI -> 系统 Bluetooth 服务 -> Frameworks 广播/API -> `YX_BluetoothSDK platform` 接收 -> `modules` 整理状态 -> 上层 UI、语音、Launcher/SystemUI。
|
||||
|
||||
## 3. SDK 内部分层
|
||||
|
||||
`YX_BluetoothSDK` 是最值得先读的模块,建议按下面顺序看:
|
||||
|
||||
| 层 | 包路径 | 职责 |
|
||||
|---|---|---|
|
||||
| 对外控制层 | `com.yaxon.bluetoothsdk.manager` | 单例入口,给 App/语音/音乐模块调用,例如 `BtPhoneControlManager`、`BtContactsControlManager`、`BtMusicControlManager` |
|
||||
| 业务模块层 | `com.yaxon.bluetoothsdk.modules` | 真正组织业务状态机、监听、数据库、语音/投屏同步,例如 `BtContactsManager`、`BtPhoneManager`、`BtMusicManager`、`BtInfoPushManager` |
|
||||
| 平台适配层 | `com.yaxon.bluetoothsdk.platform` | 封装 Android 蓝牙 API 和广播,例如 `BluetoothHfpClient`、`BluetoothPbapClient`、`BluetoothAvrcpClient`、`BluetoothConnectListenerClient` |
|
||||
| 音频层 | `com.yaxon.bluetoothsdk.audio` | 蓝牙音乐音频焦点、A2DP mute/unmute、MediaSession 媒体键 |
|
||||
| 数据层 | `com.yaxon.bluetoothsdk.database` | 联系人、通话记录、配对设备、收藏等本地 SQLite 数据 |
|
||||
| 工具层 | `utils` | 系统联系人/通话记录读取、号码处理、日志、权限等 |
|
||||
|
||||
开发时一般从 `ControlManager` 找入口,然后下钻到 `modules`,再看 `platform` 是调用系统 API 还是接收广播。
|
||||
|
||||
## 4. 启动与初始化
|
||||
|
||||
蓝牙电话应用开机常驻入口:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
BootReceiver["YX_BlueTooth BootReceiver"] --> Service["BluetoothService.onCreate"]
|
||||
Service --> SDK["初始化 BtPhone/BtContacts/BtCallRecords 等控制器"]
|
||||
Main["MainActivity.onCreate/initData"] --> VM["SettingViewModel / Fragment ViewModel"]
|
||||
VM --> Managers["BtSettingControlManager / BtContactsControlManager / BtPhoneControlManager"]
|
||||
```
|
||||
|
||||
关键文件:
|
||||
|
||||
- `YX_BlueTooth/src/main/java/com/yaxon/bluetooth/receiver/BootReceiver.java`
|
||||
- `YX_BlueTooth/src/main/java/com/yaxon/bluetooth/service/BluetoothService.java`
|
||||
- `YX_BlueTooth/src/main/java/com/yaxon/bluetooth/main/MainActivity.java`
|
||||
- `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/modules/BtSettingManager.java`
|
||||
|
||||
`BtSettingManager.init()` 会初始化 `BluetoothHfpClient`、`BluetoothA2dpSinkClient`、`BluetoothDeviceClient`、`BluetoothMapConnectClient`、`BluetoothConnectListenerClient`,并在蓝牙已打开时初始化已配对设备列表。它还会延迟检查已连接设备,并把当前活跃蓝牙 MAC 同步给语音模块。
|
||||
|
||||
## 5. 蓝牙开关、扫描、配对、连接
|
||||
|
||||
### 5.1 状态来源
|
||||
|
||||
蓝牙开关状态来自 `BluetoothAdapter.ACTION_STATE_CHANGED`,SDK 侧由 `BluetoothConnectListenerClient.setBluetoothSwitchState()` 处理:
|
||||
|
||||
| 状态值 | Android 常量 | 含义 |
|
||||
|---|---|---|
|
||||
| `10` | `BluetoothAdapter.STATE_OFF` | 蓝牙已关闭 |
|
||||
| `11` | `BluetoothAdapter.STATE_TURNING_ON` | 正在打开 |
|
||||
| `12` | `BluetoothAdapter.STATE_ON` | 蓝牙已打开 |
|
||||
| `13` | `BluetoothAdapter.STATE_TURNING_OFF` | 正在关闭 |
|
||||
|
||||
注意:`BluetoothAdapter.enable()` / `disable()` 返回 `true` 只代表请求被接受,不代表最终状态已切到 `ON/OFF`。语音场景必须看后续 `blueState -> 12` 或 `blueState -> 10`。
|
||||
|
||||
### 5.2 连接状态
|
||||
|
||||
连接状态由 `BluetoothConnectListenerClient` 聚合 HFP、A2DP、A2DP Sink 等 profile 广播,再通知各模块:
|
||||
|
||||
- `notifyBluetoothConnected()`:写入连接 MAC、连接名、连接状态,并回调 `onConnect`
|
||||
- `notifyBluetoothDisconnect()`:清理蓝牙音乐信息,写入断开状态,并回调 `onDisconnect`
|
||||
- `setBondState()`:处理配对状态
|
||||
- `setPairingRequest()`:处理配对请求
|
||||
|
||||
### 5.3 HFP 与 A2DP 的关系
|
||||
|
||||
交接说明里特别强调:蓝牙连接包含 `hfp`(电话)和 `a2dp`(音乐/音频连接);通讯录同步需要再连 `pbap`,同步完成后需要断开 `pbap`。
|
||||
|
||||
## 6. 通讯录与通话记录同步(PBAP)
|
||||
|
||||
PBAP 是 Phone Book Access Profile,用于从手机拉取通讯录和通话记录。本项目中通讯录和通话记录共享一次 PBAP 同步窗口:联系人完成、通话记录完成后,才认为本轮电话本下载整体完成,并主动断开 PBAP,避免阻塞和卡死。
|
||||
|
||||
### 6.1 主流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant UI as ContactsFragment/CallLogsFragment
|
||||
participant CM as BtContactsControlManager
|
||||
participant M as BtContactsManager
|
||||
participant P as BluetoothPbapClient
|
||||
participant SYS as Android PBAP/System Provider
|
||||
participant DB as DataContactsHelper/DataCallRecordHelper
|
||||
participant V as ViewModel/Voice
|
||||
|
||||
UI->>CM: phoneBookPullRequest(context)
|
||||
CM->>M: phoneBookPullRequest(context)
|
||||
M->>P: connectPbap 或 phoneBookPullRequest
|
||||
P->>SYS: 删除系统 Contacts/CallLog 缓存
|
||||
P->>SYS: 发送 Intent.ACTION_USER_UNLOCKED
|
||||
SYS-->>P: contacts.download.complete
|
||||
P-->>M: onContactsPullCompleted()
|
||||
M->>SYS: ContactUtils.getAllContacts()
|
||||
M->>DB: deleteContacts + saveContactsList
|
||||
M-->>V: onContactsPhoneBook(list)
|
||||
SYS-->>P: calllogs.download.complete
|
||||
P-->>CallRecords: onCallLogsPullCompleted()
|
||||
CallRecords->>SYS: CallLogUtils.getCallLogList()
|
||||
CallRecords->>DB: clearCallRecord + saveCallRecordList
|
||||
CallRecords-->>V: onCallRecords(list)
|
||||
M->>P: contacts + calllogs 都完成后 disconnectPbap()
|
||||
```
|
||||
|
||||
### 6.2 关键代码入口
|
||||
|
||||
| 场景 | 文件/方法 |
|
||||
|---|---|
|
||||
| UI 点击同步联系人 | `ContactsFragment.phoneBookPullRequest()` |
|
||||
| UI 点击/通话页触发同步 | `CallLogsFragment` -> `CallHistoryViewModel.phoneBookPullRequest()` |
|
||||
| SDK 对外入口 | `BtContactsControlManager.phoneBookPullRequest()` |
|
||||
| 同步状态、权限、自动同步 | `BtContactsManager.phoneBookPullRequest()`、`isAutoSync()`、`checkContactsPermissionGranted()` |
|
||||
| PBAP 连接和系统广播 | `BluetoothPbapClient.connectPbap()`、`phoneBookPullRequest()`、`PbapClientReceiver` |
|
||||
| 联系人读取与保存 | `ContactUtils.getAllContacts()`、`DataContactsHelper.savePhoneBookList()` |
|
||||
| 通话记录读取与保存 | `CallLogUtils.getCallLogList()`、`BtCallRecordsManager.loadCallsLog()`、`DataCallRecordHelper.saveCallRecordList()` |
|
||||
| UI 状态判断 | `ContactsFragment.syncPhoneBookSynchronized()`、`CallLogsFragment.notifyPhoneRecordList()` |
|
||||
|
||||
### 6.3 关键状态位
|
||||
|
||||
| 状态 | 说明 | 风险 |
|
||||
|---|---|---|
|
||||
| `isPhoneBookPulling` | PBAP 本轮同步是否正在进行 | UI loading 和重复点击判断要优先看它 |
|
||||
| `isContactsPullCompeted` / `getContactLoadWonType()` | SDK 本轮联系人读取、写库、回调是否完成 | 比 `isPhoneBookSynchronized()` 更能代表本轮同步完成 |
|
||||
| `isPhoneBookSynchronized()` | 本地 DB 当前设备是否已有至少一条联系人 | 只能代表“本地有数据”,不代表本轮 PBAP 完成 |
|
||||
| `isCallRecordUpdated()` | 本地 DB 当前设备是否已有通话记录 | 通话记录页显示和 loading 判断会用到 |
|
||||
|
||||
### 6.4 已验证历史结论
|
||||
|
||||
- 清空蓝牙本地 SQLite 表不是通讯录同步失败的直接原因;正常清空后 PBAP 会重新写入。
|
||||
- `isPhoneBookSynchronized()` 只表示 DB 有联系人,不能作为“本轮同步完成”的唯一条件。
|
||||
- 曾出现 `YX_CarControl` 和 `YX_BlueTooth` 双进程同时初始化 PBAP,导致重复 `phoneBookPullRequest`、重复删写联系人表;当前应统一由 `com.yaxon.bluetooth` 负责 PBAP 同步。
|
||||
- 联系人同步中应优先显示 loading,避免在旧库数据或第一条联系人写入后提前显示“0 个联系人”或旧列表。
|
||||
- 通话记录 Adapter 曾因传入同一个 list 导致 `clear()` 自清空,已通过传 `new ArrayList<>(mCallRecordList)` 规避。
|
||||
|
||||
### 6.5 排查日志关键字
|
||||
|
||||
| 阶段 | 关键字 |
|
||||
|---|---|
|
||||
| 请求开始 | `BluetoothPbapClient: phoneBookPullRequest` |
|
||||
| PBAP 连接变化 | `PbapClientReceiver device name`、`prevState`、`state` |
|
||||
| 联系人下载完成 | `BtContactsManager: onContactsPullCompleted` |
|
||||
| 联系人读取完成 | `contacts read completed size =` |
|
||||
| 联系人 UI 收到 | `ContactListViewModel: onContactsPhoneBook =` |
|
||||
| 通话记录读取 | `mCallRecordBeanList size =` |
|
||||
| 通话记录保存 | `saveCallRecordList size =` |
|
||||
| 通话记录 UI | `CallLogsFragment: notifyPhoneRecordList list ==` |
|
||||
| 失败 | `onContactsPullFailed`、`contacts synchronization failed`、`通讯录同步失败` |
|
||||
|
||||
## 7. 蓝牙电话(HFP)
|
||||
|
||||
HFP 是 Hands-Free Profile,用于拨号、接听、拒接、挂断、通话音频状态等。
|
||||
|
||||
### 7.1 电话状态
|
||||
|
||||
| 状态值 | 常量 | 说明 |
|
||||
|---|---|---|
|
||||
| `0` | `CALL_STATE_ACTIVE` | 通话中 |
|
||||
| `1` | `CALL_STATE_HELD` | 保持中 |
|
||||
| `2` | `CALL_STATE_DIALING` | 正在拨号 |
|
||||
| `3` | `CALL_STATE_ALERTING` | 正在响铃,项目中通常合并到拨号处理 |
|
||||
| `4` | `CALL_STATE_INCOMING` | 来电 |
|
||||
| `5` | `CALL_STATE_WAITING` | 第三方等待 |
|
||||
| `6` | `CALL_STATE_HELD_BY_RESPONSE_AND_HOLD` | 响应并保持,项目中通常合并到保持处理 |
|
||||
| `7` | `CALL_STATE_TERMINATED` | 挂断 |
|
||||
|
||||
### 7.2 拨号调用链
|
||||
|
||||
PDF《蓝牙电话交互流程解析》给出的拨号链路,对应当前项目可理解为:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["YX_BlueTooth UI / BluetoothService / Voice"] --> B["BtPhoneControlManager.dialing"]
|
||||
B --> C["BtPhoneManager.dialing"]
|
||||
C --> D["BluetoothHfpClient.dial"]
|
||||
D --> E["BluetoothHeadsetClient.dial"]
|
||||
E --> F["BluetoothHeadsetClientBinder.dial"]
|
||||
F --> G["HeadsetClientService.dial"]
|
||||
G --> H["HeadsetClientStateMachine.Connected.dial"]
|
||||
H --> I["NativeInterface.dial"]
|
||||
I --> J["com_android_bluetooth_hfpclient.dialNative"]
|
||||
J --> K["顾凯 SDK / 蓝牙芯片"]
|
||||
```
|
||||
|
||||
接听、拒接、挂断与拨号类似,只是 Frameworks API 分别换成:
|
||||
|
||||
- `BluetoothHeadsetClient.acceptCall()`
|
||||
- `BluetoothHeadsetClient.rejectCall()`
|
||||
- `BluetoothHeadsetClient.terminateCall()`
|
||||
|
||||
### 7.3 状态回调链
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant FW as BluetoothHeadsetClient 广播
|
||||
participant HFP as BluetoothHfpClient
|
||||
participant M as BtPhoneManager
|
||||
participant UI as BluetoothPhoneViewModel/UI/Window
|
||||
participant Push as BtInfoPushManager
|
||||
participant Voice as BtVoiceControlManager
|
||||
|
||||
FW-->>HFP: ACTION_CALL_CHANGED
|
||||
HFP->>HFP: getCurrentCalls()
|
||||
HFP-->>M: OnCallPhoneStateListener.callState(list)
|
||||
M->>M: 转成 CallingState
|
||||
M-->>UI: onHfpCallChanged(list)
|
||||
M->>Push: setPhoneState / setPhoneCallState / setPhoneGroups
|
||||
M->>Voice: notifyBtInComing / notifyBtCall / notifyBtAccept / notifyBtHangup
|
||||
```
|
||||
|
||||
### 7.4 关键文件
|
||||
|
||||
- `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/manager/BtPhoneControlManager.java`
|
||||
- `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/modules/BtPhoneManager.java`
|
||||
- `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/platform/BluetoothHfpClient.java`
|
||||
- `YX_BlueTooth/src/main/java/com/yaxon/bluetooth/viewmodel/BluetoothPhoneViewModel.java`
|
||||
- `YX_BlueTooth/src/main/java/com/yaxon/bluetooth/main/BluetoothPhoneActivity.java`
|
||||
- `YX_BlueTooth/src/main/java/com/yaxon/bluetooth/window/TelephoneWindowControl.java`
|
||||
- `YX_BlueTooth/src/main/java/com/yaxon/bluetooth/window/ThirdCallingControl.java`
|
||||
- `YX_BlueTooth/src/main/java/com/yaxon/bluetooth/service/BluetoothService.java`
|
||||
|
||||
### 7.5 排查日志关键字
|
||||
|
||||
| 问题 | 关键字 |
|
||||
|---|---|
|
||||
| 拨号没有发出 | `BluetoothHfpClient: dial phoneNumber`、`start dial phoneNumber` |
|
||||
| HFP 未连接 | `hfp_phone_protocol_not_connected`、`isHfpConnect disconnect` |
|
||||
| 来电/去电 UI 不刷新 | `ACTION_CALL_CHANGED`、`clientCallList`、`onHfpCallChanged` |
|
||||
| 挂断/拒接失败 | `hangupCall`、`rejectCall`、`acceptCall flag` |
|
||||
| 通话音频异常 | `ACTION_AUDIO_STATE_CHANGED`、`audio connection state`、`connectAudio`、`disconnectAudio` |
|
||||
|
||||
## 8. 蓝牙音乐(A2DP/AVRCP/MediaSession)
|
||||
|
||||
蓝牙音乐涉及两条线:
|
||||
|
||||
- A2DP:音频流链路,决定声音是否从手机到车机。
|
||||
- AVRCP/MediaBrowser/MediaSession:播放控制、播放状态、歌曲元数据、媒体按键。
|
||||
|
||||
### 8.1 主流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant UI as YX_Music/BluetoothMusicFragment
|
||||
participant CM as BtMusicControlManager
|
||||
participant M as BtMusicManager
|
||||
participant Audio as BtMusicAudioManager
|
||||
participant AVRCP as BluetoothAvrcpClient/MediaBrowserClient
|
||||
participant Push as BtInfoPushManager/DataManager
|
||||
participant L as Launcher/SystemUI/Voice
|
||||
|
||||
UI->>CM: requestAudioFocus/playBtMusic
|
||||
CM->>M: requestAudioFocus/playBtMusic
|
||||
M->>Audio: requestAudioFocus()
|
||||
Audio->>M: setA2dpUnMute / informAudioFocusStateNative=1
|
||||
M->>AVRCP: play()
|
||||
AVRCP-->>M: onPlaybackStateChanged / onMetadataChanged
|
||||
M-->>UI: onPlayMusicState/onPlayMusicInfo
|
||||
M->>Push: sendMusicInfoToLauncher(BT_MUSIC_INFO)
|
||||
Push-->>L: ContentObserver/DataManager 读取 BT_MUSIC_INFO
|
||||
```
|
||||
|
||||
### 8.2 关键代码入口
|
||||
|
||||
| 场景 | 文件/方法 |
|
||||
|---|---|
|
||||
| 蓝牙音乐页面 | `YX_Music/src/music/java/com/yaxon/musicplay/view/music/BluetoothMusicFragment.java` |
|
||||
| 音乐 ViewModel | `YX_Music/src/main/java/com/yaxon/musicplay/viewmodel/BluetoothMusicViewModel.java` |
|
||||
| SDK 控制入口 | `BtMusicControlManager.playBtMusic()`、`pauseBtMusic()`、`requestAudioFocus()` |
|
||||
| 音乐业务状态 | `BtMusicManager.onPlaybackStateChanged()`、`onMetadataChanged()` |
|
||||
| 音频焦点和媒体键 | `BtMusicAudioManager.requestAudioFocus()`、`onMediaButtonEvent()` |
|
||||
| AVRCP 控制 | `BluetoothAvrcpClient.play/pause/previous/next()` |
|
||||
| A2DP 音频状态 | `BluetoothA2dpSinkClient` |
|
||||
| Launcher/SystemUI 显示 | `BtInfoPushManager.sendMusicInfoToLauncher()`、`DataUtils.BT_MUSIC_INFO` |
|
||||
|
||||
### 8.3 焦点与保护逻辑
|
||||
|
||||
`BtMusicManager.onPlaybackStateChanged()` 中有一条关键保护:如果蓝牙音乐开始播放,但当前蓝牙音乐不在前台且没有蓝牙音乐焦点,就会 mute A2DP 并 `pauseBtMusic()`。这是为了防止手机端或后台异常播放抢声道,但也会影响 Launcher 首页音乐卡片冷启动首次播放场景。
|
||||
|
||||
历史上已经通过 SDK 侧 `BtMusicAudioManager` 的 MediaSession 兜底处理过 Launcher 首次点击:
|
||||
|
||||
- MediaSession 在无焦点但蓝牙音乐是当前音源时也可接媒体键。
|
||||
- 收到 `KEYCODE_MEDIA_PLAY_PAUSE` 后先申请焦点,再 `playBtMusic()`。
|
||||
- A2DP 连接、元数据、播放状态变化后刷新 MediaSession,避免第一次点击只激活 session、第二次才播放。
|
||||
|
||||
### 8.4 封面高风险点
|
||||
|
||||
蓝牙音乐封面风险集中在固定路径:
|
||||
|
||||
```text
|
||||
/sdcard/ID3/id3cover.JPEG
|
||||
```
|
||||
|
||||
问题模式:
|
||||
|
||||
- 系统/底层复用同一个封面路径。
|
||||
- 歌曲元数据先到,封面路径后到。
|
||||
- 文件可能短时间为 0 字节或半写入。
|
||||
- 空 `albumUrl` 或无效文件可能覆盖当前有效封面。
|
||||
|
||||
排查关键字:
|
||||
|
||||
- `albumUrl = /sdcard/ID3/id3cover.JPEG`
|
||||
- `length = 0`
|
||||
- `Failed to create image decoder`
|
||||
- `获取bitmap为null`
|
||||
- `skip invalid album file`
|
||||
- `loadFileImageToView success`
|
||||
|
||||
## 9. 语音与蓝牙交互
|
||||
|
||||
### 9.1 语音开关蓝牙
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["TXZ / VoiceService 请求<br/>openBluetooth / closeBluetooth"] --> B["VoiceProtocol.handleBluetooth"]
|
||||
B --> C["BlueToothHelper.openBlueToothByVoice / closeBlueToothByVoice"]
|
||||
C --> D["BluetoothAdapter.enable / disable"]
|
||||
D --> E["BluetoothMonitorReceiver.ACTION_STATE_CHANGED"]
|
||||
E --> F["BlueToothHelper.syncBluetoothStatusToTxzByStateChanged"]
|
||||
F --> G["VoiceEventHelper.notifyBluetoothOpenStaus / notifyBluetoothConnectStaus"]
|
||||
```
|
||||
|
||||
关键文件:
|
||||
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/protocol/VoiceProtocol.java`
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/helper/BlueToothHelper.java`
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/receiver/BluetoothMonitorReceiver.java`
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/helper/VoiceEventHelper.java`
|
||||
|
||||
重点:
|
||||
|
||||
- `openBlueToothByVoice()` / `closeBlueToothByVoice()` 做了同目标去抖、相反目标保护、有限重试、延迟状态回填。
|
||||
- `BluetoothMonitorReceiver` 收到 `STATE_ON/OFF` 后立即同步 TXZ,并延迟补发状态。
|
||||
- 不能以 `enable()/disable()` 返回值作为最终成功依据。
|
||||
|
||||
### 9.2 语音电话与通讯录
|
||||
|
||||
语音电话/通讯录状态同步主要由 SDK 侧 `BtVoiceManager` 和 `BtVoiceControlManager` 承接:
|
||||
|
||||
- 电话来电:`BtPhoneManager` -> `BtVoiceControlManager.notifyBtInComing`
|
||||
- 去电:`notifyBtCall`
|
||||
- 接通:`notifyBtAccept`
|
||||
- 挂断:`notifyBtHangup`
|
||||
- 联系人同步完成:`BtVoiceManager.syncBtActiveDeviceMac`、`BtVoiceControlManager.notifyBtContactReload`
|
||||
- 通话记录变化:`BtVoiceManager.notifyCallRecordChange`
|
||||
|
||||
## 10. Launcher/SystemUI/投屏联动
|
||||
|
||||
### 10.1 数据通道
|
||||
|
||||
SDK 通过 `BtInfoPushManager` 写入公共数据,外围模块通过 `ContentObserver` 或 `DataManager.getObject()` 读取。
|
||||
|
||||
| 数据 | 写入方 | 读取方 |
|
||||
|---|---|---|
|
||||
| `DataUtils.BT_MUSIC_INFO` | `BtInfoPushManager` | `YX_Launcher`、`YX_SystemUI`、`YX_Voice` |
|
||||
| `DataUtils.BT_INFO` | `BtInfoPushManager` | Launcher/SystemUI/投屏相关 |
|
||||
| 电话状态、联系人、号码、通话时长 | `BtPhoneManager` -> `BtInfoPushManager` | 仪表、Launcher、SystemUI、语音 |
|
||||
|
||||
### 10.2 常见现象
|
||||
|
||||
- Launcher 卡片能显示蓝牙音乐元数据,不代表按钮控制一定会走蓝牙音乐控制链路;按钮可能只是全局媒体键。
|
||||
- SystemUI/Launcher 读取封面路径时要防空路径、0 字节、解码失败、同一首歌空封面覆盖已有封面。
|
||||
- 电话投屏状态依赖 `BtInfoPushManager.setPhoneState()`、`setPhoneCallState()`、`setPhoneGroups()`。
|
||||
|
||||
## 11. 数据存储
|
||||
|
||||
| 数据 | 类 | 说明 |
|
||||
|---|---|---|
|
||||
| 联系人 | `DataContactsHelper` | 按蓝牙设备 MAC 存储联系人 |
|
||||
| 通话记录 | `DataCallRecordHelper` | 按蓝牙设备 MAC 存储通话记录,过滤网络电话等异常号码 |
|
||||
| 已配对设备 | `DataPairedHelper` | 配对设备列表 |
|
||||
| 收藏 | `DataCollectionHelper` | 收藏联系人/号码 |
|
||||
| 系统 Provider | `ContactUtils`、`CallLogUtils` | PBAP 下载完成后从系统联系人/通话记录 Provider 读取 |
|
||||
| 跨模块状态 | `DataManager`、`YxIPC` | 音乐、电话、语音、Launcher/SystemUI 状态同步 |
|
||||
|
||||
开发时要分清:
|
||||
|
||||
- 系统联系人/通话记录 Provider 是 PBAP 下载中间数据。
|
||||
- SDK 自己的 SQLite 是业务最终缓存。
|
||||
- `DataManager` 是跨应用状态和展示数据的同步通道。
|
||||
|
||||
## 12. 常见问题排查索引
|
||||
|
||||
| 问题 | 先看模块 | 关键日志 |
|
||||
|---|---|---|
|
||||
| 蓝牙打不开/关不掉,语音已回复成功 | `YX_Voice`、`BluetoothConnectListenerClient` | `openBlueTooth`、`closeBlueTooth`、`blueState -> 10/11/12/13`、`syncBluetoothStatusToTxz` |
|
||||
| 手机能连但电话不可用 | HFP | `hfp onServiceConnected`、`updateHfpConnectedState`、`isHfpConnect` |
|
||||
| 手机能播但车机无声 | A2DP/焦点 | `bluetooth music requestAudioFocus`、`setA2dpUnMute`、`informAudioFocusStateNative` |
|
||||
| Launcher 首页点播放无效 | MediaSession/焦点 | `WidgetMedia: KEYCODE_MEDIA_PLAY_PAUSE`、`MediaSessionService: Sending KeyEvent`、`BtMusicAudioManager: onMediaButtonEvent` |
|
||||
| 通讯录不同步 | PBAP | `phoneBookPullRequest`、`onContactsPullCompleted`、`contacts read completed size`、`onContactsPhoneBook` |
|
||||
| 通话记录为空 | PBAP/Adapter/UI | `mCallRecordBeanList size`、`saveCallRecordList size`、`notifyPhoneRecordList list ==` |
|
||||
| 封面闪烁/消失/上一首封面 | 蓝牙音乐封面 | `albumUrl`、`length = 0`、`decodeFile`、`skip invalid album file` |
|
||||
| 电话 UI 不弹/不消失 | HFP/UI/悬浮窗 | `ACTION_CALL_CHANGED`、`onHfpCallChanged`、`CallingState`、`TelephoneWindowControl` |
|
||||
| 断电上电状态错 | ACC/POWER/SOURCE_ID | `POWER_MODE`、`ACC_STATE`、`SOURCE_ID`、`restoreBtMusicIfNeeded` |
|
||||
|
||||
## 13. 开发路线图
|
||||
|
||||
建议按这个顺序熟悉:
|
||||
|
||||
1. 先读现有文档:`蓝牙模块流程概览.md`、`蓝牙框架原理以及数据通讯交互流程.pdf`、`蓝牙电话交互流程解析.pdf`、`徐工项目蓝牙模块交接说明.docx`。
|
||||
2. 看 `YX_BluetoothSDK` 分层:先 `manager`,再 `modules`,最后 `platform/audio/database`。
|
||||
3. 跟一遍 PBAP:从 `ContactsFragment.phoneBookPullRequest()` 跟到 `BluetoothPbapClient.phoneBookPullRequest()`,再跟回 `onContactsPullCompleted()`。
|
||||
4. 跟一遍 HFP:从 `BluetoothPhoneViewModel.acceptCall/rejectCall` 或 `BtPhoneControlManager.dialing()` 跟到 `BluetoothHfpClient`。
|
||||
5. 跟一遍蓝牙音乐:从 `BluetoothMusicFragment` 跟到 `BtMusicControlManager`、`BtMusicManager`、`BtMusicAudioManager`、`BluetoothAvrcpClient`。
|
||||
6. 跟语音开关蓝牙:从 `VoiceProtocol.handleBluetooth()` 跟到 `BlueToothHelper` 和 `BluetoothMonitorReceiver`。
|
||||
7. 看外围联动:`BtInfoPushManager` 写 `BT_MUSIC_INFO/BT_INFO`,再看 Launcher/SystemUI 的读取和显示。
|
||||
8. 最后看历史问题:`agent.md` 中的 PBAP 双进程、联系人 loading、通话记录自清空、封面固定路径、Launcher 首次点击播放。
|
||||
|
||||
## 14. 修改代码时的注意事项
|
||||
|
||||
- PBAP 同步不要在多个进程重复初始化监听,联系人/通话记录同步应以 `YX_BlueTooth` 进程为主。
|
||||
- UI 判断“同步完成”不要只看 `isPhoneBookSynchronized()`,本轮同步期间还要看 `isPhoneBookPulling` 和 `getContactLoadWonType()`。
|
||||
- PBAP 完成后要断开 PBAP,否则历史上有“阻塞、软件卡死”的风险。
|
||||
- 蓝牙开关语音反馈要等最终 `STATE_ON/OFF`,不能只看 `enable/disable result=true`。
|
||||
- 蓝牙音乐播放控制必须先处理音频焦点和 A2DP unmute,再发 AVRCP play。
|
||||
- 封面路径下发/展示前要校验文件存在、非 0 字节、可解码,且要处理固定路径重写竞态。
|
||||
- 通话记录/联系人传给 Adapter 或回调前尽量使用快照,避免共享 list 被清空或并发修改。
|
||||
- `destroy()` 类清理要注意真正 `shutdown()` 线程池,历史代码里存在只调用 `isShutdown()` 的可疑写法。
|
||||
|
||||
## 15. 已知潜在风险
|
||||
|
||||
| 风险 | 说明 |
|
||||
|---|---|
|
||||
| `BtMusicControlManager.isA2dpSinkConnected()` | 历史排查中怀疑可能固定返回 false,需要结合当前代码确认 |
|
||||
| 多处线程池销毁 | 部分 `destroy()` 里可能只调用 `isShutdown()` 而不是 `shutdown()` |
|
||||
| `BluetoothMapConnectClient.isMapConnect()` | 历史排查中提到潜在 NPE |
|
||||
| PBAP 同步耗时 | 现场 1973 联系人约 85 秒级,日志时间还可能因设备校时跳变 |
|
||||
| 固定封面路径 | `/sdcard/ID3/id3cover.JPEG` 会复用、清零、半写入,跨 Music/Launcher/SystemUI 都要防 |
|
||||
| 全局媒体键路由 | Launcher 卡片点击可能先被系统媒体 session 路由影响,需看 `MediaSessionService` 日志 |
|
||||
|
||||
## 16. 构建、部署、底层日志
|
||||
|
||||
常用构建:
|
||||
|
||||
```powershell
|
||||
.\gradlew :YX_BluetoothSDK:assembleDebug --console plain
|
||||
.\gradlew :YX_BlueTooth:assembleDebug --console plain
|
||||
.\gradlew :YX_Music:assembleDebug --console plain
|
||||
.\gradlew :YX_Voice:assembleDebug --console plain
|
||||
```
|
||||
|
||||
交接说明里的部署注意点:
|
||||
|
||||
- 蓝牙音乐修改后,需手动打包更新到 `third_apps` 目录下。
|
||||
- 配合顾凯 SDK 修改时,可以打开顾凯 SDK 日志:
|
||||
|
||||
```shell
|
||||
adb shell setprop persist.bluetooth.btsnoopenable true
|
||||
```
|
||||
|
||||
日志生成位置:
|
||||
|
||||
```text
|
||||
/data/misc/bluetooth/logs
|
||||
```
|
||||
|
||||
烧录文档补充:
|
||||
|
||||
- `pac` 格式通过 `SDToolBox -> SDFactoryTool` 烧录。
|
||||
- `zip` 格式为 U 盘升级,将 `totalUpdate.zip` 放 U 盘根目录,系统弹窗升级。
|
||||
|
||||
## 17. 参考资料
|
||||
|
||||
- `F:\AI\Obsidian\项目文档\徐工\蓝牙\蓝牙模块流程概览.md`
|
||||
- `F:\AI\Obsidian\项目文档\徐工\蓝牙\bluetooth_git_summary.md`
|
||||
- `F:\AI\Obsidian\项目文档\徐工\蓝牙\徐工项目蓝牙模块交接说明.docx`
|
||||
- `F:\AI\Obsidian\项目文档\徐工\蓝牙\徐工项目蓝牙模块主流程.xlsx`
|
||||
- `F:\AI\Obsidian\项目文档\徐工\蓝牙\蓝牙框架原理以及数据通讯交互流程.pdf`
|
||||
- `F:\AI\Obsidian\项目文档\徐工\蓝牙\蓝牙电话交互流程解析.pdf`
|
||||
- `F:\AI\Obsidian\项目文档\徐工\蓝牙\徐工项目软件烧录文档.pdf`
|
||||
|
||||
## 18. 快速入口清单
|
||||
|
||||
### SDK
|
||||
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\modules\BtSettingManager.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\modules\BtPhoneManager.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\modules\BtContactsManager.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\modules\BtCallRecordsManager.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\modules\BtMusicManager.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\modules\BtInfoPushManager.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\audio\BtMusicAudioManager.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\platform\BluetoothConnectListenerClient.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\platform\BluetoothHfpClient.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\platform\BluetoothPbapClient.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\platform\BluetoothAvrcpClient.java`
|
||||
- `F:\zdCode\xugong\YX_BluetoothSDK\src\main\java\com\yaxon\bluetoothsdk\platform\MediaBrowserClient.java`
|
||||
|
||||
### 蓝牙电话应用
|
||||
|
||||
- `F:\zdCode\xugong\YX_BlueTooth\src\main\java\com\yaxon\bluetooth\main\MainActivity.java`
|
||||
- `F:\zdCode\xugong\YX_BlueTooth\src\main\java\com\yaxon\bluetooth\main\BluetoothPhoneActivity.java`
|
||||
- `F:\zdCode\xugong\YX_BlueTooth\src\main\java\com\yaxon\bluetooth\fragment\ContactsFragment.java`
|
||||
- `F:\zdCode\xugong\YX_BlueTooth\src\main\java\com\yaxon\bluetooth\fragment\CallLogsFragment.java`
|
||||
- `F:\zdCode\xugong\YX_BlueTooth\src\main\java\com\yaxon\bluetooth\viewmodel\ContactListViewModel.java`
|
||||
- `F:\zdCode\xugong\YX_BlueTooth\src\main\java\com\yaxon\bluetooth\viewmodel\CallHistoryViewModel.java`
|
||||
- `F:\zdCode\xugong\YX_BlueTooth\src\main\java\com\yaxon\bluetooth\viewmodel\BluetoothPhoneViewModel.java`
|
||||
- `F:\zdCode\xugong\YX_BlueTooth\src\main\java\com\yaxon\bluetooth\service\BluetoothService.java`
|
||||
- `F:\zdCode\xugong\YX_BlueTooth\src\main\java\com\yaxon\bluetooth\provider\BluetoothContactsProvider.java`
|
||||
|
||||
### 音乐、语音和外围
|
||||
|
||||
- `F:\zdCode\xugong\YX_Music\src\music\java\com\yaxon\musicplay\view\music\BluetoothMusicFragment.java`
|
||||
- `F:\zdCode\xugong\YX_Music\src\main\java\com\yaxon\musicplay\viewmodel\BluetoothMusicViewModel.java`
|
||||
- `F:\zdCode\xugong\YX_Voice\src\main\java\com\yaxon\voice\protocol\VoiceProtocol.java`
|
||||
- `F:\zdCode\xugong\YX_Voice\src\main\java\com\yaxon\voice\helper\BlueToothHelper.java`
|
||||
- `F:\zdCode\xugong\YX_Voice\src\main\java\com\yaxon\voice\receiver\BluetoothMonitorReceiver.java`
|
||||
- `F:\zdCode\xugong\YX_Voice\src\main\java\com\yaxon\voice\helper\VoiceEventHelper.java`
|
||||
- `F:\zdCode\xugong\YX_Launcher\src\main\java\com\yaxon\launcher\view\WidgetsMedia.java`
|
||||
- `F:\zdCode\xugong\YX_SystemUI\src\main\java\com\android\systemui\sdk\view\navigation\MediaControlView.java`
|
||||
@@ -0,0 +1,297 @@
|
||||
# 徐工项目蓝牙模块流程概览
|
||||
|
||||
> 整理目的:帮助快速理解蓝牙模块架构和核心流程
|
||||
|
||||
---
|
||||
|
||||
## 一、整体架构
|
||||
|
||||
### 1.1 模块组成
|
||||
|
||||
| 模块 | 说明 |
|
||||
|------|------|
|
||||
| **YX_BlueTooth** | 上层应用,蓝牙电话、音乐界面 |
|
||||
| **YX_BluetoothSDK** | SDK模块,封装蓝牙协议 |
|
||||
| **Frameworks中间件** | android.bluetooth API |
|
||||
| **系统蓝牙应用** | packages/apps/Bluetooth/ |
|
||||
| **蓝牙协议栈** | system/bt,底层协议实现 |
|
||||
| **第三方SDK** | 顾凯芯片商提供 |
|
||||
|
||||
### 1.2 调用层级(从上到下)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ YX_Bluetooth (上层应用) │
|
||||
│ ↓ android.bluetooth API │
|
||||
│ Frameworks中间件 │
|
||||
│ ↓ Binder IPC │
|
||||
│ Bluetooth Process (系统蓝牙应用) │
|
||||
│ ↓ JNI │
|
||||
│ 蓝牙协议栈 (system/bt) │
|
||||
│ ↓ HIDL │
|
||||
│ 供应商实现 (顾凯SDK) │
|
||||
│ ↓ HCI │
|
||||
│ 蓝牙芯片 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、蓝牙电话流程
|
||||
|
||||
### 2.1 电话状态(7种)
|
||||
|
||||
| 状态值 | 名称 | 说明 |
|
||||
|--------|------|------|
|
||||
| 0 | ACTIVE | 通话中 |
|
||||
| 1 | HELD | 保持中 |
|
||||
| 2 | DIALING | 正在拨号 |
|
||||
| 3 | ALERTING | 正在响铃 |
|
||||
| 4 | INCOMING | 正在来电 |
|
||||
| 5 | WAITING | 等待中 |
|
||||
| 7 | TERMINATED | 已挂断 |
|
||||
|
||||
### 2.2 状态变化图
|
||||
|
||||
```
|
||||
来电 拨号
|
||||
┌─────────→ INCOMING ─────────→ DIALING
|
||||
│ │ │
|
||||
│ 接听来电 对方接通
|
||||
│ ↓ ↓
|
||||
IDLE ─────────── ACTIVE ───────────────┘
|
||||
│ │
|
||||
│ 挂断
|
||||
│ ↓
|
||||
└─────── TERMINATED
|
||||
```
|
||||
|
||||
### 2.3 拨号调用流程
|
||||
|
||||
```
|
||||
BluetoothHfpClient.dial() ← 上层应用入口
|
||||
↓
|
||||
BluetoothHeadsetClient.dial() ← Frameworks API
|
||||
↓ Binder
|
||||
BluetoothHeadsetClientBinder.dial()
|
||||
↓
|
||||
HeadsetClientService.dial() ← 系统蓝牙服务(中转)
|
||||
↓
|
||||
HeadsetClientStateMachine.Connected.dial()
|
||||
↓
|
||||
NativeInterface.dial() ← JNI接口
|
||||
↓
|
||||
com_android_bluetooth_hfpclient.dialNative()
|
||||
↓
|
||||
第三方SDK → 蓝牙芯片
|
||||
```
|
||||
|
||||
### 2.4 数据回调流程(反向)
|
||||
|
||||
```
|
||||
蓝牙芯片 → 第三方SDK
|
||||
↓ JNI回调
|
||||
NativeInterface (事件上报)
|
||||
↓
|
||||
HeadsetClientService (中转分发)
|
||||
↓ Event.type判断
|
||||
HeadsetClientStateMachine (业务处理)
|
||||
↓ 广播
|
||||
上层应用 BroadcastReceiver
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、蓝牙音乐流程
|
||||
|
||||
### 3.1 核心功能
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| 播放控制 | 播放/暂停/上一曲/下一曲 |
|
||||
| 音频焦点 | 与语音、导航、视频竞争焦点 |
|
||||
| 状态同步 | 播放状态同步给Launcher/投屏 |
|
||||
| 方控控制 | 方向盘按键控制音乐 |
|
||||
|
||||
### 3.2 焦点竞争场景
|
||||
|
||||
| 场景 | 处理 |
|
||||
|------|------|
|
||||
| 语音唤醒 | 蓝牙音乐暂停,释放焦点 |
|
||||
| 导航播报 | 蓝牙音乐降低音量/暂停 |
|
||||
| 视频播放 | 蓝牙音乐暂停 |
|
||||
| 倒车状态 | 蓝牙音乐暂停 |
|
||||
|
||||
---
|
||||
|
||||
## 四、通讯录同步流程
|
||||
|
||||
### 4.1 核心协议
|
||||
|
||||
| 协议 | 说明 |
|
||||
|------|------|
|
||||
| **PBAP** | Phone Book Access Profile,通讯录访问协议 |
|
||||
| **HFP** | Hands-Free Profile,电话免提协议 |
|
||||
|
||||
### 4.2 同步限制
|
||||
|
||||
| 类型 | 限制 |
|
||||
|------|------|
|
||||
| 通讯录 | 2500条,超出截断 |
|
||||
| 通话记录 | 50条 |
|
||||
|
||||
### 4.3 同步流程
|
||||
|
||||
```
|
||||
1. 连接蓝牙 → 触发PBAP连接请求
|
||||
2. 手机授权 → 开始拉取通讯录
|
||||
3. 分批接收 → 存入数据库
|
||||
4. 完成回调 → isPhoneBookPulling=false
|
||||
5. UI刷新 → 显示通讯录列表
|
||||
```
|
||||
|
||||
### 4.4 核心类
|
||||
|
||||
| 类名 | 作用 |
|
||||
|------|------|
|
||||
| BluetoothPbapClient | PBAP协议入口 |
|
||||
| BtContactsManager | 通讯录管理 |
|
||||
| isPhoneBookPulling | 同步状态标志 |
|
||||
|
||||
---
|
||||
|
||||
## 五、语音与蓝牙交互
|
||||
|
||||
### 5.1 语音控制蓝牙功能
|
||||
|
||||
| 功能 | 入口类 |
|
||||
|------|------|
|
||||
| 语音拨打电话 | VoiceEventHelper |
|
||||
| 语音拒接来电 | VoiceEventHelper |
|
||||
| 语音播放蓝牙音乐 | MediaProtocol |
|
||||
| 语音同步通讯录状态 | VoiceNewProtocolConst |
|
||||
|
||||
### 5.2 状态同步给语音
|
||||
|
||||
| 状态 | 同步方式 |
|
||||
|------|----------|
|
||||
| 蓝牙连接状态 | 广播通知语音 |
|
||||
| 来电状态 | 电话信息同步 |
|
||||
| 通讯录同步状态 | 页面打开/关闭状态 |
|
||||
|
||||
---
|
||||
|
||||
## 六、ACC电源处理
|
||||
|
||||
### 6.1 处理策略
|
||||
|
||||
| 场景 | 处理 |
|
||||
|------|------|
|
||||
| ACC OFF | 不主动断开蓝牙,保持原状态 |
|
||||
| ACC ON | 恢复连接状态,校验播放状态 |
|
||||
| 下电上电 | 播放按钮状态需重新同步 |
|
||||
|
||||
### 6.2 常见问题
|
||||
|
||||
| 问题 | 原因 | 解决 |
|
||||
|------|------|------|
|
||||
| 上电后显示播放但实际没播 | 状态未校验 | 检查实际播放状态 |
|
||||
| 进蓝牙音乐界面会暂停 | 状态未同步 | 延迟校验播放状态 |
|
||||
|
||||
---
|
||||
|
||||
## 七、核心代码类索引
|
||||
|
||||
### 7.1 电话相关
|
||||
|
||||
| 类名 | 路径 | 作用 |
|
||||
| ------------------------- | ------------ | ------ |
|
||||
| BluetoothHfpClient | YX_Bluetooth | 电话功能入口 |
|
||||
| HeadsetClientService | 系统应用 | 电话服务中转 |
|
||||
| HeadsetClientStateMachine | 系统应用 | 电话状态机 |
|
||||
|
||||
### 7.2 音乐相关
|
||||
|
||||
| 类名 | 作用 |
|
||||
| ------ | ----------------- |
|
||||
| 音频焦点管理 | AudioManager,焦点竞争 |
|
||||
| 投屏数据格式 | JSON格式传输给仪表 |
|
||||
|
||||
### 7.3 语音交互
|
||||
|
||||
| 类名 | 作用 |
|
||||
| --------------------- | ----------- |
|
||||
| VoiceEventHelper | 语音事件处理入口 |
|
||||
| MediaProtocol | 媒体协议,蓝牙音乐状态 |
|
||||
| VoiceNewProtocolConst | TXZ语音协议常量 |
|
||||
|
||||
---
|
||||
|
||||
## 八、常见问题快速定位
|
||||
|
||||
| 问题类型 | 关键类/方法 | 日志关键字 |
|
||||
|----------|-------------|------------|
|
||||
| 通讯录不同步 | BluetoothPbapClient.phoneBookPullRequest() | BtContactsManager, onContactsPullCompleted |
|
||||
| 音乐状态异常 | 音频焦点处理 | AudioManager, onFocusChange |
|
||||
| 语音拒接失败 | VoiceEventHelper拒接逻辑 | 蓝牙拒接, HFP |
|
||||
| ACC状态处理 | 电源状态监听 | ACC_OFF, ACC_ON |
|
||||
| 投屏数据异常 | JSON数据传输 | 投屏, DataCenter |
|
||||
| ANR问题 | 主线程阻塞 | ANR, SQLiteCursor |
|
||||
|
||||
---
|
||||
|
||||
## 九、开发注意事项
|
||||
|
||||
### 9.1 通讯录同步
|
||||
|
||||
- 完成后必须设置 `isPhoneBookPulling = false`
|
||||
- 同步过程需异步处理,避免阻塞UI
|
||||
- 通讯录超过2500条会截断
|
||||
|
||||
### 9.2 音频焦点
|
||||
|
||||
- 语音唤醒时蓝牙音乐必须释放焦点
|
||||
- 导航播报后需恢复播放状态
|
||||
- 倒车暂停需在倒车结束后恢复
|
||||
|
||||
### 9.3 ACC电源
|
||||
|
||||
- 不要在ACC OFF时主动断开蓝牙
|
||||
- 上电后需校验实际播放状态,避免状态不同步
|
||||
|
||||
### 9.4 UI适配
|
||||
|
||||
- 深色模式:联系人字母颜色需适配
|
||||
- 右舵项目:需单独布局资源
|
||||
- 12.3寸屏幕:需单独适配
|
||||
|
||||
---
|
||||
|
||||
## 十、参考文档
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [[蓝牙框架原理以及数据通讯交互流程.pdf]] | 蓝牙框架层级详解 |
|
||||
| [[蓝牙电话交互流程解析.pdf]] | 电话状态和调用流程 |
|
||||
| [[徐工项目蓝牙模块主流程.xlsx]] | 主流程表格 |
|
||||
| [[徐工项目蓝牙模块交接说明.docx]] | 交接说明文档 |
|
||||
| [[bluetooth_git_summary.md]] | Git提交记录汇总 |
|
||||
|
||||
---
|
||||
|
||||
## 十一、Git提交统计
|
||||
|
||||
> 统计时间: 2024-01-01 ~ 2026-05-06
|
||||
> 提交总数: 230条
|
||||
|
||||
| 功能模块 | 提交数 | 主要内容 |
|
||||
|----------|--------|----------|
|
||||
| 语音与蓝牙交互 | 35条 | 语音控制、状态同步、音频焦点 |
|
||||
| 蓝牙音乐 | 25条 | 播放状态、投屏、焦点控制 |
|
||||
| 蓝牙电话 | 40条 | 来电/去电、通话状态、投屏 |
|
||||
| 通讯录同步 | 30条 | 同步流程、UI交互 |
|
||||
| 连接状态管理 | 20条 | ACC处理、可见性、配对 |
|
||||
| UI适配 | 35条 | 深色模式、右舵、国际化 |
|
||||
| 国际化 | 15条 | 翻译、多语言 |
|
||||
| 代码优化 | 15条 | 工具类统一、构建优化 |
|
||||
| Bug修复 | 15条 | ANR、崩溃、空指针 |
|
||||
@@ -0,0 +1,103 @@
|
||||
# 蓝牙电话模块权限适配文档
|
||||
|
||||
## 一、权限 Key
|
||||
|
||||
| Key | 关联功能 |
|
||||
| -------------------------------------------- | ----------- |
|
||||
| `xcmg_permission_contacts_bluetooth_phone` | 联系人同步、通话记录 |
|
||||
| `xcmg_permission_microphone_bluetooth_phone` | 去电/接听时麦克风采集 |
|
||||
|
||||
值:`0` = 未授权,`1` = 已授权
|
||||
|
||||
读取方式:
|
||||
```java
|
||||
boolean authorized = Settings.System.getInt(
|
||||
context.getContentResolver(), "xcmg_permission_xxx", 0) == 1;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、权限关联逻辑
|
||||
|
||||
### 2.1 拨号键(去电前校验麦克风权限)
|
||||
|
||||
```
|
||||
点击拨号键
|
||||
│
|
||||
├── 麦克风权限 == 1 → 正常去电
|
||||
│
|
||||
└── 麦克风权限 == 0 → 弹出多权限勾选弹窗
|
||||
├── 勾选 + 确定授权 → 权限写入 → 正常去电
|
||||
└── 取消 → 不去电
|
||||
```
|
||||
|
||||
```java
|
||||
public void onDialClick(String phoneNumber) {
|
||||
if (!isMicAuthorized()) {
|
||||
showPermissionDialog(); // 发广播 ACTION_SHOW_MULTI_PERMISSION_DIALOG, package_name="com.yaxon.bluetooth"
|
||||
return;
|
||||
}
|
||||
doDial(phoneNumber);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 一键同步 / 刷新(同步前校验联系人权限)
|
||||
|
||||
```
|
||||
点击"一键同步" / "刷新"
|
||||
│
|
||||
├── 联系人权限 == 1 → 开始同步
|
||||
│
|
||||
└── 联系人权限 == 0 → 弹出多权限勾选弹窗
|
||||
├── 勾选 + 确定授权 → 权限写入 → 执行同步
|
||||
└── 取消 → 不执行同步
|
||||
```
|
||||
|
||||
```java
|
||||
public void onSyncClick() {
|
||||
if (!isContactsAuthorized()) {
|
||||
showPermissionDialog(); // 同上广播
|
||||
return;
|
||||
}
|
||||
doSyncContacts();
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 联系人权限控制的数据同步
|
||||
|
||||
联系人权限 == 0 时,不同步/存储联系人和通话记录到车机端。权限状态直接读 `Settings.System` 实时判断,无需回调。
|
||||
|
||||
---
|
||||
|
||||
## 三、弹窗触发方式
|
||||
|
||||
发送广播即可,CarControl 模块自动弹出对应权限的勾选框弹窗:
|
||||
|
||||
```java
|
||||
Intent intent = new Intent("com.yaxon.carcontrol.ACTION_SHOW_MULTI_PERMISSION_DIALOG");
|
||||
intent.putExtra("package_name", "com.yaxon.bluetooth");
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
context.sendBroadcast(intent);
|
||||
```
|
||||
|
||||
## 四、监听授权结果
|
||||
|
||||
如果需要授权后自动继续操作(如授权后自动拨号/同步),用 ContentObserver 监听:
|
||||
|
||||
```java
|
||||
private void registerPermissionObserver() {
|
||||
mObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
if (isMicAuthorized()) {
|
||||
doDial(mPendingPhoneNumber); // 授权后自动去电
|
||||
unregisterObserver();
|
||||
}
|
||||
}
|
||||
};
|
||||
context.getContentResolver().registerContentObserver(
|
||||
Settings.System.getUriFor("xcmg_permission_microphone_bluetooth_phone"),
|
||||
false, mObserver);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
# 徐工语音模块开发文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档记录徐工项目语音模块的开发调试相关内容,包括常用命令、协议定义、问题排查等。
|
||||
|
||||
---
|
||||
|
||||
## 常用调试命令
|
||||
|
||||
### 测试账号
|
||||
- 新账号:`T9999911`
|
||||
- 旧账号:`xgtest010002`
|
||||
|
||||
### 问题汇总文档
|
||||
[腾讯文档 - 徐工语音问题汇总](https://docs.qq.com/sheet/DRmh6ZXRVbGR4cFpk?tab=BB08J2)
|
||||
|
||||
### 电源模式设置
|
||||
```bash
|
||||
adb shell
|
||||
content insert --uri content://com.yaxon.data.provider/state/ --bind POWER_MODE:i:1
|
||||
```
|
||||
|
||||
### 缓存清理
|
||||
```bash
|
||||
# 清理同行者缓存
|
||||
adb shell pm clear com.txzing.voiceassistant
|
||||
|
||||
# 清理语音模块缓存
|
||||
adb shell pm clear com.yaxon.voice
|
||||
```
|
||||
|
||||
### 语音唤醒与调用
|
||||
```bash
|
||||
|
||||
# 直接调用语音指令
|
||||
adb shell am broadcast -a com.txznet.txz.invoke -d txznet://com.txznet.txz/comm.asr.startWithRawText?指令
|
||||
|
||||
|
||||
# 方控唤醒
|
||||
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?今天的天气"
|
||||
```
|
||||
|
||||
### 驾驶行为弹框 TTS 测试命令
|
||||
|
||||
| 测试命令 | 对应常量 | 弹框标题 | 弹框内容 |
|
||||
| --------------------------------------------------------- | -------------------------- | ------ | -------------------------------------------- |
|
||||
| adb shell am broadcast -a com.voice.test.tts.drowsy | `DROWSY_DRIVING` | `疲劳监测` | `您看起来有点累了,请注意休息!\n您可以说“稍后提醒”关闭弹窗` |
|
||||
| `adb shell am broadcast -a com.voice.test.tts.distracted` | `DISTRACTED_DRIVING` | `分心驾驶` | `为了您的骂驶安全,请集中注意力!\n您可以说“稍后提醒”关闭弹窗` |
|
||||
| `adb shell am broadcast -a com.voice.test.tts.smoking` | `SMOKING_RECKLESS_DRIVING` | `危险驾驶` | `主人,开车抽烟危险,请不要在开车时吸烟。\n您可以说“稍后提醒”关闭弹腐` |
|
||||
| `adb shell am broadcast -a com.voice.test.tts.calling` | `CALLING_RECKLESS_DRIVING` | `危险驾驶` | `开快车打电话很危险,下次可以对我说"给小明打电话"。\n您可以说“稍后提醒”关闭弹腐` |
|
||||
|
||||
### 工厂模式
|
||||
```bash
|
||||
adb shell am start com.yaxon.factory/.test.view.FactoryMainActivity
|
||||
```
|
||||
|
||||
### 日志过滤
|
||||
```bash
|
||||
# 过滤中间件报文日志
|
||||
processBodyControl
|
||||
|
||||
# 过滤语音模块日志
|
||||
package:com.yaxon.voice tag:sendCommandTxz tag:VoiceEventHelper
|
||||
|
||||
# 语音协议日志
|
||||
package:com.yaxon.voice VoiceProtocol
|
||||
|
||||
# 同行者状态同步日志
|
||||
package:com.txzing.voiceassistant tag:defaultRegisterHandler
|
||||
|
||||
# 过滤激活成功日志
|
||||
onActivationSuccess
|
||||
|
||||
# 过滤初始化日志
|
||||
initialize: versions
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 资源提交路径
|
||||
|
||||
### 同行者资源路径
|
||||
```
|
||||
Z:\znzc\034_xcmg\x9hp_xcmg\androd10_x9hp_ptg4.3p3\android10\vendor\yaxon\txz
|
||||
```
|
||||
|
||||
### 编译输出路径
|
||||
```
|
||||
Z:\znzc\034_xcmg\x9hp_xcmg\androd10_x9hp_ptg4.3p3\android10\out\target\product\x9hp_ms\obj\PACKAGING\target_files_intermediates\x9hp_ms-target_files-userdebug.znzc\SYSTEM\txz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 协议定义
|
||||
|
||||
### 车辆控制协议
|
||||
|
||||
| 功能 | 协议Key | CAN ID | 说明 |
|
||||
|------|---------|--------|------|
|
||||
| 自适应巡航控制模式 | FCS_AdpvCrsSetDstMod | 0x10FE6F2A | - |
|
||||
| 预警灵敏度 | FCS_FCWSnvtyFb | 0x18FFD02A | - |
|
||||
| 自动紧急制动 | FCS_AEBSt | 0xCF02FA0 | - |
|
||||
| 车道偏离预警 | FCS_LaneDepartureIndcnEnaSts | 0x18FE5B2A | - |
|
||||
| 车道偏离灵敏度 | FCS_LdwSnvtyFb | 0x18FFD02A | - |
|
||||
| 主驾车窗 | DDCM_DrvrWinPosn | 0x18F668EC | - |
|
||||
| 副驾车窗 | BDM_PassWinPosn | 0x18A12721 | - |
|
||||
|
||||
### 媒体控制协议
|
||||
|
||||
| 功能 | 协议Key | 参数 |
|
||||
|------|---------|------|
|
||||
| 上一首 | playPrev | `{"type":"music"}` |
|
||||
| 同步媒体焦点 | notifySyncMediaFocus | - |
|
||||
| 同步播放状态 | notifySyncFocusPlayStatus | - |
|
||||
|
||||
---
|
||||
|
||||
## 问题排查
|
||||
|
||||
### 录音唤醒问题
|
||||
1. 开启录音保存:
|
||||
```bash
|
||||
setprop persist.pcm.dump 9
|
||||
```
|
||||
|
||||
2. 讲话唤醒同行者,可以多讲几句
|
||||
|
||||
3. 关闭录音保存:
|
||||
```bash
|
||||
setprop persist.pcm.dump 0
|
||||
```
|
||||
|
||||
4. 录音文件路径:
|
||||
```
|
||||
/data/misc/audioserver/dump_audio_9.pcm
|
||||
```
|
||||
|
||||
> 注意:不及时关闭会导致录音文件持续增大
|
||||
|
||||
### 常见错误日志
|
||||
```
|
||||
tiplogRequestHandlerUtil: Request unsupported!, method = syncAcDefrostStatus
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关截图
|
||||
|
||||
### 语音界面
|
||||
![[语音图片/语音截图_1.png]]
|
||||
|
||||
![[语音图片/语音截图_2.png]]
|
||||
|
||||
![[语音图片/语音截图_3.png]]
|
||||
|
||||
![[语音图片/语音截图_4.png]]
|
||||
|
||||
### 资源路径
|
||||
![[语音图片/语音截图_5.png]]
|
||||
|
||||
![[语音图片/语音截图_6.png]]
|
||||
|
||||
![[语音图片/语音截图_7.png]]
|
||||
|
||||
### 协议相关
|
||||
![[语音图片/语音截图_8.png]]
|
||||
|
||||
![[语音图片/语音截图_9.png]]
|
||||
|
||||
![[语音图片/语音截图_10.png]]
|
||||
|
||||
![[语音图片/语音截图_11.png]]
|
||||
|
||||
### 状态同步
|
||||
![[语音图片/语音截图_12.png]]
|
||||
|
||||
![[语音图片/语音截图_13.png]]
|
||||
|
||||
![[语音图片/语音截图_14.png]]
|
||||
|
||||
![[语音图片/语音截图_15.png]]
|
||||
|
||||
![[语音图片/语音截图_16.png]]
|
||||
|
||||
![[语音图片/语音截图_17.png]]
|
||||
|
||||
![[语音图片/语音截图_18.png]]
|
||||
|
||||
![[语音图片/语音截图_19.png]]
|
||||
|
||||
![[语音图片/语音截图_20.png]]
|
||||
|
||||
![[语音图片/语音截图_21.png]]
|
||||
|
||||
---
|
||||
|
||||
*文档整理日期: 2026-05-27*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
你好,徐工, 车窗开一点 主驾有问题,副驾正常
|
||||
|
||||
|
||||
车窗全打开, 车窗关一点点 副驾是对的。主驾有问题
|
||||
@@ -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 通知路径。
|
||||
- 每个跨模块调用都有失败处理和日志。
|
||||
- 每次模块变更都在本文件记录影响范围和验证方式。
|
||||
@@ -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 |
|
||||
@@ -0,0 +1,174 @@
|
||||
# 语音唤醒异常问题分析
|
||||
|
||||
## 概述
|
||||
|
||||
本文档记录从日志文件推断ADB命令的分析流程,用于语音唤醒异常问题的排查。
|
||||
|
||||
---
|
||||
|
||||
## 分析案例
|
||||
|
||||
### 输入:log 录音分析.md
|
||||
|
||||
**文件特征:**
|
||||
- 文件大小:578KB
|
||||
- 行数:9001行
|
||||
- 无直接adb命令记录
|
||||
|
||||
### 分析步骤
|
||||
|
||||
#### 1. 查看文件开头内容
|
||||
|
||||
```text
|
||||
pid: 3211
|
||||
pid: 3294
|
||||
...
|
||||
Output thread 0xf2164c184c40, name AudioOut_D, tid 3103, type 0 (MIXER):
|
||||
I/O handle: 13
|
||||
Sample rate: 48000 Hz
|
||||
HAL format: 0x1 (AUDIO_FORMAT_PCM_16_BIT)
|
||||
Channel count: 8
|
||||
...
|
||||
```
|
||||
|
||||
#### 2. 识别日志类型
|
||||
|
||||
根据关键内容特征判断:
|
||||
|
||||
| 特征 | 内容示例 | 判断 |
|
||||
|------|----------|------|
|
||||
| 线程信息 | Output thread, Input thread | AudioFlinger dump |
|
||||
| 音频参数 | Sample rate, HAL format, Channel count | 音频系统状态 |
|
||||
| 设备信息 | AUDIO_DEVICE_OUT_BUS | 音频设备配置 |
|
||||
| 时间戳统计 | Timestamp stats, jitterMs | 性能数据 |
|
||||
|
||||
**结论:** 这是一份 AudioFlinger 服务 dump 日志
|
||||
|
||||
#### 3. 推断ADB命令
|
||||
|
||||
根据日志类型推断:
|
||||
|
||||
| 日志类型 | 推断命令 |
|
||||
| ----------------- | --------------------------------------- |
|
||||
| AudioFlinger dump | `adb shell dumpsys media.audio_flinger` |
|
||||
| AudioPolicy dump | `adb shell dumpsys media.audio_policy` |
|
||||
| 完整音频状态 | `adb shell dumpsys audio` |
|
||||
|
||||
---
|
||||
|
||||
## 常见音频Dump命令汇总
|
||||
|
||||
| 命令 | 说明 | 应用场景 |
|
||||
| --------------------------------------- | ---------------- | --------- |
|
||||
| `adb shell dumpsys media.audio_flinger` | AudioFlinger服务状态 | 录音/播放问题排查 |
|
||||
| `adb shell dumpsys media.audio_policy` | 音频策略服务状态 | 设备切换问题排查 |
|
||||
| `adb shell dumpsys audio` | 完整音频系统状态 | 全面音频问题排查 |
|
||||
| `adb shell dumpsys media.camera` | 摄像头服务状态 | 摄像头问题排查 |
|
||||
|
||||
---
|
||||
|
||||
## AudioFlinger Dump关键字解读
|
||||
|
||||
### Output Thread(输出线程)
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| Sample rate | 采样率(如48000Hz) |
|
||||
| HAL format | 硬件音频格式(PCM_16_BIT) |
|
||||
| Channel count | 通道数 |
|
||||
| Channel mask | 通道掩码 |
|
||||
| Output device | 输出设备(如AUDIO_DEVICE_OUT_BUS) |
|
||||
| Frames written | 已写入帧数 |
|
||||
|
||||
### Input Thread(输入线程)
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| Audio source | 音频源(如AUDIO_SOURCE_MIC) |
|
||||
| Input device | 输入设备 |
|
||||
| Frames read | 已读取帧数 |
|
||||
|
||||
### Timestamp Stats(时间戳统计)
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| jitterMs | 抖动(毫秒) |
|
||||
| localSR | 本地采样率 |
|
||||
| err | 错误计数 |
|
||||
|
||||
---
|
||||
|
||||
## 问题排查流程
|
||||
|
||||
### 语音唤醒异常排查步骤
|
||||
|
||||
1. **开启录音保存**
|
||||
```bash
|
||||
setprop persist.pcm.dump 9
|
||||
```
|
||||
|
||||
2. **触发语音唤醒**
|
||||
- 讲话唤醒同行者
|
||||
- 可多次尝试
|
||||
|
||||
3. **获取音频系统状态**
|
||||
```bash
|
||||
adb shell dumpsys media.audio_flinger > audio_flinger.log
|
||||
adb shell dumpsys audio > audio.log
|
||||
```
|
||||
|
||||
4. **关闭录音保存**
|
||||
```bash
|
||||
setprop persist.pcm.dump 0
|
||||
```
|
||||
|
||||
5. **提取录音文件**
|
||||
```bash
|
||||
adb pull /data/misc/audioserver/dump_audio_9.pcm
|
||||
```
|
||||
|
||||
### 分析要点
|
||||
|
||||
| 问题类型 | 检查内容 |
|
||||
|----------|----------|
|
||||
| 无法唤醒 | Input thread状态、Frames read计数 |
|
||||
| 声音异常 | jitterMs抖动、err错误计数 |
|
||||
| 设备问题 | Input/Output device配置 |
|
||||
| 格式问题 | HAL format、Sample rate |
|
||||
|
||||
---
|
||||
|
||||
## 从日志推断命令的方法总结
|
||||
|
||||
### 判断流程
|
||||
|
||||
```
|
||||
1. 查看文件开头内容
|
||||
↓
|
||||
2. 识别关键特征字段
|
||||
↓
|
||||
3. 对照常见dump格式
|
||||
↓
|
||||
4. 推断具体adb命令
|
||||
```
|
||||
|
||||
### 特征对照表
|
||||
|
||||
| 日志特征 | 对应命令 |
|
||||
|----------|----------|
|
||||
| Output/Input thread | dumpsys media.audio_flinger |
|
||||
| AudioPolicy相关 | dumpsys media.audio_policy |
|
||||
| ActivityManager | dumpsys activity |
|
||||
| PackageManager | dumpsys package |
|
||||
| SurfaceFlinger | dumpsys SurfaceFlinger |
|
||||
|
||||
---
|
||||
|
||||
## 参考文件
|
||||
|
||||
- [[项目文档/徐工/log 录音分析.md]] - 原始日志文件
|
||||
- [[项目文档/徐工/语音.md]] - 语音模块开发文档
|
||||
|
||||
---
|
||||
|
||||
*文档整理日期: 2026-05-27*
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 301 KiB |
|
After Width: | Height: | Size: 270 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
@@ -0,0 +1,27 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
This repository is a multi-module Android project defined in `settings.gradle`. App modules such as `YX_Voice`, `YX_Radio`, `YX_Factory`, and `YX_SystemUI` follow the standard `src/main`, `src/test`, and `src/androidTest` layout. Shared code lives in SDK and base modules like `YX_BluetoothSDK`, `YX_AutoMotiveSDK`, `YX_Lib_CommonBase`, and `YX_Lib_UIStyleBase`. Prebuilt platform jars are stored in `sdklibs/`, generated APKs are copied into `third_apps/<Module>/`, and root scripts such as `build_apk.sh` handle CI-oriented packaging.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
Use the Gradle wrapper from the repository root.
|
||||
|
||||
- `.\gradlew clean` clears root and module build outputs.
|
||||
- `.\gradlew :YX_Voice:assembleDebug` builds one app module for local iteration.
|
||||
- `.\gradlew :YX_BluetoothSDK:testDebugUnitTest` runs one module's JVM tests.
|
||||
- `.\gradlew :YX_Factory:connectedDebugAndroidTest` runs instrumentation tests on a connected device.
|
||||
- `bash build_apk.sh debug` or `bash build_apk.sh release` performs the multi-APK packaging flow used for `third_apps/`.
|
||||
|
||||
Prefer module-scoped commands over full-repo builds because the workspace is large.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
Follow existing Android Java and Gradle conventions: 4-space indentation, braces on the same line, `UpperCamelCase` for classes, `lowerCamelCase` for methods and fields, and `SCREAMING_SNAKE_CASE` for constants. Keep package names under `com.yaxon...` or the existing module namespace. Name resources by type and feature, such as `activity_back_car.xml`, `ic_launcher.png`, or `radio_widget_info.xml`.
|
||||
|
||||
## Testing Guidelines
|
||||
Unit tests live under `src/test/java`; device tests live under `src/androidTest/java`. Existing test classes use the `ExampleUnitTest` and `ExampleInstrumentedTest` pattern, but new tests should use feature-specific names such as `BluetoothPbapClientTest`. Add or update tests for module behavior changes when practical, especially in shared SDK modules.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
Recent history uses scoped subjects like `feat(YX_SystemUI): ...`, `fix(YX_Radio): ...`, and `modify(YX_Voice): ...`. Keep that format: `<type>(<module>): <summary>`. Pull requests should state the affected modules, user-visible behavior changes, test coverage or device validation performed, and screenshots when UI layouts or drawables change.
|
||||
|
||||
## Security & Configuration Tips
|
||||
Do not commit real secrets, device-specific `local.properties`, or modified signing material. `config.gradle` currently references shared signing and SDK paths, so treat local environment changes as workstation-only unless the team explicitly standardizes them.
|
||||
@@ -0,0 +1,159 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
车载 Android 应用系统,多模块架构。主要模块包括语音助手、车控、媒体、系统UI等。当前分支 `develop_xcmg` 为徐工(xcmg)项目开发分支。
|
||||
|
||||
## Build Commands
|
||||
|
||||
```bash
|
||||
# 编译单个模块 (Debug)
|
||||
./gradlew :YX_Voice:assembleDebug
|
||||
./gradlew :YX_CarControl:assembleDebug
|
||||
|
||||
# 编译单个模块 (Release)
|
||||
./gradlew :YX_Voice:assembleRelease
|
||||
|
||||
# 清理构建
|
||||
./gradlew clean
|
||||
|
||||
# 全量编译所有 APK (使用脚本)
|
||||
./build_apk.sh # Debug 版本
|
||||
./build_apk.sh release # Release 版本
|
||||
|
||||
# 编译 YX_Support jar 包
|
||||
./gradlew makejar # 输出到 YX_Support/build/libs/
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### 模块分层结构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ Application Layer (应用层) │
|
||||
│ YX_Voice | YX_CarControl | YX_Music | YX_Radio | YX_Video | ... │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ SDK Layer (SDK层) │
|
||||
│ YX_AutoMotiveSDK | YX_IPC_SDK | YX_MediaSDK | YX_MusicSDK | ... │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ Base Library (基础库层) │
|
||||
│ YX_Lib_CommonBase | YX_Lib_UIStyleBase | YX_Support │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 跨进程通信 (YxIPC)
|
||||
|
||||
核心跨进程通信机制,位于 `YX_IPC_SDK` 模块。
|
||||
|
||||
**使用方式:**
|
||||
```java
|
||||
// 初始化 (Application.onCreate)
|
||||
YxIPC.getInstance().bind(application, ipcConfig);
|
||||
|
||||
// 发送消息 (无回调)
|
||||
YxIPC.getInstance().sendRemoteNoCall(remotePackage, bundle);
|
||||
|
||||
// 发送消息 (有回调)
|
||||
YxIPC.getInstance().sendRemoteByCall(remotePackage, bundle, sessionId, callback);
|
||||
|
||||
// 注册消息监听
|
||||
YxIPC.getInstance().addMessageListener(messageListener);
|
||||
```
|
||||
|
||||
**关键类:** `YxIPC.java`, `YxMessenger.java`, `MessageListener.java`
|
||||
|
||||
### 语音模块架构 (YX_Voice)
|
||||
|
||||
语音助手模块,与同行者(TXZ)语音服务通信。
|
||||
|
||||
**核心类:**
|
||||
| 类 | 路径 | 职责 |
|
||||
|---|------|------|
|
||||
| VoiceManager | core/VoiceManager.java | 单例管理器,包含 VoiceEventHelper 实例 |
|
||||
| VoiceEventHelper | helper/VoiceEventHelper.java | 事件处理核心,所有语音操作入口 |
|
||||
| ProtocolManager | core/ProtocolManager.java | IPC 协议分发器 |
|
||||
| YxProtocolHandler | core/YxProtocolHandler.java | 根据包名分发协议到对应 Protocol |
|
||||
| VoiceProtocol | protocol/VoiceProtocol.java | TXZ 协议解析 |
|
||||
| CarControlProtocol | protocol/CarControlProtocol.java | 车控状态同步协议 |
|
||||
|
||||
**协议常量 (两套):**
|
||||
- `VoiceNewProtocolConst.java` (YX_Voice) - TXZ 协议常量,与语音服务通信
|
||||
- `VoiceNewConstant.java` (YX_Lib_CommonBase) - IPC 协议常量,模块间通信
|
||||
|
||||
### 车控模块 (YX_CarControl)
|
||||
|
||||
车辆硬件控制模块。
|
||||
|
||||
**关键类:**
|
||||
- `VoiceSettingManager.java` - 语音控制入口,接收 IPC 消息调用硬件
|
||||
- `CarControlsManager` (YX_AutoMotiveSDK) - 硬件控制 API
|
||||
|
||||
## Module Dependencies
|
||||
|
||||
模块间依赖关系 (典型):
|
||||
|
||||
```
|
||||
YX_Voice → YX_IPC_SDK → YX_Lib_CommonBase → YX_Support
|
||||
YX_Voice → YX_AutoMotiveSDK → (framework_classes.jar)
|
||||
YX_CarControl → YX_IPC_SDK → YX_Lib_CommonBase
|
||||
YX_CarControl → YX_SettingSDK → YX_AutoMotiveSDK
|
||||
```
|
||||
|
||||
**平台 SDK:**
|
||||
- `sdklibs/framework_classes.jar` - Android framework 类 (需要 hidden API)
|
||||
- `sdklibs/yx_support_classes.jar` - YX_Support 编译输出
|
||||
- `sdklibs/android.car.jar` - Android Car API
|
||||
|
||||
## Protocol Flow
|
||||
|
||||
语音控制指令流向:
|
||||
```
|
||||
TXZ语音 → VoiceProtocol → VoiceEventHelper → YxIPC → VoiceSettingManager → CarControlsManager → 硬件
|
||||
```
|
||||
|
||||
状态同步流向:
|
||||
```
|
||||
硬件 → CarControlsControllerCallBack → VoiceSettingManager → YxIPC → CarControlProtocol → VoiceEventHelper → TXZ
|
||||
```
|
||||
|
||||
## Package Names
|
||||
|
||||
主要模块包名:
|
||||
| 模块 | 包名 |
|
||||
|------|------|
|
||||
| YX_Voice | com.yaxon.voice |
|
||||
| YX_CarControl | com.yaxon.carcontrol |
|
||||
| TXZ语音 | com.txzing.voiceassistant |
|
||||
| YX_Music | com.yaxon.music |
|
||||
| YX_Radio | com.yaxon.radio |
|
||||
| YX_Hvac | com.yaxon.hvac |
|
||||
| YX_Launcher | com.yaxon.launcher |
|
||||
| YX_SystemUI | com.android.systemui |
|
||||
|
||||
## Signing
|
||||
|
||||
使用平台签名 (platform.jks):
|
||||
- 密钥别名: yx
|
||||
- 密钥密码: yx123456
|
||||
- 所有模块共用同一签名配置 (config.gradle)
|
||||
|
||||
## Branch Information
|
||||
|
||||
- `develop_xcmg` - 徐工项目 (当前分支)
|
||||
- `x9hp_dw` - 三一项目
|
||||
- `master` - 主分支
|
||||
|
||||
## Special Notes
|
||||
|
||||
1. **编译环境:** BuildTools 30.0.3, Gradle Plugin 4.1.3, compileSdk 29
|
||||
2. **平台 API:** 需要 `sdklibs/framework_classes.jar` 访问 hidden API
|
||||
3. **混淆:** Release 版本开启混淆 (minifyEnabled true)
|
||||
4. **输出路径:** Release APK 输出到 `third_apps/<ModuleName>/`
|
||||
5. **语音唤醒广播:** `YXUtils.ACTION_START_TXZVOICE` / `android.intent.action.start_txzvoice`
|
||||
@@ -0,0 +1,58 @@
|
||||
百度Deepway开发版本;
|
||||
|
||||
**编译yx_support指令**
|
||||
1.应用源码根目录下执行指令:gradlew makejar(可直接在AS上的Terminal中输入该指令)
|
||||
2.生成路径:YX_Support/build/libs
|
||||
|
||||
基于三一项目的开发分支建立的分支进行开发;
|
||||
|
||||
|
||||
U盘升级程序编译步骤:
|
||||
1、进入项目根目录:/sanyi/tangzhigang/android10_x9hp/(以caiqinghui服务器为例)执行:
|
||||
./build.sh all
|
||||
./build.sh pac
|
||||
|
||||
2、进入semdrive 的编译目录:/sanyi/tangzhigang/android10_x9hp/vendor/semidrive/rtos 执行:
|
||||
source ./setenv.sh
|
||||
make ota
|
||||
|
||||
编译完成后输出升级程序目录:
|
||||
\sanyi\tangzhigang\android10_x9hp\vendor\semidrive\rtos\ota_X9HP_Ref_Isolation_Android_Linux_Serdes_8G_3200
|
||||
|
||||
该目录会有两个文件:x9hp_ref-ota.zip、x9hp_ref-target_files.zip 将x9hp_ref-ota.zip文件拷到U盘根目录升级即可;
|
||||
|
||||
|
||||
外部按键/方向盘唤醒或关闭语音,通过广播方式:
|
||||
1.唤醒语音广播:YXUtils.ACTION_START_TXZVOICE 或者 “android.intent.action.start_txzvoice”
|
||||
2.关闭语音广播:YXUtils.ACTION_CLOSE_TXZVOICE 或者 “android.intent.action.close_txzvoic”
|
||||
|
||||
三一编译版本拉取代码步骤:
|
||||
1.拉取主仓库代码:
|
||||
1)git reset HEAD --hard
|
||||
2)git pull origin x9hp_dw
|
||||
|
||||
2.进入yx_app目录后拉取应用层代码
|
||||
1)git reset HEAD --hard
|
||||
2)git pull
|
||||
|
||||
请按照上诉步骤拉取代码,防止代码修改未编译进去!!!
|
||||
|
||||
样机选择操作:
|
||||
1、进入Z:\znzc\014_sanyi\android10_x9hp\vendor\semidrive\rtos\rtos\lk_boot\exdev\lcm\max96xxx\src\文件夹;
|
||||
2、编辑max96789.c文件 修改如下对应数据:
|
||||
#define BOARD_B1_EN 1 // B1
|
||||
#define BOARD_B1_EN 0 // A1
|
||||
|
||||
关于字体修改:
|
||||
1.当前全局默认是 思源黑体 CN Normal
|
||||
常规:setTypeface(Typeface.DEFAULT, Typeface.NORMAL);
|
||||
加粗:setTypeface(Typeface.DEFAULT, Typeface.BOLD);
|
||||
|
||||
2.DINPro 关于字体修改
|
||||
常规:setTypeface(Typeface.DINPro, Typeface.NORMAL);
|
||||
加粗:setTypeface(Typeface.DINPro, Typeface.BOLD);
|
||||
|
||||
工程模式密码:
|
||||
高权限密码:xgroot+系统年月日(例xgroot20260606)
|
||||
低权限密码:xg+系统年月日(例xg20260606)
|
||||
注:不同密码看到的工程模式功能列表不同
|
||||
@@ -0,0 +1,825 @@
|
||||
# agent.md
|
||||
|
||||
## 当前阶段
|
||||
|
||||
- 2026-06-05:排查并优化蓝牙通讯录/通话记录权限与同步 UI 状态。
|
||||
|
||||
## 已验证结论
|
||||
|
||||
- 清空蓝牙本地 SQLite 表不是通讯录同步失败的直接原因;正常清空后 PBAP 同步会重新写入。
|
||||
- 日志中偶现的 `ConcurrentModificationException` 指向联系人保存阶段共享列表被并发访问,属于同步完成后保存/回调链路稳定性问题。
|
||||
- 2026-06-06 新复测日志 `2026_0606_1105_50_063.log` 显示 UI 修复生效:
|
||||
- 未出现 `Dex checksum does not match`
|
||||
- 未出现 `ConcurrentModificationException`、`onContactsPullFailed`、`通讯录同步失败`
|
||||
- 同步中 `ContactsFragment` 保持 `isPhoneBookSynchronized=false isPhoneBookPulling=true`
|
||||
- 最终 `11:08:28.044` 收到 `ContactListViewModel: onContactsPhoneBook = 1973`
|
||||
- `2026_0606_1105_50_063.log` 同时确认双进程重复同步:
|
||||
- `11:06:32.967` `com.yaxon.carcontrol` PID 3859 触发 `phoneBookPullRequest`
|
||||
- `11:06:32.977` `com.yaxon.bluetooth` PID 4968 触发 `phoneBookPullRequest`
|
||||
- 两个进程都收到 `onContactsPullCompleted`、读取 `1973` 条、执行 `deleteContacts`
|
||||
- 2026-06-06 复测日志 `2026_0606_1136_51_087.log` 确认移除 `YX_CarControl` 联系人/PBAP 初始化后双进程重复同步已消失:
|
||||
- PID 3793 为 `com.yaxon.carcontrol`,只出现配对弹窗和自动同步开关日志,未出现 `BtContactsControlManager`
|
||||
- PID 5101 为 `com.yaxon.bluetooth`,唯一执行 `BluetoothPbapClient: phoneBookPullRequest`
|
||||
- 联系人同步成功:`11:38:25.186 contacts read completed size = 1973`,`11:38:41.378 onContactsPhoneBook = 1973`
|
||||
- 通话记录同步成功:`11:38:02.223 mCallRecordBeanList size = 51`,`11:38:02.953 notifyPhoneRecordList list == 51`
|
||||
- 未出现 `ConcurrentModificationException`、`onContactsPullFailed`、`通讯录同步失败`、`Dex checksum does not match`
|
||||
- 2026-06-06 用户现场验证 `2026_0606_1136_51_087.log` 对应 UI 表现符合预期:
|
||||
- 点击下载通讯录后联系人页显示“正在加载通讯录”
|
||||
- 切到通话页面时通话列表可正常显示
|
||||
- 再切回联系人页面后通讯录正常显示
|
||||
- 说明联系人同步中的空列表中间态已被 loading 承接,未再误显示 0 个联系人
|
||||
- 2026-06-06 现场重新清理 logcat 后复测,导出日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\verify_2026_0606_1348_32_838.log`:
|
||||
- `com.yaxon.carcontrol` PID 3957 只出现配对弹窗/自动同步开关日志,未出现 `BtContactsControlManager`
|
||||
- `com.yaxon.bluetooth` PID 5030 唯一执行 `BluetoothPbapClient: phoneBookPullRequest`
|
||||
- 通讯录流程成功:`12:40:35.640 phoneBookPullRequest`,`12:41:22.565 onContactsPullCompleted`,`12:41:51.884 contacts read completed size = 1973`
|
||||
- 通话记录流程成功:`12:41:27.963 mCallRecordBeanList size = 51`,`12:41:28.665 notifyPhoneRecordList list == 51`
|
||||
- 用户切回联系人页后读取并显示成功:`12:44:48.892 onContactsPhoneBook = 1973`,`isPhoneBookSynchronized = true isPhoneBookPulling=false`
|
||||
- 未出现 `ConcurrentModificationException`、`onContactsPullFailed`、`通讯录同步失败`、`Dex checksum does not match`
|
||||
- 2026-06-06 用户再次点击“同步通讯录”后复测,导出日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\verify_resync_2026_0606_1352_02_395.log`:
|
||||
- 再次点击会重新触发一次 PBAP 通讯录同步:`12:47:06.124 BluetoothPbapClient: phoneBookPullRequest`
|
||||
- 仍然只有 `com.yaxon.bluetooth` PID 5030 执行同步,`BtContactsControlManager = 0`
|
||||
- 第二次同步成功:`12:47:50.259 onContactsPullCompleted`,`13:51:27.509 contacts read completed size = 1973`,`13:51:45.832 onContactsPhoneBook = 1973`
|
||||
- 第二次通话记录也成功刷新:`12:47:55.391 mCallRecordBeanList size = 51`,`12:47:55.982 notifyPhoneRecordList list == 51`
|
||||
- 日志中出现设备时间从 `06-05 12:47` 跳到 `06-06 13:51` 的校时现象,因此第二次同步耗时不能直接按日志墙钟计算
|
||||
- 未出现 `ConcurrentModificationException`、`onContactsPullFailed`、`通讯录同步失败`、`Dex checksum does not match`
|
||||
- 2026-06-06 清空 logcat 后再次点击“同步通讯录”复测,导出日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\verify_resync_clean_2026_0606_1355_54_369.log`,补抓尾部 `verify_resync_clean_tail_2026_0606_1356_44_383.log`:
|
||||
- 本轮无时间跳变,可计算耗时:`13:54:40.708 phoneBookPullRequest` 到 `13:56:06.301 onContactsPhoneBook = 1973`,约 85.6 秒
|
||||
- PBAP 拉取阶段:`13:54:40.708` 到 `13:55:24.857 onContactsPullCompleted`,约 44.1 秒
|
||||
- 联系人读取阶段:`13:55:24.926 cursor.getCount() = 1973` 到 `13:55:51.351 contacts read completed size = 1973`,约 26.4 秒
|
||||
- 写库/页面回调阶段:`13:55:51.352 deleteContacts` 到 `13:56:06.301 onContactsPhoneBook = 1973`,约 14.9 秒
|
||||
- `BtContactsControlManager = 0`,`BluetoothPairedRequestView = 0`,说明手动同步未经过 `YX_CarControl` 配对弹窗
|
||||
- 未出现 `ConcurrentModificationException`、`onContactsPullFailed`、`通讯录同步失败`、`Dex checksum does not match`
|
||||
- 2026-06-06 通话页 loading UI 修复后复测日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0606_1405_50_910.log`:
|
||||
- 新逻辑已生效:切回通话页时出现 `CallLogsFragment: onHiddenChanged hidden=false` 后紧跟 `setIsBtConnect=true`
|
||||
- 通话记录同步完成:`14:07:31.863 mCallRecordBeanList size = 51`,`14:07:32.670 notifyPhoneRecordList list == 51`
|
||||
- 通讯录同步完成:`14:07:56.555 contacts read completed size = 1973`,`14:08:14.822 onContactsPhoneBook = 1973`
|
||||
- 切回通话页时即使 `isPhoneBookPulling=true`,日志仍显示 `CallRecordUpdated = true` 并刷新 `notifyPhoneRecordList list == 51`
|
||||
- 本轮未出现 `ConcurrentModificationException`、`onContactsPullFailed`、`通讯录同步失败`
|
||||
- 本轮出现 `Dex checksum does not match`,推测为系统 APK 覆盖推送后旧 dex/oat 缓存未刷新,需重启设备或清理对应编译缓存后再做最终确认
|
||||
- 2026-06-06 重新加载/重启后复测日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0606_1413_21_443.log`,补抓尾部 `tail_after_2026_0606_1413_21_443_2026_0606_1416_43_579.log`:
|
||||
- 未再出现 `Dex checksum does not match`
|
||||
- 通话页切回刷新逻辑生效:`CallLogsFragment: onHiddenChanged hidden=false` 后出现 `setIsBtConnect=true`
|
||||
- 通话记录同步完成:`14:14:39.747 mCallRecordBeanList size = 51`,`14:14:40.416 notifyPhoneRecordList list == 51`
|
||||
- 通讯录同步完成:`14:15:06.632 contacts read completed size = 1973`,补抓尾部 `14:15:22.731 onContactsPhoneBook = 1973`
|
||||
- PBAP 断开完成:`14:15:22.821 prevState = 2 state = 3`,`14:15:22.886 prevState = 3 state = 0`
|
||||
- 本轮未出现 `ConcurrentModificationException`、`onContactsPullFailed`、`通讯录同步失败`
|
||||
- `2026_0605_1739_21_177.log` 中“先显示 0 个联系人,随后显示联系人列表”的原因不是同步失败,而是 UI 状态提前:
|
||||
- `17:40:48.576` 收到 `BtContactsManager: onContactsPullCompleted`
|
||||
- `17:40:48.623` 系统联系人 Provider 查到 `1973` 条
|
||||
- `17:41:19.867` SDK 读联系人完成:`contacts read completed size = 1973`
|
||||
- `17:41:30.114` 页面判断 `isPhoneBookSynchronized = true isPhoneBookPulling=true`
|
||||
- `17:41:36.979` ViewModel 才收到 `onContactsPhoneBook = 1973`
|
||||
- `isPhoneBookSynchronized()` 只查 DB 是否存在 1 条联系人;保存大量联系人时第一条写入后就可能返回 true,导致联系人页提前显示空列表区域。
|
||||
|
||||
## Bug 与修复记录
|
||||
|
||||
- 2026-06-09 蓝牙音乐封面继续扩展到 `YX_SystemUI` / `YX_Launcher`:
|
||||
- 用户确认先备份,已备份 `DisplayShareViewModel.java`、`MediaControlView.java`、`WidgetsMedia.java` 到 `.codex_backup\music_cover_systemui_launcher_20260609_194529`
|
||||
- 最新日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0609_1939_16_256.log` 显示 `YX_Music` 已能在封面文件稳定后加载成功,剩余问题集中在 SystemUI/Launcher 空 `albumUrl` 或无效文件覆盖已有封面
|
||||
- `YX_SystemUI` 的 `MediaControlView` 增加蓝牙曲目 key 与封面显示状态:同一首歌收到空 `albumUrl` 或无效文件时保留当前封面;新歌收到空/无效封面时显示默认图,避免继续显示上一首封面
|
||||
- `YX_Launcher` 的 `WidgetsMedia` 按相同规则处理手写 widget 封面逻辑,并避免 `BitmapFactory.decodeFile()` 直接解码空路径
|
||||
- `YX_Launcher` 的 `DisplayShareViewModel.btMusicAlbum` 数据绑定入口增加 lastAlbum 缓存:同一首歌后续空路径/0 字节/解码失败时返回当前封面,新歌无有效封面时返回默认图
|
||||
- 已执行 `.\gradlew :YX_SystemUI:assembleDebug` 和 `.\gradlew :YX_Launcher:assembleDebug`,均编译通过
|
||||
- 已推送 `YX_SystemUI.apk` 到 `/system/app/YX_SystemUI/YX_SystemUI.apk`,推送 `YX_Launcher.apk` 到 `/system/app/YX_Launcher/YX_Launcher.apk`,并执行设备重启;重启后 `sys.boot_completed=1`,两个包路径正常
|
||||
- 2026-06-08 蓝牙音乐封面短暂显示后消失问题:
|
||||
- 最新日志显示 SDK 可收到 `albumUrl = /sdcard/ID3/id3cover.JPEG`,但 `YX_Music` 侧多次出现 `Failed to create image decoder` 和 `BluetoothMusicViewModel: 获取bitmap为null`
|
||||
- `YX_BluetoothSDK` 只转发系统蓝牙 `MediaMetadata.METADATA_KEY_ALBUM_ART_URI`,未发现生成 `/sdcard/ID3/id3cover.JPEG` 的逻辑
|
||||
- `YX_Music` 已调整封面加载兜底:先解码新图片,成功后再替换并回收旧图;解码失败时如果当前已有文件封面则保留当前封面
|
||||
- `BluetoothMusicFragment` 已调整空 `albumUrl` 处理:当前没有文件封面时才显示默认图,避免元数据短暂空值覆盖已有封面
|
||||
- 2026-06-08 最新日志 `2026_0608_1939_20_273.log` 确认 `/sdcard/ID3/id3cover.JPEG` 文件存在且可读,但长度始终为 0:
|
||||
- `BluetoothMusicViewModel: 获取bitmap为null, filePath = /sdcard/ID3/id3cover.JPEG, exists = true, length = 0, canRead = true`
|
||||
- 本轮日志中 `length 0 = 53`,未发现非 0 字节封面文件
|
||||
- `YX_BluetoothSDK` 已做最小颗粒过滤:`BtMusicManager` 和 `BtInfoPushManager` 下发封面前校验本地文件路径,0 字节/不可读/不存在的封面路径不再下发
|
||||
- 同时增加 `ALBUM_ART_URI`、`ART_URI`、`DISPLAY_ICON_URI`、`ALBUM_ART`、`ART` 字段诊断日志,暂不做 bitmap 落盘,避免扩大改动
|
||||
- 2026-06-08 最新日志 `2026_0608_1958_40_593.log` 确认切歌后封面路径晚于歌曲信息到达:
|
||||
- 点击下一首后,歌名通常先到,`albumUrl` 为空;约 2 到 4 秒后才出现固定路径 `/sdcard/ID3/id3cover.JPEG`
|
||||
- 由于系统复用同一个固定封面文件,过早解码可能读到上一首封面内容,导致“先显示上一首,过会儿显示正确”
|
||||
- `BluetoothMusicFragment` 已增加切歌封面调度:切歌或曲目 key 变化时先显示默认封面;固定 ID3 封面路径延迟 1 秒解码;使用版本号取消旧封面延迟任务
|
||||
- 2026-06-09 继续分析日志 `2026_0608_2015_49_223.log`,确认 1 秒延迟仍不足以规避固定封面文件重写竞态:
|
||||
- `skip invalid album file = 111`,说明 `YX_BluetoothSDK` 的 0 字节过滤已生效
|
||||
- `BluetoothMusicViewModel: 获取bitmap为null = 8`,说明 `YX_Music` 延迟解码时仍可能撞上 `/sdcard/ID3/id3cover.JPEG` 被底层清零或半写入
|
||||
- 典型时序:`20:18:11.761` 底层开始 `get image`,`20:18:11.803` SDK 检测 `length = 0` 并过滤,`20:18:11.808` `YX_Music` 解码同一路径失败,`20:18:12.294` 底层才提示 `avrcp image download succeed`
|
||||
- 根因是 `/sdcard/ID3/id3cover.JPEG` 为底层复用固定路径,单次下发时校验和页面实际解码之间仍存在文件重写竞态
|
||||
- 本轮按用户要求先只修改 `YX_Music`:`BluetoothMusicFragment` 对固定 ID3 封面路径增加文件刷新检测、连续两次长度/修改时间稳定后再解码、最多 20 次 300ms 重试;切歌/上一首/下一首时重置检测状态并先显示默认封面
|
||||
- `BluetoothMusicViewModel.loadFileImageToView()` 改为返回解码是否成功,解码失败时保留已有有效文件封面;无有效文件封面时才回退默认图
|
||||
- `BtContactsManager` 已增加联系人列表快照防御:
|
||||
- PBAP 联系人读取完成后使用 `contactsSnapshot`
|
||||
- 保存 DB 和回调 UI 不再直接传共享的 `mContactsList`
|
||||
- `saveContactsList()` 增加 `null` 判断和防御拷贝
|
||||
- `ContactsFragment` 已调整联系人页显示时序:
|
||||
- LiveData 收到非空联系人时,先填充 `mPhoneBookList`,再显示联系人列表
|
||||
- 已同步但本地联系人列表为空时,先显示 loading,不提前显示空列表
|
||||
- 点击一键同步且 PBAP 正在同步时,联系人页显示 loading,避免重复同步 Toast
|
||||
- 重新同步期间如果读取到旧库联系人,但本轮 PBAP 未完成(`isPhoneBookPulling=true && getContactLoadWonType=false`),忽略这批旧数据并保持 loading,避免提前显示旧通讯录列表
|
||||
- `YX_CarControl` 已移除配对弹窗中对 `BtContactsControlManager.getInstance().init(context)` 的调用:
|
||||
- `YX_CarControl` 只保留自动同步开关设置
|
||||
- 联系人/PBAP 同步统一由 `YX_BlueTooth` 进程负责
|
||||
- 避免 `YX_CarControl` 和 `YX_BlueTooth` 两个进程同时注册 PBAP 完成广播并重复删写联系人表
|
||||
- `CallLogsFragment` 已修复通话页切回后仍显示 loading 的 UI 问题:
|
||||
- `onHiddenChanged(false)` 时重新执行 `setIsBtConnect(...)`,确保切回通话页会按最新通话记录同步状态刷新 UI
|
||||
- `readCallRecordUpdated()` 中已有通话记录列表时优先显示列表,不再被 `isPhoneBookPulling=true` 覆盖成 loading
|
||||
- 补充兜底:`notifyPhoneRecordList()` 收到非空通话记录时直接关闭 loading、显示通话列表,避免通话记录已到但外层状态未及时收敛导致页面仍转圈
|
||||
- 2026-06-06 复测日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0606_1528_11_585.log` 确认联系人页重新同步期间仍会显示旧列表:
|
||||
- `15:31:00.768` 第二次 `phoneBookPullRequest`
|
||||
- `15:31:04.208` 到 `15:31:20.734` 多次切回联系人页,均为 `isPhoneBookSynchronized = true isPhoneBookPulling=true`
|
||||
- 本轮联系人实际到达为 `15:32:25.450 onContactsPhoneBook = 1973`
|
||||
- 根因是切回联系人页时 `syncPhoneBookSynchronized(true)` 只看本地库已有联系人,未优先判断“本轮同步尚未完成”,导致旧内存列表重新显示
|
||||
- 已追加联系人同步中隐藏旧列表修复:
|
||||
- `BtContactsManager.phoneBookPullRequest()` 开始新一轮同步时重置 `isContactsPullCompeted=false`
|
||||
- `ContactsFragment.syncPhoneBookSynchronized()` 优先判断 `isPhoneBookPulling && !getContactLoadWonType()`,该状态强制显示 loading 并隐藏联系人列表
|
||||
- `showContactsLoadingPanel()` 统一隐藏蓝牙连接面板并调用 `updateLoadPage(true)`
|
||||
- 2026-06-06 复测日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0606_1556_40_545.log` 确认通话记录“显示空”不是同步失败:
|
||||
- 无 `Dex checksum does not match`
|
||||
- `15:57:41.356` 通话记录同步到 `mCallRecordBeanList size = 51`
|
||||
- `15:57:41.377` 保存通话记录 `saveCallRecordList size = 51`
|
||||
- `15:58:24.959` 切回通话页后 `notifyPhoneRecordList list == 51`
|
||||
- 根因是 `CallLogsFragment.notifyPhoneRecordList()` 先填充字段 `mCallRecordList`,再把同一个 list 传给 `CallRecordAdapter.setData()`;Adapter 内部先 `clear()` 再 `addAll()`,导致自清空,日志显示 51 但 Adapter 实际为空
|
||||
- 已修复通话记录 Adapter 自清空问题:
|
||||
- `CallLogsFragment.notifyPhoneRecordList()` 改为传入 `new ArrayList<>(mCallRecordList)`,避免 Adapter 清空同一个数据源引用
|
||||
|
||||
## 验证记录
|
||||
|
||||
- 2026-06-08:蓝牙音乐封面兜底修复后,`.\gradlew :YX_Music:assembleDebug` 编译通过。第一次沙箱内编译因读取本机 Android SDK `android.jar` 权限失败,使用非沙箱权限重跑通过。
|
||||
- 2026-06-08:`YX_BluetoothSDK` 封面路径有效性过滤后,`.\gradlew :YX_BluetoothSDK:assembleDebug` 编译通过;随后 `.\gradlew :YX_Music:assembleDebug`、`.\gradlew :YX_BlueTooth:assembleDebug` 集成编译通过。
|
||||
- 2026-06-08:`BluetoothMusicFragment` 切歌封面延迟加载修复后,`.\gradlew :YX_Music:assembleDebug` 编译通过。
|
||||
- 2026-06-09:`YX_Music` 固定 ID3 封面文件稳定性检测和重试修复后,`.\gradlew :YX_Music:assembleDebug` 编译通过;尚待推送设备后复测切歌封面是否仍出现默认图/上一首封面/解码失败。
|
||||
- 2026-06-09:`YX_Music.apk` 已推送到设备 `/system/app/YX_Music/YX_Music.apk`,设备旧包已备份到 `/sdcard/YX_Music.apk.bak_20260609_112853`;尚未重启设备,需重启后复测以避免旧 dex/oat 缓存影响。
|
||||
- 2026-06-09:重新执行 `.\gradlew :YX_Music:assembleDebug` 编译通过,并再次推送 `/system/app/YX_Music/YX_Music.apk`;推送前设备当前包备份到 `/sdcard/YX_Music.apk.bak_20260609_113508`,随后已重启设备。
|
||||
- 2026-06-09:重启后启动验证日志已保存到 `C:\Users\Administrator\Desktop\徐工日志\yx_log\verify_music_yxmusic_only_20260609_1142.log`:
|
||||
- `sys.boot_completed = 1`
|
||||
- `pm path com.yaxon.music` 指向 `/system/app/YX_Music/YX_Music.apk`
|
||||
- 通过 `am start -n com.yaxon.music/com.yaxon.musicplay.view.UsbMainActivity` 可启动应用
|
||||
- 启动阶段未发现 `Dex checksum`、`FATAL EXCEPTION`、`获取bitmap为null`、`Failed to create image decoder`
|
||||
- 当前日志显示 `isMusicPlaying false`,尚未覆盖蓝牙播放中切歌封面场景;需现场播放蓝牙音乐并切歌后再抓日志确认
|
||||
- 2026-06-09:分析 `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0609_1409_00_592.log`,最后一段同专辑 `与我无关` 复用固定封面路径;`14:18:50-14:18:51` 底层写 `/sdcard/ID3/id3cover.JPEG` 时出现 `length=0 -> 16146 -> 24220 -> 43843`,`YX_Music` 已等待文件稳定,`SystemUI/Launcher` 仍会直接读固定路径。为复现确认,`YX_Music` 仅追加诊断日志:
|
||||
- `BluetoothMusicFragment` 记录 ID3 文件稳定确认、准备加载、加载失败重试、重置检查状态
|
||||
- `BluetoothMusicViewModel` 记录默认封面设置、文件封面解码成功的文件长度/修改时间/bitmap 宽高/byteCount
|
||||
- 2026-06-09:`YX_Music` 蓝牙封面诊断日志追加后,`.\gradlew :YX_Music:assembleDebug` 编译通过;已备份设备旧包到 `/sdcard/YX_Music.apk.bak_20260609_143548`,新包已推送到 `/system/app/YX_Music/YX_Music.apk` 并重启设备;重启后确认 `sys.boot_completed=1`,`pm path com.yaxon.music` 指向系统路径。
|
||||
- 2026-06-09:分析 `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0609_1451_00_890.log`,确认 `YX_Music` 未解码失败,但固定 ID3 封面稳定判断过早:
|
||||
- `loadFileImageToView success = 1125`,`获取bitmap为null = 0`,`loadFileImageToView e = 0`
|
||||
- 同一 `lastModified` 下出现多个成功加载长度,例如 `1780988430000: 8072 -> 16146 -> 27885`
|
||||
- 典型时序:`15:00:30.103` 先成功加载 `length=8072`,`15:00:30.293` 底层才 `avrcp image download succeed`,`15:00:30.403` 再成功加载 `length=27885`
|
||||
- 根因是元数据回调密集,连续两次长度/修改时间相同可在数毫秒内发生,当前稳定判断会把半写入文件误判为稳定
|
||||
- 2026-06-09:继续仅修改 `YX_Music`,延后 `SystemUI/Launcher`:
|
||||
- `BluetoothMusicFragment` 增加 `ID3_ALBUM_STABLE_DURATION_MS=500`,固定 ID3 封面必须长度/修改时间连续稳定满 500ms 才允许解码
|
||||
- 合并重复的 ID3 延迟加载请求,避免密集元数据回调堆叠多个相同 runnable
|
||||
- 已显示同一长度/修改时间的 ID3 文件时跳过重复解码,减少反复 setImageBitmap
|
||||
- `.\gradlew :YX_Music:assembleDebug` 编译通过;设备旧包备份到 `/sdcard/YX_Music.apk.bak_20260609_160339`,新包已推送到 `/system/app/YX_Music/YX_Music.apk` 并重启;重启后确认 `sys.boot_completed=1`,`pm path com.yaxon.music` 正常
|
||||
- `.\gradlew :YX_BlueTooth:assembleDebug` 已编译通过。
|
||||
- 最新 `ContactsFragment` UI 时序修改已编译通过,但在用户中断前尚未执行 `adb push` 到设备验证。
|
||||
- 2026-06-06:`YX_BlueTooth` APK 已重新 clean 编译并推送到 `/system/app/YX_BlueTooth`。
|
||||
- 2026-06-06:`CallLogsFragment` loading UI 修复后,`.\gradlew :YX_BlueTooth:assembleDebug` 编译通过,并已推送到 `/system/app/YX_BlueTooth/YX_BlueTooth.apk`,设备端大小 `21232834`。
|
||||
- 2026-06-06:`CallLogsFragment.notifyPhoneRecordList()` 非空列表强制关闭 loading 兜底后,`.\gradlew :YX_BlueTooth:assembleDebug` 编译通过,并已推送到 `/system/app/YX_BlueTooth/YX_BlueTooth.apk`,设备端大小 `21232896`。
|
||||
- 2026-06-06:`ContactsFragment` 重新同步期间过滤旧库联系人兜底后,`.\gradlew :YX_BlueTooth:assembleDebug` 编译通过,并已推送到 `/system/app/YX_BlueTooth/YX_BlueTooth.apk`,设备端大小 `21233011`。
|
||||
- 2026-06-06:联系人页切回时隐藏旧列表修复后,`.\gradlew :YX_BlueTooth:assembleDebug` 编译通过,并已推送到 `/system/app/YX_BlueTooth/YX_BlueTooth.apk`,设备端大小 `21233092`。
|
||||
- 2026-06-06:通话记录列表 Adapter 自清空修复后,`.\gradlew :YX_BlueTooth:assembleDebug` 编译通过,并已推送到 `/system/app/YX_BlueTooth/YX_BlueTooth.apk`,设备端大小 `21233566`。
|
||||
- 2026-06-06 复测日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0606_1605_11_651.log`:
|
||||
- 用户确认通话列表已有显示
|
||||
- 通话记录同步成功:`16:05:58.835 mCallRecordBeanList size = 51`,`16:05:58.843 saveCallRecordList size = 51`,`16:05:59.636 notifyPhoneRecordList list == 51`
|
||||
- 通讯录同步成功:`16:06:24.788 contacts read completed size = 1973`,`16:06:40.194 onContactsPhoneBook = 1973`
|
||||
- `BtContactsControlManager = 0`,未出现 `ConcurrentModificationException`、`onContactsPullFailed`、`通讯录同步失败`
|
||||
- 仍出现 `Dex checksum does not match`,最终验收建议重启设备后再抓一轮无 dex 缓存异常日志
|
||||
- 2026-06-06 最新复测日志 `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0606_1612_17_622.log` 作为当前最终有效验证:
|
||||
- `Dex checksum does not match = 0`
|
||||
- `com.yaxon.carcontrol` 只出现 `BluetoothPairedRequestView` 配对弹窗/自动同步开关日志,`BtContactsControlManager = 0`
|
||||
- `com.yaxon.bluetooth` 唯一触发 `16:13:20.668 phoneBookPullRequest`
|
||||
- 通话记录同步和显示成功:`16:14:11.907 mCallRecordBeanList size = 51`,`16:14:11.921 saveCallRecordList size = 51`,`16:14:12.673 notifyPhoneRecordList list == 51`;同步完成后切回通话页 `16:15:36.739 notifyPhoneRecordList list == 51`
|
||||
- 通讯录同步成功:`16:14:35.249 contacts read completed size = 1973`,`16:14:51.422 onContactsPhoneBook = 1973`
|
||||
- 未出现 `ConcurrentModificationException`、`onContactsPullFailed`、`通讯录同步失败`
|
||||
|
||||
## 待办事项
|
||||
|
||||
- 清空蓝牙联系人/通话记录表后重新验证:
|
||||
- 联系人权限允许后点击一键同步
|
||||
- 同步过程中切换联系人页/通话记录页
|
||||
- 确认不再短暂显示 0 个联系人列表
|
||||
- 确认同步完成后显示实际联系人数量
|
||||
- 确认无 `ConcurrentModificationException` 和“通讯录同步失败” Toast
|
||||
- 编译并推送 `YX_CarControl.apk` 后重启设备,重新确认只剩 `com.yaxon.bluetooth` 一个进程执行 `BtContactsManager` 联系人同步。
|
||||
|
||||
## 更新记录
|
||||
|
||||
- 2026-06-23:调整语音 `playDislike`(不喜欢这首歌)处理逻辑:
|
||||
- 用户确认本次不做文件备份。
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/protocol/VoiceProtocol.java` 中 `CMD_PLAY_DISLIKE` 从原先复用下一首逻辑改为音频源取消收藏逻辑。
|
||||
- 视频源仍保持下一个视频:`sendVideoController(CMD_VIDEO_NEXT)`。
|
||||
- 收音机源改为复用 `sendMusicUnFavorites(false)`,走现有收音机取消收藏按键链路。
|
||||
- USB/蓝牙音乐源改为复用 `sendMusicUnFavorites(true)`,向音乐模块发送 `CMD_PLAY_UNFAVORITES`。
|
||||
- 验证:`.\gradlew :YX_Voice:assembleDebug` 编译通过。
|
||||
- 2026-06-22:按 TXZ 反馈调整“可见即可说”验证方向:
|
||||
- TXZ 确认 `shadow.register` 属于网页、小程序、自绘等非常规页面的主动插词注册方式;普通原生页面不需要主动同步给 TXZ,语音侧会通过无障碍扫描 `id/text/contentDescription/clickable/scrollable`。
|
||||
- 本次选 `YX_CarControl` 的语音设置页 `fragment_voice.xml` 做普通页面扫描验证:为语音唤醒、免唤醒、免唤醒时长、系统语音包、唤醒词入口补充 `contentDescription`、`clickable/focusable` 和滚动容器 id。
|
||||
- `CustomTriStateSwitch` 按文档要求在 `onInitializeAccessibilityNodeInfo()` 中暴露 `checkable/checked/clickable/enabled`,便于 TXZ 判断自定义开关状态。
|
||||
- `VoiceFragment` 根据开关当前状态动态更新 `contentDescription`:关闭态暴露“打开/开启”,开启态暴露“关闭/关掉”,避免状态型控件同时暴露正反插词导致动作反向。
|
||||
- 暂停 `YX_CarControl` 启动后自动注册测试插词,不再自动发送 `shadow.register`,但保留 `registerVisibleSpeakKeywords(...)` / `unregisterVisibleSpeakKeywords(...)` 预留接口供后续非常规页面使用。
|
||||
- 验证:`.\gradlew :YX_CarControl:assembleDebug` 编译通过。
|
||||
- 2026-06-22 更新:语音设置页可能与既有语义命令重叠,不适合作为无障碍扫描效果验证页,已新增维保页独立测试点:
|
||||
- `fragment_maintenance.xml` 为保养里程选项和保养重置按钮补充独特测试插词:`可见测试关闭保养里程`、`可见测试五千公里`、`可见测试一万公里`、`可见测试三万公里`、`可见测试保养重置`。
|
||||
- `MaintenanceFragment` 在对应点击入口增加 `visible speak test click: ...` 日志,便于判断语音命中后是否真实触发控件点击。
|
||||
- 验证:`.\gradlew :YX_CarControl:assembleDebug` 编译通过;新包已推送到 `/system/app/YX_CarControl/YX_CarControl.apk` 并重启设备,`sys.boot_completed=1`,`pm path com.yaxon.carcontrol` 指向系统路径。
|
||||
- 2026-06-22 更新:维保页 RadioButton/contentDescription 测试现场未响应,进一步简化为系统页可见标准按钮测试:
|
||||
- 在 `fragment_system.xml` 顶部新增标准 `Button`,可见文本为 `可见测试按钮`,依赖 TXZ 扫描 `android:text`,避免 RadioButton、隐藏标签、既有语义干扰。
|
||||
- `SystemFragment` 绑定按钮点击后打印 `visible speak simple test button clicked` 并 Toast `可见测试按钮已点击`。
|
||||
- 验证:`.\gradlew :YX_CarControl:assembleDebug` 编译通过;新包已推送到 `/system/app/YX_CarControl/YX_CarControl.apk` 并重启设备,`sys.boot_completed=1`,`pm path com.yaxon.carcontrol` 指向系统路径。
|
||||
- 2026-06-13:抽取“可见即可说”业务侧公共工具:
|
||||
- 用户确认本次不做文件备份。
|
||||
- 新增 `YX_Lib_CommonBase/src/main/java/com/yaxon/common/base/voice/VisibleSpeakHelper.java`,统一封装业务模块向 `YX_Voice` 发送 `cmd.visibleSpeakRegister` / `cmd.visibleSpeakUnregister` 的 Bundle 组装和 IPC 发送逻辑。
|
||||
- `VisibleSpeakHelper` 同时提供 `parseExecute(Bundle)`,业务模块收到 `cmd.visibleSpeakExecute` 后可直接解析出 `packageName`、`className`、`pageName`、`keyword`。
|
||||
- `YX_Lib_CommonBase/build.gradle` 增加 `implementation project(path: ':YX_IPC_SDK')`,用于公共工具内部调用 `YxIPC`。
|
||||
- `YX_CarControl` 的 `VoiceSettingManager` 保留测试插词注册时机和命中日志,但注册/注销发送改为复用 `VisibleSpeakHelper`,避免后续模块重复手写 Bundle。
|
||||
- 验证:`.\gradlew :YX_CarControl:assembleDebug` 编译通过;`.\gradlew :YX_Voice:assembleDebug` 编译通过。
|
||||
- 2026-06-13 更新:为避免 `YX_Lib_CommonBase` 扩大 IPC 依赖面,已移除 `YX_Lib_CommonBase/build.gradle` 中的 `implementation project(path: ':YX_IPC_SDK')`:
|
||||
- `VisibleSpeakHelper` 改为只负责 `buildRegisterBundle(...)`、`buildUnregisterBundle(...)`、`parseExecute(...)` 等参数构造/解析,不再直接 import 或调用 `YxIPC`。
|
||||
- 业务模块仍由自身已有的 `YX_IPC_SDK` 依赖执行 `YxIPC.getInstance().sendRemoteNoCall(...)`;当前 `YX_CarControl` 已按此方式调整。
|
||||
- 验证:`.\gradlew :YX_CarControl:assembleDebug`、`.\gradlew :YX_Voice:assembleDebug` 编译通过;单独 `.\gradlew :YX_Lib_CommonBase:assembleDebug` 在沙箱内因本机 Android SDK `android.jar` 读取权限失败,非沙箱授权请求被审批服务异常拒绝,但 `YX_CarControl`/`YX_Voice` 编译已覆盖该公共库改动。
|
||||
- 2026-06-13:预留“可见即可说”自动注册框架接口:
|
||||
- 用户确认本次不做文件备份。
|
||||
- 阅读《同行者可见即可说自动注册框架对接方案.docx》后,按文档预留 `shadow.register`、`shadow.unregister`、`shadow.execute` 三段链路。
|
||||
- `YX_Lib_CommonBase` 的 `VoiceNewConstant` 增加可见即可说 IPC 命令和参数 key:包名、类名、页面名、插词列表。
|
||||
- `YX_Voice` 的 `VoiceNewProtocolConst` 增加 TXZ 侧 method/字段常量:`key_type`、`action`、`keywordList`、`cmd` 等。
|
||||
- `YX_Voice` 的 `BaseProtocol` 增加可见即可说注册/注销/执行分发;`VoiceEventHelper` 负责把应用注册转成 TXZ 请求,并把命中的插词回传给目标应用;`VoiceProtocol` 接收 TXZ `shadow.execute` 后回传应用。
|
||||
- `YX_CarControl` 的 `VoiceSettingManager` 增加 `registerVisibleSpeakKeywords(...)` / `unregisterVisibleSpeakKeywords(...)` 预留方法,并在语音 IPC 和 TXZ bind 都就绪后注册一组测试插词 `可见即可说测试#打开可见即可说测试`,命中后当前只记录 `handleVisibleSpeakExecute` 日志,不执行真实业务动作。
|
||||
- 验证:`.\gradlew :YX_Voice:assembleDebug` 编译通过;`.\gradlew :YX_CarControl:assembleDebug` 编译通过。
|
||||
- 待现场验证:推送 `YX_Voice.apk` / `YX_CarControl.apk` 后观察日志中是否出现 `registerVisibleSpeakKeywords`、`sendCommandTxz → method= shadow.register`;说出测试插词后确认是否出现 `shadow.execute` 和 `handleVisibleSpeakExecute`。
|
||||
- 已知风险:TXZ 侧 `shadow.register` 参数结构目前按文档文字和流程图推断为 `keywordList` 使用 `#` 分隔字符串;若同行者实际要求 array/list 或字段名不同,需要按现场日志调整。
|
||||
- 2026-06-12:修复语音前台 TTS 播报转发命令:
|
||||
- 用户确认本次不做文件备份。
|
||||
- 核对链路:`YX_CarControl` 的 `VoiceSettingManager.sendForegroundTtsPlay(...)` 发送 `cmd.syncForegroundTtsText` 到 `YX_Voice`。
|
||||
- `YX_Voice` 的 `BaseProtocol` 已能将 `cmd.syncForegroundTtsText` 分发到 `VoiceEventHelper.playTtsOnUi(...)`。
|
||||
- 修复点:`VoiceEventHelper.playTtsOnUi(...)` 转发 TXZ 时由 `syncBackgroundTtsText` 改为 `syncForegroundTtsText`,后台 `playTtsInBackground(...)` 保持 `syncBackgroundTtsText` 不变。
|
||||
- 验证:`.\gradlew :YX_Voice:assembleDebug` 编译通过。
|
||||
- 待现场验证:触发仪表脱手报警“请手握方向盘”或其它前台 TTS 场景,确认日志出现 `sendForegroundTtsPlay`、`playTtsOnUi` 且 TXZ 前台播报生效。
|
||||
- 2026-06-09:新增语音前台 TTS 文本同步接口 `syncForegroundTtsText`:
|
||||
- `VoiceNewConstant` 增加 IPC 入站命令 `CMD_SYNC_FOREGROUND_TTS_TEXT = "cmd.syncForegroundTtsText"`
|
||||
- `VoiceNewProtocolConst` 增加 TXZ 协议命令 `CMD_SYNC_FOREGROUND_TTS_TEXT = "syncForegroundTtsText"`
|
||||
- `BaseProtocol` 新增前台 TTS 分支,收到 `cmd.syncForegroundTtsText` 后调用 `VoiceEventHelper.playTtsOnUi(...)`
|
||||
- `VoiceEventHelper.playTtsOnUi(...)` 改为向 TXZ 发送 `syncForegroundTtsText`,后台 `syncBackgroundTtsText` 保持不变
|
||||
- `VoiceSettingManager` 新增 `sendForegroundTtsPlay(String tts)`,供 `YX_CarControl` 侧发送前台 TTS
|
||||
- `.\gradlew :YX_Voice:assembleDebug` 编译通过
|
||||
- `.\gradlew :YX_CarControl:assembleDebug` 编译通过
|
||||
- 2026-06-09:继续仅修改 `YX_Music` 蓝牙音乐封面加载策略:
|
||||
- 切歌后 `albumUrl` 为空时,不再立刻判定无封面;进入固定 ID3 封面 `/sdcard/ID3/id3cover.JPEG` 等待链路。
|
||||
- 同一首歌已经显示文件封面后,后续空 `albumUrl` 不清空当前封面。
|
||||
- ID3 封面重试从原约 6 秒扩展为前 20 次 300ms、后续 1s、最多 50 次,总窗口约 36 秒,用于覆盖封面二十几秒后才下发的场景。
|
||||
- `.\gradlew :YX_Music:assembleDebug` 编译通过;`YX_Music.apk` 已推送到 `/system/app/YX_Music/YX_Music.apk` 并重启设备,`sys.boot_completed=1`,`pm path com.yaxon.music` 指向系统路径。
|
||||
- 2026-06-16:修复蓝牙联系人页权限恢复后“正在同步通讯录”卡住:
|
||||
- 用户确认本次不做文件备份。
|
||||
- 复现日志 `2026_0616_1437_51_345.log` 显示本轮 `phoneBookPullRequest = 0`、`onContactsPullCompleted = 0`,不是 PBAP 真同步;权限置 0 后 `ContactListViewModel` 仍回调 `onContactsPhoneBook = 257`,但 `ContactsFragment` 会先清空 `mPhoneBookList` 并因无权限返回。
|
||||
- 权限重新确认后,页面状态为 `isPhoneBookSynchronized = true isPhoneBookPulling=false`,但内存列表为空,旧逻辑直接显示 `llLoading`,导致“正在同步通讯录”没有后续回调关闭。
|
||||
- `ContactsFragment` 增加本地通讯录重读收敛:已同步且列表为空、未处于 PBAP 拉取时,只触发一次 `readPhoneBook()` 从本地库回填;若回填为空则关闭 loading 并显示下载入口,避免无限 loading。
|
||||
- 验证:`.\gradlew :YX_BlueTooth:assembleDebug` 编译通过。
|
||||
- 2026-06-16:更新版本后复核日志 `2026_0616_1437_51_345.log`:
|
||||
- 日志更新时间为 `2026/6/16 15:14:16`,大小 `16500679`。
|
||||
- `15:09:33.236` 与 `15:13:01.840` 均触发 `BluetoothPbapClient: phoneBookPullRequest`,随后分别在 `15:09:40.295`、`15:13:09.663` 出现 `onContactsPullCompleted`。
|
||||
- 两轮 PBAP 均读到联系人 `257` 和通话记录 `51`,最终状态均回到 `isPhoneBookSynchronized=true isPhoneBookPulling=false`,说明真实同步链路已完成。
|
||||
- 本次日志未出现新修复分支日志 `phonebook synchronized but local list is empty, reload local phonebook`,暂不能证明本地空列表兜底分支已被执行。
|
||||
- 日志仍出现 `/system/app/YX_BlueTooth/YX_BlueTooth.apk!classes2.dex` 的 `Dex checksum does not match`,建议推送系统 APK 后重启设备或清理旧 oat/dex 缓存再复测,避免运行旧代码或混合 dex。
|
||||
- 2026-06-16:复测日志 `2026_0616_1533_52_917.log` 验证蓝牙联系人权限恢复兜底:
|
||||
- 日志更新时间为 `2026/6/16 15:37:06`,大小 `11242513`,本轮未检出 `Dex checksum does not match`。
|
||||
- `15:35:03`、`15:35:27`、`15:36:06`、`15:36:38` 多次出现通讯录权限置 0;权限关闭期间本地库仍能回调 `onContactsPhoneBook = 257`,但 UI 按权限拒绝分支处理。
|
||||
- `15:35:16.420` 和 `15:36:50.420` 出现 `phonebook synchronized but local list is empty, reload local phonebook`,证明新增兜底分支已执行。
|
||||
- 兜底触发后立即执行 `BtContactsManager: readPhoneBook`,随后回调 `ContactListViewModel: onContactsPhoneBook = 257`,页面可从本地通讯录恢复,不再停留在无限 loading。
|
||||
- 用户手动/后续触发真实 PBAP 同步时,`15:35:34.363`、`15:36:15.769`、`15:36:52.932` 出现 `phoneBookPullRequest`,并分别完成 `onContactsPullCompleted`、联系人 `257`、通话记录 `51`、`getStartPullLivedata = false`。
|
||||
- 当前结论:修复有效;后续可考虑减少权限恢复时的重复 `readPhoneBook()` 触发,但不影响主问题闭环。
|
||||
- 2026-06-23:按 TXZ 无障碍服务 `process is bad`/扫描不起来问题调整 `YX_Voice` 恢复策略:
|
||||
- 用户前置确认本次不做文件备份,直接修改。
|
||||
- `VoiceService` 不在 `onCreate()` 常态执行无障碍绑定恢复,改为 TXZ `onConnected()` 后延迟 2 秒执行一次。
|
||||
- 新增 `mTxzConnected` 与 `mAccessibilityServiceRefreshDone` 状态保护:TXZ 断开后取消待执行任务并允许下次连接重新恢复;已成功恢复后不重复重绑。
|
||||
- 恢复逻辑先读取当前 `Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES`,保留已有服务,只针对 `com.txzing.voiceassistant/com.txznet.shadow.words.ShadowAccessibilityService` 做移除再加回,触发系统重新绑定 TXZ 无障碍服务。
|
||||
- 不主动追加 `YX_Factory` 无障碍服务,避免扩大影响面;如果 Factory 已在列表中会被原样保留。
|
||||
- 补充空列表保护,避免 `ENABLED_ACCESSIBILITY_SERVICES` 为 `null` 或空字符串时 `containsAccessibilityService()` 空指针。
|
||||
- 验证:`.\gradlew :YX_Voice:assembleDebug` 编译通过。后续推送设备后重点看 `refreshAccessibilityServiceBinding rebind txz`、`ensureAccessibilityServiceEnabled`、`ShadowService: onServiceConnected`、`VisualCommandModule: tryUseAccessibilityService: result = 1`、`registerKeywords`。
|
||||
- 2026-06-23:修复语音 `playDislike`/`playUnfavorites` 把未收藏歌曲反向收藏的问题:
|
||||
- 用户确认本次不做文件备份。
|
||||
- 根因:`YX_MusicSDK` 的 `MusicService` 将 `CMD_PLAY_FAVORITES` 和 `CMD_PLAY_UNFAVORITES` 合并到 `onCollectCurrentMusic()`;下游 `SongProvider.collectPlayRecord()` 是 toggle 逻辑,当前歌曲 `isCollect=0` 时执行“取消收藏”会变成收藏。
|
||||
- `MusicService` 将收藏和取消收藏分支拆开;`CMD_PLAY_UNFAVORITES` 改调 `VoiceControlManager.onUnCollectCurrentMusic()`。
|
||||
- `VoiceControlManager.onUnCollectCurrentMusic()` 先读取当前播放歌曲,只有已收藏时才复用原 toggle 取消收藏;未收藏时跳过,避免反向收藏。
|
||||
- 收音机链路同步修正:`VoiceEventHelper.sendMusicUnFavorites(false)` 不再发送 `KEYCODE_MEDIA_RECORD` toggle 按键,改为向 `YX_Radio` 发送 `CMD_PLAY_UNFAVORITES`;`VoiceRadioManager` 收到后仅在当前电台已收藏时调用 `cancelCollection()`。
|
||||
- 验证:`.\gradlew :YX_Music:assembleDebug :YX_Voice:assembleDebug :YX_Radio:assembleDebug` 编译通过。
|
||||
|
||||
## 2026-06-24 playDislike atomic handling
|
||||
|
||||
- Continue voice `playDislike` fix without backup.
|
||||
- Further narrowed `playDislike` to one IPC command from `YX_Voice` to the target media module instead of sending cancel-favorite and next as two independent actions.
|
||||
- `VoiceEventHelper.sendMusicDislike(...)` now sends `cmd.playDislike` and carries current media type with `typeKey`.
|
||||
- `VoiceProtocol` keeps video behavior as next video; radio and music now dispatch only `sendMusicDislike(...)`.
|
||||
- `YX_MusicSDK` handles `cmd.playDislike` in `MusicService`: USB music performs safe un-favorite only when collected, then next track; Bluetooth music does not touch USB favorite state and only sends Bluetooth next when it has focus.
|
||||
- `YX_Radio` handles `cmd.playDislike` in `VoiceRadioManager`: cancel current station only when already collected, then call `nextAutoSearch()`.
|
||||
- Verification: `.\gradlew :YX_Music:assembleDebug :YX_Voice:assembleDebug :YX_Radio:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl visible-speak cleanup
|
||||
|
||||
- User confirmed no backup before editing.
|
||||
- Reverted temporary visible-speak validation code from `YX_CarControl`: removed the system page `可见测试按钮`, its click log/toast, maintenance page `可见测试...` content descriptions, and maintenance test click logs.
|
||||
- Kept formal accessibility/visible-speak enhancements for the voice settings page: dynamic switch `contentDescription`, voice settings control descriptions, and `CustomTriStateSwitch` accessibility node state.
|
||||
- Verified no remaining `可见测试`, `visible speak test`, `visible speak simple`, `btn_visible_speak_simple_test`, or `maintenance_scroll_view` test markers under `YX_CarControl/src/main`.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Follow-up: removed the shared `CustomTriStateSwitch` accessibility-node change to keep this submission scoped to the voice settings page only; remaining `YX_CarControl` diff is limited to `VoiceFragment.java`, `fragment_voice.xml`, and `strings.xml`.
|
||||
- Verification after removal: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Follow-up: kept multi-keyword visible-speak text with `#`, but changed all added `fragment_voice.xml` `contentDescription` values from hard-coded text to `@string/...` references for maintainability.
|
||||
- Verification after XML string-reference change: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Follow-up: added matching `values-en/strings.xml` translations for all new `voice_speak_*` resources while preserving `#` multi-keyword format.
|
||||
- Verification after English resource completion: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl EnergyFragment visible-speak
|
||||
|
||||
- User confirmed no backup before this round of edits.
|
||||
- Added native visible-speak accessibility text for the Energy page without using `shadow.register`, following TXZ native page scanning via `contentDescription`.
|
||||
- Scope:
|
||||
- `EnergyFragment.java`: dynamically updates charge/discharge switch `contentDescription` according to current checked state, so closed state exposes open keywords and opened state exposes close keywords.
|
||||
- `fragment_energy.xml`: added `contentDescription` for charge allow, discharge allow, reset trip after last charge, more trips, and reset statistics controls.
|
||||
- `dialog_trip_record.xml`: added `contentDescription` for subtotal trip A/B reset buttons.
|
||||
- `values/strings.xml` and `values-en/strings.xml`: added matching `energy_speak_*` multi-keyword strings using `#`.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Follow-up: moved `energy_speak_*` resources into the voice settings resource section and labeled them with `可见即可说 - 能源页面`; also labeled existing visible-speak groups for System and Voice pages in both Chinese and English string files.
|
||||
- Verification after resource regrouping: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl SystemFragment visible-speak
|
||||
|
||||
- Followed reference commit `ef20ec3ca823aece8d1beb8e45442cdab7ba420f` and reused the native page scanning approach.
|
||||
- Added `contentDescription` visible-speak keywords to System page clickable containers: factory reset, USB upgrade, system update, time setting, language setting, unit setting, disclaimer, privacy policy, and permission authorization.
|
||||
- Added matching `system_speak_*` string resources in `values/strings.xml` and `values-en/strings.xml`, with multiple keywords separated by `#`.
|
||||
- No Java behavior change was needed in `SystemFragment.java`; existing click listeners already dispatch the actions after TXZ triggers the scanned views.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Follow-up: moved the new `system_speak_*` resources into the voice settings resource section in both Chinese and English string files, because these entries are visible-speak keywords rather than ordinary System page labels.
|
||||
- Verification after resource regrouping: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_Voice background TTS toast
|
||||
|
||||
- User confirmed no backup before editing.
|
||||
- Requirement: both `playTtsOnUi()` and `playTtsInBackground()` are in use, but foreground TTS remains only a reserved API; actual playback must continue through `syncBackgroundTtsText`.
|
||||
- Added `VoiceToastHelper` in `YX_Voice` using system `Toast` with custom view, based on the existing `YX_CarControl` designed Toast style instead of using a Dialog-style helper.
|
||||
- Added independent `YX_Voice` Toast resources: `voice_toast_view.xml`, `voice_toast_bg.xml`, day/night colors, and Toast dimensions.
|
||||
- Refactored `VoiceEventHelper` so `playTtsOnUi()` and `playTtsInBackground()` both call `sendBackgroundTtsWithToast(...)`; this shows the designed Toast and sends TXZ `syncBackgroundTtsText`.
|
||||
- Kept foreground TTS command disabled; `playTtsOnUi()` comment now explicitly states foreground TTS is not supported and the reserved entry still uses background TTS.
|
||||
- Verification: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl SoundFragment visible-speak
|
||||
|
||||
- User requested native visible-speak support for the Sound page and previously confirmed no backup before editing.
|
||||
- Added Sound page keywords through native TXZ accessibility scanning via `contentDescription`; this page does not use `shadow.register`.
|
||||
- Scope:
|
||||
- `fragment_sound.xml`: added visible-speak keywords for sound field options, media/phone/navigation/voice volume bars, mute switch, and key tone switch.
|
||||
- `layout_eq.xml`: added visible-speak keywords for default, classical, pop, jazz, electronic, rock, and custom EQ options.
|
||||
- `SoundFragment.java`: dynamically refreshes mute and key tone switch `contentDescription` by current checked state, so disabled state exposes open keywords and enabled state exposes close keywords.
|
||||
- `values/strings.xml` and `values-en/strings.xml`: added `sound_speak_*` resources under `可见即可说 - 声音页面`.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Known validation boundary: the volume bars are custom `ItemCustomSeekBarView` controls; keywords are exposed for scanning, but exact voice-side adjustment behavior depends on TXZ accessibility handling of custom drag/click views.
|
||||
- Follow-up: per user decision, removed visible-speak keywords from the four custom volume bars for now; Sound page visible-speak scope remains sound field, EQ options, mute switch, and key tone switch.
|
||||
|
||||
## 2026-06-24 YX_CarControl ADAS hands-off TTS debounce
|
||||
|
||||
- User confirmed no backup before editing.
|
||||
- Symptom from `2026_0624_1540_03_018.log`: `请手握方向盘` was heard as repeated leading fragments like `请 请 请 请 请 手握方向盘`.
|
||||
- Root cause: `sendAdasLdsHandsOffWarnStChange(2)` was triggered repeatedly while the warning stayed active, so `sendForegroundTtsPlay("请手握方向盘")` and the downstream background TTS command were sent repeatedly; each new request interrupted the previous playback.
|
||||
- Fix scope: `VoiceSettingManager.sendAdasLdsHandsOffWarnStChange(int sts)` now only sends TTS when the ADAS hands-off warning enters `0x02` from a non-warning state, with a 5-second debounce against rapid signal chatter.
|
||||
- Expected validation: repeated `sendAdasLdsHandsOffWarnStChange sts = 2` logs may still appear, but repeated TTS requests should be replaced by `sendAdasLdsHandsOffWarnStChange skip duplicate tts`; `sendForegroundTtsPlay tts = 请手握方向盘`, `playTtsOnUi`, and TXZ `syncBackgroundTtsText` should no longer repeat at millisecond level.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Follow-up after reboot log `2026_0624_1612_11_547.log`: ADAS warning status still bounced between `1` and `2`; the previous 5-second debounce allowed another TTS after the time window expired, producing 15 sends and 15 duplicate skips.
|
||||
- Updated strategy: replace fixed 5-second replay debounce with a warning-cycle state gate. The first `sts=2` still plays immediately, but the warning is not considered cleared until `sts != 2` remains stable for 2 seconds; only after that can a later `sts=2` play again.
|
||||
- Verification after stable-clear update: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl ShowFragment visible-speak
|
||||
|
||||
- User requested visible-speak support for the Display page and previously confirmed no backup before editing.
|
||||
- Added native TXZ accessibility scanning keywords via `contentDescription`; this page does not use `shadow.register`.
|
||||
- Scope:
|
||||
- `fragment_show.xml`: added visible-speak keywords for screen off, theme mode, hidden display mode controls, wallpaper options, projection options, and video safety mode.
|
||||
- `ShowFragment.java`: dynamically refreshes Bluetooth phone projection, media audio projection, and video safety mode `contentDescription` according to current selected/checked state, so disabled state exposes open keywords and enabled state exposes close keywords.
|
||||
- `values/strings.xml` and `values-en/strings.xml`: added `show_speak_*` resources under `可见即可说 - 显示页面`.
|
||||
- Brightness bars are custom `ItemCustomSeekBarView` controls and were intentionally not added per the latest user decision to skip sliders for now.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-07-01 YX_CarControl SoundFragment visible-speak short keywords
|
||||
|
||||
- Log `C:\Users\Administrator\Desktop\徐工日志\2026_07_01_20_22_01\yx_log\2026_0701_2010_07_922.log` showed TXZ accessibility was connected and Sound page keywords were scanned into `VisualCommandModule offline`, but short utterances such as `古典`, `爵士`, and `主驾` returned `TxzVisualCommand matchedEntry = null`.
|
||||
- Root cause: Sound page `contentDescription` entries only exposed longer phrases such as `古典音效` and `主驾音场`; TXZ visible-command matching did not treat short utterances as substring matches.
|
||||
- Fix: prepend standalone short keywords to Sound page visible-speak string resources: `全车`, `主驾`, `副驾`, `默认`, `古典`, `流行`, `爵士`, `打击`, and `摇滚`; mirrored the same style in `values-en`.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Follow-up from log `C:\Users\Administrator\Desktop\徐工日志\9_45_17\yx_log\2026_0622_1451_07_056.log`: utterance `自定义` still returned `TxzVisualCommand matchedEntry = null` because the scanned Sound page list only contained `自定义音效#...` and `自定义音场#...`.
|
||||
- Final decision: do not add a bare `自定义` keyword because the Sound page has two visible `自定义` controls. Keep explicit `自定义音效` for EQ custom and `自定义音场` for sound-field custom to avoid duplicate keyword ambiguity.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl ConnectFragment visible-speak
|
||||
|
||||
- User requested visible-speak support for the Connect page and previously confirmed no backup before editing.
|
||||
- Added native TXZ accessibility scanning keywords via `contentDescription`; this page does not use `shadow.register`.
|
||||
- Scope:
|
||||
- `fragment_connect.xml`: added visible-speak keywords for Bluetooth settings entry, WLAN settings entry, Bluetooth switch, and WLAN switch.
|
||||
- `ConnectFragment.java`: dynamically refreshes Bluetooth and WLAN switch `contentDescription` according to current checked state, so disabled state exposes open keywords and enabled state exposes close keywords.
|
||||
- `values/strings.xml` and `values-en/strings.xml`: added `connect_speak_*` resources under `可见即可说 - 连接页面`.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
## 2026-06-24 YX_CarControl SmartDriveFragment visible-speak
|
||||
|
||||
- User requested visible-speak support for the Smart Drive page and previously confirmed no backup before editing.
|
||||
- Added native TXZ accessibility scanning keywords via `contentDescription`; this page does not use `shadow.register`.
|
||||
- Scope:
|
||||
- `fragment_smart_drive.xml`: added visible-speak keywords for ACC time gap, LDW switch/sensitivity, AEBS switch, FCW sensitivity, blind spot monitor, driver monitor, and traffic sign recognition.
|
||||
- `SmartDriveFragment.java`: dynamically refreshes LDW, AEBS, blind spot monitor, driver monitor, and traffic sign recognition switch `contentDescription` according to current checked state, so disabled state exposes open keywords and enabled state exposes close keywords.
|
||||
- `values/strings.xml` and `values-en/strings.xml`: added `smart_speak_*` resources under visible-speak resource groups.
|
||||
- Hidden BSIS/MOIS switches were intentionally not added because this fragment has no matching business listener for them in the current implementation.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl LightControlFragment visible-speak
|
||||
|
||||
- User requested visible-speak support for the Light page and previously confirmed no backup before editing.
|
||||
- Added native TXZ accessibility scanning keywords via `contentDescription`; this page does not use `shadow.register`.
|
||||
- Scope:
|
||||
- `fragment_light_control.xml`: added visible-speak keywords for ambient light, breathing mode, auto dome light, safety light radio options, smart welcome light, smart high/low beam, and logo light.
|
||||
- `LightControlFragment.java`: dynamically refreshes ambient light, breathing mode, logo light, auto dome light, smart welcome light, and smart high/low beam switch `contentDescription` according to current checked state, so disabled state exposes open keywords and enabled state exposes close keywords.
|
||||
- `values/strings.xml` and `values-en/strings.xml`: added `light_speak_*` resources under visible-speak resource groups.
|
||||
- Custom color picker, ambient light brightness, and key backlight selector were intentionally not added because they are touch-coordinate based custom selector/slider controls.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl CarControlFragment visible-speak
|
||||
|
||||
- User requested visible-speak support for the Car Control page and previously confirmed no backup before editing.
|
||||
- Added native TXZ accessibility scanning keywords via `contentDescription`; this page does not use `shadow.register`.
|
||||
- Scope:
|
||||
- `fragment_car_control.xml`: added visible-speak keywords for adaptive suspension modes, ESC OFF, climb mode, hill start assist, downhill assist, brake energy recovery, smart door lock, smart roof, rain sensor sensitivity, and wireless charging.
|
||||
- `CarControlFragment.java`: dynamically refreshes switch `contentDescription` according to current checked state, so disabled state exposes open keywords and enabled state exposes close keywords.
|
||||
- `values/strings.xml` and `values-en/strings.xml`: added `car_speak_*` resources under visible-speak resource groups.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl MaintenanceFragment visible-speak
|
||||
|
||||
- User requested visible-speak support for the Maintenance page and previously confirmed no backup before editing.
|
||||
- Added native TXZ accessibility scanning keywords via `contentDescription`; this page does not use `shadow.register`.
|
||||
- Scope:
|
||||
- `fragment_maintenance.xml`: added visible-speak keywords for maintenance mileage off, 5000 km, 10000 km, 30000 km, and maintenance reset.
|
||||
- `values/strings.xml` and `values-en/strings.xml`: added `maintenance_speak_*` resources under visible-speak resource groups.
|
||||
- No Java behavior change was needed; existing click listeners still handle mileage selection and reset confirmation.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-24 YX_CarControl PermissionAuthorizationFragment visible-speak
|
||||
|
||||
- User requested visible-speak support for the Permission Authorization secondary page and previously confirmed no backup before editing.
|
||||
- Added native TXZ accessibility scanning keywords via `contentDescription`; this page does not use `shadow.register`.
|
||||
- Scope:
|
||||
- `fragment_permission_authorization.xml`: added visible-speak keywords for back, authorization duration off/180 days/360 days, and all visible permission switches.
|
||||
- `PermissionAuthorizationFragment.java`: dynamically refreshes permission switch `contentDescription` according to current checked state, so disabled/off state exposes open keywords and enabled/on state exposes close keywords.
|
||||
- `dialog_permission_confirm.xml`: added visible-speak keywords for confirm close and cancel, covering the permission close confirmation flow.
|
||||
- `values/strings.xml` and `values-en/strings.xml`: added `permission_speak_*` resources under visible-speak resource groups.
|
||||
- Existing authorization duration, Settings.System persistence, permission confirmation, and switch enable/disable business logic were kept unchanged.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-26 YX_Voice drowsy TTS reminder dialog
|
||||
|
||||
- User confirmed no backup for this TTS reminder work.
|
||||
- Requirement update: fatigue reminder content must be read directly from `VoiceNewConstant.DROWSY_DRIVING`.
|
||||
- Kept the previous design decision that foreground TTS is only a reserved API; both `playTtsOnUi()` and `playTtsInBackground()` still send real audio through TXZ `syncBackgroundTtsText`.
|
||||
- Added `VoiceDrowsyReminderHelper` in `YX_Voice`:
|
||||
- Only triggers for `VoiceNewConstant.DROWSY_DRIVING`, with punctuation/blank normalization so half-width `!` input can still match the full-width constant.
|
||||
- Shows a service-safe overlay reminder dialog after the existing toast path.
|
||||
- Dialog title: `消息提醒`; content: `VoiceNewConstant.DROWSY_DRIVING`; buttons: `稍后提醒` and `不再提醒`.
|
||||
- `稍后提醒` only dismisses the current dialog; `不再提醒` persists a local SharedPreferences flag and suppresses future fatigue dialogs without suppressing TTS audio or toast.
|
||||
- Added `SYSTEM_ALERT_WINDOW` permission and released the overlay from `VoiceService.onDestroy()` to avoid stale windows during service restart.
|
||||
- Verification: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-26 YX_Voice remindLaterOrNever command
|
||||
|
||||
- User requested voice command `remindLaterOrNever` for the fatigue reminder dialog buttons `稍后提醒` and `不再提醒`.
|
||||
- Added TXZ protocol constant `CMD_REMIND_LATER_OR_NEVER = "remindLaterOrNever"` in `YX_Voice`.
|
||||
- `VoiceProtocol` now consumes `remindLaterOrNever` locally and calls `VoiceDrowsyReminderHelper` directly, because the reminder overlay belongs to the voice process and does not need cross-process dispatch.
|
||||
- Parameter parsing is tolerant across `type`, `value`, `action`, `cmd`, `text`, `word`, `keywordList`, `name`, and raw JSON fallback:
|
||||
- Contains `不再` / `never` / `noMore` / `not_remind`: persist `不再提醒` and dismiss.
|
||||
- Contains `稍后` / `later` / `snooze` / `delay`: dismiss only.
|
||||
- Touch buttons and voice command now share the same internal action handler.
|
||||
- Verification: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-26 YX_Voice drowsy TTS test broadcast
|
||||
|
||||
- Added handling for the already registered `com.voice.test.tts.yb` test broadcast in `YX_Voice` `TestReceiver`.
|
||||
- If the broadcast has no `tts` extra, it defaults to `VoiceNewConstant.DROWSY_DRIVING`, so a single adb command can trigger the fatigue TTS toast/dialog chain.
|
||||
- If `--es tts ...` is supplied, that custom text is sent through the same `playTtsOnUi()` path.
|
||||
- Verification: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-26 YX_Voice drowsy dialog day mode
|
||||
|
||||
- Continued without backup per user preference.
|
||||
- Matched the drowsy reminder dialog day/night colors to the `YX_CarControl` system version dialog style: light day background/text/buttons, dark night background/text/buttons, blue pressed state.
|
||||
- Added blank-area dismiss for the overlay root while the dialog container consumes inner clicks, matching `setCanceledOnTouchOutside(true)` behavior from the reference dialog.
|
||||
- Verification: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
- Follow-up: moved the drowsy dialog title to `strings.xml`, and moved fixed `remindLaterOrNever` protocol attr values `稍后提醒` / `不再提醒` to `VoiceNewProtocolConst`.
|
||||
- Verification after constant/resource cleanup: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-26 YX_Voice dialog/toast day-night compatibility
|
||||
|
||||
- Continued without backup per user preference.
|
||||
- Requirement: the voice reminder dialog and TTS toast must follow the current day/night theme, referencing the vehicle settings theme behavior.
|
||||
- Added `VoiceThemeHelper` in `YX_Voice`:
|
||||
- Reads the actual theme first from `Settings.Global.REQUEST_THEME_MODE`, which is written by the car-control theme manager.
|
||||
- Falls back to `Settings.System[DataUtils.THEME_MODE_CHANGED]`.
|
||||
- In auto mode, falls back to `Settings.Global.POST_LIGHT_STATUS`.
|
||||
- Finally falls back to the current resource `Configuration.UI_MODE_NIGHT_MASK`.
|
||||
- Updated `VoiceDialogHelper` and `VoiceToastHelper` to inflate their custom views with the themed context, so `values/colors.xml` and `values-night/colors.xml` are selected correctly.
|
||||
- Existing day/night color resources are kept in `YX_Voice`: light dialog/toast colors for day mode, dark dialog/toast colors for night mode.
|
||||
|
||||
## 2026-06-26 YX_Voice dialog theme refresh while showing
|
||||
|
||||
- User reported the dialog did not change after switching day/night mode; log `2026_0626_1644_36_540.log` was analyzed.
|
||||
- Key timeline from the log:
|
||||
- `16:45:28.982` voice received the smoking reckless driving TTS and scheduled the safety dialog.
|
||||
- `16:45:30.044` `VoiceDialogHelper: showInternal: drowsy reminder shown`, so the overlay view was already added to `WindowManager`.
|
||||
- `16:45:34.464` `VoiceEventHelper: themeMode 1` and `syncScreenMode status = darkMode`, meaning the theme switch happened several seconds after the overlay was created.
|
||||
- Root cause: a custom `WindowManager` overlay does not automatically reinflate or re-resolve `values-night` resources when the system theme changes after it is already visible.
|
||||
- Fix:
|
||||
- Added `VoiceDialogHelper.onThemeChanged()` to refresh an already-visible dialog by preserving the current title/content, removing the old overlay view, and adding a new themed view.
|
||||
- `SettingCommonObserver` now calls the refresh hook on `THEME_MODE_CHANGED` and also listens to `Settings.Global.REQUEST_THEME_MODE`.
|
||||
- `VoiceThemeHelper` now prefers the current `Settings.System[THEME_MODE_CHANGED]` value for manual light/dark mode; auto mode still uses `REQUEST_THEME_MODE` / `POST_LIGHT_STATUS` fallback.
|
||||
- Verification: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-26 YX_Voice toast theme refresh while showing
|
||||
|
||||
- User reported the TTS toast did not change after switching day/night mode; log `2026_0626_1705_01_941.log` was analyzed.
|
||||
- Key timeline:
|
||||
- `17:06:15.791` / `17:06:17.489` `VoiceEventHelper: playTtsOnUi` received HVAC CO2 TTS text and showed toast.
|
||||
- `17:06:18.900` user clicked dark mode switch, then `17:06:18.917` voice synced `lightMode`.
|
||||
- The screenshot still showed black toast because the custom toast view was created while the theme was still dark, before the theme switch.
|
||||
- Root cause: custom Toast views also do not re-resolve resources after being shown; cancelling/recreating is required if theme changes during the toast display window.
|
||||
- Fix:
|
||||
- `VoiceToastHelper` now keeps the last visible toast text and visibility window.
|
||||
- On `THEME_MODE_CHANGED` / `REQUEST_THEME_MODE` observer callback, it delays briefly, cancels the old toast, and re-shows the same text with the current themed context.
|
||||
- Added `VoiceToastHelper: refreshForThemeChangedInternal` log for validation.
|
||||
- Verification: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-27 YX_CarControl fatigue reminder interval UI
|
||||
|
||||
- User confirmed no backup and required only adding the new fatigue reminder feature, without changing historical feature logic.
|
||||
- Added the new Smart Drive "疲劳监测提醒" UI under existing "驾驶人员监测": switch + reminder interval control.
|
||||
- Interval requirement: 0~60 minutes, default 20 minutes, step 10 minutes; progress area is 702dp wide and 100dp high, so each 10-minute step maps to 117dp.
|
||||
- Existing progress controls were checked:
|
||||
- `ItemCustomSeekBarView` is shared by Sound/Light/Display pages and normally displays an icon.
|
||||
- `CustomLightSelector` is a 1~5 backlight selector with icon and dividers.
|
||||
- EQ/native SeekBars are not suitable for this horizontal reminder UI.
|
||||
- To avoid impacting shared historical controls, the temporary shared-control icon-removal approach was dropped; a dedicated no-icon `FatigueReminderIntervalSeekBarView` is used only by the new Smart Drive fatigue reminder interval layout.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Follow-up: the new fatigue reminder switch/interval still uses local keys in `SmartDriveFragment`, but reads/writes through `DataManager` + `DataUtils.STATE_URI` and now registers `ContentObserver` callbacks, matching the existing data-center sync style. `YX_CarControl` compiles against `sdklibs/yx_support_classes.jar`, so adding constants only in `YX_Support` source does not affect this module build unless the support jar is regenerated or the dependency is changed.
|
||||
- Verification after the data-center observer adjustment: `.\gradlew :YX_CarControl:assembleDebug` completed successfully.
|
||||
- Update: per user request, moved the fatigue reminder keys to `YX_Support` `DataUtils`: `FATIGUE_REMINDER_SWITCH` and `FATIGUE_REMINDER_INTERVAL_MINUTE`. The interval value is stored as an integer minute value, default 20.
|
||||
- Data center parity with `FATIGUE_MONITOR_SWITCH`: added `YX_DataCenterService` initialization in `YXContentProvider.mHasState`, update dispatch in `YXContentProvider.update()`, new `MessageEvent` IDs 2097/2098, and `ProviderData` SharedPreferences `putInt/getInt` persistence for the reminder switch and integer interval.
|
||||
- Build note: both `YX_CarControl` and `YX_DataCenterService` compile against `sdklibs/yx_support_classes.jar`, so `YX_Support:makeJar` or the existing support-jar replacement flow is needed before compiling these consumers with the new `DataUtils` constants.
|
||||
|
||||
## 2026-06-28 YX_Voice fatigue reminder interval
|
||||
|
||||
- User confirmed `YX_Voice` must associate the SmartDrive fatigue reminder settings:
|
||||
- `DataUtils.FATIGUE_REMINDER_SWITCH`
|
||||
- `DataUtils.FATIGUE_REMINDER_INTERVAL_MINUTE`
|
||||
- `DROWSY_DRIVING`, `DISTRACTED_DRIVING`, `SMOKING_RECKLESS_DRIVING`, and `CALLING_RECKLESS_DRIVING` reminder dialogs are now gated by the reminder switch and throttled by the interval minute value.
|
||||
- `VoiceDialogHelper` reads the DataCenter switch before showing; when enabled, it stores the last shown time and skips repeated dialogs until the configured interval expires. Interval `0` means no throttling.
|
||||
- Update: user clarified `不再提醒` and `稍后提醒` must not persist locally and must recover after reboot. `VoiceDialogHelper` now keeps both the last shown time and the current-process "never remind" flag only in static memory; it does not write SharedPreferences or change `FATIGUE_REMINDER_SWITCH` for these two dialog actions.
|
||||
- Update: user clarified the four dialog reminders are four independent functions. The current-process "never remind" flag and the last shown time are now tracked separately for `DROWSY_DRIVING`, `DISTRACTED_DRIVING`, `SMOKING_RECKLESS_DRIVING`, and `CALLING_RECKLESS_DRIVING`; one type's button action or interval throttle does not suppress the other types.
|
||||
- `SettingCommonObserver` and `BaseVoiceService` now observe the two fatigue reminder URIs; turning the switch off dismisses a pending/showing reminder overlay.
|
||||
- Verification: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-06-29 YX_Voice radio syncMediaFocus
|
||||
|
||||
- User confirmed no backup before editing.
|
||||
- Log `2026_0629_1152_07_466.log` showed Radio playback was active and TXZ received `syncFocusPlayStatus=true` plus `syncRadioPlayType=fm`, but no `syncMediaFocus: radio`.
|
||||
- Root cause: `MediaObserver` only sent media focus on `SOURCE_ID` changes; Radio startup in the log updated `RADIO_INFO` playback state without a reliable `SOURCE_ID` change notification.
|
||||
- Fix: when `RADIO_INFO` reports `mState == 2` and current `SOURCE_ID` is `YXUtils.SOURCE_RADIO`, `MediaObserver` now sends `notifySyncMediaFocus(VoiceNewProtocolConst.RADIO)` before syncing play status.
|
||||
- Verification: `.\gradlew :YX_Voice:assembleDebug` completed successfully.
|
||||
|
||||
## 2026-07-01 YX_BlueTooth ACC state cleanup
|
||||
|
||||
- User confirmed no backup before editing.
|
||||
- Requirement: check whether Bluetooth still depends on legacy `ACC_STATE`; Xugong currently follows power mode rather than old ACC state.
|
||||
- Finding: `YX_BlueTooth` `BluetoothService` still registered `ACC_STATE`, but the old disconnect/reconnect logic in that branch had already been commented out and only logged `ACC state`.
|
||||
- Fix: removed the unused `ACC_STATE_URI` constant, removed the `ACC_STATE` observer registration, and deleted the dead `case ACC_STATE_URI` branch.
|
||||
- Kept the active `LOW_VOLTAGE_POWER_STATE` logic unchanged because it still performs Bluetooth phone/headset disconnect and phone reconnect behavior; only changed misleading logs/comments from `CAN ACC OFF/ON` to `LOW_VOLTAGE_POWER_STATE OFF/ON`.
|
||||
- Verification: `.\gradlew :YX_BlueTooth:assembleDebug --console plain` completed successfully.
|
||||
|
||||
## 2026-07-02 YX_CarControl sound page visible-speak coverage check
|
||||
|
||||
- Rechecked Sound page main visible controls:
|
||||
- Sound field: all-cabin, driver, passenger, custom sound field.
|
||||
- Sound effect: default, classical, pop, jazz, electronic, rock, custom sound effect.
|
||||
- Switches: mute and key tone.
|
||||
- Sliders are intentionally not added to visible-speak yet, matching the previous decision.
|
||||
- Fixes after the coverage check:
|
||||
- The clickable custom-effect triangle in `layout_eq.xml` now uses `sound_speak_eq_user` instead of the literal `Triangle Button`.
|
||||
- `sound_speak_close_mute` now also includes bare `jingyin` / `Mute`, so the same short utterance can match both on and off states.
|
||||
- Boundary note: the custom EQ floating window (`layout_eq_user.xml` / `EqUserFloatView`) has its own EQ buttons and seek bars but is a service overlay / secondary UI, not currently treated as part of the Sound main-page visible-speak scope.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug --console plain` completed successfully.
|
||||
|
||||
## 2026-07-02 YX_CarControl voice page visible-speak short keywords
|
||||
|
||||
- Analyzed log `2026_0702_1025_08_858.log` for Voice page visible-speak.
|
||||
- At `15:08:37`, `VoiceFragment: onStart` and `syncVoiceSettingStatus status = true` were logged.
|
||||
- TXZ offline list contained Voice page entries such as `打开免唤醒#开启免唤醒`, `免唤醒10秒#设置免唤醒10秒#选择10秒`, `免唤醒15秒#设置免唤醒15秒#选择15秒`, and `免唤醒30秒#设置免唤醒30秒#选择30秒`.
|
||||
- User utterance `免唤醒` failed because the visible-speak entry only had open/close phrases, not the bare short keyword.
|
||||
- User utterance `10秒` was recognized by TXZ ASR as `十秒`; the visible-speak entry did not include `十秒`, so `matchedEntry = null`.
|
||||
- Fix:
|
||||
- Added bare `语音唤醒` to both voice wakeup switch states.
|
||||
- Added bare `免唤醒` to both wake-free switch states.
|
||||
- Added short numeric and Chinese-number forms for duration entries: `10秒#十秒`, `15秒#十五秒`, `30秒#三十秒`.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug --console plain` completed successfully.
|
||||
|
||||
## 2026-07-02 YX_CarControl sound page visible-speak key tone
|
||||
|
||||
- User reported saying bare `按键音` on Sound page did not respond.
|
||||
- Finding: `SoundFragment` dynamically sets the key-tone switch `contentDescription` based on current state; original entries only exposed `打开按键音#开启按键音` or `关闭按键音#关掉按键音`.
|
||||
- Root cause inference: TXZ visible-speak matching does not reliably treat `按键音` as a substring match for these longer phrases.
|
||||
- Fix: added bare `按键音` to both `sound_speak_open_key_tone` and `sound_speak_close_key_tone`; English resources added matching bare `Key tone`.
|
||||
- Expected verification: on Sound page, say `按键音`; log should show the offline entry containing `按键音#...` and `TxzVisualCommand` matched entry for `按键音`.
|
||||
|
||||
## 2026-07-02 YX_CarControl SmartDrive fatigue visible-speak short keywords
|
||||
|
||||
- Analyzed log `C:/Users/Administrator/Desktop/徐工日志/2026_07_02_15_25_54/yx_log/2026_0702_1025_08_858.log`.
|
||||
- Root cause: SmartDrive page offline visible-speak list only exposed state-specific phrases such as `关闭疲劳监测提醒#关掉疲劳监测提醒`; the bare utterance `疲劳监测提醒` produced `matchedEntry = null`.
|
||||
- Fix: added bare short keywords to both open and close resources for `smart_speak_*_fatigue_monitor` and `smart_speak_*_fatigue_reminder`.
|
||||
- Verification: `.\gradlew :YX_CarControl:assembleDebug --console plain` completed successfully.
|
||||
|
||||
## 2026-07-03 YX_Launcher boot-time Bluetooth music widget play
|
||||
|
||||
- User confirmed no backup before editing.
|
||||
- Requirement: after boot, clicking the Launcher main-page music card play button should play Bluetooth music.
|
||||
- Root cause:
|
||||
- `YX_Launcher` main page uses `WidgetsMedia`, whose play/prev/next buttons only sent global media keys.
|
||||
- On cold boot, Bluetooth music focus/MediaSession may not yet be established, so `KEYCODE_MEDIA_PLAY_PAUSE` can be ignored and does not explicitly trigger Bluetooth AVRCP play.
|
||||
- `WidgetsMedia.init()` queried current focus package but hard-coded the initial client id as USB music, so `com.yaxon.music` could be treated as USB music even when `SOURCE_ID` was Bluetooth music.
|
||||
- `SystemUtils.startBtMusic()` sends `is_click_bluetooth_music=true`, but `UsbMainActivity` only handled `VoiceControlManager.PAGE_TYPE`; the legacy Bluetooth-music extra was ignored.
|
||||
- Fix:
|
||||
- `WidgetsMedia` now resolves the initial card source from `SOURCE_ID` when focus package is `com.yaxon.music` or null.
|
||||
- For Bluetooth music source, Launcher card play/prev/next sends explicit broadcasts to `YX_Music` instead of relying only on global media keys.
|
||||
- Added `BluetoothMusicControlReceiver` in `YX_Music` to call `BtMusicControlManager` directly for play/pause/previous/next.
|
||||
- Play from stopped/cold state retries for up to 10 attempts at 500 ms intervals, with a request token so a later pause cancels stale retries.
|
||||
- `UsbMainActivity` now handles `is_click_bluetooth_music=true` in both initial launch and `onNewIntent()` and switches to the Bluetooth music page.
|
||||
- Verification:
|
||||
- `.\gradlew :YX_Music:assembleDebug --console plain` completed successfully.
|
||||
- `.\gradlew :YX_Launcher:assembleDebug --console plain` completed successfully.
|
||||
|
||||
## 2026-07-03 YX_Launcher Bluetooth music widget retest log analysis
|
||||
|
||||
- User provided retest logs:
|
||||
- `C:/Users/Administrator/Desktop/徐工日志/2026_07_03_11_12_02/yx_log/2026_0703_1050_00_000/2026_0703_1049_41_742.log`
|
||||
- `C:/Users/Administrator/Desktop/徐工日志/2026_07_03_11_12_02/yx_log/2026_0703_1050_33_402.log`
|
||||
- Key evidence:
|
||||
- At `07-03 11:02:37.547`, `WidgetMedia: KEYCODE_MEDIA_PLAY_PAUSE:` appears, proving the Launcher card play button click reached `WidgetsMedia`.
|
||||
- No `WidgetMedia: sendBtMusicControl action = ...`, no `BluetoothMusicControlReceiver: onReceive action = ...`, no `BtMusicControlManager: playBtMusic`, and no `BluetoothAvrcpClient: play` appear in the same retest logs.
|
||||
- Around the click, `NuPlayerDriver` / `MediaPlayer` logs appear, indicating the click path did not execute the explicit Bluetooth music broadcast control path.
|
||||
- Earlier logs show `WidgetMedia: initMedia: packageName ->null ,clientId: com.yaxon.musicsdk.manager` and `initMedia:onMusicInfo`, so the Launcher widget initially identified the source as USB music.
|
||||
- Later `WidgetMedia: onBtMusicInfo` logs prove Bluetooth music metadata can still update the card, but metadata display alone does not prove the button control path is using Bluetooth control.
|
||||
- Current conclusion: this retest log is consistent with either an old Launcher/Music package still running, or `isBtMusicControlSource()` evaluating false when the click happens. The click reached Launcher, but did not reach the new explicit Bluetooth music control receiver.
|
||||
- Next validation/fix direction:
|
||||
- On device, confirm the flashed `YX_Launcher.apk` contains the `sendBtMusicControl` code and `YX_Music.apk` contains `BluetoothMusicControlReceiver`.
|
||||
- Add a click-time diagnostic log for `mCurrentMediaSource` and `Utils.isBtMusicSource()` if another code change is needed.
|
||||
- If source detection is false at click time, make `WidgetsMedia` prefer the currently displayed `BtMusicInfo` / latest card mode for play/prev/next routing, not only `SOURCE_ID`.
|
||||
|
||||
## 2026-07-03 YX_BluetoothSDK Bluetooth music auto-pause after boot
|
||||
|
||||
- User asked to re-analyze log `C:/Users/Administrator/Desktop/徐工日志/2026_07_03_11_28_17/yx_log/2026_0703_1127_33_000.log` after reverting `YX_Launcher` `WidgetsMedia` and the `YX_Music` explicit receiver changes.
|
||||
- Key evidence:
|
||||
- This log does not contain `WidgetMedia: KEYCODE_MEDIA_PLAY_PAUSE`, so it does not prove the Launcher play button click entered `WidgetsMedia` in this capture.
|
||||
- At `07-03 11:27:30.608`, Bluetooth A2DP reports `Stream started`.
|
||||
- At `07-03 11:27:30.618/30.619`, `BluetoothMediaBrowserService` reports `PlaybackState state=3`, meaning Bluetooth music did enter playing state.
|
||||
- At `07-03 11:27:30.643`, `BtMusicManager: onPlaybackStateChanged isPlaying = true`.
|
||||
- Immediately after, `BtMusicAudioManager: setA2dpMute`, `informAudioFocusStateNative:0`, `BtMusicManager: onPlaybackStateChanged pauseBtMusic>`, `BtMusicManager: pauseBtMusic`, and `BluetoothAvrcpClient: pause` appear.
|
||||
- Root cause inference from current code:
|
||||
- `BtMusicManager.onPlaybackStateChanged()` contains protection logic: if Bluetooth music starts while `!isForeground()` and `!mBtMusicAudioManager.isFocus()`, it mutes A2DP and calls `pauseBtMusic()`.
|
||||
- During Launcher main-page startup, Bluetooth music fragment is not foreground and Bluetooth music audio focus is not held, so when phone-side/A2DP playback starts, the SDK treats it as unauthorized background playback and actively pauses it.
|
||||
- Current conclusion: this log points to `YX_BluetoothSDK` foreground/focus guard actively stopping Bluetooth music, not to AVRCP/A2DP inability to play. The system can play briefly, then the SDK pauses it because the Bluetooth music page is not foreground and focus is false.
|
||||
- Next fix direction: for Launcher card play-after-boot, ensure the Bluetooth music control path first marks/request-focus for Bluetooth music or create a controlled exception in `BtMusicManager` for a user-initiated Launcher card play request; avoid relying only on raw global media key when the Bluetooth music page is not foreground.
|
||||
|
||||
## 2026-07-03 YX_Launcher Bluetooth music widget latest 11:33 log analysis
|
||||
|
||||
- User provided latest log:
|
||||
- `C:/Users/Administrator/Desktop/徐工日志/2026_07_03_11_34_00/yx_log/2026_0703_1133_34_699.log`
|
||||
- Current code state after revert:
|
||||
- `YX_Launcher/src/main/java/com/yaxon/launcher/view/WidgetsMedia.java` play/previous/next buttons only call `YXUtils.sendKey(...)`.
|
||||
- No `sendBtMusicControl`, no explicit `YX_Music` receiver, and no current-source based Bluetooth control path exists in the reverted code.
|
||||
- Key evidence:
|
||||
- At `07-03 11:33:27.386`, `BtMusicManager` receives Bluetooth metadata: artist `王菲`, title `如愿 (电影《我和我的父辈》主题推广曲)`.
|
||||
- At `07-03 11:33:27.429`, Bluetooth playback state is stopped: `BtMusicManager: onPlaybackStateChanged isPlaying = false`.
|
||||
- At `07-03 11:33:27.735`, Launcher receives `WidgetMedia: onBtMusicInfo`, so the card can display Bluetooth music information.
|
||||
- At `07-03 11:33:42.946` and `07-03 11:33:48.389`, the Launcher card play button click reaches `WidgetsMedia`: `KEYCODE_MEDIA_PLAY_PAUSE`.
|
||||
- At `07-03 11:33:49.325`, previous button click reaches `WidgetsMedia`: `KEYCODE_MEDIA_PREVIOUS`.
|
||||
- Immediately after these clicks, logs only show `NuPlayerDriver` / `MediaPlayer` / `bus7_system_sound_out` short system-audio playback and stop/reset.
|
||||
- The log contains no `BtMusicControlManager: playBtMusic`, no `BtMusicManager: playBtMusic`, no `BluetoothAvrcpClient: play`, no `bluetooth music requestAudioFocus`, and no `setA2dpUnMute` after the Launcher button clicks.
|
||||
- Current conclusion:
|
||||
- This log proves the Launcher button click is received, but the click is not converted into a Bluetooth music play command.
|
||||
- Metadata display is working through `BtInfoPushManager -> WidgetMedia`, but control still depends on global media keys.
|
||||
- In the boot/main-Launcher scene, Bluetooth music is not foreground and does not hold focus, so the Bluetooth SDK media session is not ready to receive/respond to `KEYCODE_MEDIA_PLAY_PAUSE`.
|
||||
- Combined with the 11:27 log, the failure is a two-part issue: Launcher sends only global media keys, and `BtMusicManager` blocks or pauses Bluetooth playback when it starts without foreground/focus.
|
||||
- Next fix direction:
|
||||
- Do not rely on raw global media keys for Launcher Bluetooth card controls.
|
||||
- Add a controlled Bluetooth-music play entry that first requests/marks Bluetooth music focus, then calls `playBtMusic()`, or explicitly route Launcher card play/previous/next to a Bluetooth control API when the card is showing Bluetooth music.
|
||||
- Keep the `BtMusicManager` background-play guard intact unless there is a verified user-initiated Launcher play flag/focus path.
|
||||
|
||||
## 2026-07-03 YX_BluetoothSDK media-key fallback for Launcher BT widget
|
||||
|
||||
- User clarified: do not modify `YX_Launcher`.
|
||||
- Fix scope:
|
||||
- `YX_Launcher` remains unchanged; `WidgetsMedia` still sends `KEYCODE_MEDIA_PLAY_PAUSE` / previous / next.
|
||||
- Change is limited to `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/audio/BtMusicAudioManager.java`.
|
||||
- Fix:
|
||||
- `BtMusicAudioManager` now registers its Bluetooth music `MediaSession` during initialization instead of only after Bluetooth music obtains audio focus.
|
||||
- The session pre-handles media keys and only takes over when Bluetooth music already has focus, current `SOURCE_ID` is `SOURCE_BT_MUSIC`, or boot-time `SOURCE_ID` is `SOURCE_NULL` while valid `BT_MUSIC_INFO` exists.
|
||||
- When it takes over a play/previous/next key without focus, it requests Bluetooth music audio focus first, then calls `playBtMusic()` / `preBtMusic()` / `nextBtMusic()`.
|
||||
- `releaseAudioFocus()` no longer releases the MediaSession; it downgrades the session after focus loss so boot-time Launcher media keys can still reach Bluetooth music later.
|
||||
- Verification:
|
||||
- `.\gradlew :YX_BluetoothSDK:assembleDebug --console plain` completed successfully.
|
||||
- Confirmed no diff in `YX_Launcher/src/main/java/com/yaxon/launcher/view/WidgetsMedia.java`.
|
||||
- Retest log expectation:
|
||||
- After clicking Launcher card play, logs should show `BtMusicAudioManager: onMediaButtonEvent pre-handle`, `bluetooth music requestAudioFocus`, `setA2dpUnMute`, `BtMusicManager: playBtMusic`, and `BluetoothAvrcpClient: play`.
|
||||
- The previous failure pattern should disappear: click should no longer only show `NuPlayerDriver` / `MediaPlayer` short system sound with no Bluetooth play command.
|
||||
|
||||
## 2026-07-03 YX_BluetoothSDK first-click media-key routing follow-up
|
||||
|
||||
- User provided retest log:
|
||||
- `C:/Users/Administrator/Desktop/徐工日志/2026_07_03_13_50_05/yx_log/2026_0703_1348_33_113.log`
|
||||
- Key evidence:
|
||||
- At `07-03 13:48:28.358`, Launcher already received Bluetooth music info: `WidgetMedia: onBtMusicInfo ... mPlaySts = 0`.
|
||||
- First click around `07-03 13:48:51.498` only shows `McuService: WindowManagerGlobal = ACTION_DOWN` and system click-audio logs. There is no `MediaSessionService: Sending KeyEvent ... KEYCODE_MEDIA_PLAY_PAUSE`, no `BtMusicAudioManager: onMediaButtonEvent`, and no `BtMusicManager: playBtMusic`.
|
||||
- After the first click, Android reports `Media button session is changed to com.yaxon.music/Music`.
|
||||
- Second click around `07-03 13:48:54.527` is routed correctly: `MediaSessionService: Sending KeyEvent ... KEYCODE_MEDIA_PLAY_PAUSE ... to com.yaxon.music/Music`, then `BtMusicAudioManager: onMediaButtonEvent`, `bluetooth music requestAudioFocus: result = 1`, `setA2dpUnMute`, `BtMusicManager: playBtMusic`, and `BluetoothAvrcpClient: play`.
|
||||
- Updated conclusion:
|
||||
- The remaining symptom is not AVRCP play failure. The second click proves the Bluetooth SDK play path works.
|
||||
- The first click fails because the Bluetooth music `MediaSession` becomes the active media-button session only after the first click/system playback activity, so the first media key is not delivered to Bluetooth music.
|
||||
- Fix update:
|
||||
- Keep `YX_Launcher` and `YX_Music` unchanged.
|
||||
- In `BtMusicAudioManager`, allow `FLAG_EXCLUSIVE_GLOBAL_PRIORITY` when Bluetooth music is not focused but is a safe inactive media-button candidate: A2DP connected and either `SOURCE_ID == SOURCE_BT_MUSIC`, or `SOURCE_ID == SOURCE_NULL` with valid Bluetooth music info.
|
||||
- In `BtMusicManager`, refresh the Bluetooth music MediaSession after A2DP connect, playback-state updates, and metadata updates so the session is ready before the first Launcher card click.
|
||||
- Verification:
|
||||
- `.\gradlew :YX_BluetoothSDK:assembleDebug --console plain` completed successfully.
|
||||
- Confirmed no diff in `YX_Launcher/src/main/java/com/yaxon/launcher/view/WidgetsMedia.java`.
|
||||
- Confirmed no diff under `YX_Music`.
|
||||
- Next retest expectation:
|
||||
- The first Launcher card play click should immediately show `MediaSessionService: Sending KeyEvent ... KEYCODE_MEDIA_PLAY_PAUSE ... to com.yaxon.music/Music` followed by `BtMusicAudioManager: onMediaButtonEvent pre-handle`, `bluetooth music requestAudioFocus`, `setA2dpUnMute`, `BtMusicManager: playBtMusic`, and `BluetoothAvrcpClient: play`.
|
||||
|
||||
## 2026-07-03 YX_BluetoothSDK 14:54 log coverage check
|
||||
|
||||
- User provided log:
|
||||
- `C:/Users/Administrator/Desktop/徐工日志/2026_07_03_14_54_53/yx_log/2026_0703_1454_33_435.log`
|
||||
- Coverage result:
|
||||
- The log has only about 5720 lines and mainly covers early boot around `01-01 08:00:01` to `01-01 08:00:10` plus Android startup timestamps around `06-30 11:09:15` to `06-30 11:09:16`.
|
||||
- It does not contain `WidgetMedia`, `KEYCODE_MEDIA_PLAY_PAUSE`, `BtMusicAudioManager`, `BtMusicManager`, `BluetoothAvrcpClient`, `MediaSessionService: Sending KeyEvent`, or `07-03 14:54` runtime events.
|
||||
- The same directory only contains an empty zipped log entry `2026_0703_1454_05_407.log`.
|
||||
- Conclusion:
|
||||
- This capture does not cover the Launcher music-card click or Bluetooth music playback path, so it cannot validate whether the first-click fix succeeded or failed.
|
||||
- Next log requirement:
|
||||
- Need a log segment that includes the actual click time and contains at least Launcher `WidgetMedia` or system `MediaSessionService` media-key lines.
|
||||
|
||||
## 2026-07-03 YX_BluetoothSDK 15:02 retest validates first-click fix
|
||||
|
||||
- User provided log:
|
||||
- `C:/Users/Administrator/Desktop/徐工日志/2026_07_03_15_03_26/yx_log/2026_0703_1502_33_334.log`
|
||||
- Key evidence:
|
||||
- At `07-03 15:02:28.813`, Bluetooth metadata arrived: `BtMusicManager: artist = 伍佰 title = 世界第一等(Live)`.
|
||||
- At `07-03 15:02:28.878`, before any Launcher click, Android changed the global priority session to `com.yaxon.music/Music`.
|
||||
- At `07-03 15:02:29.311`, Launcher received Bluetooth info and displayed the card: `WidgetMedia: onBtMusicInfo ... mPlaySts = 0`.
|
||||
- At `07-03 15:02:49.194`, the first Launcher card play click reached `WidgetMedia: KEYCODE_MEDIA_PLAY_PAUSE`.
|
||||
- The same first click was routed immediately to Bluetooth music: `MediaSessionService: Sending KeyEvent ... KEYCODE_MEDIA_PLAY_PAUSE ... to com.yaxon.music/Music`.
|
||||
- `BtMusicAudioManager` received the media button while `isFocus=false`, requested focus, unmuted A2DP, then called `BtMusicManager: playBtMusic` and `BluetoothAvrcpClient: play`.
|
||||
- At `07-03 15:02:49.633` and continuously afterward, `BtMusicManager: onPlaybackStateChanged isPlaying = true` appears, with no subsequent `pauseBtMusic` or `BluetoothAvrcpClient: pause`.
|
||||
- Conclusion:
|
||||
- The SDK fix is effective for this retest. First Launcher card click now starts Bluetooth music directly; the previous "first click only arms the session, second click plays" pattern is gone.
|
||||
|
||||
## 2026-07-03 YX_BluetoothSDK 15:04 retest also validates first-click fix
|
||||
|
||||
- User provided log:
|
||||
- `C:/Users/Administrator/Desktop/徐工日志/2026_07_03_15_05_45/yx_log/2026_0703_1504_32_996.log`
|
||||
- Key evidence:
|
||||
- At `07-03 15:04:27.802`, Bluetooth metadata arrived: `BtMusicManager: artist = 任贤齐 title = 伤心太平洋 (电视剧《神雕侠侣》片尾曲)`.
|
||||
- At `07-03 15:04:27.835`, before the click, global priority session changed to `com.yaxon.music/Music`.
|
||||
- At `07-03 15:04:28.211`, Launcher card displayed Bluetooth music info with `mPlaySts = 0`.
|
||||
- At `07-03 15:04:50.143`, first Launcher play click logged `WidgetMedia: KEYCODE_MEDIA_PLAY_PAUSE`.
|
||||
- The first click was immediately routed to Bluetooth music: `MediaSessionService: Sending KeyEvent ... KEYCODE_MEDIA_PLAY_PAUSE ... to com.yaxon.music/Music`.
|
||||
- `BtMusicAudioManager` received both down/up events while `isFocus=false`, requested focus, unmuted A2DP, called `BtMusicManager: playBtMusic`, and `BluetoothAvrcpClient: play`.
|
||||
- At `07-03 15:04:50.599` and afterward, playback state remained `isPlaying = true`, with no `pauseBtMusic` or AVRCP pause afterward.
|
||||
- Conclusion:
|
||||
- This second retest confirms the fix is stable for repeated boot/Launcher-card first-click scenarios.
|
||||
|
||||
## 2026-07-03 YX_BluetoothSDK BT music restore after power off
|
||||
|
||||
- New requirement: if Bluetooth music is playing and power-off interrupts it, next power-on should restore Bluetooth music playback.
|
||||
- Scope remains limited to `YX_BluetoothSDK`; `YX_Launcher` and `YX_Music` are not modified.
|
||||
- Fix:
|
||||
- Added SDK private persisted flags `bt_music_had_focus` and `bt_music_was_playing`.
|
||||
- `BtMusicAudioManager` persists Bluetooth focus ownership after successful focus request.
|
||||
- `BtMusicManager` persists Bluetooth playback state only when Bluetooth music is the explicit `SOURCE_ID` or has focus.
|
||||
- Added `ACC_STATE` and `POWER_MODE` observers. `POWER_MODE=0/3` snapshots power-off state; `POWER_MODE=1` and `ACC_STATE=ON` trigger restore checks.
|
||||
- Restore requires all conditions: persisted had-focus, persisted was-playing, explicit `SOURCE_ID == SOURCE_BT_MUSIC`, ACC/IGN on, A2DP connected, and currently not playing.
|
||||
- Clear restore state only during normal ACC-on source/focus loss paths, not during `POWER_MODE=0/3/4` power-down phases.
|
||||
- Risk control:
|
||||
- Auto-restore does not use the Launcher default Bluetooth-source fallback. Missing `SOURCE_ID` uses `SOURCE_NULL` and will not auto-play.
|
||||
- USB music and radio are protected because restore requires explicit Bluetooth source.
|
||||
- Manual pause clears `bt_music_was_playing` while powered on and focused.
|
||||
- Verification:
|
||||
- `.\gradlew :YX_BluetoothSDK:assembleDebug --console plain` completed successfully.
|
||||
- Confirmed `git diff -- YX_Launcher YX_Music` is empty.
|
||||
|
||||
## 2026-07-07 YX_BluetoothSDK pause Bluetooth music during TXZ TTS
|
||||
|
||||
- User confirmed no backup before editing.
|
||||
- Log analyzed:
|
||||
- `C:/Users/Administrator/Desktop/徐工日志/2026_07_07_19_07_57/yx_log/2026_0707_1849_48_792.log`
|
||||
- Finding:
|
||||
- TXZ TTS requests `Synthesis` audio focus with `focusGain=2`.
|
||||
- Bluetooth music receives `AUDIOFOCUS_LOSS_TRANSIENT`, but previous `BtMusicAudioManager` handling only called `setA2dpMute()`, so the phone-side Bluetooth playback could continue progressing.
|
||||
- Radio and USB music handle transient focus loss as a real paused playback state, which explains the different behavior.
|
||||
- Fix:
|
||||
- In `BtMusicAudioManager`, `AUDIOFOCUS_LOSS_TRANSIENT` now records whether Bluetooth music was playing, calls `setA2dpMute()`, and calls `pauseBtMusic()` when it was playing.
|
||||
- Existing `AUDIOFOCUS_GAIN` recovery logic remains responsible for auto-resuming only when `isPlayingLossFocus` is true and the user did not pause manually.
|
||||
- Verification:
|
||||
- `.\gradlew :YX_BluetoothSDK:assembleDebug` completed successfully.
|
||||
@@ -0,0 +1,239 @@
|
||||
# Codex Xugong
|
||||
|
||||
## Workspace
|
||||
|
||||
- Root: `D:\zdCode\xugong`
|
||||
- Project type: multi-module Android project
|
||||
- Main module registry: `settings.gradle`
|
||||
|
||||
## Fast Start
|
||||
|
||||
下次进入这个项目,优先按下面顺序建立上下文,不需要全仓扫描。
|
||||
|
||||
1. 先确认当前任务目标
|
||||
2. 再定位相关模块
|
||||
3. 只沿调用链读取必要代码
|
||||
4. 需要修改时,再扩展到相邻模块
|
||||
|
||||
推荐开场信息:
|
||||
|
||||
```text
|
||||
继续处理 xugong 项目
|
||||
当前问题:<一句话描述>
|
||||
相关模块:<模块名列表>
|
||||
已知结论:<如果有,写 1-3 句>
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
继续处理 xugong 项目的蓝牙通讯录重复同步问题
|
||||
相关模块:YX_Voice / YX_BluetoothSDK / YX_BlueTooth
|
||||
已知结论:syncBtPhoneContactStatus 在连接成功后和 PBAP 通讯录下载完成后各发送了一次
|
||||
```
|
||||
|
||||
## Module Heuristics
|
||||
|
||||
当前仓库很大,但常见问题可先按职责收敛:
|
||||
|
||||
- `YX_Voice`: 语音协议、事件上报、蓝牙状态同步到语音侧
|
||||
- `YX_BluetoothSDK`: 蓝牙协议、PBAP、联系人/通话记录同步
|
||||
- `YX_BlueTooth`: 蓝牙业务 UI、ViewModel、页面触发入口
|
||||
- `YX_Lib_CommonBase`: 常量、公共协议字段
|
||||
|
||||
如果问题和蓝牙联系人同步有关,默认先看:
|
||||
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/helper/VoiceEventHelper.java`
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/protocol/YxProtocol.java`
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/receiver/BluetoothMonitorReceiver.java`
|
||||
- `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/modules/BtContactsManager.java`
|
||||
- `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/platform/BluetoothPbapClient.java`
|
||||
|
||||
## Current Topic
|
||||
|
||||
### Issue
|
||||
|
||||
日志文件:
|
||||
|
||||
- `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0513_1747_33_545.log`
|
||||
|
||||
问题:
|
||||
|
||||
- 打开蓝牙并连接手机后,`syncBtPhoneContactStatus` 发送了 2 次
|
||||
|
||||
### Current Conclusion
|
||||
|
||||
`syncBtPhoneContactStatus` 的两次发送不是单纯由“蓝牙打开”触发,而是两段不同链路:
|
||||
|
||||
1. 蓝牙连接成功后立即上报一次当前联系人
|
||||
2. 首次连接触发 PBAP 通讯录下载,下载完成后再次上报一次
|
||||
|
||||
关键日志时间点:
|
||||
|
||||
- `2026-05-13 17:48:07.393` 第一次发送 `syncBtPhoneContactStatus`
|
||||
- `2026-05-13 17:48:13.662` `BtContactsManager` 触发 `phoneBookPullRequest`
|
||||
- `2026-05-13 17:48:14.270` 第二次发送 `syncBtPhoneContactStatus`
|
||||
|
||||
### Relevant Code Paths
|
||||
|
||||
当前已确认的主要入口:
|
||||
|
||||
- `YX_Voice/.../YxProtocol.java`
|
||||
- `BLUETOOTH_CONNECT_STATUS` 中调用 `VoiceManager.VOICE_EVENT_HELPER.notifyContact()`
|
||||
- `YX_Voice/.../BluetoothMonitorReceiver.java`
|
||||
- `ACTION_CONTACTS_DOWNLOAD_COMPLETE` 中调用 `VoiceManager.VOICE_EVENT_HELPER.notifyContact()`
|
||||
- `YX_Voice/.../VoiceEventHelper.java`
|
||||
- `initNotifyBluetoothStatus()` 中会补发一次 `notifyContact()`
|
||||
|
||||
联系人下载链路:
|
||||
|
||||
- `BtContactsManager.onPbabStatusChanged(...)`
|
||||
- `BluetoothPbapClient.phoneBookPullRequest(...)`
|
||||
- `ContactUtils.getAllContacts(...)`
|
||||
- 完成后回到语音侧再触发联系人同步
|
||||
|
||||
## Suggested Fix
|
||||
|
||||
优先按“数据就绪事件”而不是“连接事件”驱动联系人同步。
|
||||
|
||||
建议顺序:
|
||||
|
||||
1. 去掉连接成功后立即 `notifyContact()` 的路径
|
||||
2. 保留 PBAP 下载完成后的联系人同步
|
||||
3. 保留显式查询联系人时的主动同步
|
||||
4. 给 `notifyContact()` 增加幂等保护
|
||||
|
||||
推荐幂等键:
|
||||
|
||||
- `activeDeviceMac`
|
||||
- `contactJson` 的 hash
|
||||
|
||||
推荐规则:
|
||||
|
||||
- 同一 `mac`
|
||||
- 同一份联系人内容
|
||||
|
||||
则跳过重复发送 `syncBtPhoneContactStatus`
|
||||
|
||||
### Minimal Safe Change
|
||||
|
||||
如果只做最小改动,先改这一条:
|
||||
|
||||
- 删除 `YxProtocol.BLUETOOTH_CONNECT_STATUS` 里的 `notifyContact()`
|
||||
|
||||
保留:
|
||||
|
||||
- PBAP 下载完成广播触发的 `notifyContact()`
|
||||
- 手动查询联系人时触发的 `notifyContact()`
|
||||
|
||||
同时把初始化补发改成带条件:
|
||||
|
||||
- 仅当当前已连接
|
||||
- 且本地已有该 `mac` 的联系人缓存
|
||||
|
||||
才补发联系人
|
||||
|
||||
## Re-entry Notes
|
||||
|
||||
如果下次关闭终端后重新进入,直接:
|
||||
|
||||
```powershell
|
||||
cd D:\zdCode\xugong
|
||||
```
|
||||
|
||||
然后对 Codex 说:
|
||||
|
||||
```text
|
||||
按 codex_xugong.md 继续
|
||||
```
|
||||
|
||||
或者补一句:
|
||||
|
||||
```text
|
||||
按 codex_xugong.md 继续,开始改蓝牙联系人重复同步
|
||||
```
|
||||
|
||||
## Session Log
|
||||
|
||||
### 2026-05-13
|
||||
|
||||
当前分析聚焦在“蓝牙联系人同步到语音侧”的链路。
|
||||
|
||||
#### Logs Conclusion
|
||||
|
||||
日志文件:
|
||||
|
||||
- `C:\Users\Administrator\Desktop\徐工日志\yx_log\2026_0513_1747_33_545.log`
|
||||
|
||||
结论:
|
||||
|
||||
- `syncBtPhoneContactStatus` 确实发送了 2 次
|
||||
- 不是单纯“蓝牙打开”导致 2 次
|
||||
- 实际是:
|
||||
1. 蓝牙连接成功后先上报一次联系人
|
||||
2. PBAP 通讯录下载完成后又上报一次联系人
|
||||
|
||||
#### Uncommitted Code Review
|
||||
|
||||
已分析当前工作区未提交改动,重点文件:
|
||||
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/helper/ContactHelper.java`
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/helper/VoiceEventHelper.java`
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/protocol/BluetoothProtocol.java`
|
||||
- `YX_Voice/src/main/java/com/yaxon/voice/helper/BlueToothHelper.java`
|
||||
- `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/modules/BtSettingManager.java`
|
||||
- `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/modules/BtContactsManager.java`
|
||||
- `YX_BluetoothSDK/src/main/java/com/yaxon/bluetoothsdk/modules/BtVoiceManager.java`
|
||||
|
||||
当前未提交改动的主要目的:
|
||||
|
||||
- 修复“切换不同手机后,把多个手机的通讯录一起同步给语音侧”的问题
|
||||
|
||||
当前结论:
|
||||
|
||||
1. 这次改动的主方向是对的
|
||||
2. 关键修复已经落在“按当前活动设备 `macAddress` 过滤联系人”
|
||||
3. `notifyContact()` 不再直接读全量蓝牙联系人,而是:
|
||||
- 先取 `activeDeviceMac`
|
||||
- 再调用 `getContactsNew(macAddress)`
|
||||
4. `ContactHelper.getContactsNew(macAddress)` 已经对 `content://com.yaxon.bluetooth.contact/table_contacts` 加了:
|
||||
- `selection = "macAddress = ?"`
|
||||
- `selectionArgs = new String[]{macAddress}`
|
||||
5. 数据表列名 `macAddress` 已核对,和 `YX_BluetoothSDK` 里的数据库定义一致
|
||||
|
||||
这意味着:
|
||||
|
||||
- “多台手机联系人混发”的问题,当前未提交代码已经基本修住
|
||||
|
||||
#### Remaining Risks
|
||||
|
||||
这批改动还没有解决的点:
|
||||
|
||||
1. 仍可能对同一台手机重复同步 2 次联系人
|
||||
- 连接成功一次
|
||||
- PBAP 下载完成一次
|
||||
|
||||
2. `notifyContact()` 现在强依赖 `activeDeviceMac`
|
||||
- 如果某个时序里先触发 `notifyContact()`
|
||||
- 但语音侧还没收到 `cmd.syncBtActiveDeviceMac`
|
||||
- 这次同步会直接跳过,日志会打印 `notifyContact: no active device`
|
||||
|
||||
#### Next Step
|
||||
|
||||
明天继续时,建议在当前基础上做这两件事:
|
||||
|
||||
1. 给 `notifyContact()` 增加幂等保护
|
||||
- 去重键建议:`macAddress + contactJson/hash`
|
||||
|
||||
2. 收敛联系人同步触发时机
|
||||
- 区分“连接事件”
|
||||
- 区分“PBAP 下载完成事件”
|
||||
- 避免同一份联系人重复发给语音侧
|
||||
|
||||
#### Resume Prompt
|
||||
|
||||
明天可直接输入:
|
||||
|
||||
```text
|
||||
按 codex_xugong.md 继续,基于当前未提交代码继续处理蓝牙联系人同步去重
|
||||
```
|
||||
@@ -0,0 +1,145 @@
|
||||
# 联系人 JSON 数据组装说明
|
||||
|
||||
## JSON 结构
|
||||
|
||||
最终组装为一个根对象,根对象下只有 `contact` 数组:
|
||||
|
||||
```json
|
||||
{
|
||||
"contact": [
|
||||
{
|
||||
"name": "张三",
|
||||
"number": "13800138000"
|
||||
},
|
||||
{
|
||||
"name": "李四",
|
||||
"number": "+8613900139000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
空联系人时返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"contact": []
|
||||
}
|
||||
```
|
||||
|
||||
## 组装规则
|
||||
|
||||
1. 每个联系人 item 只包含两个字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "联系人姓名",
|
||||
"number": "联系人号码"
|
||||
}
|
||||
```
|
||||
|
||||
2. 优先使用 `number_detail` 字段。
|
||||
|
||||
`number_detail` 是 JSON 数组字符串,用于表示同一个联系人下的多个号码,例如:
|
||||
|
||||
```json
|
||||
["13800138000", "13900139000"]
|
||||
```
|
||||
|
||||
3. 如果 `number_detail` 不为空,则解析其中每一个号码,并分别展开成独立联系人 item。
|
||||
|
||||
例如:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "张三",
|
||||
"number_detail": ["13800138000", "13900139000"]
|
||||
}
|
||||
```
|
||||
|
||||
会组装为:
|
||||
|
||||
```json
|
||||
{
|
||||
"contact": [
|
||||
{
|
||||
"name": "张三",
|
||||
"number": "13800138000"
|
||||
},
|
||||
{
|
||||
"name": "张三",
|
||||
"number": "13900139000"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
4. 如果 `number_detail` 为空,或者解析失败,则使用 `number` 字段兜底。
|
||||
|
||||
5. 号码为空时不加入数组。
|
||||
|
||||
6. 号码会做格式清洗,只去除以下字符:
|
||||
|
||||
```text
|
||||
- 空格 ( )
|
||||
```
|
||||
|
||||
保留数字和 `+`。
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
+86 138-0013-8000 -> +8613800138000
|
||||
138 0013 8000 -> 13800138000
|
||||
```
|
||||
|
||||
7. 会按 `name + "|" + number` 去重,同一姓名同一号码只保留一条。
|
||||
|
||||
## 核心组装代码
|
||||
|
||||
```java
|
||||
JSONArray contactArray = new JSONArray();
|
||||
Set<String> uniqueKeys = new HashSet<>();
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
String name = cursor.getString(idxName);
|
||||
String number = cursor.getString(idxNumber);
|
||||
String numberDetail = cursor.getString(idxNumberDetail);
|
||||
|
||||
if (!TextUtils.isEmpty(numberDetail)) {
|
||||
try {
|
||||
JSONArray numbers = new JSONArray(numberDetail);
|
||||
for (int i = 0; i < numbers.length(); i++) {
|
||||
addContactItem(contactArray, uniqueKeys, name, numbers.optString(i, ""));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
addContactItem(contactArray, uniqueKeys, name, number);
|
||||
}
|
||||
} else {
|
||||
addContactItem(contactArray, uniqueKeys, name, number);
|
||||
}
|
||||
}
|
||||
|
||||
JSONObject root = new JSONObject();
|
||||
root.put("contact", contactArray);
|
||||
return root.toString();
|
||||
```
|
||||
|
||||
```java
|
||||
private void addContactItem(JSONArray contactArray, Set<String> uniqueKeys,
|
||||
String name, String number) {
|
||||
if (TextUtils.isEmpty(number)) return;
|
||||
|
||||
String formattedNumber = number.replaceAll("[-\\s()]", "");
|
||||
if (TextUtils.isEmpty(formattedNumber)) return;
|
||||
|
||||
String key = (name == null ? "" : name) + "|" + formattedNumber;
|
||||
if (uniqueKeys.contains(key)) return;
|
||||
uniqueKeys.add(key);
|
||||
|
||||
JSONObject item = new JSONObject();
|
||||
item.put("name", name);
|
||||
item.put("number", formattedNumber);
|
||||
contactArray.put(item);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,72 @@
|
||||
# xugong_init
|
||||
|
||||
## 用途
|
||||
|
||||
这个文件记录 `xugong` 仓库的本地初始化结果,以及下次进入仓库时的最小启动步骤。
|
||||
|
||||
## 当前结论
|
||||
|
||||
当前仓库已经完成基础初始化校验,不需要每次重新初始化。
|
||||
|
||||
已确认可用:
|
||||
|
||||
- 仓库根目录:`D:\zdCode\xugong`
|
||||
- 当前分支:`develop_xcmg`
|
||||
- Android SDK:由 `local.properties` 指向本机 SDK
|
||||
- JDK:`Java 1.8`
|
||||
- Gradle Wrapper:`gradlew.bat` 可运行
|
||||
- Gradle:首次 Wrapper 解压和项目识别已完成
|
||||
|
||||
## 下次进入项目
|
||||
|
||||
直接进入仓库:
|
||||
|
||||
```powershell
|
||||
cd D:\zdCode\xugong
|
||||
```
|
||||
|
||||
如果只是开始开发,通常不需要重新初始化,直接执行需要的任务即可。
|
||||
|
||||
例如:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat projects
|
||||
.\gradlew.bat :YX_Voice:assembleDebug
|
||||
.\gradlew.bat :YX_Launcher:assembleDebug
|
||||
```
|
||||
|
||||
## 什么时候需要重新检查初始化
|
||||
|
||||
只有以下情况才建议重新检查:
|
||||
|
||||
- 换了电脑
|
||||
- 重装了 JDK / Android Studio / Android SDK
|
||||
- 删除了 `~/.gradle` 缓存
|
||||
- `local.properties` 被改动或丢失
|
||||
- Gradle 报环境错误
|
||||
- Android SDK 路径失效
|
||||
|
||||
## 快速排查命令
|
||||
|
||||
检查 Java:
|
||||
|
||||
```powershell
|
||||
java -version
|
||||
```
|
||||
|
||||
检查 Gradle Wrapper:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat -version
|
||||
```
|
||||
|
||||
检查模块识别:
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat projects
|
||||
```
|
||||
|
||||
## 备注
|
||||
|
||||
- 仓库当前存在未提交改动,操作时不要随意执行重置或清理命令。
|
||||
- 该工程是多模块 Android 项目,模块清单以 `settings.gradle` 为准。
|
||||