手套箱 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)。
| 常量 | 完整 ID | Zone/Area | 类型 | 读写 | 含义 |
|---|---|---|---|---|---|
Peripheral.GLOVE_BOX | 0x6140b407 | PERIPHERAL / GLOBAL | INT32 | RW(PERMISSION_VENDOR_EXTENSION) | 手套箱开关(值域 CommonParams.OpenClose) |
Peripheral.GLOVE_BOX_MOTOR_CMD | 0x6140b408 | 同上 | INT32 | RO | 电机指令(GloveBoxMotorCmd)——本仓未消费 |
Peripheral.GLOVE_BOX_LOCK_TYPE_CONFIG | 0x6140b409 | 同上 | INT32 | RO | 锁类型配置字(GloveBoxLockTypeConfig)——门控 |
Peripheral.GLOVE_BOX_UNAVL_REASON | 0x6140b40a | 同上 | INT32 | RO | 不可用原因(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→车) |
|---|---|---|---|
| 0 | CLOSE | 手套箱已关 → Tab0 未选中 | App 从不下发(关是用户手动物理合上) |
| 1 | OPEN | 手套箱已开 → Tab0 选中,再点提示「请手动关闭」 | openGloveBox() 唯一写入值 |
2.2 GLOVE_BOX_LOCK_TYPE_CONFIG(值域 GloveBoxLockTypeConfig,SDK Peripheral.java:1430-1433)
| 值 | 常量 | 含义 | App 行为 |
|---|---|---|---|
| 1 | MANUAL | 手动手套箱(无电动锁) | 整类入口隐藏;MIS 开箱回 1003 |
| 2 | POWER | 电动手套箱 | 正常显示/受理 |
| (读不到) | — | 默认按 MANUAL 处理 | 隐藏(CarConfigManager.kt:133-140 默认值 MANUAL) |
2.3 GLOVE_BOX_UNAVL_REASON(值域 GloveBoxUnavlReason,SDK Peripheral.java:1435-1439)
消费点:GloveBoxController.showGloveBoxSwitchUnavailableNotify()(:288-302)。
| 值 | 常量 | 含义 | UI 表现 |
|---|---|---|---|
| 0 | IDLE | 无不可用原因 | — |
| 1 | NOT_DIS_ARMED | 车辆未解锁(未撤防) | Toast glove_box_fail_need_unlock「请解锁车辆后重试」 |
| 2 | ANTY_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 索引:
| 层 | 位置 | 调用 |
|---|---|---|
| Controller | GloveBoxController.kt:224 | setVehicleProperty(GLOVE_BOX, OPEN) |
| 基类 | base/settingsVehicleLib/.../CarPropertyMgrPreferenceController.java:606-615 | setCarProperty(...) |
| Settings 管理器 | base/settingsVehicleLib/.../SettingsCarPropertyManager.kt:430-449 | setIntProperty(async) |
| VCM | base/settingsVehicleLib/.../VehicleControlManager.java:128-141 | mMiCarServiceManager.setIntProperty |
| SDK | com.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 或查不到即被隐藏(符合逻辑) |
| 点了开箱没反应无 Toast | 0x6140b40a(UNAVL_REASON) | 1=未解锁/2=防玩,有 Toast;0 时应能开 |
| 点了开箱 Toast「请手动关闭」 | 0x6140b407 当前值 | 已是 1(OPEN)——箱还开着 |
| 下发了 OPEN 但箱没开 | 0x6140b407 是否回读到 1;0x6140b408 电机指令 | 属性回了 1 但物理没动 → 车身/电机侧问题,转底层 |
| 语音开箱返回 1003 | 0x6140b409 | 非 POWER,符合逻辑 |