Home | History | Annotate | Download | only in audio
      1 page.title=Providing Audio Playback for Auto
      2 page.tags="auto", "car", "automotive", "audio"
      3 page.article=true
      4 
      5 page.metaDescription=Learn how to extend your audio apps for use in Android Auto devices.
      6 page.image=auto/images/assets/icons/media_app_playback.png
      7 
      8 @jd:body
      9 
     10 <div id="tb-wrapper">
     11 <div id="tb">
     12   <h2>Dependencies and Prerequisites</h2>
     13   <ul>
     14     <li>Android 5.0 (API level 21) or higher</li>
     15   </ul>
     16 
     17     <h2>This class teaches you how to</h2>
     18 
     19     <ol>
     20       <li><a href="#overview">Provide Audio Services</a></li>
     21       <li><a href="#config_manifest">Configure Your Manifest</a></li>
     22       <li><a href="#isconnected">Determine if Your App is Connected</a></li>
     23       <li><a href="#alarm">Handle Alarms</a></li>
     24       <li><a href="#mediaadv">Handle Media Advertisements</a></li>
     25       <li><a href="#implement_browser">Build a Browser Service</a></li>
     26       <li><a href="#implement_callback">Implement Play Controls</a></li>
     27       <li><a href="#support_voice">Support Voice Actions</a></li>
     28     </ol>
     29 
     30     <h2>Related Samples</h2>
     31 
     32     <ul>
     33       <li><a href="{@docRoot}samples/MediaBrowserService/index.html">
     34         MediaBrowserService</a></li>
     35       <li><a href="//github.com/googlesamples/android-UniversalMusicPlayer"
     36         class="external-link">Universal Media Player</a></li>
     37     </ul>
     38 
     39     <h2>See Also</h2>
     40 
     41     <ul>
     42       <li>
     43         <a href="{@docRoot}shareables/auto/AndroidAuto-audio-apps.pdf">
     44               User Experience Guidelines: Audio Apps</a>
     45       </li>
     46       <li><a href="{@docRoot}training/managing-audio/index.html">Managing Audio
     47         Playback</a></li>
     48       <li><a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>
     49       </li>
     50     </ul>
     51 
     52 </div>
     53 </div>
     54 
     55 <a class="notice-developers-video wide"
     56 href="https://www.youtube.com/watch?v=Q96Sw6v4ULg">
     57 <div>
     58     <h3>Video</h3>
     59     <p>Devbytes: Android Auto Audio</p>
     60 </div>
     61 </a>
     62 
     63 <p>
     64   Drivers want to access their music and other audio content on the road. Audio books, podcasts,
     65   sports commentary, and recorded talks can make a long trip educational, inspirational, and
     66   enjoyable. The Android framework allows you to extend your audio app so users can listen to their
     67   favorite tunes and audio content using a simple, yet customizable user interface.
     68 </p>
     69 
     70 <p>
     71   Apps running on mobile devices with Android 5.0 or higher can provide audio services for
     72   dashboard systems running Android Auto. By configuring your app with a few settings and
     73   implementing a service for accessing music tracks, you can enable Auto devices to discover your
     74   app and provide a browse and playback interface for your app's audio content.
     75 </p>
     76 
     77 <p>
     78   This class assumes that you have built an app that plays audio through an Android device's
     79   integrated speakers or connected headphones. It describes how to extend your app to allow Auto
     80   devices to browse your content listings and play it through a car stereo system.
     81 </p>
     82 
     83 
     84 <h2 id="overview">Provide Audio Services</h2>
     85 
     86 <p>
     87   Audio apps do not directly control a car dashboard device that runs Android Auto. When the user
     88   connects an Android mobile device into a dashboard system, Android Auto discovers your app through
     89   manifest entries that indicate what audio services your app can provide. The dashboard system
     90   displays a launcher icon for your app as a music provider and the user can choose to use your
     91   app's services. If the user launches your app, the Auto device queries your app to see what
     92   content is available, displays your content items to the user, and sends requests to your app to
     93   control playback with actions such as play, pause, or skip track.
     94 </p>
     95 
     96 <p>To enable your app to provide audio content for Auto devices, you need to:
     97 </p>
     98 
     99 <ul>
    100   <li>Configure your app manifest to do the following:</li>
    101     <ul>
    102       <li>Declare that your app can provide audio content for Auto devices.</li>
    103       <li>Define a service that provides a browsable list of your audio tracks.</li>
    104     </ul>
    105   </li>
    106   <li>Build a service that provides audio track listing information extending
    107     {@link android.service.media.MediaBrowserService}.</li>
    108   <li>Register a {@link android.media.session.MediaSession} object and implement the
    109     {@link android.media.session.MediaSession.Callback} object to enable playback controls.</li>
    110 </ul>
    111 
    112 
    113 <h2 id="config_manifest">Configure Your Manifest</h2>
    114 
    115 <p>
    116   When a user plugs an Android mobile device into a dashboard device running Auto, the system
    117   requests a list of installed apps that include <a href=
    118   "{@docRoot}guide/topics/manifest/manifest-intro.html">app manifest</a> entries to indicate they
    119   support services for Auto devices and how to access them. This section describes how to configure
    120   your app manifest to indicate your app supports audio services for Auto devices, and allow
    121   dashboard system to connect with your app.
    122 </p>
    123 
    124 
    125 <h3 id="manifest-car-app">Declare Auto audio support</h3>
    126 
    127 <p>
    128   You indicate that your app supports cars capabilities using the following manifest entry:
    129 </p>
    130 
    131 <pre>
    132 &lt;application&gt;
    133     ...
    134     &lt;meta-data android:name="com.google.android.gms.car.application"
    135         android:resource="&#64;xml/automotive_app_desc"/&gt;
    136     ...
    137 &lt;application&gt;
    138 </pre>
    139 
    140 <p>
    141   This manifest entry refers to a secondary XML file, where you declare what Auto capabilities your
    142   app supports. For an app that supports audio for cars, add an XML file to the {@code res/xml/}
    143   resources directory as {@code automotive_app_desc.xml}, with the following content:
    144 </p>
    145 
    146 <pre>
    147 &lt;automotiveApp&gt;
    148     &lt;uses name="media"/&gt;
    149 &lt;/automotiveApp&gt;
    150 </pre>
    151 
    152 <p>
    153   For more information about declaring capabilities for Auto devices, see <a href=
    154   "{@docRoot}training/auto/start/index.html#auto-metadata">Getting Started with Auto</a>.
    155 </p>
    156 
    157 
    158 <h3 id="manifest-service">Declare your media browser service</h3>
    159 
    160 <p>
    161   Auto devices expect to connect to a service in order to browse audio track
    162   listings. You declare this service in your manifest to allow the dashboard system to discover
    163   this service and connect to your app.
    164 </p>
    165 
    166 <p>The following code example shows how to declare this listing browser service in your manifest:</p>
    167 
    168 <pre>
    169 &lt;application&gt;
    170     ...
    171     &lt;service android:name="<em>.MyMediaBrowserService</em>"
    172                 android:exported="true"&gt;
    173         &lt;intent-filter&gt;
    174             <strong>&lt;action android:name=</strong>
    175                 <strong>"android.media.browse.MediaBrowserService"/&gt;</strong>
    176         &lt;/intent-filter&gt;
    177     &lt;/service&gt;
    178     ...
    179 &lt;application&gt;
    180 </pre>
    181 
    182 <p>
    183   The service your app provides for browsing audio tracks must extend the
    184   {@link android.service.media.MediaBrowserService}. The implementation of this service is discussed
    185   in the <a href="#implement_browser">Build a Browser Service</a> section.
    186 </p>
    187 
    188 <p class="note">
    189   <strong>Note:</strong> Other clients can also contact your app's browser service aside from Auto
    190   devices. These media clients might be other apps on a user's mobile device, or they might be other
    191   remote clients.
    192 </p>
    193 
    194 <h3 id="manifest-icon">Specify a notification icon</h3>
    195 
    196 <p>
    197   The Auto user interface shows notifications about your audio app to the user during the course
    198   of operation. For example, if the user has a navigation app running, and one song finishes
    199   and a new song starts, the Auto device shows the user a notification to indicate the change with
    200   an icon from your app. You can specify an icon that is used to represent your app for these
    201   notifications using the following manifest declaration:
    202 </p>
    203 
    204 <pre>
    205 &lt;application&gt;
    206     ...
    207     &lt;meta-data android:name="com.google.android.gms.car.notification.SmallIcon"
    208         android:resource="&#64;drawable/ic_notification" /&gt;
    209     ...
    210 &lt;application&gt;
    211 </pre>
    212 
    213 <p class="note"><strong>Note:</strong> The icon you provide should have transparency enabled, so the
    214 icon's background gets filled in with the app's primary color.</p>
    215 
    216 <h2 id="isconnected">Determine if Your App is Connected</h2>
    217 <p>
    218 It is possible to determine if your app is selected as the current media app.</p>
    219 <p>
    220 Android Auto broadcasts an intent with <code>com.google.android.gms.car.media.STATUS</code>
    221 action when a user connects or disconnects from a media app. The broadcast intent is
    222 scoped to the package name of the media app selected. You can register a broadcast receiver in your
    223 app, preferably in your <a href="{@docRoot}reference/android/service/media/MediaBrowserService.html">
    224 MediaBrowserService</a> implementation and listen for this intent
    225 and adjust advertisements, metadata, and UI buttons in your app to operate safely in a vehicle.</p>
    226 
    227 <p>The broadcasted intent has a String extra <code>media_connection_status</code>, that
    228 contains either <code>media_connected</code> or <code>media_disconnected</code> string that represents
    229  the current connection status. </p>
    230 
    231 <pre>
    232 IntentFilter filter = new IntentFilter("com.google.android.gms.car.media.STATUS");
    233 BroadcastReceiver receiver = new BroadcastReceiver() {
    234     ...
    235     public void onReceive(Context context, Intent intent) {
    236         String status = intent.getStringExtra("media_connection_status");
    237         boolean isConnectedToCar = "media_connected".equals(status);
    238         // adjust settings based on the connection status
    239     }
    240 };
    241 registerReceiver(receiver, filter);
    242 </pre>
    243 
    244 <h2 id="alarm">Handle Alarms</h2>
    245 <p>
    246 To prevent user distraction, Android Auto media apps must not start playing audio
    247  through the car speakers unless a user consciously starts playback (such as
    248  when the user presses play in your app). Even a user-scheduled alarm from the
    249  media app must not start playing music through the car speakers.
    250  If your media app has an alarm feature, the app should determine if the phone
    251  is in
    252 <a href="{@docRoot}reference/android/content/res/Configuration.html#UI_MODE_TYPE_CAR">car mode</a>
    253 before playing any audio. Your app can do this by calling
    254 <a href="{@docRoot}reference/android/app/UiModeManager.html">UiModeManager.getCurrentModeType()</a>,
    255  which checks whether the device is running in car mode.
    256 </p>
    257 
    258 <p>
    259 If the device is in car mode, media apps that support alarms must do one of the
    260 following things:
    261 
    262 <ul>
    263 <li>Disable the alarm.</li>
    264 <li>Play the alarm over
    265 <a href="{@docRoot}reference/android/media/AudioManager.html#STREAM_ALARM">STREAM_ALARM</a>,
    266  and provide a UI on the phone screen to disable the alarm.</li>
    267 </ul>
    268 
    269 The following code snippet checks whether an app is running in car mode:
    270 <pre>
    271  public static boolean isCarUiMode(Context c) {
    272       UiModeManager uiModeManager = (UiModeManager) c.getSystemService(Context.UI_MODE_SERVICE);
    273       if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) {
    274             LogHelper.d(TAG, "Running in Car mode");
    275             return true;
    276       } else {
    277           LogHelper.d(TAG, "Running on a non-Car mode");
    278           return false;
    279         }
    280   }
    281 </pre>
    282 
    283 <h2 id="mediaadv">Handle Media Advertisements</h2>
    284 <p>By default, Android Auto displays a notification when
    285 the media metadata changes during an audio playback session. When a media
    286 app switches from playing music to running an advertisement, it is distracting
    287 (and unnecessary) to display a notification to the user. To prevent Android Auto
    288 from displaying a notification in this case, you must set the media metadata
    289 key {@code android.media.metadata.ADVERTISEMENT} to 1, as shown in the code
    290 snippet below:
    291 
    292 <pre>
    293 
    294 &#64;Override
    295 public static final String EXTRA_METADATA_ADVERTISEMENT =
    296             "android.media.metadata.ADVERTISEMENT";
    297 
    298 public void onPlayFromMediaId(String mediaId, Bundle extras) {
    299     MediaMetadata.Builder builder = new MediaMetadata.Builder();
    300     // ...
    301     if (isAd(mediaId)) {
    302         builder.putLong(EXTRA_METADATA_ADVERTISEMENT, 1);
    303     }
    304     // ...
    305     mediaSession.setMetadata(builder.build());
    306 }
    307 
    308 </pre>
    309 
    310 <h2 id="implement_browser">Build a Browser Service</h2>
    311 
    312 <p>Auto devices interact with your app by contacting its implementation of a
    313   {@link android.service.media.MediaBrowserService}, which
    314 you declare in your app manifest. This service allows Auto devices to find out what content your app
    315 provides. Connected Auto devices can also query your app's media browser service to contact the
    316 {@link android.media.session.MediaSession} provided by your app, which handles content playback
    317 commands.</p>
    318 
    319 <p>You create a media browser service by extending the
    320 {@link android.service.media.MediaBrowserService} class.
    321 Connected Auto devices can contact your service to do the following:</p>
    322 
    323 <ul>
    324   <li>Browse your app's content hierarchy, in order to present a menu to the
    325     user</li>
    326   <li>Get the token for your app's {@link android.media.session.MediaSession}
    327     object, in order to control audio playback</li>
    328 </ul>
    329 
    330 
    331 <h3 id="browser_workflow">Media browser service workflow</h3>
    332 
    333 <ol>
    334 
    335 <li>When your app's audio services are requested by a user through a connected Auto device, the
    336 dashboard system contacts your app's media browser service.
    337 In your implementation of the {@link android.service.media.MediaBrowserService#onCreate()
    338 onCreate()} method, you must create and register a {@link
    339 android.media.session.MediaSession} object and its callback object.</li>
    340 
    341 <li>The Auto device calls the browser service's {@link
    342 android.service.media.MediaBrowserService#onGetRoot onGetRoot()} method to get the top node of
    343 your content hierarchy. The node retrieved by this call is not used as a menu item, it is only used
    344 to retrieve its child nodes, which are subsequently displayed as the top menu items.
    345 </li>
    346 
    347 <li>Auto invokes the {@link android.service.media.MediaBrowserService#onLoadChildren
    348 onLoadChildren()} method to get the children of the root node, and uses this information to
    349 present a menu to the user.</li>
    350 
    351 <li>If the user selects a submenu, Auto invokes
    352 {@link android.service.media.MediaBrowserService#onLoadChildren
    353 onLoadChildren()} again to retrieve the child nodes of the selected menu item.</li>
    354 
    355 <li>If the user begins playback, Auto invokes the appropriate media session
    356 callback method to perform that action. For more information, see the section about how to
    357 <a href="#implement_callback">Implement Playback Controls</a>. </li>
    358 
    359 </ol>
    360 
    361 
    362 <h3 id="build_hierarchy">Building your content hierarchy</h3>
    363 
    364 <p>Auto devices acting as audio clients call your app's {@link
    365 android.service.media.MediaBrowserService} to find out what content you have
    366 available. You need to implement two methods in your browser service to support
    367 this: {@link android.service.media.MediaBrowserService#onGetRoot
    368 onGetRoot()} and {@link
    369 android.service.media.MediaBrowserService#onLoadChildren
    370 onLoadChildren()}.</p>
    371 
    372 <p>Each node in your content hierarchy is represented by a  {@link
    373 android.media.browse.MediaBrowser.MediaItem} object. Each of these objects is
    374 identified by a unique ID string. The client treats these ID strings as
    375 opaque tokens. When a client wants to browse to a submenu, or play a content
    376 item, it passes the ID token. Your app is responsible for associating the ID
    377 token with the appropriate menu node or content item.</p>
    378 
    379 <p class="note"><strong>Note:</strong> You should consider providing different content
    380 hierarchies depending on what client is making the query. In particular, Auto
    381 applications have strict limits on how large a menu they can display. This is
    382 intended to minimize distracting the driver, and to make it easy for the driver
    383 to operate the app via voice commands. For more information on the Auto user
    384 experience restrictions, see the <a href="{@docRoot}shareables/auto/AndroidAuto-audio-apps.pdf">
    385 Auto Audio Apps</a> guidelines.</p>
    386 
    387 <p>Your implementation of {@link android.service.media.MediaBrowserService#onGetRoot
    388 onGetRoot()} returns information about the root node of the menu
    389 hierarchy. This root node is the parent of the top items of your browse hierarchy.
    390 The method is passed information about the calling client. You can use this
    391 information to decide if the client should have access to your content at all.
    392 For example, if you want to limit your app's content to a list of approved
    393 clients, you can compare the passed {@code clientPackageName} to your whitelist
    394 and verify the certificate used to sign the caller's APK.
    395 If the caller can't be verified to be an approved package, return null to deny access to
    396 your content. For an example of an app that validates that the caller is an
    397 approved app, see the
    398 <a href="https://github.com/googlesamples/android-UniversalMusicPlayer/blob/master/mobile/src/main/java/com/example/android/uamp/PackageValidator.java"
    399 class="external-link"><code>PackageValidator</code></a> class in the
    400 <a href="https://github.com/googlesamples/android-UniversalMusicPlayer"
    401 class="external-link">Universal Android Music Player</a> sample app.
    402 </p>
    403 
    404 <p>A typical implementation of {@link
    405 android.service.media.MediaBrowserService#onGetRoot onGetRoot()} might
    406 look like this:</p>
    407 
    408 <pre>
    409 &#64;Override
    410 public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
    411     Bundle rootHints) {
    412 
    413     // Verify that the specified package is allowed to access your
    414     // content! You'll need to write your own logic to do this.
    415     if (!isValid(clientPackageName, clientUid)) {
    416         // If the request comes from an untrusted package, return null.
    417         // No further calls will be made to other media browsing methods.
    418 
    419         return null;
    420     }
    421 
    422     return new BrowserRoot(MY_MEDIA_ROOT_ID, null);
    423 }
    424 </pre>
    425 
    426 <p>
    427   The Auto device client builds the top-level menu by calling {@link
    428   android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()}
    429   with the root node object and getting its children. The client builds
    430   submenus by calling the same method with other child nodes. The following
    431   example code shows a simple implementation of {@link
    432   android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()} method:
    433 </p>
    434 
    435 <pre>
    436 &#64;Override
    437 public void onLoadChildren(final String parentMediaId,
    438     final Result&lt;List&lt;MediaItem&gt;&gt; result) {
    439 
    440     // Assume for example that the music catalog is already loaded/cached.
    441 
    442     List&lt;MediaItem&gt; mediaItems = new ArrayList&lt;&gt;();
    443 
    444     // Check if this is the root menu:
    445     if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) {
    446 
    447         // build the MediaItem objects for the top level,
    448         // and put them in the mediaItems list
    449     } else {
    450 
    451         // examine the passed parentMediaId to see which submenu we're at,
    452         // and put the children of that menu in the mediaItems list
    453     }
    454     result.sendResult(mediaItems);
    455 }
    456 </pre>
    457 
    458 <p>
    459   For examples of how to implement {@link
    460   android.service.media.MediaBrowserService#onLoadChildren onLoadChildren()},
    461   see the <a href="{@docRoot}samples/MediaBrowserService/index.html">
    462   MediaBrowserService</a> and
    463   <a href="https://github.com/googlesamples/android-UniversalMusicPlayer"
    464   class="external-link">Universal Android Music Player</a> sample apps.
    465 </p>
    466 
    467 <h2 id="implement_callback">Enable Playback Control</h2>
    468 
    469 <p>
    470   Auto devices use {@link android.media.session.MediaSession} objects to pass playback control
    471   commands to an app that is providing audio services. Your audio app must create an instance of
    472   this object to pass to the dashboard device and implement callback methods to enable remote
    473   control of audio playback.
    474 </p>
    475 
    476 <h3 id="registering_mediasession">Register a media session</h3>
    477 
    478 <p>An Auto device using your app as audio service needs to obtain a {@link
    479 android.media.session.MediaSession} object from your app. The Auto device uses the session object
    480 to send playback commands requested by the Auto user back to your app.</p>
    481 
    482 <p>When you initialize your browser service, you register that session object with your {@link
    483 android.service.media.MediaBrowserService} by calling the {@link
    484 android.service.media.MediaBrowserService#setSessionToken setSessionToken()} method. This step
    485 allows clients such as an Auto device to retrieve that object by calling your browser service's
    486 {@link android.service.media.MediaBrowserService#getSessionToken getSessionToken()} method.</p>
    487 
    488 <p>In your browser service's {@link
    489 android.service.media.MediaBrowserService#onCreate() onCreate()} method,
    490 create a {@link android.media.session.MediaSession}. You can then query
    491 the {@link android.media.session.MediaSession} to get its token, and register
    492 the token with your browser service:</p>
    493 
    494 <pre>
    495 public void onCreate() {
    496     super.onCreate();
    497 
    498     ...
    499     // Start a new MediaSession
    500     MediaSession mSession = new MediaSession(this, "session tag");
    501     setSessionToken(mSession.getSessionToken());
    502 
    503     // Set a callback object to handle play control requests, which
    504     // implements MediaSession.Callback
    505     mSession.setCallback(new MyMediaSessionCallback());
    506 
    507     ...
    508 </pre>
    509 
    510 <p>
    511   When you create the media session object, you set a callback object that is used to handle
    512   playback control requests. You create this callback object by providing an implementation of the
    513   {@link android.media.session.MediaSession.Callback} class for your app. The next section
    514   discusses how to implement this object.
    515 </p>
    516 
    517 
    518 <h3 id="playback-commands">Implement play commands</h3>
    519 
    520 <p>When an Auto device requests playback of an audio track from your app, it uses the
    521 {@link android.media.session.MediaSession.Callback} class from your app's
    522 {@link android.media.session.MediaSession} object, which it obtained from your app's
    523 media browse service. When an Auto user wants to play content or control content playback,
    524 such as pausing play or skipping to the next track, Auto invokes one
    525 of the callback object's methods.</p>
    526 
    527 <p>To handle content playback, your app must extend the abstract {@link
    528 android.media.session.MediaSession.Callback} class and implement the methods
    529 that your app supports. The most important callback methods are as follows:</p>
    530 
    531 <dl>
    532 
    533 <dt>{@link android.media.session.MediaSession.Callback#onPlay onPlay()}</dt>
    534 <dd>Invoked if the user chooses play without choosing a specific item. Your
    535 app should play its default content. If playback was paused with
    536 {@link android.media.session.MediaSession.Callback#onPause onPause()}, your
    537 app should resume playback.</dd>
    538 
    539 <p class="note">
    540   <strong>Note:</strong> Google Play requires your app not to play music immediately when it
    541   launches. For more information on this and other requirements, see
    542 <a href="{@docRoot}distribute/essentials/quality/auto.html">Auto App Quality</a>.
    543 </p>
    544 
    545 <dt>{@link android.media.session.MediaSession.Callback#onPlayFromMediaId
    546 onPlayFromMediaId()}</dt>
    547 <dd>Invoked when the user chooses to play a specific item. The method is passed
    548 the item's media ID, which you assigned to the item in the content
    549 hierarchy.</dd>
    550 
    551 <dt>{@link android.media.session.MediaSession.Callback#onPlayFromSearch
    552 onPlayFromSearch()}</dt>
    553 <dd>Invoked when the user chooses to play from a search query. The app should
    554 make an appropriate choice based on the passed search string.</dd>
    555 
    556 <dt>{@link android.media.session.MediaSession.Callback#onPause onPause()}</dt>
    557 <dd>Pause playback.</dd>
    558 
    559 <dt>{@link android.media.session.MediaSession.Callback#onSkipToNext
    560 onSkipToNext()}</dt>
    561 <dd>Skip to the next item.</dd>
    562 
    563 <dt>{@link android.media.session.MediaSession.Callback#onSkipToPrevious
    564 onSkipToPrevious()}</dt>
    565 <dd>Skip to the previous item.</dd>
    566 
    567 <dt>{@link android.media.session.MediaSession.Callback#onStop onStop()}</dt>
    568 <dd>Stop playback.</dd>
    569 
    570 </dl>
    571 
    572 <p>Your app should override these methods to provide any desired functionality.
    573 In some cases you might not implement a method if it is not supported by your app.
    574 For example, if your app plays a live stream (such as a sports
    575 broadcast), the skip to next function might not make sense. In that case, you
    576 could simply use the default implementation of
    577 {@link android.media.session.MediaSession.Callback#onSkipToNext
    578 onSkipToNext()}.</p>
    579 
    580 <p>When your app receives a request to play content, it should play audio the same way it
    581 would in a non-Auto situation (as if the user was listening through a device speaker
    582 or connected headphones). The audio content is automatically sent to the dashboard system
    583 to be played over the car's speakers.</p>
    584 
    585 <p>For more information about playing audio content, see
    586 <a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a>,
    587 <a href="{@docRoot}training/managing-audio/index.html">Managing Audio Playback</a>, and
    588 <a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>.</p>
    589 
    590 <a class="notice-developers-video wide"
    591 href="https://www.youtube.com/watch?v=xc2HZSwPcwM">
    592 <div>
    593     <h3>Video</h3>
    594     <p>Devbytes: Android Auto Voice Actions</p>
    595 </div>
    596 </a>
    597 <h2 id="support_voice">Support Voice Actions</h2>
    598 
    599 <p>To reduce driver distractions, you can add voice actions in your audio playback app. With voice
    600 action support, users can launch your app and play audio by providing voice input on Auto screens.
    601 If your audio playback app is already active and the user says
    602 <i>Play a song</i>, the system starts playing music without requiring the user to look at or touch
    603 the screen.</p>
    604 
    605 <h3 id="enable_playback">Enable your app to handle audio playback requests</h3>
    606 
    607 <p>Enable your audio app to launch with a voice command such as <i>"Play [search query] on
    608 [your app name]"</i> by adding the following entry in your manifest:</p>
    609 
    610 <pre>
    611 &lt;activity>
    612     &lt;intent-filter>
    613         &lt;action android:name=
    614              "android.media.action.MEDIA_PLAY_FROM_SEARCH" />
    615         &lt;category android:name=
    616              "android.intent.category.DEFAULT" />
    617     &lt;/intent-filter>
    618 &lt;/activity>
    619 </pre>
    620 
    621 <p>When the user says <i>Play music on [your app name]</i> on an Auto screen, Auto
    622 attempts to launch your app and play audio by calling your apps
    623 <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>MediaSession.Callback.onPlayFromSearch()</code></a>
    624 method. If the user has not specified criteria such as a track name or music genre, the
    625 <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>MediaSession.Callback.onPlayFromSearch()</code></a>
    626 method receives an empty query parameter. Your app should respond by immediately playing audio, such
    627 as a song from a random queue or the most recent playlist.
    628 </p>
    629 
    630 <h3 id="parse_voice">Parse the voice query to build the playback queue</h3>
    631 
    632 <p>When a user searches for a specific criteria, such as <i>Play jazz on [your app name]</i>
    633 or <i>Listen to [song title]</i>, the
    634 <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>onPlayFromSearch()</code></a>
    635 callback method receives the voice search results in the query parameter and an extras bundle. For
    636 more information on how to handle search queries to play audio content, see
    637 <a href="https://developer.android.com/guide/components/intents-common.html#PlaySearch">Play music
    638 based on a search query</a>.
    639 </p>
    640 
    641 <p>To parse the voice search query to play back audio content in your app, follow these steps:</p>
    642 
    643 <ol>
    644   <li>Use the extras bundle and search query string returned from the voice search to filter
    645   results.</li>
    646   <li>Build the audio content queue based on these results.</li>
    647   <li>Play the audio content.</li>
    648 </ol>
    649 
    650 <p>The
    651 <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>onPlayFromSearch()</code></a>
    652 method takes an extras parameter with more detailed information from the voice search.
    653 These extras help you find the audio content in your app for playback. If the search results are
    654 unable to provide this data, you can implement logic to parse the raw search query and play the
    655 appropriate tracks based on the query.
    656 </p>
    657 
    658 <p>The following extras are supported in Android Auto:</p>
    659 
    660 <ul>
    661   <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_ALBUM"><code>android.intent.extra.album</code></a></li>
    662   <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_ARTIST"><code>android.intent.extra.artist</code></a></li>
    663   <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_GENRE"><code>android.intent.extra.genre</code></a></li>
    664   <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_PLAYLIST"><code>android.intent.extra.playlist</code></a></li>
    665   <li><a href="{@docRoot}reference/android/provider/MediaStore.html#EXTRA_MEDIA_TITLE"><code>android.intent.extra.title</code></a></li>
    666 </ul>
    667 
    668 <p>The following snippet shows how to override the
    669 <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>onPlayFromSearch()</code></a>
    670 method in your
    671 <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html"><code>MediaSession.Callback</code></a>
    672 implementation to handle the search query and extras for playing audio content in your app:
    673 </p>
    674 
    675 <pre>
    676 &#64;Override
    677 public void onPlayFromSearch(String query, Bundle extras) {
    678     if (TextUtils.isEmpty(query)) {
    679         // The user provided generic string e.g. 'Play music'
    680         // Build appropriate playlist queue
    681     } else {
    682         // Build a queue based on songs that match "query" or "extras" param
    683         String mediaFocus = extras.getString(MediaStore.EXTRA_MEDIA_FOCUS);
    684         if (TextUtils.equals(mediaFocus,
    685                 MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE)) {
    686             isArtistFocus = true;
    687             artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST);
    688         } else if (TextUtils.equals(mediaFocus,
    689                 MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE)) {
    690             isAlbumFocus = true;
    691             album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM);
    692         }
    693 
    694         // Implement additional "extras" param filtering
    695     }
    696 
    697     // Implement your logic to retrieve the queue
    698     if (isArtistFocus) {
    699         result = searchMusicByArtist(artist);
    700     } else if (isAlbumFocus) {
    701         result = searchMusicByAlbum(album);
    702     }
    703 
    704     if (result == null) {
    705         // No focus found, search by query for song title
    706         result = searchMusicBySongTitle(query);
    707     }
    708 
    709     if (result != null && !result.isEmpty()) {
    710         // Immediately start playing from the beginning of the search results
    711         // Implement your logic to start playing music
    712         playMusic(result);
    713     } else {
    714         // Handle no queue found. Stop playing if the app
    715         // is currently playing a song
    716     }
    717 }
    718 </pre>
    719 
    720 <p class="note">
    721   <strong>Note:</strong> To minimize driver distractions, immediately initiate audio content
    722   playback in the
    723   <a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlayFromSearch(java.lang.String, android.os.Bundle)"><code>onPlayFromSearch()</code></a>
    724   method when you have generated the audio content queue based on the user's request.
    725 </p>
    726 
    727 <p>For a more detailed example on how to implement voice search to play audio content in your app,
    728 see the
    729 <a href="//github.com/googlesamples/android-UniversalMusicPlayer/">Universal Media Player</a>
    730 sample.
    731 </p>
    732 
    733 <h3 id="implement_playback_controls">Implement playback control actions</h3>
    734 
    735 <p>To provide a hands-free experience while users drive and listen to audio content in Android Auto,
    736 your app should allow users to control audio content playback with voice actions. When users speak
    737 commands such as <i>Next song</i>, <i>Pause music</i>, or <i>Resume music</i>, the system
    738 triggers the corresponding callback method where you implement the playback control action.
    739 </p>
    740 
    741 <p>To provide voice-enabled playback controls, first enable the hardware controls by setting these
    742 flags in your apps
    743 <a href="{@docRoot}reference/android/media/session/MediaSession.html"><code>MediaSession</code></a>
    744 object:
    745 </p>
    746 
    747 <pre>
    748 mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
    749     MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
    750 </pre>
    751 
    752 <p>Then, implement the callback methods with the playback controls that you support in your app.
    753 Heres a list of voice-enabled playback controls supported by Android Auto:
    754 </p>
    755 
    756 <table>
    757   <tr>
    758     <th>Example phrase</th>
    759     <th>Callback method</th>
    760   </tr>
    761   <tr>
    762     <td><i>"Next song"</i></td>
    763     <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onSkipToNext()"><code>onSkipToNext()</code></a></td>
    764   </tr>
    765   <tr>
    766     <td><i>"Previous song"</i></td>
    767     <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onSkipToPrevious()"><code>onSkipToPrevious()</code></a></td>
    768   </tr>
    769   <tr>
    770     <td><i>"Pause music"</i></td>
    771     <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPause()"><code>onPause()</code></a></td>
    772   </tr>
    773   <tr>
    774     <td><i>"Stop music"</i></td>
    775     <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onStop()"><code>onStop()</code></a></td>
    776   </tr>
    777   <tr>
    778     <td><i>"Resume music"</i></td>
    779     <td><a href="{@docRoot}reference/android/media/session/MediaSession.Callback.html#onPlay()"><code>onPlay()</code></a></td>
    780   </tr>
    781 </table>
    782 
    783 <p>For a more detailed example on how to implement voice-enabled playback actions in your app, see
    784 the
    785 <a href="//github.com/googlesamples/android-UniversalMusicPlayer/">Universal Media Player</a>
    786 sample.
    787 </p>
    788