| page.title=Providing Audio Playback for Auto |
| page.tags="auto", "car", "automotive", "audio" |
| page.article=true |
| |
| page.metaDescription=Learn how to extend your audio apps for use in Android Auto devices. |
| page.image=auto/images/assets/icons/media_app_playback.png |
| |
| @jd:body |
| |
| <div id="tb-wrapper"> |
| <div id="tb"> |
| <h2>Dependencies and Prerequisites</h2> |
| <ul> |
| <li>Android 5.0 (API level 21) or higher</li> |
| </ul> |
| |
| <h2>This class teaches you how to</h2> |
| |
| <ol> |
| <li><a href="#overview">Provide Audio Services</a></li> |
| <li><a href="#config_manifest">Configure Your Manifest</a></li> |
| <li><a href="#isconnected">Determine if Your App is Connected</a></li> |
| <li><a href="#alarm">Handle Alarms</a></li> |
| <li><a href="#mediaadv">Handle Media Advertisements</a></li> |
| <li><a href="#implement_browser">Build a Browser Service</a></li> |
| <li><a href="#implement_callback">Implement Play Controls</a></li> |
| <li><a href="#support_voice">Support Voice Actions</a></li> |
| </ol> |
| |
| <h2>Related Samples</h2> |
| |
| <ul> |
| <li><a href="{@docRoot}samples/MediaBrowserService/index.html"> |
| MediaBrowserService</a></li> |
| <li><a href="//github.com/googlesamples/android-UniversalMusicPlayer" |
| class="external-link">Universal Media Player</a></li> |
| </ul> |
| |
| <h2>See Also</h2> |
| |
| <ul> |
| <li> |
| <a href="{@docRoot}shareables/auto/AndroidAuto-audio-apps.pdf"> |
| User Experience Guidelines: Audio Apps</a> |
| </li> |
| <li><a href="{@docRoot}training/managing-audio/index.html">Managing Audio |
| Playback</a></li> |
| <li><a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a> |
| </li> |
| </ul> |
| |
| </div> |
| </div> |
| |
| <a class="notice-developers-video wide" |
| href="https://www.youtube.com/watch?v=Q96Sw6v4ULg"> |
| <div> |
| <h3>Video</h3> |
| <p>Devbytes: Android Auto Audio</p> |
| </div> |
| </a> |
| |
| <p> |
| Drivers want to access their music and other audio content on the road. Audio books, podcasts, |
| sports commentary, and recorded talks can make a long trip educational, inspirational, and |
| enjoyable. The Android framework allows you to extend your audio app so users can listen to their |
| favorite tunes and audio content using a simple, yet customizable user interface. |
| </p> |
| |
| <p> |
| Apps running on mobile devices with Android 5.0 or higher can provide audio services for |
| dashboard systems running Android Auto. By configuring your app with a few settings and |
| implementing a service for accessing music tracks, you can enable Auto devices to discover your |
| app and provide a browse and playback interface for your app's audio content. |
| </p> |
| |
| <p> |
| This class assumes that you have built an app that plays audio through an Android device's |
| integrated speakers or connected headphones. It describes how to extend your app to allow Auto |
| devices to browse your content listings and play it through a car stereo system. |
| </p> |
| |
| |
| <h2 id="overview">Provide Audio Services</h2> |
| |
| <p> |
| Audio apps do not directly control a car dashboard device that runs Android Auto. When the user |
| connects an Android mobile device into a dashboard system, Android Auto discovers your app through |
| manifest entries that indicate what audio services your app can provide. The dashboard system |
| displays a launcher icon for your app as a music provider and the user can choose to use your |
| app's services. If the user launches your app, the Auto device queries your app to see what |
| content is available, displays your content items to the user, and sends requests to your app to |
| control playback with actions such as play, pause, or skip track. |
| </p> |
| |
| <p>To enable your app to provide audio content for Auto devices, you need to: |
| </p> |
| |
| <ul> |
| <li>Configure your app manifest to do the following:</li> |
| <ul> |
| <li>Declare that your app can provide audio content for Auto devices.</li> |
| <li>Define a service that provides a browsable list of your audio tracks.</li> |
| </ul> |
| </li> |
| <li>Build a service that provides audio track listing information extending |
| {@link android.service.media.MediaBrowserService}.</li> |
| <li>Register a {@link android.media.session.MediaSession} object and implement the |
| {@link android.media.session.MediaSession.Callback} object to enable playback controls.</li> |
| </ul> |
| |
| |
| <h2 id="config_manifest">Configure Your Manifest</h2> |
| |
| <p> |
| When a user plugs an Android mobile device into a dashboard device running Auto, the system |
| requests a list of installed apps that include <a href= |
| "{@docRoot}guide/topics/manifest/manifest-intro.html">app manifest</a> entries to indicate they |
| support services for Auto devices and how to access them. This section describes how to configure |
| your app manifest to indicate your app supports audio services for Auto devices, and allow |
| dashboard system to connect with your app. |
| </p> |
| |
| |
| <h3 id="manifest-car-app">Declare Auto audio support</h3> |
| |
| <p> |
| You indicate that your app supports cars capabilities using the following manifest entry: |
| </p> |
| |
| <pre> |
| <application> |
| ... |
| <meta-data android:name="com.google.android.gms.car.application" |
| android:resource="@xml/automotive_app_desc"/> |
| ... |
| <application> |
| </pre> |
| |
| <p> |
| This manifest entry refers to a secondary XML file, where you declare what Auto capabilities your |
| app supports. For an app that supports audio for cars, add an XML file to the {@code res/xml/} |
| resources directory as {@code automotive_app_desc.xml}, with the following content: |
| </p> |
| |
| <pre> |
| <automotiveApp> |
| <uses name="media"/> |
| </automotiveApp> |
| </pre> |
| |
| <p> |
| For more information about declaring capabilities for Auto devices, see <a href= |
| "{@docRoot}training/auto/start/index.html#auto-metadata">Getting Started with Auto</a>. |
| </p> |
| |
| |
| <h3 id="manifest-service">Declare your media browser service</h3> |
| |
| <p> |
| Auto devices expect to connect to a service in order to browse audio track |
| listings. You declare this service in your manifest to allow the dashboard system to discover |
| this service and connect to your app. |
| </p> |
| |
| <p>The following code example shows how to declare this listing browser service in your manifest:</p> |
| |
| <pre> |
| <application> |
| ... |
| <service android:name="<em>.MyMediaBrowserService</em>" |
| android:exported="true"> |
| <intent-filter> |
| <strong><action android:name=</strong> |
| <strong>"android.media.browse.MediaBrowserService"/></strong> |
| </intent-filter> |
| </service> |
| ... |
| <application> |
| </pre> |
| |
| <p> |
| The service your app provides for browsing audio tracks must extend the |
| {@link android.service.media.MediaBrowserService}. The implementation of this service is discussed |
| in the <a href="#implement_browser">Build a Browser Service</a> section. |
| </p> |
| |
| <p class="note"> |
| <strong>Note:</strong> Other clients can also contact your app's browser service aside from Auto |
| devices. These media clients might be other apps on a user's mobile device, or they might be other |
| remote clients. |
| </p> |
| |
| <h3 id="manifest-icon">Specify a notification icon</h3> |
| |
| <p> |
| The Auto user interface shows notifications about your audio app to the user during the course |
| of operation. For example, if the user has a navigation app running, and one song finishes |
| and a new song starts, the Auto device shows the user a notification to indicate the change with |
| an icon from your app. You can specify an icon that is used to represent your app for these |
| notifications using the following manifest declaration: |
| </p> |
| |
| <pre> |
| <application> |
| ... |
| <meta-data android:name="com.google.android.gms.car.notification.SmallIcon" |
| android:resource="@drawable/ic_notification" /> |
| ... |
| <application> |
| </pre> |
| |
| <p class="note"><strong>Note:</strong> The icon you provide should have transparency enabled, so the |
| icon's background gets filled in with the app's primary color.</p> |
| |
| <h2 id="isconnected">Determine if Your App is Connected</h2> |
| <p> |
| It is possible to determine if your app is selected as the current media app.</p> |
| <p> |
| Android Auto broadcasts an intent with <code>com.google.android.gms.car.media.STATUS</code> |
| action when a user connects or disconnects from a media app. The broadcast intent is |
| scoped to the package name of the media app selected. You can register a broadcast receiver in your |
| app, preferably in your <a href="{@docRoot}reference/android/service/media/MediaBrowserService.html"> |
| MediaBrowserService</a> implementation and listen for this intent |
| and adjust advertisements, metadata, and UI buttons in your app to operate safely in a vehicle.</p> |
| |
| <p>The broadcasted intent has a String extra <code>media_connection_status</code>, that |
| contains either <code>media_connected</code> or <code>media_disconnected</code> string that represents |
| the current connection status. </p> |
| |
| <pre> |
| IntentFilter filter = new IntentFilter("com.google.android.gms.car.media.STATUS"); |
| BroadcastReceiver receiver = new BroadcastReceiver() { |
| ... |
| public void onReceive(Context context, Intent intent) { |
| String status = intent.getStringExtra("media_connection_status"); |
| boolean isConnectedToCar = "media_connected".equals(status); |
| // adjust settings based on the connection status |
| } |
| }; |
| registerReceiver(receiver, filter); |
| </pre> |
| |
| <h2 id="alarm">Handle Alarms</h2> |
| <p> |
| To prevent user distraction, Android Auto media apps must not start playing audio |
| through the car speakers unless a user consciously starts playback (such as |
| when the user presses play in your app). Even a user-scheduled alarm from the |
| media app must not start playing music through the car speakers. |
| If your media app has an alarm feature, the app should determine if the phone |
| is in |
| <a href="{@docRoot}reference/android/content/res/Configuration.html#UI_MODE_TYPE_CAR">car mode</a> |
| before playing any audio. Your app can do this by calling |
| <a href="{@docRoot}reference/android/app/UiModeManager.html">UiModeManager.getCurrentModeType()</a>, |
| which checks whether the device is running in car mode. |
| </p> |
| |
| <p> |
| If the device is in car mode, media apps that support alarms must do one of the |
| following things: |
| |
| <ul> |
| <li>Disable the alarm.</li> |
| <li>Play the alarm over |
| <a href="{@docRoot}reference/android/media/AudioManager.html#STREAM_ALARM">STREAM_ALARM</a>, |
| and provide a UI on the phone screen to disable the alarm.</li> |
| </ul> |
| |
| The following code snippet checks whether an app is running in car mode: |
| <pre> |
| public static boolean isCarUiMode(Context c) { |
| UiModeManager uiModeManager = (UiModeManager) c.getSystemService(Context.UI_MODE_SERVICE); |
| if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) { |
| LogHelper.d(TAG, "Running in Car mode"); |
| return true; |
| } else { |
| LogHelper.d(TAG, "Running on a non-Car mode"); |
| return false; |
| } |
| } |
| </pre> |
| |
| <h2 id="mediaadv">Handle Media Advertisements</h2> |
| <p>By default, Android Auto displays a notification when |
| the media metadata changes during an audio playback session. When a media |
| app switches from playing music to running an advertisement, it is distracting |
| (and unnecessary) to display a notification to the user. To prevent Android Auto |
| from displaying a notification in this case, you must set the media metadata |
| key {@code android.media.metadata.ADVERTISEMENT} to 1, as shown in the code |
| snippet below: |
| |
| <pre> |
| |
| @Override |
| public static final String EXTRA_METADATA_ADVERTISEMENT = |
| "android.media.metadata.ADVERTISEMENT"; |
| |
| public void onPlayFromMediaId(String mediaId, Bundle extras) { |
| MediaMetadata.Builder builder = new MediaMetadata.Builder(); |
| // ... |
| if (isAd(mediaId)) { |
| builder.putLong(EXTRA_METADATA_ADVERTISEMENT, 1); |
| } |
| // ... |
| mediaSession.setMetadata(builder.build()); |
| } |
| |
| </pre> |
| |
| <h2 id="implement_browser">Build a Browser Service</h2> |
| |
| <p>Auto devices interact with your app by contacting its implementation of a |
| {@link android.service.media.MediaBrowserService}, which |
| you declare in your app manifest. This service allows Auto devices to find out what content your app |
| provides. Connected Auto devices can also query your app's media browser service to contact the |
| {@link android.media.session.MediaSession} provided by your app, which handles content playback |
| commands.</p> |
| |
| <p>You create a media browser service by extending the |
| {@link android.service.media.MediaBrowserService} class. |
| Connected Auto devices can contact your service to do the following:</p> |
| |
| <ul> |
| <li>Browse your app's content hierarchy, in order to present a menu to the |
| user</li> |
| <li>Get the token for your app's {@link android.media.session.MediaSession} |
| object, in order to control audio playback</li> |
| </ul> |
| |
| |
| <h3 id="browser_workflow">Media browser service workflow</h3> |
| |
| <ol> |
| |
| <li>When your app's audio services are requested by a user through a connected Auto device, the |
| dashboard system contacts your app's media browser service. |
| In your implementation of the {@link android.service.media.MediaBrowserService#onCreate() |
| onCreate()} method, you must create and register a {@link |
| android.media.session.MediaSession} object and its callback object.</li> |
| |
| <li>The Auto device calls the browser service's {@link |
| android.service.media.MediaBrowserService#onGetRoot onGetRoot()} method to get the top node of |
| your content hierarchy. The node retrieved by this call is not used as a menu item, it is only used |
| to retrieve its child nodes, which are subsequently displayed as the top menu items. |
| </li> |
| |
| <li>Auto invokes the {@link android.service.media.MediaBrowserService#onLoadChildren |
| onLoadChildren()} method to get the children of the root node, and uses this information to |
| present a menu to the user.</li> |
| |
| <li>If the user selects a submenu, Auto invokes |
| {@link android.service.media.MediaBrowserService#onLoadChildren |
| onLoadChildren()} again to retrieve the child nodes of the selected menu item.</li> |
| |
| <li>If the user begins playback, Auto invokes the appropriate media session |
| callback method to perform that action. For more information, see the section about how to |
| <a href="#implement_callback">Implement Playback Controls</a>. </li> |
| |
| </ol> |
| |
| |
| <h3 id="build_hierarchy">Building your content hierarchy</h3> |
| |
| <p>Auto devices acting as audio clients call your app's {@link |
| android.service.media.MediaBrowserService} to find out what content you have |
| available. You need to implement two methods in your browser service to support |
| this: {@link android.service.media.MediaBrowserService#onGetRoot |
| onGetRoot()} and {@link |
| android.service.media.MediaBrowserService#onLoadChildren |
| onLoadChildren()}.</p> |
| |
| <p>Each node in your content hierarchy is represented by a {@link |
| android.media.browse.MediaBrowser.MediaItem} object. Each of these objects is |
| identified by a unique ID string. The client treats these ID strings as |
| opaque tokens. When a client wants to browse to a submenu, or play a content |
| item, it passes the ID token. Your app is responsible for associating the ID |
| token with the appropriate menu node or content item.</p> |
| |
| <p class="note"><strong>Note:</strong> You should consider providing different content |
| hierarchies depending on what client is making the query. In particular, Auto |
| applications have strict limits on how large a menu they can display. This is |
| intended to minimize distracting the driver, and to make it easy for the driver |
| to operate the app via voice commands. For more information on the Auto user |
| experience restrictions, see the <a href="{@docRoot}shareables/auto/AndroidAuto-audio-apps.pdf"> |
| Auto Audio Apps</a> guidelines.</p> |
| |
| <p>Your implementation of {@link android.service.media.MediaBrowserService#onGetRoot |
| onGetRoot()} returns information about the root node of the menu |
| hierarchy. This root node is the parent of the top items of your browse hierarchy. |
| The method is passed information about the calling client. You can use this |
| information to decide if the client should have access to your content at all. |
| For example, if you want to limit your app's content to a list of approved |
| clients, you can compare the passed {@code clientPackageName} to your whitelist |
| and verify the certificate used to sign the caller's APK. |
| If the caller can't be verified to be an approved package, return null to deny access to |
| your content. For an example of an app that validates that the caller is an |
| approved app, see the |
| <a href="https://github.com/googlesamples/android-UniversalMusicPlayer/blob/master/mobile/src/main/java/com/example/android/uamp/PackageValidator.java" |
| class="external-link"><code>PackageValidator</code></a> class in the |
| <a href="https://github.com/googlesamples/android-UniversalMusicPlayer" |
| class="external-link">Universal Android Music Player</a> sample app. |
| </p> |
| |
| <p>A typical implementation of {@link |
| android.service.media.MediaBrowserService#onGetRoot onGetRoot()} might |
| look like this:</p> |
| |
| <pre> |
| @Override |
| public BrowserRoot onGetRoot(String clientPackageName, int clientUid, |
| Bundle rootHints) { |
| |
| // Verify that the specified package is allowed to access your |
| // content! You'll need to write your own logic to do this. |
| if (!isValid(clientPackageName, clientUid)) { |
| // If the request comes from an untrusted package, return null. |
| // No further calls will be made to other media browsing methods. |
| |
| return null; |
| } |
| |
| return new BrowserRoot(MY_MEDIA_ROOT_ID, null); |
| } |
| </pre> |
| |
| <p> |
| The Auto device client builds the top-level menu by calling {@link |
| android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()} |
| with the root node object and getting its children. The client builds |
| submenus by calling the same method with other child nodes. The following |
| example code shows a simple implementation of {@link |
| android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()} method: |
| </p> |
| |
| <pre> |
| @Override |
| public void onLoadChildren(final String parentMediaId, |
| final Result<List<MediaItem>> result) { |
| |
| // Assume for example that the music catalog is already loaded/cached. |
| |
| List<MediaItem> mediaItems = new ArrayList<>(); |
| |
| // Check if this is the root menu: |
| if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) { |
| |
| // build the MediaItem objects for the top level, |
| // and put them in the mediaItems list |
| } else { |
| |
| // examine the passed parentMediaId to see which submenu we're at, |
| // and put the children of that menu in the mediaItems list |
| } |
| result.sendResult(mediaItems); |
| } |
| </pre> |
| |
| <p> |
| For examples of how to implement {@link |
| android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()}, |
| see the <a href="{@docRoot}samples/MediaBrowserService/index.html"> |
| MediaBrowserService</a> and |
| <a href="https://github.com/googlesamples/android-UniversalMusicPlayer" |
| class="external-link">Universal Android Music Player</a> sample apps. |
| </p> |
| |
| <h2 id="implement_callback">Enable Playback Control</h2> |
| |
| <p> |
| Auto devices use {@link android.media.session.MediaSession} objects to pass playback control |
| commands to an app that is providing audio services. Your audio app must create an instance of |
| this object to pass to the dashboard device and implement callback methods to enable remote |
| control of audio playback. |
| </p> |
| |
| <h3 id="registering_mediasession">Register a media session</h3> |
| |
| <p>An Auto device using your app as audio service needs to obtain a {@link |
| android.media.session.MediaSession} object from your app. The Auto device uses the session object |
| to send playback commands requested by the Auto user back to your app.</p> |
| |
| <p>When you initialize your browser service, you register that session object with your {@link |
| android.service.media.MediaBrowserService} by calling the {@link |
| android.service.media.MediaBrowserService#setSessionToken setSessionToken()} method. This step |
| allows clients such as an Auto device to retrieve that object by calling your browser service's |
| {@link android.service.media.MediaBrowserService#getSessionToken getSessionToken()} method.</p> |
| |
| <p>In your browser service's {@link |
| android.service.media.MediaBrowserService#onCreate() onCreate()} method, |
| create a {@link android.media.session.MediaSession}. You can then query |
| the {@link android.media.session.MediaSession} to get its token, and register |
| the token with your browser service:</p> |
| |
| <pre> |
| public void onCreate() { |
| super.onCreate(); |
| |
| ... |
| // Start a new MediaSession |
| MediaSession mSession = new MediaSession(this, "session tag"); |
| setSessionToken(mSession.getSessionToken()); |
| |
| // Set a callback object to handle play control requests, which |
| // implements MediaSession.Callback |
| mSession.setCallback(new MyMediaSessionCallback()); |
| |
| ... |
| </pre> |
| |
| <p> |
| When you create the media session object, you set a callback object that is used to handle |
| playback control requests. You create this callback object by providing an implementation of the |
| {@link android.media.session.MediaSession.Callback} class for your app. The next section |
| discusses how to implement this object. |
| </p> |
| |
| |
| <h3 id="playback-commands">Implement play commands</h3> |
| |
| <p>When an Auto device requests playback of an audio track from your app, it uses the |
| {@link android.media.session.MediaSession.Callback} class from your app's |
| {@link android.media.session.MediaSession} object, which it obtained from your app's |
| media browse service. When an Auto user wants to play content or control content playback, |
| such as pausing play or skipping to the next track, Auto invokes one |
| of the callback object's methods.</p> |
| |
| <p>To handle content playback, your app must extend the abstract {@link |
| android.media.session.MediaSession.Callback} class and implement the methods |
| that your app supports. The most important callback methods are as follows:</p> |
| |
| <dl> |
| |
| <dt>{@link android.media.session.MediaSession.Callback#onPlay onPlay()}</dt> |
| <dd>Invoked if the user chooses play without choosing a specific item. Your |
| app should play its default content. If playback was paused with |
| {@link android.media.session.MediaSession.Callback#onPause onPause()}, your |
| app should resume playback.</dd> |
| |
| <p class="note"> |
| <strong>Note:</strong> Google Play requires your app not to play music immediately when it |
| launches. For more information on this and other requirements, see |
| <a href="{@docRoot}distribute/essentials/quality/auto.html">Auto App Quality</a>. |
| </p> |
| |
| <dt>{@link android.media.session.MediaSession.Callback#onPlayFromMediaId |
| onPlayFromMediaId()}</dt> |
| <dd>Invoked when the user chooses to play a specific item. The method is passed |
| the item's media ID, which you assigned to the item in the content |
| hierarchy.</dd> |
| |
| <dt>{@link android.media.session.MediaSession.Callback#onPlayFromSearch |
| onPlayFromSearch()}</dt> |
| <dd>Invoked when the user chooses to play from a search query. The app should |
| make an appropriate choice based on the passed search string.</dd> |
| |
| <dt>{@link android.media.session.MediaSession.Callback#onPause onPause()}</dt> |
| <dd>Pause playback.</dd> |
| |
| <dt>{@link android.media.session.MediaSession.Callback#onSkipToNext |
| onSkipToNext()}</dt> |
| <dd>Skip to the next item.</dd> |
| |
| <dt>{@link android.media.session.MediaSession.Callback#onSkipToPrevious |
| onSkipToPrevious()}</dt> |
| <dd>Skip to the previous item.</dd> |
| |
| <dt>{@link android.media.session.MediaSession.Callback#onStop onStop()}</dt> |
| <dd>Stop playback.</dd> |
| |
| </dl> |
| |
| <p>Your app should override these methods to provide any desired functionality. |
| In some cases you might not implement a method if it is not supported by your app. |
| For example, if your app plays a live stream (such as a sports |
| broadcast), the skip to next function might not make sense. In that case, you |
| could simply use the default implementation of |
| {@link android.media.session.MediaSession.Callback#onSkipToNext |
| onSkipToNext()}.</p> |
| |
| <p>When your app receives a request to play content, it should play audio the same way it |
| would in a non-Auto situation (as if the user was listening through a device speaker |
| or connected headphones). The audio content is automatically sent to the dashboard system |
| to be played over the car's speakers.</p> |
| |
| <p>For more information about playing audio content, see |
| <a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a>, |
| <a href="{@docRoot}training/managing-audio/index.html">Managing Audio Playback</a>, and |
| <a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>.</p> |
| |
| <a class="notice-developers-video wide" |
| href="https://www.youtube.com/watch?v=xc2HZSwPcwM"> |
| <div> |
| <h3>Video</h3> |
| <p>Devbytes: Android Auto Voice Actions</p> |
| </div> |
| </a> |
| <h2 id="support_voice">Support Voice Actions</h2> |
| |
| <p>To reduce driver distractions, you must add voice actions in your audio playback app. With voice |
| action support, users can launch your app and play audio by providing voice input on Auto screens. |
| If your audio playback app is already active and the user says |
| <i>“Play a song”</i>, the system starts playing music without requiring the user to look at or touch |
| the screen.</p> |
| |
| <h3 id="enable_playback">Enable your app to handle audio playback requests</h3> |
| |
| <p>Enable your audio app to launch with a voice command such as <i>"Play [search query] on |
| [your app name]"</i> by adding the following entry in your manifest:</p> |
| |
| <pre> |
| <activity> |
| <intent-filter> |
| <action android:name= |
| "android.media.action.MEDIA_PLAY_FROM_SEARCH" /> |
| <category android:name= |
| "android.intent.category.DEFAULT" /> |
| </intent-filter> |
| </activity> |
| </pre> |
| |
| <p>When the user says <i>“Play music on [your app name]”</i> on an Auto screen, Auto |
| attempts to launch your app and play audio by calling your app’s |
| <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>MediaSession.Callback.onPlayFromSearch()</code></a> |
| method. If the user has not specified criteria such as a track name or music genre, the |
| <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>MediaSession.Callback.onPlayFromSearch()</code></a> |
| method receives an empty query parameter. Your app should respond by immediately playing audio, such |
| as a song from a random queue or the most recent playlist. |
| </p> |
| |
| <h3 id="parse_voice">Parse the voice query to build the playback queue</h3> |
| |
| <p>When a user searches for a specific criteria, such as <i>“Play jazz on [your app name]”</i> |
| or <i>“Listen to [song title]”</i>, the |
| <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>onPlayFromSearch()</code></a> |
| callback method receives the voice search results in the query parameter and an extras bundle. For |
| more information on how to handle search queries to play audio content, see |
| <a href="https://developer.android.com/guide/components/intents-common.html#PlaySearch">Play music |
| based on a search query</a>. |
| </p> |
| |
| <p>To parse the voice search query to play back audio content in your app, follow these steps:</p> |
| |
| <ol> |
| <li>Use the extras bundle and search query string returned from the voice search to filter |
| results.</li> |
| <li>Build the audio content queue based on these results.</li> |
| <li>Play the audio content.</li> |
| </ol> |
| |
| <p>The |
| <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>onPlayFromSearch()</code></a> |
| method takes an extras parameter with more detailed information from the voice search. |
| These extras help you find the audio content in your app for playback. If the search results are |
| unable to provide this data, you can implement logic to parse the raw search query and play the |
| appropriate tracks based on the query. |
| </p> |
| |
| <p>The following extras are supported in Android Auto:</p> |
| |
| <ul> |
| <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_ALBUM"><code>android.intent.extra.album</code></a></li> |
| <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_ARTIST"><code>android.intent.extra.artist</code></a></li> |
| <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_GENRE"><code>android.intent.extra.genre</code></a></li> |
| <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_PLAYLIST"><code>android.intent.extra.playlist</code></a></li> |
| <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_TITLE"><code>android.intent.extra.title</code></a></li> |
| </ul> |
| |
| <p>The following snippet shows how to override the |
| <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>onPlayFromSearch()</code></a> |
| method in your |
| <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html"><code>MediaSession.Callback</code></a> |
| implementation to handle the search query and extras for playing audio content in your app: |
| </p> |
| |
| <pre> |
| @Override |
| public void onPlayFromSearch(String query, Bundle extras) { |
| if (TextUtils.isEmpty(query)) { |
| // The user provided generic string e.g. 'Play music' |
| // Build appropriate playlist queue |
| } else { |
| // Build a queue based on songs that match "query" or "extras" param |
| String mediaFocus = extras.getString(MediaStore.EXTRA_MEDIA_FOCUS); |
| if (TextUtils.equals(mediaFocus, |
| MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE)) { |
| isArtistFocus = true; |
| artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST); |
| } else if (TextUtils.equals(mediaFocus, |
| MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE)) { |
| isAlbumFocus = true; |
| album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM); |
| } |
| |
| // Implement additional "extras" param filtering |
| } |
| |
| // Implement your logic to retrieve the queue |
| if (isArtistFocus) { |
| result = searchMusicByArtist(artist); |
| } else if (isAlbumFocus) { |
| result = searchMusicByAlbum(album); |
| } |
| |
| if (result == null) { |
| // No focus found, search by query for song title |
| result = searchMusicBySongTitle(query); |
| } |
| |
| if (result != null && !result.isEmpty()) { |
| // Immediately start playing from the beginning of the search results |
| // Implement your logic to start playing music |
| playMusic(result); |
| } else { |
| // Handle no queue found. Stop playing if the app |
| // is currently playing a song |
| } |
| } |
| </pre> |
| |
| <p class="note"> |
| <strong>Note:</strong> To minimize driver distractions, immediately initiate audio content |
| playback in the |
| <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>onPlayFromSearch()</code></a> |
| method when you have generated the audio content queue based on the user's request. |
| </p> |
| |
| <p>For a more detailed example on how to implement voice search to play audio content in your app, |
| see the |
| <a href="//github.com/googlesamples/android-UniversalMusicPlayer/">Universal Media Player</a> |
| sample. |
| </p> |
| |
| <h3 id="implement_playback_controls">Implement playback control actions</h3> |
| |
| <p>To provide a hands-free experience while users drive and listen to audio content in Android Auto, |
| your app should allow users to control audio content playback with voice actions. When users speak |
| commands such as <i>“Next song”</i>, <i>“Pause music”</i>, or <i>“Resume music”</i>, the system |
| triggers the corresponding callback method where you implement the playback control action. |
| </p> |
| |
| <p>To provide voice-enabled playback controls, first enable the hardware controls by setting these |
| flags in your app’s |
| <a href="{@docRoot}reference/android/media/session/MediaSession.html"><code>MediaSession</code></a> |
| object: |
| </p> |
| |
| <pre> |
| mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | |
| MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS); |
| </pre> |
| |
| <p>Then, implement the callback methods with the playback controls that you support in your app. |
| Here’s a list of voice-enabled playback controls supported by Android Auto: |
| </p> |
| |
| <table> |
| <tr> |
| <th>Example phrase</th> |
| <th>Callback method</th> |
| </tr> |
| <tr> |
| <td><i>"Next song"</i></td> |
| <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onSkipToNext()"><code>onSkipToNext()</code></a></td> |
| </tr> |
| <tr> |
| <td><i>"Previous song"</i></td> |
| <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onSkipToPrevious()"><code>onSkipToPrevious()</code></a></td> |
| </tr> |
| <tr> |
| <td><i>"Pause music"</i></td> |
| <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPause()"><code>onPause()</code></a></td> |
| </tr> |
| <tr> |
| <td><i>"Stop music"</i></td> |
| <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onStop()"><code>onStop()</code></a></td> |
| </tr> |
| <tr> |
| <td><i>"Resume music"</i></td> |
| <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlay()"><code>onPlay()</code></a></td> |
| </tr> |
| </table> |
| |
| <p>For a more detailed example on how to implement voice-enabled playback actions in your app, see |
| the |
| <a href="//github.com/googlesamples/android-UniversalMusicPlayer/">Universal Media Player</a> |
| sample. |
| </p> |