Most pages in Car Settings are implemented as a series of
fragments that extend SettingsFragment
,
with each of them having their own activity defined in CarSettingActivities
.
These static activities are extended from BaseCarSettingsActivity
.
In addition to these settings, you can inject preferences from other system apps to
appear in CarSettings.
Add a new preference in Car Settings
To add a new setting:
- Define an XML file:
- Ensure all preferences have defined
android:key
. The list of keys is maintained inpreference_keys.xml
. Preferences keys should be unique. - For search indexing purposes, preference screens should also have
a defined
android:key
. The list of preference screen keys is maintained inpreference_screen_keys.xml
. Preference screen keys should also be unique. - If the preference displays static information only (for example,
no special business logic), set the preference controller as
com.android.car.settings.common.DefaultRestrictionsPreferenceController
. - If the preference requires business logic, set the preference controller with a new preference controller name.
- Ensure all preferences have defined
- (If required) Create the preference controller in the appropriate
package, which extends
PreferenceController
. See the Javadoc if needed. - Create a fragment with
getPreferenceScreenResId
returning the XML file defined in Step 1. - Create an activity in
CarSettingActivities
that extendsBaseCarSettingsActivity
and then implementgetInitialFragment()
, returning the fragment defined in Step 3. - Update
AndroidManifest.xml
to include the activity defined in Step 4.
Example
The following material illustrates this process.
- Define an XML file named
demo_fragment.xml
:<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/demo_label" android:key="@string/psk_demo"> <Preference android:icon="@drawable/ic_settings_demo_preference_1" android:key="@string/pk_demo_preference_1" android:title="@string/demo_preference_1_title" settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"> <intent android:targetPackage="com.android.car.settings" android:targetClass="com.android.car.settings.common.CarSettingActivities$DemoSetting1Activity"/> </Preference> <Preference android:icon="@drawable/ic_settings_demo_preference_2" android:key="@string/pk_demo_preference_2" android:title="@string/demo_preference_2_title" settings:controller="com.android.car.settings.example.MyCustomRestrictionsPreferenceController"> <intent android:targetPackage="com.android.car.settings" android:targetClass="com.android.car.settings.common.CarSettingActivities$DemoSetting2Activity"/> </Preference> </PreferenceScreen>
- Add the preference keys to
preference_keys
:<resources> [...] <string name="pk_demo_preference_1" translatable="false">demo_preference_1</string> <string name="pk_demo_preference_2" translatable="false">demo_preference_2</string> </resources>
- Add the preference screen key to
preference_screen_keys.xml
:<resources> [...] <string name="psk_demo" translatable="false">demo_screen</string> </resources>
For the first example preference, use
DefaultRestrictionsPreferenceController
. For the second preference, use a custom preference controller, which needs to be defined. For this example, you can customize this preference to available admin users only. To do so, define the following custom controller:public class MyCustomRestrictionsPreferenceController extends PreferenceController<Preference> { private final UserManager mUserManager; public MyCustomRestrictionsPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions) { super(context, preferenceKey, fragmentController, uxRestrictions); mUserManager = UserManager.get(context); } @Override protected Class<Preference> getPreferenceType() { return Preference.class; } @Override public int getAvailabilityStatus() { return mUserManager.isAdminUser() ? AVAILABLE : DISABLED_FOR_USER; } }
- To create a fragment, override
getPreferenceScreenResId
: - To hold the new fragment, create an activity in
CarSettingActivities
: - Update the manifest file with the new activity:
- Isn't directly implemented in the CarSettings app (such as injecting a setting implemented by OEMs).
- Should appear in the CarSettings app.
- To mark the activity as an injected setting, add an intent-filter to the activity.
- Tell the CarSettings app which category it belongs to. The category is a
constant, defined in
CategoryKey
, and is used to indicate at which level of CarSettings the injected setting should appear in. We provide a set of categories insideCategoryKey
, but there are no restrictions for OEMs to define their own categories. - (optional) Add summary text when the setting is displayed:
<activity android:name="Settings$DemoSettingsActivity" <!-- Mark the activity as an injected setting --> <intent-filter> <action android:name="com.android.settings.action.EXTRA_SETTINGS"/> </intent-filter> <!-- Tell CarSettings app which category it belongs to --> <meta-data android:name="com.android.settings.category" android:value="com.android.settings.category.demo_category"/> <!-- Tell CarSettings the what the preference title should be --> <meta-data android:name="com.android.settings.title" android:value="@string/app_name" /> <!-- Optional: specify the icon to show with the preference --> <meta-data android:name="com.android.settings.icon" android:resource="@drawable/ic_demo" android:value="true"/> <!-- Optional: Add a summary text when the string is displayed --> <meta-data android:name="com.android.settings.summary" android:resource="@string/demo_summary"/> </activity>
public class DemoFragment extends SettingsFragment { @Override @XmlRes protected int getPreferenceScreenResId() { return R.xml.demo_fragment; } }
public class CarSettingActivities { [...] public static class DemoActivity extends BaseCarSettingsActivity { @Nullable @Override protected Fragment getInitialFragment() { return new DemoFragment(); } } }
<application [...] <activity android:name=".common.CarSettingActivities$DemoActivity" android:exported="true"> <meta-data android:name="distractionOptimized" android:value="true"/> </activity> [...] </application>
Add an external intent preference within Car Settings
As an alternative to injected preferences, it's also possible to insert a preference directly into Car Settings that intents out into another app. This can be done by simply adding a preference to a preference screen with an intent action that resolves to an external app. Like other preferences in Car Settings, these preferences have the same XML attributes available to them.
<Preference android:key="@string/pk_demo_preference" android:title="@string/demo_preference_title" android:summary="@string/demo_preference_summary" settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"> <intent android:action="android.intent.action.DEMO_ACTION"/> </Preference>
Add an injected preference
Injected preferences contain intents leading to external or internal activities. As an example, the Google setting item on the Settings home page is an injected preference. Injected preferences are particularly useful when any of the following is true. The setting:
To configure an activity as an injected setting:
To have the injected setting appear on a specific page in the CarSettings app, include the following sample code in the XML, modifying variables where appropriate:
<com.android.car.settings.common.LogicalPreferenceGroup <!-- Replace key string --> android:key="@string/pk_system_extra_settings" <!-- Indicates the preferences in the group should be injected in. ExtraSettingsPreferenceController contains the logic to pull in injected preferences. --> settings:controller="com.android.settings.common.ExtraSettingsPreferenceController"> <!-- Tells the controller what activities should be pulled into this preference group. --> <intent android:action="com.android.settings.action.EXTRA_SETTINGS"> <!-- Name and value should match the metadata in your activity --> <extra android:name="com.android.settings.category" android:value="com.android.settings.category.demo_category"/> </intent> </com.android.car.settings.common.LogicalPreferenceGroup>