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