docs: Displaying a Now Playing Card
Change-Id: I68cd305618caff24cf2de564d7b085c663702d0c
This commit is contained in:
@@ -892,6 +892,10 @@ include the action bar on devices running Android 2.1 or higher."
|
||||
<a href="<?cs var:toroot ?>training/tv/playback/details.html">
|
||||
Building a Details View</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<?cs var:toroot ?>training/tv/playback/now-playing.html">
|
||||
Displaying a Now Playing Card</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -46,4 +46,7 @@ startpage=true
|
||||
|
||||
<dt><b><a href="details.html">Building a Details View</a></b></dt>
|
||||
<dd>Learn how to use the Leanback support library to build a details page for media items.</dd>
|
||||
|
||||
<dt><b><a href="now-playing.html">Displaying a Now Playing Card</a></b></dt>
|
||||
<dd>Learn how to use a MediaSession to display a Now Playing card on the home screen.</dd>
|
||||
</dl>
|
||||
|
||||
167
docs/html/training/tv/playback/now-playing.jd
Normal file
167
docs/html/training/tv/playback/now-playing.jd
Normal file
@@ -0,0 +1,167 @@
|
||||
page.title=Displaying a Now Playing Card
|
||||
page.tags="nowplaying","mediasession"
|
||||
|
||||
trainingnavtop=true
|
||||
|
||||
@jd:body
|
||||
|
||||
<div id="tb-wrapper">
|
||||
<div id="tb">
|
||||
<h2>This lesson teaches you to</h2>
|
||||
<ol>
|
||||
<li><a href="#session">Start a Media Session</a></li>
|
||||
<li><a href="#card">Display a Now Playing Card</a></li>
|
||||
<li><a href="#state">Update the Playback State</a></li>
|
||||
<li><a href="#respond">Respond to User Action</a></li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>TV apps may allow users to play music or other media in the background while using other
|
||||
applications. If your app allows this type of use, it must must
|
||||
provide a means for the user to return to the app to pause the music or switch to a new song. The
|
||||
Android framework enables TV apps to do this by displaying a <em>Now Playing</em> card on the home
|
||||
screen in the recommendations row.</p>
|
||||
|
||||
<p>The Now Playing card is a system artifact that displays on the
|
||||
home screen in the recommendations row for an active media session. It includes the media metadata
|
||||
such as the album art, title, and app icon. When the user selects it, the system opens the the app
|
||||
that owns the session.</p>
|
||||
|
||||
<p>This lesson shows how to use the {@link android.media.session.MediaSession} class to implement
|
||||
the Now Playing card.</p>
|
||||
|
||||
<h2 id="session">Start a Media Session</h2>
|
||||
|
||||
<p>A playback app can run as an <a href="{@docRoot}guide/components/activities">activity</a> or
|
||||
as a <a href="{@docRoot}guide/components/services">service</a>. The service is required for
|
||||
background playback because it can continue to play media even after the activity that launched it
|
||||
has been destroyed. For this discussion, the media playback app is assumed to be running in a
|
||||
{@link android.service.media.MediaBrowserService}.</p>
|
||||
|
||||
<p>In your service's {@link android.service.media.MediaBrowserService#onCreate() onCreate()}
|
||||
method, create a new {@link android.media.session.MediaSession#MediaSession(android.content.Context, java.lang.String) MediaSession},
|
||||
set the callback and flags appropriate to a media app, and set the session token for the
|
||||
{@link android.service.media.MediaBrowserService}.</p>
|
||||
|
||||
<pre>
|
||||
mSession = new MediaSession(this, "MusicService");
|
||||
mSession.setCallback(new MediaSessionCallback());
|
||||
mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
|
||||
MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
||||
|
||||
// for the MediaBrowserService
|
||||
setSessionToken(mSession.getSessionToken());
|
||||
</pre>
|
||||
|
||||
<p class="note"<strong>Note:</strong> The Now Playing card will display only for a media session with
|
||||
the {@link android.media.session.MediaSession#FLAG_HANDLES_TRANSPORT_CONTROLS} flag set.</p>
|
||||
|
||||
<h2 id="card">Display a Now Playing Card</h2>
|
||||
|
||||
<p>The Now Playing card shows up after {@link android.media.session.MediaSession#setActive(boolean) setActive(true)}
|
||||
is called, if the session is the highest priority session in the system. Also, note that your app
|
||||
must request the audio focus, as described in <a href="{@docRoot}training/managing-audio/audio-focus">
|
||||
Managing Audio Focus</a>.</p>
|
||||
|
||||
<pre>
|
||||
private void handlePlayRequest() {
|
||||
|
||||
tryToGetAudioFocus();
|
||||
|
||||
if (!mSession.isActive()) {
|
||||
mSession.setActive(true);
|
||||
}
|
||||
...
|
||||
</pre>
|
||||
|
||||
<p>The card is removed from the home screen when {@link android.media.session.MediaSession#setActive(boolean) setActive(false)}
|
||||
is called or if another app initiates media playback. You may want to remove the card from the home
|
||||
screen some time after playback is paused, depending on how long you want to keep the card up,
|
||||
usually 5 to 30 minutes.</p>
|
||||
|
||||
<h2 id="state">Update the Playback State</h2>
|
||||
|
||||
<p>As with any media app, update the playback state in the {@link android.media.session.MediaSession}
|
||||
so that the card can display the current metadata, as shown in the following example:</p>
|
||||
|
||||
<pre>
|
||||
private void updatePlaybackState() {
|
||||
long position = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
|
||||
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
|
||||
position = mMediaPlayer.getCurrentPosition();
|
||||
}
|
||||
PlaybackState.Builder stateBuilder = new PlaybackState.Builder()
|
||||
.setActions(getAvailableActions());
|
||||
stateBuilder.setState(mState, position, 1.0f);
|
||||
mSession.setPlaybackState(stateBuilder.build());
|
||||
}
|
||||
private long getAvailableActions() {
|
||||
long actions = PlaybackState.ACTION_PLAY |
|
||||
PlaybackState.ACTION_PLAY_FROM_MEDIA_ID |
|
||||
PlaybackState.ACTION_PLAY_FROM_SEARCH;
|
||||
if (mPlayingQueue == null || mPlayingQueue.isEmpty()) {
|
||||
return actions;
|
||||
}
|
||||
if (mState == PlaybackState.STATE_PLAYING) {
|
||||
actions |= PlaybackState.ACTION_PAUSE;
|
||||
}
|
||||
if (mCurrentIndexOnQueue > 0) {
|
||||
actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS;
|
||||
}
|
||||
if (mCurrentIndexOnQueue < mPlayingQueue.size() - 1) {
|
||||
actions |= PlaybackState.ACTION_SKIP_TO_NEXT;
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2 id="metadata">Display the Media Metadata</h2>
|
||||
|
||||
<p>For the track currently playing, set the {@link android.media.MediaMetadata} with the
|
||||
{@link android.media.session.MediaSession#setMetadata(android.media.MediaMetadata) setMetadata()}
|
||||
method. This method of the media session object lets you provide information to the Now Playing card
|
||||
about the track such as the title, subtitle, and various icons. The following example assumes your
|
||||
track's data is stored in a custom data class, {@code MediaData}.</p>
|
||||
|
||||
<pre>
|
||||
private void updateMetadata(MediaData myData) {
|
||||
MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder();
|
||||
// To provide most control over how an item is displayed set the
|
||||
// display fields in the metadata
|
||||
metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE,
|
||||
myData.displayTitle);
|
||||
metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE,
|
||||
myData.displaySubtitle);
|
||||
metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI,
|
||||
myData.artUri);
|
||||
// And at minimum the title and artist for legacy support
|
||||
metadataBuilder.putString(MediaMetadata.METADATA_KEY_TITLE,
|
||||
myData.title);
|
||||
metadataBuilder.putString(MediaMetadata.METADATA_KEY_ARTIST,
|
||||
myData.artist);
|
||||
// A small bitmap for the artwork is also recommended
|
||||
metadataBuilder.putString(MediaMetadata.METADATA_KEY_ART,
|
||||
myData.artBitmap);
|
||||
// Add any other fields you have for your data as well
|
||||
mSession.setMetadata(metadataBuilder.build());
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2 id="respond">Respond to User Action</h2>
|
||||
|
||||
<p>When the user selects the Now Playing card, the system opens the app that owns the session.
|
||||
If your app provides a {@link android.app.PendingIntent} to pass to
|
||||
{@link android.media.session.MediaSession#setSessionActivity(android.app.PendingIntent) setSessionActivity()},
|
||||
the system launches the activity you specify, as demonstrated below. If not, the default system
|
||||
intent opens. The activity you specify must provide playback controls that allow users to pause or
|
||||
stop playback.</p>
|
||||
|
||||
<pre>
|
||||
Intent intent = new Intent(mContext, MyActivity.class);
|
||||
PendingIntent pi = PendingIntent.getActivity(context, 99 /*request code*/,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
mSession.setSessionActivity(pi);
|
||||
</pre>
|
||||
|
||||
Reference in New Issue
Block a user