35 · 复合连接互斥弹窗(连接蓝牙将断开 ICCOA Carlink)
核心文件:
ConnectionUtils.kt(判定矩阵 + 弹窗本体,:170-283)、controller/BluetoothBondedDevicesPrefController.java(入口①connectMis:203)、controller/BluetoothOperationsController.java(入口②:157)、view/MiBluetoothPairingDialogActivity.kt(入口③:145)、MiBluetoothUtils.kt(配对变体入口:269) 适用范围:连接/配对蓝牙时与活跃复合连接(ICCOA Carlink / CarPlay / 小米设备互联 / AndroidAuto)互斥的二次确认弹窗 关联:33 §8 MisComplexSdk 在详情页的监听、03 §7 MIS 联动、02-蓝牙-配对流程 代码基线:dev 主线 2026-08-27(micarConnectionSettings为 app 层、跨 flavor 共享;Controller 行号含 PS3 修复后)
0. 一句话结论
标题「连接蓝牙」、内容「继续连接将会断开正在使用的 ICCOA Carlink」的弹窗 = 车机当前有活跃 ICCOA Carlink 复合连接时,用户从任一入口发起蓝牙连接,ConnectionUtils.confirmConnectWhenMisExist(:222)判定类型后弹出的互斥二次确认;点「连接」先断 Carlink 再真连蓝牙。
1. 弹窗本体:switchBluetoothDeviceUnderMis(ConnectionUtils.kt:257)
| 元素 | 资源 | zh 值 |
|---|---|---|
| 标题(连接场景) | micar_bluetooth_connect_device_confirm_title(zh:87) | 连接蓝牙 |
| 标题(配对场景) | micar_bluetooth_pair_device_confirm_title | 配对蓝牙 |
| 内容(连接场景) | micar_bluetooth_connect_device_confirm_desc(zh:89) | 继续连接将会断开正在使用的 %1$s |
| 内容(配对场景) | micar_bluetooth_pair_device_confirm_desc(zh:90) | 继续配对将会断开正在使用的 %1$s |
| %1$s 填充 | getConnectType()(:170)按 connInfo.type 查表 | CARPLAY→“Apple CarPlay”;CARLINK→“ICCOA Carlink”(zh:13);MIRROR→小米设备互联;AA→Android Auto |
| 按钮 | ..._confirm_postive / operation_cancel | 连接(配对)/ 取消 |
所以看到「…断开正在使用的 ICCOA Carlink」即可反推:弹窗时刻 getConnectInfo().type == CONNECT_TYPE_CARLINK。
requestTopDisplay=true 时 window.setType(TYPE_APPLICATION_OVERLAY)(:278-281)——弹窗可越过前台应用置顶。入口①②传 false,仅配对流程可能传 true。
2. 判定矩阵(confirmConnectWhenMisExist :222-248)
flowchart TD A[用户发起蓝牙连接] --> B{"MisComplexSdk.getConnectInfo()<br/>当前有复合连接?"} B -->|null| C[不弹,直接连接] B -->|非null| D{当前复合连接 connInfo.type} D -->|CARLINK<br/>ICCOA Carlink| E[弹窗<br/>不看地址,连哪台都弹] D -->|CARPLAY| F{"待连设备地址 == connInfo.btMac?<br/>(同一台手机)"} F -->|是| E F -->|否| C D -->|MIRROR 小米设备互联| C D -->|ANDROID_AUTO| C E --> G{用户选择} G -->|连接| H["disconnectByBluetooth(type)<br/>断当前复合连接 → connectDevice"] G -->|取消| I[中止连接]
语义(:218-220 注释原文):连接蓝牙影响所有 CarLink,影响同一设备的 CarPlay,不影响小米设备互联,不影响 AndroidAuto——Carlink 数据走蓝牙链路所以必被冲掉;CarPlay 只在重连同一台手机时冲突;Mirror/AA 数据不走蓝牙,无需确认。
3. 四个触发入口
| 入口 | 场景 | 代码路径 | 函数 |
|---|---|---|---|
| ① | 已配对列表点行/右侧图标(设备未连接分支) | BluetoothBondedDevicesPrefController :176 handlePreferClick → :188 → connectMis:203 | confirmConnect |
| ② | 设备详情页点「连接」(PreferenceAction.Connect) | BluetoothOperationsController.handlePreferenceChanged:157 | confirmConnect |
| ③ | 被动收到配对即连接请求 | MiBluetoothPairingDialogActivity.handlePairingIntent:145(前置 !isPairingAsClient && connectInfo != null,防 MIS 自发起配对被劫持) | confirmConnect |
| ④ | 主动配对场景 | MiBluetoothUtils.kt:269 | confirmPair(同矩阵,文案换「继续配对…」) |
4. 用户选择后的动作
- 连接/配对(:272-274 → 调用方回调):先
MisComplexSdk.disconnectByBluetooth(connInfo.type)断当前复合连接(:234-236),再执行真正的connectDevice/doPairDevice。 - 取消:连接场景①②直接中止;入口③取消额外
cachedDevice.performUnpair(null)+ dismiss(PairingDialogActivity:151-156)——被动配对被拒绝即取消配对。
5. 姊妹函数(同族确认,共用 getConnectInfo() 快照)
confirmDeleteDeviceWhenMisExist(:296+):删设备对 CarLink 无影响(type != CARLINK才判),同设备的 Mirror/CarPlay/AA 受影响 → 弹「取消配对」确认;AA 特殊:确认后主动断开,防止删设备后立刻触发蓝牙回连配对弹窗。confirmDisconnectWhenMisConnected(BluetoothOperationsController 断开分支 :169+ 引用):断开蓝牙时是否提示冲掉复合连接,内部条件待验证。
6. 排障要点与坑
- 误弹第一嫌疑 =
getConnectInfo()快照陈旧:弹与不弹完全由该快照决定;若 Carlink 实际已断但 aar 侧缓存未清(同族先例:3960 activeCount 陈旧虚高),会出现「没有 Carlink 在用却弹窗」。排查先 dumpMisComplexSdk连接信息与实际连接对账。 - 日志锚点(可复制 grep):
d-confirm connect(...) when mis:... exist(:247)/d-confirm pair(...) when mis:... exist(:214)标记进入判定;confirm switch connect bluetooth device(:273)标记用户点了确认。三连可还原「弹没弹→用户选了啥」。 - CARLINK 分支不看地址:任何设备(包括与 Carlink 同一台手机)发起蓝牙连接都弹;CarPlay 分支才比
btMac。别按 CarPlay 的直觉套 Carlink。 - 弹窗可置顶(
requestTopDisplay→ OVERLAY):遇到「莫名顶层弹窗」先查调用方是否传 true,再查是哪个入口。 - 连接与配对是两条文案:看到「继续配对…」标题「配对蓝牙」走的是
confirmPairWhenMisExist(:186),矩阵相同但语义是配对前确认,别混入口。 - 判定在 Settings 侧、执行在外部 aar:
MisComplexSdk是com.xiaomi.phonecarlink:complexaar(详见 33 §8),实际断连动作跨进程异步完成——点「连接」后 Carlink 断开与新蓝牙连接的时序交叠在 aar/外部 app 侧,Settings 不保证先后。