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