Add Android Automotive OS support to your media app

Android Automotive OS allows users to install apps in the car. In order to reach users on this platform, you need to distribute a driver-optimized app that is compatible with Android Automotive OS. You can re-use almost all of the code and resources in your Android Auto app, but you must create a separate build that meets the requirements on this page.

Development overview

Adding Android Automotive OS support is simple and only requires a few steps:

  1. Enable automotive features in Android Studio
  2. Create an automotive module
  3. Update your gradle dependencies
  4. Add settings or sign-in activities (Optional)

Design considerations

Android Automotive OS takes care of laying out the media content that it receives from your app's media browser service. This means that your app doesn't draw the UI and your app does not start any of your activities when a user triggers media playback.

If you are implementing Settings or Sign-in activities, these activities must be vehicle-optimized. You should refer to the Design guidelines for Android Automotive OS while designing those areas of your app.

Set up your project

You need to set up several different parts of your app's project to enable support for Android Automotive OS.

Enable automotive features in Android Studio

To build and test Android Automotive OS features you must use Android Studio 3.6 Beta 1 or higher.

Follow these steps to enable Automotive OS features:

  1. Be sure the file studioFlags.xml exists in one of the following locations, depending on your operating system:

    • Windows: %USERPROFILE%\.AndroidStudioPreview3.5\config\options
    • macOS: ~/Library/Preferences/AndroidStudioPreview3.5/options
    • Linux: ~/.AndroidStudioPreview3.5/config/options
  2. Add the following entry to the studioFlags.xml file:

    <application>
    <component name="StudioFlags">
      <option name="data">
        <map>
          <entry key="npw.templates.automotive" value="true" />
        </map>
      </option>
    </component>
    </application>
    

Create an automotive module

Some components of Android Automotive OS, such as the manifest, have platform-specific requirements, so you need to create a module that can keep the code for these components separate from other code in your project, such as the code used for your phone app.

Follow these steps to add an automotive module to your project:

  1. In Android Studio, select File > New > New Module.
  2. Select Automotive Module, then click Next.
  3. Provide an Application/Library name. This is the name that users see for your app on Android Automotive OS.
  4. Provide a Module name.
  5. Adjust the Package name to match your app.
  6. Select API 28:Android 9.0 (Pie) for the Minimum SDK, and then click Next.

    All cars that support Android Automotive OS run on Android 9 (API level 28) or higher, so selecting this value targets 100% of cars that use Android Automotive OS.

  7. Select Add No Activity, and click Finish.

After creating your module in Android Studio, open the AndroidManifest.xml in your new automotive module:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.media">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" />

    <uses-feature
        android:name="android.hardware.type.automotive"
        android:required="true" />

</manifest>

You'll notice some standard app information in the <application> element, but there's also a <uses-feature> element that declares support for Android Automotive OS. Also note that there are no activities declared in the manifest.

If you implement a Settings or Sign-in activities, add them here. These activities are triggered by the system using explicit intents and are the only activities that should be declared within the manifest for your Android Automotive OS app.

Intent filters

Android Automotive OS uses explicit intents to trigger activities in your media app. The manifest file should not contain any activities that have CATEGORY_LAUNCHER or ACTION_MAIN intent filters.

Activities like the one in the following example usually target a phone, or some other mobile device. These activities should be declared in the module that builds the phone app, not in the module that builds your Android Automotive OS app.

<activity android:name=".MyActivity">
    <intent-filter>
        <!-- You can't use either of these intents for Android Automotive OS -->
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <!--
        In their place, you can include other intent filters for any activities
        that your app needs for Android Automotive OS, such as settings or
        sign-in activities.
        -->
    </intent-filter>
</activity>

Update your gradle dependencies

We recommend that you keep your media browser service in a separate module that you share between your phone app and your automotive module. If you're using this approach, you need to update your automotive module to include the shared module, as shown in the following snippet:

my-auto-module/build.gradle

buildscript {
  ...
  dependencies {
    ...
    implementation project(':shared_module_name')
  }
}

Implement settings and sign-in activities

In addition to your media browser service, you can also provide vehicle-optimized Settings and Sign-in activities for your Android Automotive OS app. These activities allow you provide app functionality that isn't included in the Android Media APIs.

You should only implement these activities if your Automotive OS app needs to allow users to sign in or specify app settings. These activities aren't used by Android Auto.

Add a Settings activity

You can add a vehicle-optimized Settings activity so that users can configure settings for your app in their car. Your settings activity can also provide other workflows, like signing in or out of a user's account or switching user accounts. Remember that this activity is only triggered by an app running on Android Automotive OS. Phone apps connected to Android Auto do not use it.

Settings activity workflows

The Settings activity can provide the user with different workflows. The following diagram shows how a user interacts with your Settings activity using Android Automotive OS:

Workflows for a Settings activity

Figure 1. Settings activity workflows

Declare a Settings activity

You must declare your Settings activity in your app's manifest file, as shown in the following code snippet:

<application>
    ...
    <activity android:name=".AppSettingsActivity"
              android:exported="true"
              android:theme="@style/SettingsActivity"
              android:label="@string/app_settings_activity_title">
        <intent-filter>
            <action android:name="android.intent.action.APPLICATION_PREFERENCES"/>
        </intent-filter>
    </activity>
    ...
<application>

Implement your Settings activity

When a user launches your app, Android Automotive OS detects the Settings activity that you declared and displays an affordance, such as an icon. The user can tap or select this affordance using their car's display to navigate to the activity. Android Automotive OS sends the ACTION_APPLICATION_PREFERENCES intent that tells your app to start your settings activity.

Add a Sign-in activity

If your app requires a user to sign in before they can use your app, you can add a vehicle-optimized Sign-in activity that handles signing in and out of your app. You can also add sign-in and sign-out workflows to a Settings activity, but you should use a dedicated Sign-in activity if your app cannot be used until a user signs in. Remember that this activity is only triggered by an app running on Android Automotive OS. Phone apps connected to Android Auto do not use it.

Sign-in activity workflow

The following diagram shows how a user interacts with your Sign-in activity using Android Automotive OS:

Workflows for a Sign-in activity

Figure 2. Sign-in activity workflows

Require sign in at app start

To require a user to sign in before they can use your app, your media browser service must do the following things:

  1. In your service's onLoadChildren() method, send a null result using the sendResult() method.
  2. Set the media session's PlaybackState to STATE_ERROR using the setState() method. This tells Android Automotive OS that no other operations can be performed until the error has been resolved.
  3. Set the media session's PlaybackState error code to ERROR_CODE_AUTHENTICATION_EXPIRED. This tells Android Automotive OS that the user needs to authenticate.
  4. Set the media session's PlaybackState error message using the setErrorMessage() method. Because this error message is user-facing, the message must be localized for the user's current locale.
  5. Set the media session's PlaybackState extras using the setExtras() method. Include the following two keys:

    • android.media.extras.ERROR_RESOLUTION_ACTION_LABEL: A string that is displayed on the button that begins the sign-in workflow. Because this string is user-facing, it must be localized for the user's current locale.
    • android.media.extras.ERROR_RESOLUTION_ACTION_INTENT: A PendingIntent that directs the user to your Sign-in activity when the user taps the button referred to by the android.media.extras.ERROR_RESOLUTION_ACTION_LABEL.

The following code snippet shows how your app can require the user to sign in before using your app:

Kotlin

val signInIntent = Intent(this, SignInActivity::class.java)
val signInActivityPendingIntent = PendingIntent.getActivity(this, 0,
    signInIntent, 0)
val extras = Bundle().apply {
    putString(
        "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL",
        "Sign in"
    )
    putParcelable(
        "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT",
        signInActivityPendingIntent
    )
}

val playbackState = PlaybackStateCompat.Builder()
        .setState(PlaybackStateCompat.STATE_ERROR, 0, 0f)
        .setErrorMessage(
            PlaybackStateCompat.ERROR_CODE_AUTHENTICATION_EXPIRED,
            "Authentication required"
        )
        .setExtras(extras)
        .build()
mediaSession.setPlaybackState(playbackState)

Java

Intent signInIntent = new Intent(this, SignInActivity.class);
PendingIntent signInActivityPendingIntent = PendingIntent.getActivity(this, 0,
    signInIntent, 0);
Bundle extras = new Bundle();
extras.putString(
    "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL",
    "Sign in");
extras.putParcelable(
    "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT",
    signInActivityPendingIntent);

PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder()
    .setState(PlaybackStateCompat.STATE_ERROR, 0, 0f)
    .setErrorMessage(
            PlaybackStateCompat.ERROR_CODE_AUTHENTICATION_EXPIRED,
            "Authentication required"
    )
    .setExtras(extras)
    .build();
mediaSession.setPlaybackState(playbackState);

After the user has successfully authenticated, your app must set the PlaybackState back to a state other than STATE_ERROR and then take the user back to Android Automotive OS by calling the activity's finish() method.

Implement your Sign-in activity

Google offers a variety of identity tools that you can use to help users sign in to your app in their cars. Some tools, such as Firebase Authentication, provide full-stack toolkits that can help you build customized authentication experiences. Other tools leverage a user's existing credentials or other technologies to help you build seamless sign-in experiences for users.

We recommend the following tools to help you build an easier sign-in experience for users that have previously signed in on another device:

  • Google Sign-in: If you've already implemented Google Sign-in for other devices (such as your phone app), you should also implement Google Sign-in for your Android Automotive OS app to support existing Google Sign-in users.
  • Autofill with Google: If users have opted into Autofill with Google on their other Android devices, their credentials are saved to the Google password manager. Then, when the user signs in to your Android Automotive OS app, Autofill with Google suggests relevant saved credentials. Using Autofill with Google requires no application development effort; however, application developers should optimize their apps for better quality results. Autofill with Google is supported by all devices running Android Oreo 8.0 (API level 26) or higher (including Android Automotive OS).

Handle sign-in protected actions

Some apps allow a user to access some actions anonymously, but require the user to sign in before they can perform other actions. For example, a user might be able to play music in an app before signing in, but they must sign in before they can skip a song.

In this case, when the user attempts to perform the restricted action (skipping a song), your app could suggest that user authenticate by issuing a non-fatal error. By using a non-fatal error, the system displays the message to the user without interrupting playback for the current media item. To implement non-fatal error handling, complete the following steps:

  1. Set the errorCode for the media session's PlaybackState to ERROR_CODE_AUTHENTICATION_EXPIRED. This tells Android Automotive OS that user needs to authenticate.
  2. Keep the state for the media session's PlaybackState as is—don't set it to STATE_ERROR. This is what tells the system that the error is non-fatal.
  3. Set the media session's PlaybackState extras using the setExtras() method. Include the following two keys:

    • android.media.extras.ERROR_RESOLUTION_ACTION_LABEL: A string that is displayed on the button that begins the sign-in workflow. Because this string is user-facing, it must be localized for the user's current locale.
    • android.media.extras.ERROR_RESOLUTION_ACTION_INTENT: A PendingIntent that directs the user to your Sign-in activity when the user taps the button referred to by the android.media.extras.ERROR_RESOLUTION_ACTION_LABEL.
  4. Retain the rest of the media session's PlaybackState state as is. This allows playback for the current media item to continue while the user decides whether to sign in or not.