Every vehicle feature that can be configured ends up in Settings, which makes it one of the largest and most contested surfaces on the head unit — and one of the few places a driver is genuinely expected to read.
The first question: who does this setting belong to?#
Adding an entry#
Car Settings is built on the standard preference framework, with automotive styling from .
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/comfort_settings_title">
<com.android.car.ui.preference.CarUiPreferenceCategory
android:title="@string/seat_comfort">
<com.android.car.ui.preference.CarUiSeekBarDialogPreference
android:key="seat_massage_intensity"
android:title="@string/massage_intensity"
android:max="5"/>
<com.android.car.ui.preference.CarUiSwitchPreference
android:key="seat_heating_auto"
android:title="@string/auto_seat_heating"
android:summary="@string/auto_seat_heating_summary"/>
</com.android.car.ui.preference.CarUiPreferenceCategory>
</PreferenceScreen>Backing a preference with a vehicle property#
Where a setting is a vehicle property, do not keep a shadow copy.
class ChargeLimitPreferenceController(
context: Context,
private val properties: CarPropertyManager,
) : PreferenceController(context) {
override fun onCreateInternal() {
properties.registerCallback(
callback,
VehiclePropertyIds.EV_CHARGE_PERCENT_LIMIT,
CarPropertyManager.SENSOR_RATE_ONCHANGE,
)
}
// Write to the vehicle. Do NOT update the UI here.
override fun handlePreferenceChanged(preference: Preference, newValue: Any): Boolean {
properties.setFloatProperty(
VehiclePropertyIds.EV_CHARGE_PERCENT_LIMIT, GLOBAL, newValue as Float,
)
return false // the callback will update it, once the vehicle confirms
}
private val callback = object : CarPropertyManager.CarPropertyEventCallback {
override fun onChangeEvent(value: CarPropertyValue<*>) {
preference.value = value.value as Float // confirmed state
}
override fun onErrorEvent(propertyId: Int, areaId: Int) {
refreshFromVehicle()
}
}
}Settings while driving#
Most of Settings should not be reachable while moving, and the platform will enforce it.
<activity android:name=".ComfortSettingsActivity">
<meta-data android:name="distractionOptimized" android:value="true"/>
</activity>Search#
Car Settings is large, and drivers will not find things by browsing.
<SwitchPreference
android:key="auto_seat_heating"
android:title="@string/auto_seat_heating"
android:summary="@string/auto_seat_heating_summary"
settings:keywords="@string/auto_seat_heating_keywords"/>Include the words people actually use, not the words in your specification. Drivers search for "warm seat", not "thermal comfort actuation".
OEM customisation#
Almost every vehicle replaces or heavily modifies Settings, and the layers available are the same ones from the theming topic.
adb shell dumpsys activity service com.android.car.settings
adb shell cmd overlay list | grep -i settings
adb shell am start -n com.android.car.settings/.common.CarSettingActivityWhat good looks like#
- Decide the owner first — vehicle, driver, or vehicle property.
- Never shadow a vehicle property. Read it, write it, render from the confirmation.
- Use CarUi preference classes, so theming and distraction handling are free.
- Be honest about
distractionOptimized. - Add search keywords in the driver's vocabulary.
- Overlay before forking.
Next#
The apps module, where these surfaces are consumed.

