Distraction optimization in Car Settings

Distraction optimization (DO) is provided as a tool to reduce the driver's interaction with the Settings app while a car is moving. Some settings may need to be changed while driving, so the app isn't completely blocked. However, by default, most preferences are disabled with only key and easily updated preferences being enabled.

Enabled apps while driving

Figure 1. Enabled apps while driving

Entire activities can also be blocked if they aren't distraction optimized, as shown below. This method is currently used primarily for settings search.

All activities blocked

Figure 2. All activities blocked

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

High-level customization

When a preference is disabled while driving, tapping on it displays a toast message stating that the preference isn't available while driving, provided the preference has a preference controller attached to it. The message uses the restricted_while_driving string, which can be customized with an overlay (provided the string is less than the 60-character limit).

Customized overlay

Figure 3. Customized overlay

The entire DO framework can be disabled using config_always_ignore_ux_restrictions. Setting this to true means that the driver can interact with every aspect of the Settings app.

<bool name="config_always_ignore_ux_restrictions">true</bool>

If the configuration above is set to false, the Settings app falls back to config_ignore_ux_restrictions to determine which preferences should be enabled while driving. The strings provided here should point to the strings defined in preference_keys.xml.

Example

To show how to enable a deeply nested setting while driving, this example demonstrates how to enable the Text-to-Speech (TTS) output settings. For this to work, add all the settings in the hierarchy to config_ignore_ux_restrictions. This includes the system, languages and input, and TTS preferences to the config, since our hierarchy is System->Languages & Input->Text-to-speech output. However, the preferences within the text-to-speech fragment is still disabled. To enable them, we need to add the keys for the preferences we want to be accessible. In this example, we want to enable the playback preferences but not the engine preference so we add pk_tts_playback_group to our config.

<string-array name="config_ignore_ux_restrictions">
    [...]
    <item>@string/pk_system_settings_entry</item>
    <item>@string/pk_languages_and_input_settings</item>
    <item>@string/pk_tts_settings_entry</item>
    <item>@string/pk_tts_playback_group</item>
</string-array>

Detailed customization

There are some preferences that might require more customized behavior than simply enabling/disabling a preference based on the 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's no configuration based solution to make these kinds of adjustments. Instead you can create a custom class that extends PreferenceController and overrides onApplyUxRestrictions() to make the desired changes.

When a custom preference controller is created, you can overlay the relevant XML file to replace the default preference controller with your own implementation.

Examples

In CarSettings, some preferences have this more customized behavior, which can be used as examples for additional customization. For example, in the Wi-Fi access point list, the desired behavior is to only show saved access points while driving (and hiding the rest). To achieve this, do the following:

} else if (shouldApplyUxRestrictions(getUxRestrictions())) {
    wifiEntries = getCarWifiManager().getSavedWifiEntries();
} else {
    wifiEntries = getCarWifiManager().getAllWifiEntries();
}

Because the access points that appear here are already restricted, you don't want to apply additional UxRestrictions to these preferences. Therefore, override onApplyUxRestrictions and perform an intentional no-op:

@Override
protected void onApplyUxRestrictions(CarUxRestrictions uxRestrictions) {
    // Since the list dynamically changes based on the UX restrictions, we
    // enable this fragment regardless of the restriction. Intentional no-op.
}

Another example is provided in Bluetooth-bonded devices. To continue to enable Bluetooth devices to be connected to and disconnected from but wanted to disable the ability to access additional settings for these devices. To achieve this, we again override onApplyUxRestrictions but this time, if the NO_SETUP restriction is active, hide the secondary action on the preference.

@Override
protected void onApplyUxRestrictions(CarUxRestrictions uxRestrictions) {
    super.onApplyUxRestrictions(uxRestrictions);
    if (CarUxRestrictionsHelper.isNoSetup(uxRestrictions)) {
        updateActionVisibility(getPreference(), /* isActionVisible= */ false);
    }
}