Overview

Car Settings (packages/apps/Car/Settings) is provided specifically for the Android Automotive OS (AAOS). Car Settings differs from Phone Settings (packages/apps/Settings). While Car Settings contains some familiar phone settings, Car Settings provides a car-ified visual user interface, driver distraction optimizations, and numerous customization entry points for OEMs.

In addition to the overview of Car Settings provided below, see these related topics to learn more about Car Settings:

Architecture and guidelines

Most of the pages in Car Settings are implemented as a series of fragments that extend SettingsFragment, each having their own activity defined in CarSettingActivities. These static activities are extended from BaseCarSettingsActivity. While there are a few exceptions to this rule, such as some special fragments extending BaseFragment rather than SettingsFragment and some Activities residing outside CarSettingActivities, all of which should be regarded as exceptions (not as patterns to follow).

Static preferences

A static preference is defined in XML using the Preference or CarUiPreference tag. A SettingsFragment implementation uses the getPreferenceScreenResId() method to define which XML file contains the static list of preferences to display.

Dynamic preferences

Dynamic preferences use the PreferenceGroup tag or an implementation of PreferenceGroup.

Within the CarSettings app, dynamic preferences represent a normal set of preferences that direct the user to additional pages within CarSettings, but which have been added via the Preference Controller instead of in the XML. An example is the Manage keyboards preference under Languages & Input preference which dynamically adds input methods to the preference page based on whether these input methods are permitted or not.

Action bars

The top of every settings screen has an action bar, which can contain a "back" navigation, a screen title, and supplementary action widgets (for example, buttons and switches). These action bars are similar to the ActionBar provided by Android, but are actually custom views. In Android 11 and above, this toolbar is included in the chassis base layout, which contains the views for the toolbar and a framelayout for the rest of the app content.

Supplementary action widgets are MenuItem classes and should be created in the onCreate of the respective SettingsFragment or BaseFragment. Properties such as visibility, state, and so on should be controlled by setters in the business logic of the SettingsFragment.

// ExampleSettingsFragment.java
public class ExampleSettingsFragment extends SettingsFragment {

    @Override
    protected List<MenuItem> getToolbarMenuItems() {
        return Collections.singletonList(mClearConfirmButton);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mButton = new MenuItem.Builder(getContext())
                .setTitle(R.string.text)
                .setOnClickListener(mOnClickListener)
                .setUxRestrictions(CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP)
                .build();
    }

    private void updateState() {
        button.setVisible(false);
    }
}

The action bars come with support for Distraction Optimization in Car Settings. Set the UXRestrictions in the MenuItem.Builder on creation.

Preference controllers

Each settings page can hold a number of various Preferences.

See the following image for how these components are related:

CarSettings Components

Figure 1. CarSettings Components

The PreferenceController is a lifecycle-aware component that helps to encapsulate the business logic pertaining to specific Preferences. PreferenceControllers can only be attached to the relevant Preference through XML.

// example_settings_fragment.xml
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:title="@string/example_settings_title">
  <Preference
    android:key="@string/pk_example_preference_key"
    android:title="@string/example_preference_title"
    settings:controller="com.android.car.settings.example.ExamplePreferenceController"/>
</PreferenceScreen>

Car Settings explicitly prevents the creation of PreferenceController through code in order to make it easier to modify the Settings hierarchy with minimal changes to the Java code.

It's possible that a PreferenceController needs some dynamic data to operate correctly. For example, a PreferenceController that turns off notifications for an app needs to know which app to act on. Because PreferenceControllers are always defined in XML, there is no way to provide additional constructor arguments. Instead, these additional values are provided through public setters on the PreferenceController and set using the use(...) method from the SettingsFragment.

// ExamplePreferenceController.java
public class ExamplePreferenceContorller extends PreferenceController<Preference> {

  private ExampleArg mExampleArg;

  public ExamplePreferenceController(...) {
    ...
  }

  public void setExampleArg(ExampleArg exampleArg) {
    mExampleArg = exampleArg;
  }
}

// ExampleSettingsFragment.java
public class ExampleSettingsFragment extends SettingsFragment {

  @Override
  @XmlRes
  protected int getPreferenceScreenResId() {
    Return R.xml.example_settings_fragment;
  }

  @Override
  public void onAttach(Context context) {
    ExampleArg arg = (ExampleArg) getArguments().getSerializeable(ARG_KEY);
    ExamplePreferenceController controller =
        use(ExamplePreferenceController.class, R.string.pk_example_preference_key);
    controller.setExampleArg(arg);
  }
}

The more often the use(...) method is used, the harder it becomes to keep the original goal of being able to rearrange the settings hierarchy with minimal changes to the Java code, because large sections of the existing fragment code needs to be copied to the newly created fragment. One way to minimize the difficulty of doing this is to:

  • Minimize your usage of use(...).
  • Try to keep every call to use(...) in one place in the fragment (for example, in the onAttach() method).

Intent handling

All of the intents that should be handled by the Car Settings app are defined in the manifest file. Intents are generally defined and handled like most standard Android apps, with all the activities and intent filters defined in the manifest.

Change the root fragment

If desired, the Exit icon can be displayed or hidden using config_show_settings_root_exit_icon.

Customize the theme

Customize other attributes and resources

The Car Settings app primarily uses the CarSettingTheme, which is an extension of Theme.CarUi. This theme is used to standardize the look-and-feel of system apps to ensure consistency in the system.

Customize preferences

Customizing preferences spans these additional locations:

  • The layout of some base preference classes is defined in car_preference and overlaid for car builds. Any customization layouts for the base preference classes can be replaced here.
  • Car Settings uses some custom preferences defined primarily in the common package. These should be overlaid within the Car Settings module separately from the base preference classes.