Google is committed to advancing racial equity for Black communities. See how.

Car Settings Structure

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

Architecture and Guidelines

Most Car Settings are implemented as a series of fragments that extend SettingsFragment in a single CarSettingActivity.

Action Bars

At the top of each Settings screen is an Action Bar that can contains a Back button, a screen title, and additional action widgets (including buttons and switches). While these Action Bars are similar to ActionBar provided by Android, they are actually custom views attached to the fragment layout.

It's recommended that you store all code related to Car Settings Action Bars in the relevant SettingsFragment.

Preference Controllers

Each Settings page can hold a number of Preferences. To maintain code organization, each preference (or a related group of preferences) has an associated PreferenceController.

The following image illustrates these components:

CarSettings Components

Figure 1. CarSettings Components

The PreferenceController is a lifecycle-aware component used to encapsulate the business logic that pertains to specific Preferences. PreferenceControllers can only be attached to the relevant Preference via 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>

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

A PreferenceController may require some dynamic data to operate correctly. For example, a PreferenceController that turns off notifications for an application must know which application to act on. Because PreferenceControllers are always defined in XML, it's not possible to provide additional constructor arguments. Instead, provide additional values through public setter methods on the PreferenceController and set with the use(...) method from 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 retain the original goal of being able to rearrange the settings hierarchy with minimal changes to the Java code. Large sections of the existing fragment code will need to be copied to the newly created fragment. One way to minimize this difficulty is as follows:

  • Minimize applications of use(...)
  • Call use(...) from only one location in the fragment. For example, in the onAttach() method. Keep the following in mind

    1. PreferenceController instances should not be passed references to their parent fragment or to members of a fragment. While passing the fragment can reduce the frequency of use(...), it can often lead to poorly organized code caused by low cohesion and high coupling.

    2. Maintaining a one directional dependency between SettingsFragment and PreferenceController is HIGHLY recommended. For example, only PreferenceController depends on SettingsFragment.

    Custom Activities

    Most Car Settings are defined as a series of fragments shown on a single activity. Some use cases suggest that Settings screens could be shown as a separate activity, including the need to:

    • Start a Settings activity for a result. For example, CheckLockActivity, which allows a user to confirm the lock credentials of their device.

    • Redirect to Settings without tampering with the Back button or Activity stack. For example, the Settings needed by PermissionController.

    As mentioned previously, most settings do not require custom activities. However, use BaseCarSettingsActivity in circumstances that may require them.

    Adding a New Setting

    To add a new setting:

    1. Define an XML file:

      1. Ensure all preferences contain a defined android:key. The list of keys is maintained in preference_keys.xml. Preferences keys must be unique.

      2. If the preference displays static information only (such as no special business logic), set the preference controller as:
        com.android.car.settings.common.DefaultRestrictionsPreferenceController
    2. If the preference requires business logic, set the preference controller with a new preference controller name.

      1. (If required) Create the preference controller in the appropriate package that extends PreferenceController. As needed, read the Java docs for the parent class.

      2. Create a fragment with getPreferenceScreenResId returning the XML file as defined in Step 1 above.

    Rearranging the Settings Hierarchy

    To change the settings hierarchy, move the relevant preference and PreferenceController to a different XML file. If the PreferenceController implements use(...), be sure you remove it from the previous SettingsFragment and into the new SettingsFragment.

    Intent Handling

    All the intents that should be handled by the Car Settings app are defined in the manifest file. Most of the settings intents are defined in .common.CarSettingActivity because Car Settings is primarily built from fragments in a single activity.

    To define which fragment to open, FragmentResolver maintains the mapping from the intent to the fragment.

    To add a new intent:

    1. Define the intent to be handled in the Car Settings manifest.

    2. Create a mapping to the relevant fragment in FragmentResolver (provided a custom activity is not also required).

    Intents handled by a custom activity will handle intents just as in any other Android application.

    Changing the Root Fragment

    By default, Car Settings displays the QuickSettingsFragment when the app launches.

    Customizing Themes

    Customizing Other Attributes and Resources

    The Car Settings app uses the CarSettingsTheme, which is an extension of Theme.DeviceDefault.NoActionBar.

    To make changes to the look-and-feel of the Car Settings app, you can overlay the Device Default theme.

    Alert: Do this only if you're sure you want to modify the look-and-feel of the entire system. Directly overlaying the device default theme can lead to unintended side effects to the look-and-feel of other applications displayed on your device. Alternatively, overlay the CarSettingsTheme (along with any of the other values in the res/values/ directory) to make changes to the Car Settings app only.

    Customizing Preferences

    The customizing of preferences occurs in several locations.

    The layout of several basic preference classes is defined in car_preference and is overlaid for car builds. Any customization layouts for base preference classes can be replaced here.

    Car Settings uses custom preferences defined largely in the common package. These should be overlayed within the Car Settings module separately from the base preference classes.

    Distraction Optimization

    Distraction Optimization (DO) is provided as a tool to reduce the driver's interaction with the Settings app while the car is moving. The default implementation disables the preferences so that the user does not interact with the app while the car is moving.

    Basic customizations to the behavior of DO can be accomplished through configuration overlays. If you require more fine-grained customization, additional changes can be made through code.

    High-Level Customization

    To disable the entire DO framework, use config_always_ignore_ux_restrictions.

    Note: Placing a preference key in config_ignore_ux_restrictions only enables that specific preference while driving. To ensure that the user can actually interact with a preference, double check that all preferences in the navigation hierarchy are listed in config_ignore_ux_restrictions.

    You can set the value to:

    false Driver can interact with every aspect of the Settings app.
    true Settings app falls back to config_ignore_ux_restrictions so as to determine which preferences should be enabled while driving. The strings provided here should point to the strings defined in preference_keys.xml.

    Fine-Grained Customization

    Some preferences may require more customized behavior than enabling or disabling a preference based upon driving state. For example, Bluetooth and Wi-Fi have already been modified to show saved Bluetooth devices or Wi-Fi access points while driving.

    Currently, there is no configuration-based solution to make these types of adjustments. Instead, you can create a custom PreferenceController which overrides onApplyUxRestrictions() to make the desired changes. For example, Wi-Fi.

    Note: onApplyUxRestrictions() is called after updateState() while the preference controller is refreshing the user interface. Once a custom preference controller is created, you can overlay the relevant XML file to replace the default preference controller with your own implementation.

    Other Configurations

    To see other configs, go to config.xml.