1page.title=Displaying a Now Playing Card 2page.tags="nowplaying","mediasession" 3 4trainingnavtop=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 22applications. If your app allows this type of use, it must must 23provide a means for the user to return to the app to pause the music or switch to a new song. The 24Android framework enables TV apps to do this by displaying a <em>Now Playing</em> card on the home 25screen in the recommendations row.</p> 26 27<p>The Now Playing card is a system artifact that displays on the 28home screen in the recommendations row for an active media session. It includes the media metadata 29such as the album art, title, and app icon. When the user selects it, the system opens the the app 30that owns the session.</p> 31 32<p>This lesson shows how to use the {@link android.media.session.MediaSession} class to implement 33the 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 38as a <a href="{@docRoot}guide/components/services">service</a>. The service is required for 39background playback because it can continue to play media even after the activity that launched it 40has 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()} 44method, create a new {@link android.media.session.MediaSession#MediaSession(android.content.Context, java.lang.String) MediaSession}, 45set 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> 49mSession = new MediaSession(this, "MusicService"); 50mSession.setCallback(new MediaSessionCallback()); 51mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | 52 MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS); 53 54// for the MediaBrowserService 55setSessionToken(mSession.getSessionToken()); 56</pre> 57 58<p class="note"<strong>Note:</strong> The Now Playing card will display only for a media session with 59the {@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)} 64is called, if the session is the highest priority session in the system. Also, note that your app 65must request the audio focus, as described in <a href="{@docRoot}training/managing-audio/audio-focus"> 66Managing Audio Focus</a>.</p> 67 68<pre> 69private 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)} 80is called or if another app initiates media playback. You may want to remove the card from the home 81screen some time after playback is paused, depending on how long you want to keep the card up, 82usually 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} 87so that the card can display the current metadata, as shown in the following example:</p> 88 89<pre> 90private void updatePlaybackState() { 91 long position = PlaybackState.PLAYBACK_POSITION_UNKNOWN; 92 if (mMediaPlayer != null && 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} 100private 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 > 0) { 111 actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS; 112 } 113 if (mCurrentIndexOnQueue < 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()} 124method. This method of the media session object lets you provide information to the Now Playing card 125about the track such as the title, subtitle, and various icons. The following example assumes your 126track's data is stored in a custom data class, {@code MediaData}.</p> 127 128<pre> 129private 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. 155If your app provides a {@link android.app.PendingIntent} to pass to 156{@link android.media.session.MediaSession#setSessionActivity(android.app.PendingIntent) setSessionActivity()}, 157the system launches the activity you specify, as demonstrated below. If not, the default system 158intent opens. The activity you specify must provide playback controls that allow users to pause or 159stop playback.</p> 160 161<pre> 162Intent 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