Home | History | Annotate | Download | only in playback
      1 page.title=Displaying a Now Playing Card
      2 page.tags="nowplaying","mediasession"
      3 
      4 trainingnavtop=true
      5 
      6 @jd:body
      7 
      8 <div id="tb-wrapper">
      9 <div id="tb">
     10   <h2>This lesson teaches you to</h2>
     11   <ol>
     12     <li><a href="#session">Start a Media Session</a></li>
     13     <li><a href="#card">Display a Now Playing Card</a></li>
     14     <li><a href="#state">Update the Playback State</a></li>
     15     <li><a href="#respond">Respond to User Action</a></li>
     16   </ol>
     17 
     18 </div>
     19 </div>
     20 
     21 <p>TV apps may allow users to play music or other media in the background while using other
     22 applications. If your app allows this type of use, it must must
     23 provide a means for the user to return to the app to pause the music or switch to a new song. The
     24 Android framework enables TV apps to do this by displaying a <em>Now Playing</em> card on the home
     25 screen in the recommendations row.</p>
     26 
     27 <p>The Now Playing card is a system artifact that displays on the
     28 home screen in the recommendations row for an active media session. It includes the media metadata
     29 such as the album art, title, and app icon. When the user selects it, the system opens the the app
     30 that owns the session.</p>
     31 
     32 <p>This lesson shows how to use the {@link android.media.session.MediaSession} class to implement
     33 the Now Playing card.</p>
     34 
     35 <h2 id="session">Start a Media Session</h2>
     36 
     37 <p>A playback app can run as an <a href="{@docRoot}guide/components/activities">activity</a> or
     38 as a <a href="{@docRoot}guide/components/services">service</a>. The service is required for
     39 background playback because it can continue to play media even after the activity that launched it
     40 has been destroyed. For this discussion, the media playback app is assumed to be running in a
     41 {@link android.service.media.MediaBrowserService}.</p>
     42 
     43 <p>In your service's {@link android.service.media.MediaBrowserService#onCreate() onCreate()}
     44 method, create a new {@link android.media.session.MediaSession#MediaSession(android.content.Context, java.lang.String) MediaSession},
     45 set the callback and flags appropriate to a media app, and set the session token for the
     46 {@link android.service.media.MediaBrowserService}.</p>
     47 
     48 <pre>
     49 mSession = new MediaSession(this, "MusicService");
     50 mSession.setCallback(new MediaSessionCallback());
     51 mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
     52         MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
     53 
     54 // for the MediaBrowserService
     55 setSessionToken(mSession.getSessionToken());
     56 </pre>
     57 
     58 <p class="note"<strong>Note:</strong> The Now Playing card will display only for a media session with
     59 the {@link android.media.session.MediaSession#FLAG_HANDLES_TRANSPORT_CONTROLS} flag set.</p>
     60 
     61 <h2 id="card">Display a Now Playing Card</h2>
     62 
     63 <p>The Now Playing card shows up after {@link android.media.session.MediaSession#setActive(boolean) setActive(true)}
     64 is called, if the session is the highest priority session in the system. Also, note that your app
     65 must request the audio focus, as described in <a href="{@docRoot}training/managing-audio/audio-focus">
     66 Managing Audio Focus</a>.</p>
     67 
     68 <pre>
     69 private void handlePlayRequest() {
     70 
     71     tryToGetAudioFocus();
     72 
     73     if (!mSession.isActive()) {
     74         mSession.setActive(true);
     75     }
     76 ...
     77 </pre>
     78 
     79 <p>The card is removed from the home screen when {@link android.media.session.MediaSession#setActive(boolean) setActive(false)}
     80 is called or if another app initiates media playback. You may want to remove the card from the home
     81 screen some time after playback is paused, depending on how long you want to keep the card up,
     82 usually 5 to 30 minutes.</p>
     83 
     84 <h2 id="state">Update the Playback State</h2>
     85 
     86 <p>As with any media app, update the playback state in the {@link android.media.session.MediaSession}
     87 so that the card can display the current metadata, as shown in the following example:</p>
     88 
     89 <pre>
     90 private void updatePlaybackState() {
     91     long position = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
     92     if (mMediaPlayer != null &amp;&amp; mMediaPlayer.isPlaying()) {
     93         position = mMediaPlayer.getCurrentPosition();
     94     }
     95     PlaybackState.Builder stateBuilder = new PlaybackState.Builder()
     96             .setActions(getAvailableActions());
     97     stateBuilder.setState(mState, position, 1.0f);
     98     mSession.setPlaybackState(stateBuilder.build());
     99 }
    100 private long getAvailableActions() {
    101     long actions = PlaybackState.ACTION_PLAY |
    102             PlaybackState.ACTION_PLAY_FROM_MEDIA_ID |
    103             PlaybackState.ACTION_PLAY_FROM_SEARCH;
    104     if (mPlayingQueue == null || mPlayingQueue.isEmpty()) {
    105         return actions;
    106     }
    107     if (mState == PlaybackState.STATE_PLAYING) {
    108         actions |= PlaybackState.ACTION_PAUSE;
    109     }
    110     if (mCurrentIndexOnQueue &gt; 0) {
    111         actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS;
    112     }
    113     if (mCurrentIndexOnQueue &lt; mPlayingQueue.size() - 1) {
    114         actions |= PlaybackState.ACTION_SKIP_TO_NEXT;
    115     }
    116     return actions;
    117 }
    118 </pre>
    119 
    120 <h2 id="metadata">Display the Media Metadata</h2>
    121 
    122 <p>For the track currently playing, set the {@link android.media.MediaMetadata} with the
    123 {@link android.media.session.MediaSession#setMetadata(android.media.MediaMetadata) setMetadata()}
    124 method. This method of the media session object lets you provide information to the Now Playing card
    125 about the track such as the title, subtitle, and various icons. The following example assumes your
    126 track's data is stored in a custom data class, {@code MediaData}.</p>
    127 
    128 <pre>
    129 private void updateMetadata(MediaData myData) {
    130     MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder();
    131     // To provide most control over how an item is displayed set the
    132     // display fields in the metadata
    133     metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE,
    134             myData.displayTitle);
    135     metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE,
    136             myData.displaySubtitle);
    137     metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI,
    138             myData.artUri);
    139     // And at minimum the title and artist for legacy support
    140     metadataBuilder.putString(MediaMetadata.METADATA_KEY_TITLE,
    141             myData.title);
    142     metadataBuilder.putString(MediaMetadata.METADATA_KEY_ARTIST,
    143             myData.artist);
    144     // A small bitmap for the artwork is also recommended
    145     metadataBuilder.putString(MediaMetadata.METADATA_KEY_ART,
    146             myData.artBitmap);
    147     // Add any other fields you have for your data as well
    148     mSession.setMetadata(metadataBuilder.build());
    149 }
    150 </pre>
    151 
    152 <h2 id="respond">Respond to User Action</h2>
    153 
    154 <p>When the user selects the Now Playing card, the system opens the app that owns the session.
    155 If your app provides a {@link android.app.PendingIntent} to pass to
    156 {@link android.media.session.MediaSession#setSessionActivity(android.app.PendingIntent) setSessionActivity()},
    157 the system launches the activity you specify, as demonstrated below. If not, the default system
    158 intent opens. The activity you specify must provide playback controls that allow users to pause or
    159 stop playback.</p>
    160 
    161 <pre>
    162 Intent intent = new Intent(mContext, MyActivity.class);
    163     PendingIntent pi = PendingIntent.getActivity(context, 99 /*request code*/,
    164             intent, PendingIntent.FLAG_UPDATE_CURRENT);
    165     mSession.setSessionActivity(pi);
    166 </pre>
    167 
    168