Skip to content

HMI, System UI & UX

Car Settings and preferences

Where every vehicle configuration surface lives — adding an entry, keeping it usable while driving, and deciding whether a setting belongs to the car, the driver, or neither.

Intermediate5 minSettings · HMI · OEM

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 .

res/xml/comfort_preferences.xml
<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.

The vehicle is the source of truth
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.

Only mark screens that are genuinely safe
<activity android:name=".ComfortSettingsActivity">
    <meta-data android:name="distractionOptimized" android:value="true"/>
</activity>

Car Settings is large, and drivers will not find things by browsing.

Making an entry searchable
<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.

Where an entry is coming from
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.CarSettingActivity

What 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.

References & further reading

Code links target the main branch on cs.android.com. AOSP moves — if a path 404s, search the symbol instead.