1 page.title=Displaying a Now Playing Card 2 page.tags=tv, mediasession 3 helpoutsWidget=true 4 5 trainingnavtop=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 23 background. 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 26 screen when there is an active {@link android.media.session.MediaSession}. 27 The card includes media metadata such as album art, title, and app icon. 28 When 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 31 the <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 35 media 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} 41 when your app is preparing to play media. The following code snippet 42 is an example of how to set the appropriate callback and flags:</p> 43 44 <pre> 45 mSession = new MediaSession(this, "MusicService"); 46 mSession.setCallback(new MediaSessionCallback()); 47 mSession.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 52 only for a media session with 53 the {@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)} 59 when 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> 63 private 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)} 75 call deactivates the media session, 76 or when another app initiates media playback. 77 If playback is completely stopped and there is no active media, 78 your app should deactivate the media session immediately. 79 If playback is paused, your app should deactivate the media session 80 after 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} 85 so the card can show the state of the current media.</p> 86 87 <pre> 88 private 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 99 private 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()} 125 method. This method of the media session object lets you provide information to 126 the <em>Now Playing</em> card about the track such as the title, subtitle, 127 and various icons. The following example assumes your 128 track's data is stored in a custom data class, {@code MediaData}.</p> 129 130 <pre> 131 private 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 157 opens the app that owns the session. 158 If your app provides a {@link android.app.PendingIntent} to 159 {@link android.media.session.MediaSession#setSessionActivity(android.app.PendingIntent) setSessionActivity()}, 160 the system launches the activity you specify, as demonstrated below. If not, the default system 161 intent opens. The activity you specify must provide playback controls that allow users to pause or 162 stop playback.</p> 163 164 <pre> 165 Intent 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