This undoes the automerger skip which occured in
commit e740c84dc3 and
replays it as a standard (NOT -s ours) merge.
Change-Id: If5a47be26f73d6a0735c425cd66310a3e2a89086
171 lines
6.5 KiB
Plaintext
171 lines
6.5 KiB
Plaintext
page.title=Displaying a Now Playing Card
|
|
page.tags=tv, mediasession
|
|
helpoutsWidget=true
|
|
|
|
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 must display a <em>Now Playing</em> card when playing media behind the launcher or in the
|
|
background. This card allows users to return to the app that is currently playing media.</p>
|
|
|
|
<p>The Android framework displays a <em>Now Playing</em> card on the home
|
|
screen when there is an active {@link android.media.session.MediaSession}.
|
|
The card includes media metadata such as album art, title, and app icon.
|
|
When the user selects the card, the system opens the app.</p>
|
|
|
|
<p>This lesson shows how to use the {@link android.media.session.MediaSession} class to implement
|
|
the <em>Now Playing</em> card.</p>
|
|
|
|
<img src="{@docRoot}images/training/tv/playback/now-playing-screen.png" />
|
|
<p class="img-caption"><strong>Figure 1.</strong> Display a <em>Now Playing</em> card when playing
|
|
media in the background.</p>
|
|
|
|
<h2 id="session">Start a Media Session</h2>
|
|
|
|
<p>Create a
|
|
{@link android.media.session.MediaSession#MediaSession(android.content.Context, java.lang.String) MediaSession}
|
|
when your app is preparing to play media. The following code snippet
|
|
is an example of how to set the appropriate callback and flags:</p>
|
|
|
|
<pre>
|
|
mSession = new MediaSession(this, "MusicService");
|
|
mSession.setCallback(new MediaSessionCallback());
|
|
mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
|
|
MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
|
</pre>
|
|
|
|
<p class="note"<strong>Note:</strong> The <em>Now Playing</em> 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 <em>Now Playing</em> card only appears for active sessions. You must call
|
|
{@link android.media.session.MediaSession#setActive(boolean) setActive(true)}
|
|
when playback begins. Your app must also request audio focus, as described in
|
|
<a href="{@docRoot}training/managing-audio/audio-focus.html">Managing Audio Focus</a>.</p>
|
|
|
|
<pre>
|
|
private void handlePlayRequest() {
|
|
|
|
tryToGetAudioFocus();
|
|
|
|
if (!mSession.isActive()) {
|
|
mSession.setActive(true);
|
|
}
|
|
...
|
|
</pre>
|
|
|
|
<p>The card is removed from the launcher screen when a
|
|
{@link android.media.session.MediaSession#setActive(boolean) setActive(false)}
|
|
call deactivates the media session,
|
|
or when another app initiates media playback.
|
|
If playback is completely stopped and there is no active media,
|
|
your app should deactivate the media session immediately.
|
|
If playback is paused, your app should deactivate the media session
|
|
after a delay, usually between 5 to 30 minutes.</p>
|
|
|
|
<h2 id="state">Update the Playback State</h2>
|
|
|
|
<p>Update the playback state in the {@link android.media.session.MediaSession}
|
|
so the card can show the state of the current media.</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_PAUSE |
|
|
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;
|
|
} else {
|
|
actions |= PlaybackState.ACTION_PLAY;
|
|
}
|
|
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>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 <em>Now Playing</em> 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.putBitmap(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 <em>Now Playing</em> card, the system
|
|
opens the app that owns the session.
|
|
If your app provides a {@link android.app.PendingIntent} 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>
|
|
|