first commit

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

No files matched your search

@@ -0,0 +1,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、崩溃、空指针 |