# 05_Launcher卡片流程 ## Launcher 卡片做什么 Launcher 蓝牙音乐卡片负责: ```text 1. 显示蓝牙音乐标题 2. 显示歌手 3. 显示封面 4. 显示播放状态 5. 显示当前进度和总时长 6. 提供上一曲、播放/暂停、下一曲按钮 ``` 核心文件: ```text F:\zdCode\tongli\YX_Launcher\src\main\java\com\yaxon\launcher\card\BluetoothMusicCardView.java F:\zdCode\tongli\YX_Launcher\src\main\res\layout\card_bluetoothmusic.xml ``` ## 卡片显示流程 ```text 1. BluetoothAvrcpClient 收到歌曲信息或播放状态 ↓ 2. BtInfoPushManager.sendMusicInfoToLauncher() 或 sendMusicStateToLauncher() ↓ 3. 组装 BtMusicInfo ↓ 4. DataManager.putObject(BT_MUSIC_INFO, btInfo) ↓ 5. 发送 ACTION_UPDATE_MUSIC_WIDGET 广播 ↓ 6. Launcher 的 Id3Info 读取 BT_MUSIC_INFO ↓ 7. Id3Info 回调 BluetoothMusicCardView.onBtMusicInfo() ↓ 8. BluetoothMusicCardView.bindInfo() ↓ 9. 更新卡片 UI ``` ## 卡片显示字段 | 卡片内容 | 数据字段 | |---|---| | 歌曲名 | `BtMusicInfo.mTitle` | | 歌手 | `BtMusicInfo.mArtist` | | 封面 | `BtMusicInfo.mAlbumUrl` | | 播放状态 | `BtMusicInfo.mPlayState` | | 当前进度 | `BtMusicInfo.mPlayPosition` | | 总时长 | `BtMusicInfo.mSongLen` | ## 卡片进度条逻辑 ```text 1. 收到 BtMusicInfo ↓ 2. 保存 mLastPositionMs ↓ 3. 保存 mLastDurationMs ↓ 4. 保存 mLastUpdateUptimeMs ↓ 5. 如果是播放中 ↓ 6. 每秒用本地时间估算进度 ↓ 7. updateProgress() ``` 这意味着: ```text Launcher 卡片不是每秒都等蓝牙栈回调, 而是在播放中自己按时间推进进度条。 ``` ## 卡片控制流程 ```text 1. 用户点击 Launcher 卡片按钮 ↓ 2. BluetoothMusicCardView.onClick() ↓ 3. notifyBtSourceActive() ↓ 4. DataManager.putInt(SOURCE_ID, SOURCE_BT_MUSIC) ↓ 5. sendBtControl(cmd) ↓ 6. DataManager.putInt(MUSIC_BT_CONTROL_STATE, cmd) ↓ 7. BtMusicAudioManager 的 ContentObserver 收到变化 ↓ 8. 如果蓝牙音乐没有焦点,先 requestAudioFocus() ↓ 9. 根据 cmd 调用 BtMusicManager ↓ 10. BtMusicManager 调用 BluetoothAvrcpClient ↓ 11. 手机音乐 App 响应 ↓ 12. MUSIC_BT_CONTROL_STATE 重置为 -1 ``` ## 卡片按钮命令 | 卡片按钮 | 写入命令 | |---|---| | 上一曲 | `StateUtils.MUSIC_BT_CONTROL_PRE` | | 下一曲 | `StateUtils.MUSIC_BT_CONTROL_NEXT` | | 播放 | `StateUtils.MUSIC_BT_CONTROL_PLAY` | | 暂停 | `StateUtils.MUSIC_BT_CONTROL_PAUSE` | ## 为什么要重置为 -1 ```text 如果连续点击同一个按钮,比如连续点下一曲: 第一次写入 MUSIC_BT_CONTROL_NEXT ↓ ContentObserver 触发 ↓ 处理完成后写回 -1 ↓ 下一次再写 MUSIC_BT_CONTROL_NEXT ↓ 值发生变化,ContentObserver 可以再次触发 ``` 如果不重置,同一个值可能不会再次触发观察。