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