• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &amp;&amp; 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 &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>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