手套箱 04 · 信号链路与属性

本篇回答:手套箱的值从哪来、到哪去、每个数字什么意思。 基线:fuben31_micarsettings/MiCarSettings @ dev;SDK:mi.car:vehicle.support:0.11.65-SNAPSHOT

1. 属性 ID 清单

手套箱信号常量在仓内是引用外部 SDK mi.car.config.Peripheral 的别名, 真实定义在 SDK 侧(~/.gradle/caches/.../mi/car/config/Peripheral.java:585-615)。

常量完整 IDZone/Area类型读写含义
Peripheral.GLOVE_BOX0x6140b407PERIPHERAL / GLOBALINT32RW(PERMISSION_VENDOR_EXTENSION)手套箱开关(值域 CommonParams.OpenClose)
Peripheral.GLOVE_BOX_MOTOR_CMD0x6140b408同上INT32RO电机指令(GloveBoxMotorCmd)——本仓未消费
Peripheral.GLOVE_BOX_LOCK_TYPE_CONFIG0x6140b409同上INT32RO锁类型配置字(GloveBoxLockTypeConfig)——门控
Peripheral.GLOVE_BOX_UNAVL_REASON0x6140b40a同上INT32RO不可用原因(GloveBoxUnavlReason)——Toast 驱动

仓内别名(base/settingsBaseLib/src/main/java/com/android/car/settings/miauto/vehicle/MiCarPropertyIds.java:1484-1487):

// 手套箱
public static final int GLOVE_BOX = Peripheral.GLOVE_BOX;                    // DrivingCtrl 类下
// 手套箱类型
public static final int GLOVE_BOX_TYPE = Peripheral.GLOVE_BOX_LOCK_TYPE_CONFIG;

分组说明:Zone 上属 PERIPHERAL(外设域,与 Window/Door/Mirror/Light 等并列); 但 MiCarPropertyIds.java 把它们归在 DrivingCtrl 内部类下(与陡坡缓降、制动踏板感等车身控制类同段)。 检索时注意两个名字都试试。

2. 状态值语义表

2.1 GLOVE_BOX(值域 CommonParams.OpenClose,SDK CommonParams.java:45-48)

值常量上行(车→App)下行(App→车)
0CLOSE手套箱已关 → Tab0 未选中App 从不下发(关是用户手动物理合上)
1OPEN手套箱已开 → Tab0 选中,再点提示「请手动关闭」openGloveBox() 唯一写入值

2.2 GLOVE_BOX_LOCK_TYPE_CONFIG(值域 GloveBoxLockTypeConfig,SDK Peripheral.java:1430-1433)

值常量含义App 行为
1MANUAL手动手套箱(无电动锁)整类入口隐藏;MIS 开箱回 1003
2POWER电动手套箱正常显示/受理
(读不到)—默认按 MANUAL 处理隐藏(CarConfigManager.kt:133-140 默认值 MANUAL)

2.3 GLOVE_BOX_UNAVL_REASON(值域 GloveBoxUnavlReason,SDK Peripheral.java:1435-1439)

消费点:GloveBoxController.showGloveBoxSwitchUnavailableNotify()(:288-302)。

值常量含义UI 表现
0IDLE无不可用原因—
1NOT_DIS_ARMED车辆未解锁(未撤防)Toast glove_box_fail_need_unlock「请解锁车辆后重试」
2ANTY_PLAY防玩模式(频繁操作)Toast glove_box_fail_anty_play「操作过于频繁」
其它——代客模式 → glove_box_fail_valet_mode;否则无提示(Resources.ID_NULL)

2.4 GLOVE_BOX_MOTOR_CMD(值域 GloveBoxMotorCmd,SDK Peripheral.java:1423-1428)

IDLE=0 / CLOCKWISE=1 / COUNTER_CLOCKWISE=2 / BREAK=3。 本仓未消费——仅供排障时在 bugreport/CARSIGNAL 日志里认出它。

3. 订阅与初始化时序

订阅集合(GloveBoxController.kt:99-102),areaId 走默认 DEFAULT_AREA_ID:

override fun getPropertyIdSet() = ArraySet<Int>().apply {
    add(MiCarPropertyIds.DrivingCtrl.GLOVE_BOX)   // 0x6140b407
    add(Driving.CAR_MODE_STATUS)                  // 驾驶模式(代客/正常)
}
sequenceDiagram
    participant Frag as VehicleControlSettingsFragment
    participant Ctrl as GloveBoxController
    participant Mgr as SettingsCarPropertyManager
    participant VCM as VehicleControlManager
    participant SDK as MiCarPropertyManager(SDK)
    participant VEH as vehicled

    Frag->>Ctrl: onCreate()
    Ctrl->>Mgr: new + setCarManagerCallback(this)
    Note over Mgr: CarPropertyMgrPreferenceController.java:514-516
    Mgr->>VCM: lazy init
    VCM->>SDK: MiCar.getCarManager(PROPERTY_SERVICE)
    SDK-->>VEH: Binder 连接
    VEH-->>Mgr: onPropertyManagerPrepared
    Mgr->>SDK: registerPropertyCallback(dispatcher, {GLOVE_BOX, CAR_MODE_STATUS})
    Note over Mgr,SDK: SettingsCarPropertyManager.kt:239-247
    SDK->>VEH: subscribe
    VEH-->>SDK: 首帧值 + 后续变化
    SDK-->>Mgr: mEventCallbackDispatcher.onChange
    Mgr-->>Ctrl: onHandlePropertyChange(value, shouldUpdateUI)
    Ctrl->>Ctrl: getProperty(GLOVE_BOX)<br/>getIntProperty(CAR_MODE_STATUS)
    Ctrl->>Ctrl: 更新 Tab 状态 + refreshUi()

4. 下发(开箱)时序

sequenceDiagram
    participant U as 用户
    participant Ctrl as GloveBoxController
    participant Base as CarPropertyMgrPreferenceController
    participant Mgr as SettingsCarPropertyManager
    participant VCM as VehicleControlManager
    participant SDK as MiCarPropertyManager
    participant VEH as vehicled

    U->>Ctrl: 点击(密码/账号验证已通过)
    Ctrl->>Base: setVehicleProperty(GLOVE_BOX, OPEN=1)
    Note over Ctrl: GloveBoxController.kt:224-227
    Base->>Mgr: setCarProperty(propId, propVal, areaId, isSync=false)
    Note over Base,Mgr: CarPropertyMgrPreferenceController.java:606-615
    Mgr->>VCM: setIntProperty(propId, 1, areaId)<br/>(async, ThreadPoolUtils)
    Note over Mgr,VCM: SettingsCarPropertyManager.kt:445-449
    VCM->>SDK: mMiCarServiceManager.setIntProperty
    Note over VCM,SDK: VehicleControlManager.java:132-141
    SDK->>VEH: Binder setIntProperty(0x6140b407, GLOBAL, 1)
    VEH-->>SDK: onChange(GLOVE_BOX=OPEN)
    SDK-->>Mgr: dispatcher
    Mgr-->>Ctrl: onHandlePropertyChange
    Ctrl->>Ctrl: Tab0.mIsSelected=true + refreshUi

调用链 file:line 索引:

层位置调用
ControllerGloveBoxController.kt:224setVehicleProperty(GLOVE_BOX, OPEN)
基类base/settingsVehicleLib/.../CarPropertyMgrPreferenceController.java:606-615setCarProperty(...)
Settings 管理器base/settingsVehicleLib/.../SettingsCarPropertyManager.kt:430-449setIntProperty(async)
VCMbase/settingsVehicleLib/.../VehicleControlManager.java:128-141mMiCarServiceManager.setIntProperty
SDKcom.mi.car:MiCarPropertySDK:1.0.12(base/settingsBaseLib/build.gradle:103)Binder → vehicled

读链路:VehicleControlManager.java:175-183 getProperty(propId, areaId); 缓存+自动注册见 SettingsCarPropertyManager.kt:398-412。

5. UI 控件构建器(VehicleBodyPropertyMap)

VehicleBodyPropertyMap.kt(文件头注释:「车辆控制创建TAB工具类」)不是信号映射表, 而是「属性 ID + 图标 + 文案 + Tab 标志」→ VehicleQuickCtrl 的工厂。 手套箱两条(:40-63):

// Tab0 开箱
fun createGloveBoxSwitchCtrl() = VehicleQuickCtrl<Any?>(
        MiCarPropertyIds.DrivingCtrl.GLOVE_BOX,
        R.drawable.ic_glove_box_switch, R.string.glove_box_switch)
    .withDefault(CommonParams.OpenClose.OPEN)      // 默认值 OPEN(1)
    .withAllowClickWhenDisabled(true)              // 不可用也可点(为了弹 Toast)
    .withTabFlag(TabKeyMapHelper.TAB_FLAG_GLOVE_BOX_SWITCH)
 
// Tab1 密码设置(复用同一属性 ID 作 key,动作是跳 Activity)
fun createGloveBoxPasswordSetCtrl() = VehicleQuickCtrl<Any?>(
        MiCarPropertyIds.DrivingCtrl.GLOVE_BOX,
        R.drawable.ic_glove_box_settings, R.string.glove_box_pwd_set)
    .withDefault(false)
    .withAllowClickWhenDisabled(true)
    .withTabFlag(TabKeyMapHelper.TAB_FLAG_GLOVE_BOX_PASSWORD_SET)

注意 withAllowClickWhenDisabled(true):两个 Tab 置灰时仍可点击—— 这是故意的,为了能在不可用时弹出原因 Toast(02 篇)。排查「置灰还能点」不是 bug。

6. CarConfigManager 配置门控

base/settingsVehicleLib/src/main/java/com/android/car/settings/miauto/CarConfigManager.kt:129-140:

fun getGloveBoxLockType(): Int {
    val res = getIntProperty(
        MiCarPropertyIds.DrivingCtrl.GLOVE_BOX_TYPE,        // 0x6140b409
        Peripheral.GloveBoxLockTypeConfig.MANUAL)           // 默认 MANUAL
    MLog.tag(TAG).d("getGloveBoxLockType: $res")
    return res
}

消费方两处:

  • VehicleControlSettingsFragment.java:143-147 —— 页面显隐(01 篇 §3.1);
  • GloveBoxNavigationHandler.kt:64-67 —— MIS 开箱前置检查(05 篇)。

7. 排障时信号怎么对

现象查什么期望
入口整个不显示CARSIGNAL 里 0x6140b409 的值电动车型应为 2(POWER);为 1 或查不到即被隐藏(符合逻辑)
点了开箱没反应无 Toast0x6140b40a(UNAVL_REASON)1=未解锁/2=防玩,有 Toast;0 时应能开
点了开箱 Toast「请手动关闭」0x6140b407 当前值已是 1(OPEN)——箱还开着
下发了 OPEN 但箱没开0x6140b407 是否回读到 1;0x6140b408 电机指令属性回了 1 但物理没动 → 车身/电机侧问题,转底层
语音开箱返回 10030x6140b409非 POWER,符合逻辑