01 · 连接主页架构与路由

入口 Fragment:connection/view/ConnectionSettingsTopFragment.java 页面 XML:res/xml/connection_settings_fragment.xml 路径相对 settingsPage/micarConnectionSettings/src/main/

1. 在车设中的定位

连接页是车设 13 个一级页面之一,与车辆控制/灯光/门窗锁/驾驶/辅助驾驶/安全/能量/显示/声音/IoT/语音/服务/系统 并列。

  • 菜单声明:app/src/region/{cn|global}/res/xml/miauto_top_level_menu_fragment.xml:79-86
    • key: @string/psk_settings_connection_entry
    • fragment: com.android.car.settings.miauto.connection.view.ConnectionSettingsTopFragment
    • settings:hiddenFeatures="@string/micar_common_settings_lemans_ece" → Lemans ECE 车型隐藏入口
  • 页面别名:PageAlias.PAGE_CONNECTION = "connection"base/settingsBaseUi/.../common/pageroute/PageAlias.kt:31),PageRouterConfig.kt:22 映射到 R.string.psk_settings_connection_entry

2. 继承链与注解

classDiagram
    direction TB
    class SettingsFragment
    class BaseXmlParserSettingsFragment {
        <<abstract>>
        +List~Integer~ getPreferenceKeyResIdsToRemove()
        #removePreference(int keyResId)
    }
    class TopLevelSettingsFragment {
        <<abstract 一级页通用能力>>
        -左侧 margin 136dp / 顶部 230dp
        -锚点跳转动画 / Folme 弹簧滚动
        +getPageAlias()*
        +getPreferenceScreenResId()*
    }
    class ConnectionSettingsTopFragment {
        +getRightFragment() → ConnectionSettingsRightFragment
        +getPageAlias() = "connection"
        +getPreferenceScreenResId() = R.xml.connection_settings_fragment
        +getPreferenceKeyResIdsToRemove()
        -gatherController()
        -notifyConnectStateChange(ConnectInfo)
    }
    class BaseRightFragment {
        <<右侧车模容器>>
        +int getInitCarModelImgRes()*
    }
    class ConnectionSettingsRightFragment {
        +getInitCarModelImgRes() 雷达/卡钳 4 图
    }
    SettingsFragment <|-- BaseXmlParserSettingsFragment
    BaseXmlParserSettingsFragment <|-- TopLevelSettingsFragment
    TopLevelSettingsFragment <|-- ConnectionSettingsTopFragment
    BaseRightFragment <|-- ConnectionSettingsRightFragment

基类 TopLevelSettingsFragmentbase/settingsBaseUi/.../miauto/TopLevelSettingsFragment.java)封装一级页通用能力。BaseXmlParserSettingsFragment 提供 getPreferenceKeyResIdsToRemove() 模板方法(:1083-1091removePreferencesIfNeed 在 Preference 树构建后逐个 removePreference)。

三大注解(ConnectionSettingsTopFragment.java:57-60

注解定义作用
@VoiceSearchProvidersettingsCommon/plugin/voice/voicesearchannotation/标记参与语音搜索;APT VoiceSearchProcessor 反射调 getPreferenceScreenResId()/getPageAlias()/getPreferenceKeyResIdsToRemove() 生成索引。约束:反射发生在 Fragment 未 attach 时,getPreferenceKeyResIdsToRemove() 内严禁调 getContext()/getString()(见 BaseXmlParserSettingsFragment.java:1064-1074
@Module(TAG_CONNECTION)settingsCommon/plugin/router/annotation/Module.java注册到路由模块表,SettingsConstant.TAG_CONNECTION = "micarConnectionSettings"。须在 SettingsApplication.java:34@Modules({...}) 列出才会被 Router.merge() 合并
@MonitorFragmentcom.mi.car.dfx_sdk.MonitorFragment(外部 SDK)DFX 埋点标记,13 个一级 Fragment 都加

3. 页面结构(connection_settings_fragment.xml)

4 个 MiCarPreferenceCategory + 若干 SpacePreference 间隔。Entry 详见 00-README 四大类入口表。其中:

  • 蓝牙/WLAN/热点 通过 静态 XML <intent android:action=.../> 跳转,controller 只管状态显示
  • 手车互联 4 项 无静态 intent,靠 controller 的 doConnect() 发 URI
  • 蜂窝网络 NewTabPreference,Tab 内完成切换
  • 卫星 通过 intent android.settings.SATELLITE_COMMUNICATE
flowchart TB
    subgraph Top["ConnectionSettingsTopFragment"]
        C1["① 基础连接<br/>蓝牙·WLAN·热点"]
        C2["② 手车互联<br/>小米互联·CarPlay·CarLink·AndroidAuto"]
        C3["③ 蜂窝网络<br/>优先运营商(DCD隐藏)"]
        C4["④ 移动网络<br/>卫星通信(无能力隐藏)"]
    end

4. 动态显隐机制(getPreferenceKeyResIdsToRemove)

ConnectionSettingsTopFragment.java:168-199。三类”能力探测器”:

  • 包名探测 ConnectionUtils.kt:35-59PackageUtils.isPkgInstalled
  • 平台探测 DeviceUtil.java:226-228ro.board.platform == "msmnile"
  • 卫星探测 TelephonyUtil.isSupportSatelliteByDevice → 反射 TelephonyManagerEx(flavor 源码)
flowchart TD
    Start([getPreferenceKeyResIdsToRemove])
    Q1{isPhoneCarLinkSupported?<br/>4 互联 app 任一预装}
    Q1 -- 否 --> R0[删 整个手车互联 Category<br/>+ vehicle_network_category_space]
    Q1 -- 是 --> Q2{逐项: MiuiShare/CarPlay/CarLink/AA<br/>不支持则删对应 entry}
    Q1 & Q2 --> Q6{DeviceUtil.isDCDPlatform?}
    Q6 -- 是 --> R5[删 蜂窝网络 Category + space]
    Q6 --> Q7{isSupportSatelliteByDevice?}
    Q7 -- 否 --> R6[删 移动网络 Category<br/>= 整个卫星分组]
    End([return idsToRemove])
    R0 & R2 & R5 & R6 --> End
行号条件(不成立时)删除的 key
171-173!isPhoneCarLinkSupported()pk_connection_complex_category + pk_connection_vehicle_network_category_space
175-186逐项 !isXxxSupported()对应 miui_share/carplay/carlink/android_auto entry
190-193isDCDPlatform()pk_connection_vehicle_network_category + space(注释:XCD 默认双卡)
195-197!isSupportSatelliteByDevice()pk_connection_mobile_network(整个卫星分组)

耦合点pk_connection_vehicle_network_category_space 在”全无互联”和”DCD 平台”两个分支都被删,改动时注意。

5. 路由与跳转

连接页如何被加载SettingsApplication.java:28-37 注册模块 → APT 生成 RouterHelper.merge()Router.java 合并路由表 → 主菜单 Fragment 加载 XML,用户点击时 Preference 框架 onPreferenceStartFragment() 自动实例化 ConnectionSettingsTopFragment。外部 URI 经 Router.dispatcher(uri) 暂存,Fragment onResume 匹配路由表分发。

子入口跳转

入口方式目标
蓝牙intent BLUETOOTH_SETTINGSBluetoothSettingsActivity
WLANintent WIFI_SETTINGS(+extra refer)WifiSettingsActivity
热点intent HOTSPOT_SETTINGSHotspotSettingActivity / MiCarHotspotSettingsActivity(两套)
小米互联URI mis://complex/connect?action=mirror_setting外部 app(点标题图标走 mirror_guide 引导)
CarPlay/CarLink/AAURI mis://complex/connect?action={carplay,carlink,android_auto}_connect外部 app
蜂窝Tab 内 TelephonyUtil.setDefaultChannel无外部跳转
卫星intent SATELLITE_COMMUNICATESatelliteSettingsActivity

URI 常量在 ConnectionConstants.kt:5-10,前缀 mis://complex/connect?action=,由目标 app 自己的 Activity 捕获(Settings 仅发 ACTION_VIEW无 fallback UIActivityNotFoundException 只打日志)。

6. 手车互联状态分发(MisComplexSdk)

MisComplexSdk 是外部 aar com.xiaomi.phonecarlink:complex:0.1.40,对 IMisComplex AIDL service 的封装,实际连接业务跑在外部 app 进程。init(ctx, false, false)app/.../AsyncThreadStartTask.java:217-220(两 bool = withMirror/withCarWith,Settings 都传 false,仅作 listener/caller)。

sequenceDiagram
    participant App as 外部 app 进程<br/>(com.mi.car.carplay 等)
    participant Aar as MisComplexSdk aar
    participant Top as ConnectionSettingsTopFragment
    participant Ctl as BaseVehicleLinkPreferenceController[4]
    participant UI as BasicPreference

    Top->>Aar: registComplexConnectListener (onCreate:138)
    Note over App: 手机连接 CarPlay
    App->>Aar: onComplexConnected(ConnectInfo{type=CARPLAY,...})
    Aar->>Top: onComplexConnected(info) (:127)
    Top->>Top: notifyConnectStateChange(info) 遍历 (:141-148)
    loop 每个 controller
        Top->>Ctl: onConnectStateChange(type, info)
        Ctl->>Aar: getConnectInfo() (:59)
        alt info.type == controller.getCurrentConnectType()
            Ctl->>UI: updateRightText(displayName)
        else 不匹配
            Ctl->>UI: updateRightText("")
        end
    end
    Note over App: 服务挂掉
    App->>Aar: onBinderDied()
    Aar->>Top: onBinderDied (:121) → notifyConnectStateChange(null)
    Note over UI: 所有 entry 右侧文案清空

关键设计updateConnectStatus全局 getConnectInfo() 而非回调传入的 infoBaseVehicleLinkPreferenceController.java:57-67),前提假设同一时刻只有一种互联 activeonServiceDisconnected/onBinderDied 传 null → 全清空。onResumeInternal/onCreateInternal 也各刷一次保证回页即同步。

7. 右侧车模(ConnectionSettingsRightFragment)

ConnectionSettingsRightFragment.kt:13-41,根据两项车控配置选车模图:

  • MiCarSettings.isCfgRadarUIEnable()(雷达)/ isCfgCaliperPainted()(卡钳)
雷达卡钳资源
micar_car_model_connection_settings(默认,含 Kunlun)
..._low_have_radar_no_caliper
..._low_no_radar_have_caliper
..._low_no_radar_no_caliper

isUseDefaultCarModel()DeviceUtil.isKunLun() 分支,Kunlun 强制默认图。

8. 设计要点与坑

  1. 能力探测耦合:包名/平台/卫星判断全集中在 getPreferenceKeyResIdsToRemove() 一个方法(:168-199)。
  2. PackageUtils.isPkgInstalled 局限PackageUtils.java:87-111):不带 MATCH_UNINSTALLED_PACKAGESdisabled 但 installed 的包仍判”支持” → 可能入口可见但点击无响应(ActivityNotFoundException 被 catch 无用户反馈)。
  3. lazy 不刷新:互联能力 by lazy 进程内只查一次,安装/卸载 app 后需重启 Settings 入口才更新。
  4. 锚点功能TopLevelSettingsFragment.isAnchorAvailable() 要求 isTopLevelPageByAlias() && isAfterKunlunVehicleStage(E4U4_2),连接页仅在 Kunlun E4U4.2+ 显示分组快速跳转锚点。
  5. 遗留 keypreference_keys.xml:10-11pk_connection_wireless_charge_entrypk_connection_mobile_to_vehicle_entry 已声明但未在 connection_settings_fragment.xml 使用(疑似遗留)。
  6. ⚠️ 双 flavor TelephonyUtilsrc/{xcddif,dcddif}/.../TelephonyUtil.kt,DCD 版 isSupportSatelliteByDevice 反射 receiver 传错(见 对抗记录 Bug 1)。
  7. ⚠️ manifest SATELLITE 拼写AndroidManifest.xml:109,113 同时注册 COMMUNICATE+COMMUNITE(见对抗记录 Bug 3)。