16、设置应用:车载设置界面定制、系统设置项扩展、多用户设置
车载系统的设置应用,说实话,跟手机上的设置完全是两码事。手机设置你做得再花哨,用户顶多点几下。车载设置不一样——它直接关系到驾驶安全、用户体验,还有整车厂的品牌调性。我参与过好几个车厂的项目,每次在设置这块都要反复打磨,因为这里是最容易暴露「这车机是公版方案」的地方。
今天我们就来聊聊,怎么把 Android Automotive OS 的设置应用,做出真正的「车规级」体验。
16.1 车载设置界面的定制思路
Android Automotive OS 自带的 Settings 应用,其实跟手机版同源。但你不能直接拿来用。为什么?因为车载场景下,用户的操作路径、关注点、甚至字体大小都不一样。
我个人习惯的做法是:先梳理出车载特有的设置分类,再基于 AOSP 的 Settings 框架做增量定制。
16.1.1 界面层级重构
车载设置通常分为三个层级:
- 一级页面:驾驶相关、车辆控制、系统设置、账户与隐私
- 二级页面:具体功能开关,比如「自动落锁」「倒车影像延迟」
- 三级页面:详细配置,比如「Wi-Fi 高级选项」「显示校准」
嗯,这里要注意:车载设置尽量不要超过三级。驾驶员在行驶中操作,层级越深越危险。
核心原则:车载设置界面,所有可操作项必须满足「3秒触达」原则。也就是从首页到完成设置,点击次数不超过3次。
16.1.2 自定义 Preference 组件
AOSP 的 Settings 基于 PreferenceFragment 构建。车载定制时,我们通常需要自定义 Preference 样式:
// 自定义一个带车辆图标的 SwitchPreference
public class VehicleSwitchPreference extends SwitchPreference {
public VehicleSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.vehicle_preference_switch);
setIcon(Resources.getSystem().getDrawable(
android.R.drawable.ic_menu_car, context.getTheme()));
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
// 调整字体大小,适配车载大屏
TextView title = view.findViewById(android.R.id.title);
if (title != null) {
title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
}
}
}
我在项目中遇到过一个问题:车机屏幕分辨率差异巨大,从 720p 到 4K 都有。如果直接用 dp 写死,低分辨率下文字会挤在一起。后来我们统一用 sp + 最小宽度限定符来解决。
16.2 系统设置项扩展
车载系统需要很多手机没有的设置项。比如「驾驶模式」「充电策略」「空调联动」等。这些设置项不能随便加,需要遵循 Android 的 Settings.System 或 Settings.Global 机制。
16.2.1 添加自定义设置项
扩展设置项的标准做法是:
- 在 SettingsProvider 中注册新的 URI
- 定义对应的常量类
- 在 Settings 应用中添加 UI 入口
举个例子,添加一个「自动折叠后视镜」的设置:
// 1. 在 SettingsProvider 的 database 中添加
public static final String KEY_AUTO_FOLD_MIRROR = "auto_fold_mirror";
// 2. 定义常量类
public final class VehicleSettings {
public static final String AUTO_FOLD_MIRROR = "auto_fold_mirror";
public static boolean isAutoFoldMirror(Context context) {
return Settings.System.getInt(context.getContentResolver(),
AUTO_FOLD_MIRROR, 1) == 1;
}
}
// 3. 在 Settings 应用中添加 Preference
public class VehicleSettingsFragment extends PreferenceFragment {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.vehicle_settings, rootKey);
SwitchPreference mirrorPref = findPreference("auto_fold_mirror");
mirrorPref.setOnPreferenceChangeListener((pref, newValue) -> {
boolean enabled = (Boolean) newValue;
// 调用车辆 HAL 接口执行操作
VehicleHalClient.setProperty(
VehicleProperty.MIRROR_FOLD, enabled);
return true;
});
}
}
注意:千万不要把车辆控制逻辑直接写在 Settings 应用里。我曾经见过一个项目,把空调控制代码直接写在 Preference 的 onClick 中,结果导致设置页面 ANR。正确的做法是通过 Vehicle HAL 或 CarService 代理调用。
16.2.2 设置项的权限控制
有些设置项需要特殊权限,比如「修改驾驶模式」「重置车辆数据」。Android Automotive OS 提供了 android.car.permission.CAR_CONTROL_AUDIO_SETTINGS 等系统权限。你需要:
- 在 AndroidManifest.xml 中声明权限
- 在 Settings 中检查权限,没有权限时隐藏或禁用
- 对于敏感设置,增加二次确认弹窗
16.3 多用户设置
车载多用户跟手机多用户完全是两码事。手机多用户是「不同的人用同一台手机」,车载多用户是「不同的人开同一辆车,但车是共享的」。所以车载多用户的核心是:用户配置与车辆状态分离。
16.3.1 用户配置的存储策略
每个用户的设置应该存储在 /data/system/users/<userId>/ 下。但车辆的一些物理设置(比如座椅位置、方向盘角度)不能跟着用户走——因为换驾驶员时,车还在路上跑。
我建议的做法是:
- 用户专属设置:壁纸、音效偏好、导航历史 → 存储在用户目录
- 车辆共享设置:自动大灯、雨量感应、驾驶模式 → 存储在全局 Settings
- 记忆类设置:座椅位置、后视镜角度 → 存储在用户目录,但需要与车辆 ECU 同步
16.3.2 多用户切换流程
车载多用户切换不能像手机那样直接锁屏。想象一下:驾驶员正在高速上开车,突然切换用户导致设置重置——这太危险了。
正确的流程应该是:
- 车辆熄火后,系统记录当前用户状态
- 下次点火时,检测钥匙或手机蓝牙,自动匹配用户
- 如果匹配失败,显示用户选择界面(仅限停车时)
- 切换用户时,逐步恢复设置(先恢复安全相关,再恢复娱乐相关)
经验之谈:我曾经在某个项目中,把用户切换做成了「一键切换」,结果测试时发现切换过程中座椅突然移动,差点夹到人。后来我们改成了「渐进式恢复」——先恢复后视镜和方向盘,再恢复座椅,每个步骤间隔 500ms,并且有物理防夹检测。
16.3.3 多用户下的设置界面适配
设置界面需要区分「当前用户可修改」和「仅管理员可修改」。比如:
| 设置项 | 普通用户 | 管理员用户 |
|---|---|---|
| 个人壁纸 | 可修改 | 可修改 |
| 驾驶模式 | 可修改 | 可修改 |
| 车辆锁定策略 | 只读 | 可修改 |
| 恢复出厂设置 | 隐藏 | 可修改 |
实现时,可以在 Preference 的 onPrepare 方法中动态控制可见性和可用性:
@Override
public void onPrepare() {
UserManager um = (UserManager) getContext()
.getSystemService(Context.USER_SERVICE);
boolean isAdmin = um.isAdminUser();
Preference resetPref = findPreference("factory_reset");
if (resetPref != null) {
resetPref.setVisible(isAdmin);
}
}
16.4 知识体系总览
下面这张图,是我自己总结的车载设置应用的核心架构。你看一眼,基本就能明白各个模块之间的关系:
这张图把车载设置应用拆成了三个核心模块。你开发的时候,可以照着这个结构去组织代码。每个模块之间通过 ContentProvider 和 CarService 通信,不要直接耦合。
16.5 避坑指南
最后,分享几个我踩过的坑:
- 不要直接修改 AOSP Settings 的源码。我曾经为了省事,直接在 Settings 源码里加车辆控制代码,结果每次 Google 发安全补丁,合并代码都痛苦得要死。正确的做法是用 overlay 机制。
- 多用户切换时,别忘了恢复音频焦点。用户切换后,如果音乐还在播放,新用户可能会被吓到。我们后来在切换流程中加了音频焦点释放和重新获取的逻辑。
- 设置项的默认值要跟车辆硬件匹配。比如有的车没有座椅加热,那设置里就不要出现这个选项。我建议在 Settings 启动时,通过 VehicleHal 查询硬件能力,动态生成设置项。
车载设置应用,说白了就是「把手机那套东西,改造成适合车用的样子」。但就是这「改造」二字,里面全是细节。希望今天的内容能帮你少走一些弯路。
公众号:蓝海资料掘金营,微信deep3321