diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index ad9eb3a7212fe..8b233a39c3593 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -892,6 +892,10 @@ include the action bar on devices running Android 2.1 or higher." Building a Details View +
  • + + Displaying a Now Playing Card +
  • diff --git a/docs/html/training/tv/playback/index.jd b/docs/html/training/tv/playback/index.jd index d7167e7e8aab0..118fc6c5600d2 100644 --- a/docs/html/training/tv/playback/index.jd +++ b/docs/html/training/tv/playback/index.jd @@ -46,4 +46,7 @@ startpage=true
    Building a Details View
    Learn how to use the Leanback support library to build a details page for media items.
    + +
    Displaying a Now Playing Card
    +
    Learn how to use a MediaSession to display a Now Playing card on the home screen.
    diff --git a/docs/html/training/tv/playback/now-playing.jd b/docs/html/training/tv/playback/now-playing.jd new file mode 100644 index 0000000000000..b64beb0882720 --- /dev/null +++ b/docs/html/training/tv/playback/now-playing.jd @@ -0,0 +1,167 @@ +page.title=Displaying a Now Playing Card +page.tags="nowplaying","mediasession" + +trainingnavtop=true + +@jd:body + +
    +
    +

    This lesson teaches you to

    +
      +
    1. Start a Media Session
    2. +
    3. Display a Now Playing Card
    4. +
    5. Update the Playback State
    6. +
    7. Respond to User Action
    8. +
    + +
    +
    + +

    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 Now Playing card on the home +screen in the recommendations row.

    + +

    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.

    + +

    This lesson shows how to use the {@link android.media.session.MediaSession} class to implement +the Now Playing card.

    + +

    Start a Media Session

    + +

    A playback app can run as an activity or +as a service. 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}.

    + +

    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}.

    + +
    +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());
    +
    + +

    Note: The Now Playing card will display only for a media session with +the {@link android.media.session.MediaSession#FLAG_HANDLES_TRANSPORT_CONTROLS} flag set.

    + +

    Display a Now Playing Card

    + +

    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 +Managing Audio Focus.

    + +
    +private void handlePlayRequest() {
    +
    +    tryToGetAudioFocus();
    +
    +    if (!mSession.isActive()) {
    +        mSession.setActive(true);
    +    }
    +...
    +
    + +

    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.

    + +

    Update the Playback State

    + +

    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:

    + +
    +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;
    +}
    +
    + +

    Display the Media Metadata

    + +

    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}.

    + +
    +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());
    +}
    +
    + +

    Respond to User Action

    + +

    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.

    + +
    +Intent intent = new Intent(mContext, MyActivity.class);
    +    PendingIntent pi = PendingIntent.getActivity(context, 99 /*request code*/,
    +            intent, PendingIntent.FLAG_UPDATE_CURRENT);
    +    mSession.setSessionActivity(pi);
    +
    +