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 && 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 > 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()} 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