02 · 蜂窝网络与卫星通信

蜂窝:telecomm/TeleCommunicationSelectController.kt 卫星:connection/controller/MobileNetworkSatelliteController.ktsatellite/SatelliteSettingDialog.ktsrc/{xcddif,dcddif}/.../TelephonyUtil.kt 网络:network/NetworkFlowGuideDialog.ktnetwork/QrCodeBitmapUtils.kt

1. 蜂窝网络(双卡运营商选择)

TeleCommunicationSelectController.kt:25-245蜂窝网络分组在 DCD 平台整体隐藏(见 连接主页 §4)。

背景

注释 :35 说明:XCD P2.1 板子同时有两张 eSIM(卡1电信,卡2移动),这是该功能存在的硬件前提。三 Tab(:36-38,80-97):

  • NETWORK_CTCC=0(中国电信)/ NETWORK_CMCC=1(中国移动)/ NETWORK_AUTO=2(智能双卡)

文案(直抄 strings.xml)

  • title micar_connection_vehicle_network_title = “优先运营商”
  • Tab:micar_connection_vehicle_network_CT=“中国电信”、..._CMCC=“中国移动”、..._smart_mode=“智能双卡”
  • summary:CTCC=“优先使用中国电信,网络状态差时自动切换”;CMCC=“优先使用中国移动,网络状态差时自动切换”;auto=“根据网络状态动态切换运营商,提高网络服务质量”

关键行为

  • 缓存 Settings.Global.VEHICLE_MOBILE_NETWORK_SELECTION(:32,185-191)
  • onResumeInternal:99-125:读缓存→异步 getCurrentMobileNet() 实查→不一致则更新
  • onSelectTabChanged:143-183:异步 TelephonyUtil.setDefaultChannel(channel),失败回滚 UI
  • TelephonyUtil 双卡实现在 xcd flavorsrc/xcddif/.../TelephonyUtil.kt:119-172,反射 TelephonyManagerEx.setUserDefaultChannel);dcd flavor 空实现dcddif/.../:119-127,注释”dcd没有使用,为编译通过”)

通话状态保护

  • updateEnableState:56-68 注册 TelephonyCallback.PreciseCallStateListener(:204-210),CALL_STATE_OFFHOOK/RINGING 时 Tab 置灰
  • 禁用时点击 onDisabledTabClicked:70-78 弹”SIM 切换失败”对话框(通话中禁用)
  • 多 TelephonyManager callback 用 ConcurrentHashMap<TelephonyManager, TelephonyCallback>(:48)一一对应——重要坑:FWK Binder 解注册只释放最后注册的,不一一对应会 callback 超限(注释 :43-47)

2. 卫星通信

能力判断

ConnectionSettingsTopFragment.java:195-197!TelephonyUtil.isSupportSatelliteByDevice()→移除整个”移动网络”分组。TelephonyUtil(flavor 源码)反射隐藏类 android.telephony.TelephonyManagerExisSupportSatelliteByDevice()

⚠️ 已确认 bug(对抗记录 Bug 1):dcddif 版(:43,:47)invoke 传 _defaultMgr(TelephonyManager 实例)而非 telephonyMgrExDefault(TelephonyManagerEx),receiver 类型不匹配→IllegalArgumentException→catch→返回 false。DCD 平台卫星恒隐藏。xcddif 版传值正确。实际影响取决于 DCD 是否真支持卫星(需现场验证)。

入口与跳转

MobileNetworkSatelliteController.kt:22-93

  • XML 直接写 <intent android:action="android.settings.SATELLITE_COMMUNICATE"/>(connection_settings_fragment.xml:140),点击/点图标都拉起 SatelliteSettingsActivity(manifest:101,109)

⚠️ 已确认问题(对抗记录 Bug 3):manifest :109,113 同时注册 SATELLITE_COMMUNICATE(正确)和 SATELLITE_COMMUNITE(拼写错误,少 C),推测兼容调用方笔误。

  • 文案(直抄):title=“卫星通信”、summary=“可通过天通卫星接打电话”、status_on=“已开启”、status_off=“已关闭”
  • 右侧文案:监听广播 com.android.app.action.SATELLITE_STATE_CHANGE(:36,40-53),extra is_enable,异步查 isSatelliteEnable(SLOT_DEFAULT)(:79-92)

卫星弹窗流程

SatelliteSettingsActivity.kt:10-23 加载 SatelliteSettingDialog。三态:CONNECTING(0x1)/CONNECTED(0x2)/DISCONNECTED(0x3)(:311-314)。

  • 进入:isSatelliteEnable() 决定初态(:282-283)+ registerTelephonyCallback(:285)
  • 点”开启”:异步 setSatelliteEnable(ctx,true)→CONNECTING+旋转动画+MSG_TIME_OUT_CHECK 延时 TIME_TO_WAIT=120s(:190,317);超时未 STATE_IN_SERVICE→toast 失败+finish(:54-65)
  • 点”关闭”:setSatelliteEnable(ctx,false)→DISCONNECTED→finish(:246-258)
  • 点”去拨号”:发 mi.car.intent.action.SELECT_SATELLITE,包名 com.android.car.dialer(:319-320,260-268)
  • ServiceState.STATE_IN_SERVICE 回调→CONNECTED(:104-119)

卫星能力绑在 SIM slot 1SLOT_N801=1(:311 注释”n801默认卫星卡”)。registerTelephonyCallback(:123)反射 SubscriptionManager.getSubscriptionId(slotId) 拿 subId,失败用 -1 fallback(:131-136)。

sequenceDiagram
    participant U as 用户
    participant Ctl as MobileNetworkSatelliteController
    participant Dlg as SatelliteSettingDialog
    participant Tu as TelephonyUtil(反射)
    participant TM as TelephonyManager(subId)
    participant FWK as Modem
    U->>Ctl: 点击"卫星通信"
    Ctl->>Dlg: intent SATELLITE_COMMUNICATE
    Dlg->>Tu: isSatelliteEnable()
    Dlg->>TM: registerTelephonyCallback(subId=getSubscriptionId(SLOT_N801=1))
    U->>Dlg: 点"开启"
    Dlg->>Tu: setSatelliteEnable(ctx,true)
    Dlg->>Dlg: CONNECTING + 120s 超时
    FWK->>TM: STATE_IN_SERVICE
    TM->>Dlg: onServiceStateChanged→CONNECTED
    U->>Dlg: 点"去拨号"
    Dlg->>U: 启动 com.android.car.dialer

⚠️ 已确认 bug(对抗记录 Bug 2):137 注册在 mTelephonyManager.createForSubscriptionId(finalSubId) 返回的新实例:275 解注册在原 mTelephonyManager 上——实例不一致,callback 可能泄漏/解注册失败。

3. 网络引导与二维码

NetworkFlowGuideDialog(network/NetworkFlowGuideDialog.kt:18-101

“流量赠送用户领取引导弹窗”,继承 BaseConflictDialogActivity。

  • 接收 intent extra content_data(JSON)→ ContentData(popTitle, popContent, type, value)(:54-56,95-100)
  • 校验 type=="qr" 才显示(:21,59-65),否则 finish
  • QrCodeBitmapUtils.createQRCodeWithLogo(url,size,size,R.drawable.ic_network_guide,logoSize,logoSize) 生成中间带 logo 二维码(:75-90),ViewOutlineProvider 圆角
  • onPause 直接 finish(:48-51)——一次性弹窗,被动接收(拉起方不在本仓)

QrCodeBitmapUtils(network/QrCodeBitmapUtils.kt:19-134

通用二维码工具,zxing QRCodeWriter,纠错 M、utf-8、margin 0、deleteWhite 去白边(:68-75,120-133);createQRCodeWithLogo 中心贴 logo(:42-47)。被 NetworkFlowGuideDialog 与 HotspotQrCodeUtils 共用。

4. 平台差异与坑(DCD vs XCD)

  • DCD 平台 = ro.board.platform == "msmnile"(DeviceUtil.java:226-228)
  • DCD 隐藏蜂窝网络(双卡选择);XCD P2.1 双 eSIM 才显示
  • TelephonyUtil flavor:xcd 双卡实实现 / dcd 空实现仅占位编译
  • ⚠️ dcddif isSupportSatelliteByDevice 反射 receiver bug(见 §2)
  • ⚠️ manifest SATELLITE 双拼写(COMMUNICATE+COMMUNITE)
  • ⚠️ SatelliteSettingDialog 注册/解注册 TelephonyManager 实例不一致
  • 卫星连接最长等 120s,超时 toast 失败+finish,用户需重新点击
  • 卫星能力绑 SIM slot 1(SLOT_N801=1)

关键调用点速查

关注点位置
双卡 Tab 切换TeleCommunicationSelectController.kt:143-183
setDefaultChannel(xcd)src/xcddif/…/TelephonyUtil.kt:119-172
通话中禁用TeleCommunicationSelectController.kt:56-68,204-210
卫星入口状态刷新MobileNetworkSatelliteController.kt:36-53
卫星开关弹窗SatelliteSettingDialog.kt:190,246-258
卫星 120s 超时SatelliteSettingDialog.kt:54-65,317
卫星拨号SatelliteSettingDialog.kt:260-268,319-320
isSupportSatelliteByDevicesrc/{xcddif,dcddif}/…/TelephonyUtil.kt:35-63
网络引导 QRNetworkFlowGuideDialog.kt:75-90

附录 A · 平台契约实证与对接人(N801PROB-138847, 2026-08-31)

「受理即 true」契约断点(源码实锤,/home/zbc/pangu/yu7)

  • 受理层 miui/frameworks/telephony/common/telephony/auto/com/android/phone/data/MultiInternetRouteController.java:392 setUserDefaultChannel:先写 Settings.Global 记偏好 → 调 SmartDataChannelController.setApnDefaultChannel(...) 丢弃其返回值 → 无条件 return true(仅非法 channel / 同值重复才 false)。
  • 执行层 .../data/SmartDataChannelController.java:1710 setApnDefaultChannel:目标通道 rat 非 LTE/NR 时打 setApnDefaultChannel ignore due to rat=X !return false——false 已存在,断点在受理层没接住
  • API common/base/java/android/telephony/TelephonyManagerEx.java:117,javadoc 仅 “success or not” 未定义受理/完成语义。
  • 后果:调用方(车机设置优先运营商 Tab)按「true=成功」持久化并保持选中态,单卡/无服务环境下用户看到「选了移动但永远电信」零反馈。
  • 修复落点:受理层透传执行层返回值,或对无卡/无服务通道直接 false;执行层 rat=0 防护不动(强切=整车断网)。
  • 证据包:jira-data/N801PROB-138847/analysis/platform-evidence-package.md。

平台对接人(用户亲述,confirmed 2026-08-31)庄员 zhuangyuan@xiaomi.com——TelephonyManagerEx / SmartDataChannelController / 多网数据通道切换类问题直接转他。