/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import static android.media.MediaPlayerBase.BUFFERING_STATE_UNKNOWN;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayerBase.BuffState;
import android.media.MediaPlayerBase.PlayerState;
import android.media.MediaPlaylistAgent.RepeatMode;
import android.media.MediaPlaylistAgent.ShuffleMode;
import android.media.update.ApiLoader;
import android.media.update.MediaSession2Provider;
import android.media.update.MediaSession2Provider.BuilderBaseProvider;
import android.media.update.MediaSession2Provider.CommandButtonProvider;
import android.media.update.MediaSession2Provider.ControllerInfoProvider;
import android.media.update.ProviderCreator;
import android.net.Uri;
import android.os.Bundle;
import android.os.IInterface;
import android.os.ResultReceiver;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.concurrent.Executor;

See Also:
@hide Allows a media app to expose its transport controls and playback information in a process to other processes including the Android framework and other apps. Common use cases are as follows.
  • Bluetooth/wired headset key events support
  • Android Auto/Wearable support
  • Separating UI process and playback process

A MediaSession2 should be created when an app wants to publish media playback information or handle media keys. In general an app only needs one session for all playback, though multiple sessions can be created to provide finer grain controls of media.

If you want to support background playback, MediaSessionService2 is preferred instead. With it, your playback can be revived even after playback is finished. See MediaSessionService2 for details.

A session can be obtained by Builder. The owner of the session may pass its session token to other processes to allow them to create a MediaController2 to interact with the session.

When a session receive transport control commands, the session sends the commands directly to the the underlying media player set by Builder or updatePlayer.

When an app is finished performing playback it must call close() to clean up the session and notify any controllers.

MediaSession2 objects should be used on the thread on the looper.

/** * @hide * Allows a media app to expose its transport controls and playback information in a process to * other processes including the Android framework and other apps. Common use cases are as follows. * <ul> * <li>Bluetooth/wired headset key events support</li> * <li>Android Auto/Wearable support</li> * <li>Separating UI process and playback process</li> * </ul> * <p> * A MediaSession2 should be created when an app wants to publish media playback information or * handle media keys. In general an app only needs one session for all playback, though multiple * sessions can be created to provide finer grain controls of media. * <p> * If you want to support background playback, {@link MediaSessionService2} is preferred * instead. With it, your playback can be revived even after playback is finished. See * {@link MediaSessionService2} for details. * <p> * A session can be obtained by {@link Builder}. The owner of the session may pass its session token * to other processes to allow them to create a {@link MediaController2} to interact with the * session. * <p> * When a session receive transport control commands, the session sends the commands directly to * the the underlying media player set by {@link Builder} or * {@link #updatePlayer}. * <p> * When an app is finished performing playback it must call {@link #close()} to clean up the session * and notify any controllers. * <p> * {@link MediaSession2} objects should be used on the thread on the looper. * * @see MediaSessionService2 */
public class MediaSession2 implements AutoCloseable { private final MediaSession2Provider mProvider;
@hide
/** * @hide */
@IntDef({ERROR_CODE_UNKNOWN_ERROR, ERROR_CODE_APP_ERROR, ERROR_CODE_NOT_SUPPORTED, ERROR_CODE_AUTHENTICATION_EXPIRED, ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED, ERROR_CODE_CONCURRENT_STREAM_LIMIT, ERROR_CODE_PARENTAL_CONTROL_RESTRICTED, ERROR_CODE_NOT_AVAILABLE_IN_REGION, ERROR_CODE_CONTENT_ALREADY_PLAYING, ERROR_CODE_SKIP_LIMIT_REACHED, ERROR_CODE_ACTION_ABORTED, ERROR_CODE_END_OF_QUEUE, ERROR_CODE_SETUP_REQUIRED}) @Retention(RetentionPolicy.SOURCE) public @interface ErrorCode {}
This is the default error code and indicates that none of the other error codes applies.
/** * This is the default error code and indicates that none of the other error codes applies. */
public static final int ERROR_CODE_UNKNOWN_ERROR = 0;
Error code when the application state is invalid to fulfill the request.
/** * Error code when the application state is invalid to fulfill the request. */
public static final int ERROR_CODE_APP_ERROR = 1;
Error code when the request is not supported by the application.
/** * Error code when the request is not supported by the application. */
public static final int ERROR_CODE_NOT_SUPPORTED = 2;
Error code when the request cannot be performed because authentication has expired.
/** * Error code when the request cannot be performed because authentication has expired. */
public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3;
Error code when a premium account is required for the request to succeed.
/** * Error code when a premium account is required for the request to succeed. */
public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4;
Error code when too many concurrent streams are detected.
/** * Error code when too many concurrent streams are detected. */
public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5;
Error code when the content is blocked due to parental controls.
/** * Error code when the content is blocked due to parental controls. */
public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6;
Error code when the content is blocked due to being regionally unavailable.
/** * Error code when the content is blocked due to being regionally unavailable. */
public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7;
Error code when the requested content is already playing.
/** * Error code when the requested content is already playing. */
public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8;
Error code when the application cannot skip any more songs because skip limit is reached.
/** * Error code when the application cannot skip any more songs because skip limit is reached. */
public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9;
Error code when the action is interrupted due to some external event.
/** * Error code when the action is interrupted due to some external event. */
public static final int ERROR_CODE_ACTION_ABORTED = 10;
Error code when the playback navigation (previous, next) is not possible because the queue was exhausted.
/** * Error code when the playback navigation (previous, next) is not possible because the queue * was exhausted. */
public static final int ERROR_CODE_END_OF_QUEUE = 11;
Error code when the session needs user's manual intervention.
/** * Error code when the session needs user's manual intervention. */
public static final int ERROR_CODE_SETUP_REQUIRED = 12;
Interface definition of a callback to be invoked when a MediaItem2 in the playlist didn't have a DataSourceDesc but it's needed now for preparing or playing it. #see #setOnDataSourceMissingHelper
/** * Interface definition of a callback to be invoked when a {@link MediaItem2} in the playlist * didn't have a {@link DataSourceDesc} but it's needed now for preparing or playing it. * * #see #setOnDataSourceMissingHelper */
public interface OnDataSourceMissingHelper {
Called when a MediaItem2 in the playlist didn't have a DataSourceDesc but it's needed now for preparing or playing it. Returned data source descriptor will be sent to the player directly to prepare or play the contents.

An exception may be thrown if the returned DataSourceDesc is duplicated in the playlist, so items cannot be differentiated.

Params:
  • session – the session for this event
  • item – media item from the controller
Returns:a data source descriptor if the media item. Can be null if the content isn't available.
/** * Called when a {@link MediaItem2} in the playlist didn't have a {@link DataSourceDesc} * but it's needed now for preparing or playing it. Returned data source descriptor will be * sent to the player directly to prepare or play the contents. * <p> * An exception may be thrown if the returned {@link DataSourceDesc} is duplicated in the * playlist, so items cannot be differentiated. * * @param session the session for this event * @param item media item from the controller * @return a data source descriptor if the media item. Can be {@code null} if the content * isn't available. */
@Nullable DataSourceDesc onDataSourceMissing(@NonNull MediaSession2 session, @NonNull MediaItem2 item); }
Callback to be called for all incoming commands from MediaController2s.

If it's not set, the session will accept all controllers and all incoming commands by default.

/** * Callback to be called for all incoming commands from {@link MediaController2}s. * <p> * If it's not set, the session will accept all controllers and all incoming commands by * default. */
// TODO(jaewan): Move this to updatable for default implementation (b/74091963) public static abstract class SessionCallback {
Called when a controller is created for this session. Return allowed commands for controller. By default it allows all connection requests and commands.

You can reject the connection by return null. In that case, controller receives ControllerCallback.onDisconnected(MediaController2) and cannot be usable.

Params:
  • session – the session for this event
  • controller – controller information.
Returns:allowed commands. Can be null to reject connection.
/** * Called when a controller is created for this session. Return allowed commands for * controller. By default it allows all connection requests and commands. * <p> * You can reject the connection by return {@code null}. In that case, controller receives * {@link MediaController2.ControllerCallback#onDisconnected(MediaController2)} and cannot * be usable. * * @param session the session for this event * @param controller controller information. * @return allowed commands. Can be {@code null} to reject connection. */
public @Nullable SessionCommandGroup2 onConnect(@NonNull MediaSession2 session, @NonNull ControllerInfo controller) { SessionCommandGroup2 commands = new SessionCommandGroup2(); commands.addAllPredefinedCommands(); return commands; }
Called when a controller is disconnected
Params:
  • session – the session for this event
  • controller – controller information
/** * Called when a controller is disconnected * * @param session the session for this event * @param controller controller information */
public void onDisconnected(@NonNull MediaSession2 session, @NonNull ControllerInfo controller) { }
Called when a controller sent a command that will be sent directly to the player. Return false here to reject the request and stop sending command to the player.
Params:
  • session – the session for this event
  • controller – controller information.
  • command – a command. This method will be called for every single command.
See Also:
Returns:true if you want to accept incoming command. false otherwise.
/** * Called when a controller sent a command that will be sent directly to the player. Return * {@code false} here to reject the request and stop sending command to the player. * * @param session the session for this event * @param controller controller information. * @param command a command. This method will be called for every single command. * @return {@code true} if you want to accept incoming command. {@code false} otherwise. * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PLAY * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PAUSE * @see SessionCommand2#COMMAND_CODE_PLAYBACK_STOP * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PREPARE * @see SessionCommand2#COMMAND_CODE_SESSION_FAST_FORWARD * @see SessionCommand2#COMMAND_CODE_SESSION_REWIND * @see SessionCommand2#COMMAND_CODE_PLAYBACK_SEEK_TO * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM * @see SessionCommand2#COMMAND_CODE_PLAYLIST_ADD_ITEM * @see SessionCommand2#COMMAND_CODE_PLAYLIST_REMOVE_ITEM * @see SessionCommand2#COMMAND_CODE_PLAYLIST_GET_LIST * @see SessionCommand2#COMMAND_CODE_SET_VOLUME */
public boolean onCommandRequest(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull SessionCommand2 command) { return true; }
Called when a controller set rating of a media item through MediaController2.setRating(String, Rating2).

To allow setting user rating for a MediaItem2, the media item's metadata should have Rating2 with the key MediaMetadata.METADATA_KEY_USER_RATING, in order to provide possible rating style for controller. Controller will follow the rating style.

Params:
  • session – the session for this event
  • controller – controller information
  • mediaId – media id from the controller
  • rating – new rating from the controller
/** * Called when a controller set rating of a media item through * {@link MediaController2#setRating(String, Rating2)}. * <p> * To allow setting user rating for a {@link MediaItem2}, the media item's metadata * should have {@link Rating2} with the key {@link MediaMetadata#METADATA_KEY_USER_RATING}, * in order to provide possible rating style for controller. Controller will follow the * rating style. * * @param session the session for this event * @param controller controller information * @param mediaId media id from the controller * @param rating new rating from the controller */
public void onSetRating(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull String mediaId, @NonNull Rating2 rating) { }
Called when a controller sent a custom command through MediaController2.sendCustomCommand(SessionCommand2, Bundle, ResultReceiver).
Params:
  • session – the session for this event
  • controller – controller information
  • customCommand – custom command.
  • args – optional arguments
  • cb – optional result receiver
/** * Called when a controller sent a custom command through * {@link MediaController2#sendCustomCommand(SessionCommand2, Bundle, ResultReceiver)}. * * @param session the session for this event * @param controller controller information * @param customCommand custom command. * @param args optional arguments * @param cb optional result receiver */
public void onCustomCommand(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull SessionCommand2 customCommand, @Nullable Bundle args, @Nullable ResultReceiver cb) { }
Called when a controller requested to play a specific mediaId through MediaController2.playFromMediaId(String, Bundle).
Params:
  • session – the session for this event
  • controller – controller information
  • mediaId – media id
  • extras – optional extra bundle
See Also:
/** * Called when a controller requested to play a specific mediaId through * {@link MediaController2#playFromMediaId(String, Bundle)}. * * @param session the session for this event * @param controller controller information * @param mediaId media id * @param extras optional extra bundle * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID */
public void onPlayFromMediaId(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull String mediaId, @Nullable Bundle extras) { }
Called when a controller requested to begin playback from a search query through MediaController2.playFromSearch(String, Bundle)

An empty query indicates that the app may play any music. The implementation should attempt to make a smart choice about what to play.

Params:
  • session – the session for this event
  • controller – controller information
  • query – query string. Can be empty to indicate any suggested media
  • extras – optional extra bundle
See Also:
/** * Called when a controller requested to begin playback from a search query through * {@link MediaController2#playFromSearch(String, Bundle)} * <p> * An empty query indicates that the app may play any music. The implementation should * attempt to make a smart choice about what to play. * * @param session the session for this event * @param controller controller information * @param query query string. Can be empty to indicate any suggested media * @param extras optional extra bundle * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_SEARCH */
public void onPlayFromSearch(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull String query, @Nullable Bundle extras) { }
Called when a controller requested to play a specific media item represented by a URI through MediaController2.playFromUri(Uri, Bundle)
Params:
  • session – the session for this event
  • controller – controller information
  • uri – uri
  • extras – optional extra bundle
See Also:
/** * Called when a controller requested to play a specific media item represented by a URI * through {@link MediaController2#playFromUri(Uri, Bundle)} * * @param session the session for this event * @param controller controller information * @param uri uri * @param extras optional extra bundle * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_URI */
public void onPlayFromUri(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull Uri uri, @Nullable Bundle extras) { }
Called when a controller requested to prepare for playing a specific mediaId through MediaController2.prepareFromMediaId(String, Bundle).

During the preparation, a session should not hold audio focus in order to allow other sessions play seamlessly. The state of playback should be updated to MediaPlayerBase.PLAYER_STATE_PAUSED after the preparation is done.

The playback of the prepared content should start in the later calls of MediaSession2.play().

Override onPlayFromMediaId to handle requests for starting playback without preparation.

Params:
  • session – the session for this event
  • controller – controller information
  • mediaId – media id to prepare
  • extras – optional extra bundle
See Also:
/** * Called when a controller requested to prepare for playing a specific mediaId through * {@link MediaController2#prepareFromMediaId(String, Bundle)}. * <p> * During the preparation, a session should not hold audio focus in order to allow other * sessions play seamlessly. The state of playback should be updated to * {@link MediaPlayerBase#PLAYER_STATE_PAUSED} after the preparation is done. * <p> * The playback of the prepared content should start in the later calls of * {@link MediaSession2#play()}. * <p> * Override {@link #onPlayFromMediaId} to handle requests for starting * playback without preparation. * * @param session the session for this event * @param controller controller information * @param mediaId media id to prepare * @param extras optional extra bundle * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID */
public void onPrepareFromMediaId(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull String mediaId, @Nullable Bundle extras) { }
Called when a controller requested to prepare playback from a search query through MediaController2.prepareFromSearch(String, Bundle).

An empty query indicates that the app may prepare any music. The implementation should attempt to make a smart choice about what to play.

The state of playback should be updated to MediaPlayerBase.PLAYER_STATE_PAUSED after the preparation is done. The playback of the prepared content should start in the later calls of MediaSession2.play().

Override onPlayFromSearch to handle requests for starting playback without preparation.

Params:
  • session – the session for this event
  • controller – controller information
  • query – query string. Can be empty to indicate any suggested media
  • extras – optional extra bundle
See Also:
/** * Called when a controller requested to prepare playback from a search query through * {@link MediaController2#prepareFromSearch(String, Bundle)}. * <p> * An empty query indicates that the app may prepare any music. The implementation should * attempt to make a smart choice about what to play. * <p> * The state of playback should be updated to {@link MediaPlayerBase#PLAYER_STATE_PAUSED} * after the preparation is done. The playback of the prepared content should start in the * later calls of {@link MediaSession2#play()}. * <p> * Override {@link #onPlayFromSearch} to handle requests for starting playback without * preparation. * * @param session the session for this event * @param controller controller information * @param query query string. Can be empty to indicate any suggested media * @param extras optional extra bundle * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH */
public void onPrepareFromSearch(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull String query, @Nullable Bundle extras) { }
Called when a controller requested to prepare a specific media item represented by a URI through MediaController2.prepareFromUri(Uri, Bundle).

During the preparation, a session should not hold audio focus in order to allow other sessions play seamlessly. The state of playback should be updated to MediaPlayerBase.PLAYER_STATE_PAUSED after the preparation is done.

The playback of the prepared content should start in the later calls of MediaSession2.play().

Override onPlayFromUri to handle requests for starting playback without preparation.

Params:
  • session – the session for this event
  • controller – controller information
  • uri – uri
  • extras – optional extra bundle
See Also:
/** * Called when a controller requested to prepare a specific media item represented by a URI * through {@link MediaController2#prepareFromUri(Uri, Bundle)}. * <p> * During the preparation, a session should not hold audio focus in order to allow * other sessions play seamlessly. The state of playback should be updated to * {@link MediaPlayerBase#PLAYER_STATE_PAUSED} after the preparation is done. * <p> * The playback of the prepared content should start in the later calls of * {@link MediaSession2#play()}. * <p> * Override {@link #onPlayFromUri} to handle requests for starting playback without * preparation. * * @param session the session for this event * @param controller controller information * @param uri uri * @param extras optional extra bundle * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_URI */
public void onPrepareFromUri(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull Uri uri, @Nullable Bundle extras) { }
Called when a controller called MediaController2.fastForward()
Params:
  • session – the session for this event
/** * Called when a controller called {@link MediaController2#fastForward()} * * @param session the session for this event */
public void onFastForward(@NonNull MediaSession2 session) { }
Called when a controller called MediaController2.rewind()
Params:
  • session – the session for this event
/** * Called when a controller called {@link MediaController2#rewind()} * * @param session the session for this event */
public void onRewind(@NonNull MediaSession2 session) { }
Called when the player's current playing item is changed

When it's called, you should invalidate previous playback information and wait for later callbacks.

Params:
  • session – the controller for this event
  • player – the player for this event
  • item – new item
/** * Called when the player's current playing item is changed * <p> * When it's called, you should invalidate previous playback information and wait for later * callbacks. * * @param session the controller for this event * @param player the player for this event * @param item new item */
// TODO(jaewan): Use this (b/74316764) public void onCurrentMediaItemChanged(@NonNull MediaSession2 session, @NonNull MediaPlayerBase player, @NonNull MediaItem2 item) { }
Called when the player is prepared, i.e. it is ready to play the content referenced by the given data source.
Params:
  • session – the session for this event
  • player – the player for this event
  • item – the media item for which buffering is happening
/** * Called when the player is <i>prepared</i>, i.e. it is ready to play the content * referenced by the given data source. * @param session the session for this event * @param player the player for this event * @param item the media item for which buffering is happening */
public void onMediaPrepared(@NonNull MediaSession2 session, @NonNull MediaPlayerBase player, @NonNull MediaItem2 item) { }
Called to indicate that the state of the player has changed. See MediaPlayerBase.getPlayerState() for polling the player state.
Params:
  • session – the session for this event
  • player – the player for this event
  • state – the new state of the player.
/** * Called to indicate that the state of the player has changed. * See {@link MediaPlayerBase#getPlayerState()} for polling the player state. * @param session the session for this event * @param player the player for this event * @param state the new state of the player. */
public void onPlayerStateChanged(@NonNull MediaSession2 session, @NonNull MediaPlayerBase player, @PlayerState int state) { }
Called to report buffering events for a data source.
Params:
  • session – the session for this event
  • player – the player for this event
  • item – the media item for which buffering is happening.
  • state – the new buffering state.
/** * Called to report buffering events for a data source. * * @param session the session for this event * @param player the player for this event * @param item the media item for which buffering is happening. * @param state the new buffering state. */
public void onBufferingStateChanged(@NonNull MediaSession2 session, @NonNull MediaPlayerBase player, @NonNull MediaItem2 item, @BuffState int state) { }
Called to indicate that the playback speed has changed.
Params:
  • session – the session for this event
  • player – the player for this event
  • speed – the new playback speed.
/** * Called to indicate that the playback speed has changed. * @param session the session for this event * @param player the player for this event * @param speed the new playback speed. */
public void onPlaybackSpeedChanged(@NonNull MediaSession2 session, @NonNull MediaPlayerBase player, float speed) { }
Called to indicate that MediaSession2.seekTo(long) is completed.
Params:
  • session – the session for this event.
  • mpb – the player that has completed seeking.
  • position – the previous seeking request.
See Also:
/** * Called to indicate that {@link #seekTo(long)} is completed. * * @param session the session for this event. * @param mpb the player that has completed seeking. * @param position the previous seeking request. * @see #seekTo(long) */
public void onSeekCompleted(@NonNull MediaSession2 session, @NonNull MediaPlayerBase mpb, long position) { }
Called when a playlist is changed from the MediaPlaylistAgent.

This is called when the underlying agent has called PlaylistEventCallback.onPlaylistChanged(MediaPlaylistAgent, List<MediaItem2>, MediaMetadata2).

Params:
  • session – the session for this event
  • playlistAgent – playlist agent for this event
  • list – new playlist
  • metadata – new metadata
/** * Called when a playlist is changed from the {@link MediaPlaylistAgent}. * <p> * This is called when the underlying agent has called * {@link MediaPlaylistAgent.PlaylistEventCallback#onPlaylistChanged(MediaPlaylistAgent, * List, MediaMetadata2)}. * * @param session the session for this event * @param playlistAgent playlist agent for this event * @param list new playlist * @param metadata new metadata */
public void onPlaylistChanged(@NonNull MediaSession2 session, @NonNull MediaPlaylistAgent playlistAgent, @NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) { }
Called when a playlist metadata is changed.
Params:
  • session – the session for this event
  • playlistAgent – playlist agent for this event
  • metadata – new metadata
/** * Called when a playlist metadata is changed. * * @param session the session for this event * @param playlistAgent playlist agent for this event * @param metadata new metadata */
public void onPlaylistMetadataChanged(@NonNull MediaSession2 session, @NonNull MediaPlaylistAgent playlistAgent, @Nullable MediaMetadata2 metadata) { }
Called when the shuffle mode is changed.
Params:
  • session – the session for this event
  • playlistAgent – playlist agent for this event
  • shuffleMode – repeat mode
See Also:
/** * Called when the shuffle mode is changed. * * @param session the session for this event * @param playlistAgent playlist agent for this event * @param shuffleMode repeat mode * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP */
public void onShuffleModeChanged(@NonNull MediaSession2 session, @NonNull MediaPlaylistAgent playlistAgent, @MediaPlaylistAgent.ShuffleMode int shuffleMode) { }
Called when the repeat mode is changed.
Params:
  • session – the session for this event
  • playlistAgent – playlist agent for this event
  • repeatMode – repeat mode
See Also:
/** * Called when the repeat mode is changed. * * @param session the session for this event * @param playlistAgent playlist agent for this event * @param repeatMode repeat mode * @see MediaPlaylistAgent#REPEAT_MODE_NONE * @see MediaPlaylistAgent#REPEAT_MODE_ONE * @see MediaPlaylistAgent#REPEAT_MODE_ALL * @see MediaPlaylistAgent#REPEAT_MODE_GROUP */
public void onRepeatModeChanged(@NonNull MediaSession2 session, @NonNull MediaPlaylistAgent playlistAgent, @MediaPlaylistAgent.RepeatMode int repeatMode) { } }
Base builder class for MediaSession2 and its subclass. Any change in this class should be also applied to the subclasses Builder and Builder.

APIs here should be package private, but should have documentations for developers. Otherwise, javadoc will generate documentation with the generic types such as follows.

U extends BuilderBase setSessionCallback(Executor executor, C callback)

This class is hidden to prevent from generating test stub, which fails with 'unexpected bound' because it tries to auto generate stub class as follows.

abstract static class BuilderBase<
     T extends android.media.MediaSession2,
     U extends android.media.MediaSession2.BuilderBase<
             T, U, C extends android.media.MediaSession2.SessionCallback>, C>
@hide
/** * Base builder class for MediaSession2 and its subclass. Any change in this class should be * also applied to the subclasses {@link MediaSession2.Builder} and * {@link MediaLibraryService2.MediaLibrarySession.Builder}. * <p> * APIs here should be package private, but should have documentations for developers. * Otherwise, javadoc will generate documentation with the generic types such as follows. * <pre>U extends BuilderBase<T, U, C> setSessionCallback(Executor executor, C callback)</pre> * <p> * This class is hidden to prevent from generating test stub, which fails with * 'unexpected bound' because it tries to auto generate stub class as follows. * <pre>abstract static class BuilderBase< * T extends android.media.MediaSession2, * U extends android.media.MediaSession2.BuilderBase< * T, U, C extends android.media.MediaSession2.SessionCallback>, C></pre> * @hide */
static abstract class BuilderBase <T extends MediaSession2, U extends BuilderBase<T, U, C>, C extends SessionCallback> { private final BuilderBaseProvider<T, C> mProvider; BuilderBase(ProviderCreator<BuilderBase<T, U, C>, BuilderBaseProvider<T, C>> creator) { mProvider = creator.createProvider(this); }
Sets the underlying MediaPlayerBase for this session to dispatch incoming event to.
Params:
  • player – a MediaPlayerBase that handles actual media playback in your app.
/** * Sets the underlying {@link MediaPlayerBase} for this session to dispatch incoming event * to. * * @param player a {@link MediaPlayerBase} that handles actual media playback in your app. */
@NonNull U setPlayer(@NonNull MediaPlayerBase player) { mProvider.setPlayer_impl(player); return (U) this; }
Sets the MediaPlaylistAgent for this session to manages playlist of the underlying MediaPlayerBase. The playlist agent should manage MediaPlayerBase for calling MediaPlayerBase.setNextDataSources(List<DataSourceDesc>).

If the MediaPlaylistAgent isn't set, session will create the default playlist agent.

Params:
/** * Sets the {@link MediaPlaylistAgent} for this session to manages playlist of the * underlying {@link MediaPlayerBase}. The playlist agent should manage * {@link MediaPlayerBase} for calling {@link MediaPlayerBase#setNextDataSources(List)}. * <p> * If the {@link MediaPlaylistAgent} isn't set, session will create the default playlist * agent. * * @param playlistAgent a {@link MediaPlaylistAgent} that manages playlist of the * {@code player} */
U setPlaylistAgent(@NonNull MediaPlaylistAgent playlistAgent) { mProvider.setPlaylistAgent_impl(playlistAgent); return (U) this; }
Sets the VolumeProvider2 for this session to handle volume events. If not set, system will adjust the appropriate stream volume for this session's player.
Params:
  • volumeProvider – The provider that will receive volume button events.
/** * Sets the {@link VolumeProvider2} for this session to handle volume events. If not set, * system will adjust the appropriate stream volume for this session's player. * * @param volumeProvider The provider that will receive volume button events. */
@NonNull U setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) { mProvider.setVolumeProvider_impl(volumeProvider); return (U) this; }
Set an intent for launching UI for this Session. This can be used as a quick link to an ongoing media screen. The intent should be for an activity that may be started using Context.startActivity(Intent).
Params:
  • pi – The intent to launch to show UI for this session.
/** * Set an intent for launching UI for this Session. This can be used as a * quick link to an ongoing media screen. The intent should be for an * activity that may be started using {@link Context#startActivity(Intent)}. * * @param pi The intent to launch to show UI for this session. */
@NonNull U setSessionActivity(@Nullable PendingIntent pi) { mProvider.setSessionActivity_impl(pi); return (U) this; }
Set ID of the session. If it's not set, an empty string with used to create a session.

Use this if and only if your app supports multiple playback at the same time and also wants to provide external apps to have finer controls of them.

Params:
  • id – id of the session. Must be unique per package.
Throws:
Returns:
/** * Set ID of the session. If it's not set, an empty string with used to create a session. * <p> * Use this if and only if your app supports multiple playback at the same time and also * wants to provide external apps to have finer controls of them. * * @param id id of the session. Must be unique per package. * @throws IllegalArgumentException if id is {@code null} * @return */
@NonNull U setId(@NonNull String id) { mProvider.setId_impl(id); return (U) this; }
Set callback for the session.
Params:
  • executor – callback executor
  • callback – session callback.
Returns:
/** * Set callback for the session. * * @param executor callback executor * @param callback session callback. * @return */
@NonNull U setSessionCallback(@NonNull @CallbackExecutor Executor executor, @NonNull C callback) { mProvider.setSessionCallback_impl(executor, callback); return (U) this; }
Throws:
Returns:a new session
/** * Build {@link MediaSession2}. * * @return a new session * @throws IllegalStateException if the session with the same id is already exists for the * package. */
@NonNull T build() { return mProvider.build_impl(); } }
Builder for MediaSession2.

Any incoming event from the MediaController2 will be handled on the thread that created session with the build().

/** * Builder for {@link MediaSession2}. * <p> * Any incoming event from the {@link MediaController2} will be handled on the thread * that created session with the {@link Builder#build()}. */
// Override all methods just to show them with the type instead of generics in Javadoc. // This workarounds javadoc issue described in the MediaSession2.BuilderBase. public static final class Builder extends BuilderBase<MediaSession2, Builder, SessionCallback> { public Builder(Context context) { super((instance) -> ApiLoader.getProvider().createMediaSession2Builder( context, (Builder) instance)); } @Override public @NonNull Builder setPlayer(@NonNull MediaPlayerBase player) { return super.setPlayer(player); } @Override public Builder setPlaylistAgent(@NonNull MediaPlaylistAgent playlistAgent) { return super.setPlaylistAgent(playlistAgent); } @Override public @NonNull Builder setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) { return super.setVolumeProvider(volumeProvider); } @Override public @NonNull Builder setSessionActivity(@Nullable PendingIntent pi) { return super.setSessionActivity(pi); } @Override public @NonNull Builder setId(@NonNull String id) { return super.setId(id); } @Override public @NonNull Builder setSessionCallback(@NonNull Executor executor, @Nullable SessionCallback callback) { return super.setSessionCallback(executor, callback); } @Override public @NonNull MediaSession2 build() { return super.build(); } }
Information of a controller.
/** * Information of a controller. */
public static final class ControllerInfo { private final ControllerInfoProvider mProvider;
@hide
/** * @hide */
public ControllerInfo(@NonNull Context context, int uid, int pid, @NonNull String packageName, @NonNull IInterface callback) { mProvider = ApiLoader.getProvider().createMediaSession2ControllerInfo( context, this, uid, pid, packageName, callback); }
Returns:package name of the controller
/** * @return package name of the controller */
public @NonNull String getPackageName() { return mProvider.getPackageName_impl(); }
Returns:uid of the controller
/** * @return uid of the controller */
public int getUid() { return mProvider.getUid_impl(); }
Return if the controller has granted android.permission.MEDIA_CONTENT_CONTROL or has a enabled notification listener so can be trusted to accept connection and incoming command request.
Returns:true if the controller is trusted.
/** * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or * has a enabled notification listener so can be trusted to accept connection and incoming * command request. * * @return {@code true} if the controller is trusted. */
public boolean isTrusted() { return mProvider.isTrusted_impl(); }
@hide
/** * @hide */
public @NonNull ControllerInfoProvider getProvider() { return mProvider; } @Override public int hashCode() { return mProvider.hashCode_impl(); } @Override public boolean equals(Object obj) { return mProvider.equals_impl(obj); } @Override public String toString() { return mProvider.toString_impl(); } }
Button for a SessionCommand2 that will be shown by the controller.

It's up to the controller's decision to respect or ignore this customization request.

/** * Button for a {@link SessionCommand2} that will be shown by the controller. * <p> * It's up to the controller's decision to respect or ignore this customization request. */
public static final class CommandButton { private final CommandButtonProvider mProvider;
@hide
/** * @hide */
public CommandButton(CommandButtonProvider provider) { mProvider = provider; }
Get command associated with this button. Can be null if the button isn't enabled and only providing placeholder.
Returns:command or null
/** * Get command associated with this button. Can be {@code null} if the button isn't enabled * and only providing placeholder. * * @return command or {@code null} */
public @Nullable SessionCommand2 getCommand() { return mProvider.getCommand_impl(); }
Resource id of the button in this package. Can be 0 if the command is predefined and custom icon isn't needed.
Returns:resource id of the icon. Can be 0.
/** * Resource id of the button in this package. Can be {@code 0} if the command is predefined * and custom icon isn't needed. * * @return resource id of the icon. Can be {@code 0}. */
public int getIconResId() { return mProvider.getIconResId_impl(); }
Display name of the button. Can be null or empty if the command is predefined and custom name isn't needed.
Returns:custom display name. Can be null or empty.
/** * Display name of the button. Can be {@code null} or empty if the command is predefined * and custom name isn't needed. * * @return custom display name. Can be {@code null} or empty. */
public @Nullable String getDisplayName() { return mProvider.getDisplayName_impl(); }
Extra information of the button. It's private information between session and controller.
Returns:
/** * Extra information of the button. It's private information between session and controller. * * @return */
public @Nullable Bundle getExtras() { return mProvider.getExtras_impl(); }
Return whether it's enabled
Returns:true if enabled. false otherwise.
/** * Return whether it's enabled * * @return {@code true} if enabled. {@code false} otherwise. */
public boolean isEnabled() { return mProvider.isEnabled_impl(); }
@hide
/** * @hide */
public @NonNull CommandButtonProvider getProvider() { return mProvider; }
Builder for CommandButton.
/** * Builder for {@link CommandButton}. */
public static final class Builder { private final CommandButtonProvider.BuilderProvider mProvider; public Builder() { mProvider = ApiLoader.getProvider().createMediaSession2CommandButtonBuilder(this); } public @NonNull Builder setCommand(@Nullable SessionCommand2 command) { return mProvider.setCommand_impl(command); } public @NonNull Builder setIconResId(int resId) { return mProvider.setIconResId_impl(resId); } public @NonNull Builder setDisplayName(@Nullable String displayName) { return mProvider.setDisplayName_impl(displayName); } public @NonNull Builder setEnabled(boolean enabled) { return mProvider.setEnabled_impl(enabled); } public @NonNull Builder setExtras(@Nullable Bundle extras) { return mProvider.setExtras_impl(extras); } public @NonNull CommandButton build() { return mProvider.build_impl(); } } }
Constructor is hidden and apps can only instantiate indirectly through Builder.

This intended behavior and here's the reasons. 1. Prevent multiple sessions with the same tag in a media app. Whenever it happens only one session was properly setup and others were all dummies. Android framework couldn't find the right session to dispatch media key event. 2. Simplify session's lifecycle. MediaSession is available after all of MediaSession.setFlags(int), MediaSession.setCallback(Callback), and MediaSession.setActive(boolean). It was common for an app to omit one, so framework had to add heuristics to figure out which should be the highest priority for handling media key event.

@hide
/** * Constructor is hidden and apps can only instantiate indirectly through {@link Builder}. * <p> * This intended behavior and here's the reasons. * 1. Prevent multiple sessions with the same tag in a media app. * Whenever it happens only one session was properly setup and others were all dummies. * Android framework couldn't find the right session to dispatch media key event. * 2. Simplify session's lifecycle. * {@link android.media.session.MediaSession} is available after all of * {@link android.media.session.MediaSession#setFlags(int)}, * {@link android.media.session.MediaSession#setCallback( * android.media.session.MediaSession.Callback)}, * and {@link android.media.session.MediaSession#setActive(boolean)}. * It was common for an app to omit one, so framework had to add heuristics to figure out * which should be the highest priority for handling media key event. * @hide */
public MediaSession2(MediaSession2Provider provider) { super(); mProvider = provider; }
@hide
/** * @hide */
public @NonNull MediaSession2Provider getProvider() { return mProvider; }
Sets the underlying MediaPlayerBase and MediaPlaylistAgent for this session to dispatch incoming event to.

When a MediaPlaylistAgent is specified here, the playlist agent should manage MediaPlayerBase for calling MediaPlayerBase.setNextDataSources(List<DataSourceDesc>).

If the MediaPlaylistAgent isn't set, session will recreate the default playlist agent.

Params:
  • player – a MediaPlayerBase that handles actual media playback in your app
  • playlistAgent – a MediaPlaylistAgent that manages playlist of the player
  • volumeProvider – a VolumeProvider2. If null, system will adjust the appropriate stream volume for this session's player.
/** * Sets the underlying {@link MediaPlayerBase} and {@link MediaPlaylistAgent} for this session * to dispatch incoming event to. * <p> * When a {@link MediaPlaylistAgent} is specified here, the playlist agent should manage * {@link MediaPlayerBase} for calling {@link MediaPlayerBase#setNextDataSources(List)}. * <p> * If the {@link MediaPlaylistAgent} isn't set, session will recreate the default playlist * agent. * * @param player a {@link MediaPlayerBase} that handles actual media playback in your app * @param playlistAgent a {@link MediaPlaylistAgent} that manages playlist of the {@code player} * @param volumeProvider a {@link VolumeProvider2}. If {@code null}, system will adjust the * appropriate stream volume for this session's player. */
public void updatePlayer(@NonNull MediaPlayerBase player, @Nullable MediaPlaylistAgent playlistAgent, @Nullable VolumeProvider2 volumeProvider) { mProvider.updatePlayer_impl(player, playlistAgent, volumeProvider); } @Override public void close() { mProvider.close_impl(); }
Returns:player
/** * @return player */
public @NonNull MediaPlayerBase getPlayer() { return mProvider.getPlayer_impl(); }
Returns:playlist agent
/** * @return playlist agent */
public @NonNull MediaPlaylistAgent getPlaylistAgent() { return mProvider.getPlaylistAgent_impl(); }
Returns:volume provider
/** * @return volume provider */
public @Nullable VolumeProvider2 getVolumeProvider() { return mProvider.getVolumeProvider_impl(); }
Returns the SessionToken2 for creating MediaController2.
/** * Returns the {@link SessionToken2} for creating {@link MediaController2}. */
public @NonNull SessionToken2 getToken() { return mProvider.getToken_impl(); } public @NonNull List<ControllerInfo> getConnectedControllers() { return mProvider.getConnectedControllers_impl(); }
Set the AudioFocusRequest to obtain the audio focus
Params:
  • afr – the full request parameters
/** * Set the {@link AudioFocusRequest} to obtain the audio focus * * @param afr the full request parameters */
public void setAudioFocusRequest(@Nullable AudioFocusRequest afr) { // TODO(jaewan): implement this (b/72529899) // mProvider.setAudioFocusRequest_impl(focusGain); }
Sets ordered list of CommandButton for controllers to build UI with it.

It's up to controller's decision how to represent the layout in its own UI. Here's the same way (layout[i] means a CommandButton at index i in the given list) For 5 icons row layout[3] layout[1] layout[0] layout[2] layout[4] For 3 icons row layout[1] layout[0] layout[2] For 5 icons row with overflow icon (can show +5 extra buttons with overflow button) expanded row: layout[5] layout[6] layout[7] layout[8] layout[9] main row: layout[3] layout[1] layout[0] layout[2] layout[4]

This API can be called in the SessionCallback.onConnect(MediaSession2, ControllerInfo).

Params:
  • controller – controller to specify layout.
  • layout – ordered list of layout.
/** * Sets ordered list of {@link CommandButton} for controllers to build UI with it. * <p> * It's up to controller's decision how to represent the layout in its own UI. * Here's the same way * (layout[i] means a CommandButton at index i in the given list) * For 5 icons row * layout[3] layout[1] layout[0] layout[2] layout[4] * For 3 icons row * layout[1] layout[0] layout[2] * For 5 icons row with overflow icon (can show +5 extra buttons with overflow button) * expanded row: layout[5] layout[6] layout[7] layout[8] layout[9] * main row: layout[3] layout[1] layout[0] layout[2] layout[4] * <p> * This API can be called in the {@link SessionCallback#onConnect( * MediaSession2, ControllerInfo)}. * * @param controller controller to specify layout. * @param layout ordered list of layout. */
public void setCustomLayout(@NonNull ControllerInfo controller, @NonNull List<CommandButton> layout) { mProvider.setCustomLayout_impl(controller, layout); }
Set the new allowed command group for the controller
Params:
  • controller – controller to change allowed commands
  • commands – new allowed commands
/** * Set the new allowed command group for the controller * * @param controller controller to change allowed commands * @param commands new allowed commands */
public void setAllowedCommands(@NonNull ControllerInfo controller, @NonNull SessionCommandGroup2 commands) { mProvider.setAllowedCommands_impl(controller, commands); }
Send custom command to all connected controllers.
Params:
  • command – a command
  • args – optional argument
/** * Send custom command to all connected controllers. * * @param command a command * @param args optional argument */
public void sendCustomCommand(@NonNull SessionCommand2 command, @Nullable Bundle args) { mProvider.sendCustomCommand_impl(command, args); }
Send custom command to a specific controller.
Params:
  • command – a command
  • args – optional argument
  • receiver – result receiver for the session
/** * Send custom command to a specific controller. * * @param command a command * @param args optional argument * @param receiver result receiver for the session */
public void sendCustomCommand(@NonNull ControllerInfo controller, @NonNull SessionCommand2 command, @Nullable Bundle args, @Nullable ResultReceiver receiver) { // Equivalent to the MediaController.sendCustomCommand(Action action, ResultReceiver r); mProvider.sendCustomCommand_impl(controller, command, args, receiver); }
Play playback

This calls MediaPlayerBase.play().

/** * Play playback * <p> * This calls {@link MediaPlayerBase#play()}. */
public void play() { mProvider.play_impl(); }
Pause playback.

This calls MediaPlayerBase.pause().

/** * Pause playback. * <p> * This calls {@link MediaPlayerBase#pause()}. */
public void pause() { mProvider.pause_impl(); }
Stop playback, and reset the player to the initial state.

This calls MediaPlayerBase.reset().

/** * Stop playback, and reset the player to the initial state. * <p> * This calls {@link MediaPlayerBase#reset()}. */
public void stop() { mProvider.stop_impl(); }
Request that the player prepare its playback. In other words, other sessions can continue to play during the preparation of this session. This method can be used to speed up the start of the playback. Once the preparation is done, the session will change its playback state to MediaPlayerBase.PLAYER_STATE_PAUSED. Afterwards, play can be called to start playback.

This calls MediaPlayerBase.reset().

/** * Request that the player prepare its playback. In other words, other sessions can continue * to play during the preparation of this session. This method can be used to speed up the * start of the playback. Once the preparation is done, the session will change its playback * state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, {@link #play} can be called * to start playback. * <p> * This calls {@link MediaPlayerBase#reset()}. */
public void prepare() { mProvider.prepare_impl(); }
Move to a new location in the media stream.
Params:
  • pos – Position to move to, in milliseconds.
/** * Move to a new location in the media stream. * * @param pos Position to move to, in milliseconds. */
public void seekTo(long pos) { mProvider.seekTo_impl(pos); }
@hide
/** * @hide */
public void skipForward() { // To match with KEYCODE_MEDIA_SKIP_FORWARD }
@hide
/** * @hide */
public void skipBackward() { // To match with KEYCODE_MEDIA_SKIP_BACKWARD }
Notify errors to the connected controllers
Params:
  • errorCode – error code
  • extras – extras
/** * Notify errors to the connected controllers * * @param errorCode error code * @param extras extras */
public void notifyError(@ErrorCode int errorCode, @Nullable Bundle extras) { mProvider.notifyError_impl(errorCode, extras); }
Gets the current player state.
Returns:the current player state
/** * Gets the current player state. * * @return the current player state */
public @PlayerState int getPlayerState() { return mProvider.getPlayerState_impl(); }
Gets the current position.
Returns:the current playback position in ms, or MediaPlayerBase.UNKNOWN_TIME if unknown.
/** * Gets the current position. * * @return the current playback position in ms, or {@link MediaPlayerBase#UNKNOWN_TIME} if * unknown. */
public long getCurrentPosition() { return mProvider.getCurrentPosition_impl(); }
Gets the buffered position, or MediaPlayerBase.UNKNOWN_TIME if unknown.
Returns:the buffered position in ms, or MediaPlayerBase.UNKNOWN_TIME.
/** * Gets the buffered position, or {@link MediaPlayerBase#UNKNOWN_TIME} if unknown. * * @return the buffered position in ms, or {@link MediaPlayerBase#UNKNOWN_TIME}. */
public long getBufferedPosition() { return mProvider.getBufferedPosition_impl(); }
Gets the current buffering state of the player. During buffering, see getBufferedPosition() for the quantifying the amount already buffered.
Returns:the buffering state.
/** * Gets the current buffering state of the player. * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already * buffered. * * @return the buffering state. */
public @BuffState int getBufferingState() { // TODO(jaewan): Implement this return BUFFERING_STATE_UNKNOWN; }
Get the playback speed.
Returns:speed
/** * Get the playback speed. * * @return speed */
public float getPlaybackSpeed() { // TODO(jaewan): implement this (b/74093080) return -1; }
Set the playback speed.
/** * Set the playback speed. */
public void setPlaybackSpeed(float speed) { // TODO(jaewan): implement this (b/74093080) }
Sets the data source missing helper. Helper will be used to provide default implementation of MediaPlaylistAgent when it isn't set by developer.

Default implementation of the MediaPlaylistAgent will call helper when a MediaItem2 in the playlist doesn't have a DataSourceDesc. This may happen when

If it's not set, playback wouldn't happen for the item without data source descriptor.

The helper will be run on the executor that was specified by Builder.setSessionCallback(Executor, SessionCallback).

Params:
  • helper – a data source missing helper.
Throws:
See Also:
/** * Sets the data source missing helper. Helper will be used to provide default implementation of * {@link MediaPlaylistAgent} when it isn't set by developer. * <p> * Default implementation of the {@link MediaPlaylistAgent} will call helper when a * {@link MediaItem2} in the playlist doesn't have a {@link DataSourceDesc}. This may happen * when * <ul> * <li>{@link MediaItem2} specified by {@link #setPlaylist(List, MediaMetadata2)} doesn't * have {@link DataSourceDesc}</li> * <li>{@link MediaController2#addPlaylistItem(int, MediaItem2)} is called and accepted * by {@link SessionCallback#onCommandRequest( * MediaSession2, ControllerInfo, SessionCommand2)}. * In that case, an item would be added automatically without the data source.</li> * </ul> * <p> * If it's not set, playback wouldn't happen for the item without data source descriptor. * <p> * The helper will be run on the executor that was specified by * {@link Builder#setSessionCallback(Executor, SessionCallback)}. * * @param helper a data source missing helper. * @throws IllegalStateException when the helper is set when the playlist agent is set * @see #setPlaylist(List, MediaMetadata2) * @see SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2) * @see SessionCommand2#COMMAND_CODE_PLAYLIST_ADD_ITEM * @see SessionCommand2#COMMAND_CODE_PLAYLIST_REPLACE_ITEM */
public void setOnDataSourceMissingHelper(@NonNull OnDataSourceMissingHelper helper) { mProvider.setOnDataSourceMissingHelper_impl(helper); }
Clears the data source missing helper.
See Also:
  • setOnDataSourceMissingHelper(OnDataSourceMissingHelper)
/** * Clears the data source missing helper. * * @see #setOnDataSourceMissingHelper(OnDataSourceMissingHelper) */
public void clearOnDataSourceMissingHelper() { mProvider.clearOnDataSourceMissingHelper_impl(); }
Returns the playlist from the MediaPlaylistAgent.

This list may differ with the list that was specified with setPlaylist(List<MediaItem2>, MediaMetadata2) depending on the MediaPlaylistAgent implementation. Use media items returned here for other playlist agent APIs such as MediaPlaylistAgent.skipToPlaylistItem(MediaItem2).

See Also:
Returns:playlist
/** * Returns the playlist from the {@link MediaPlaylistAgent}. * <p> * This list may differ with the list that was specified with * {@link #setPlaylist(List, MediaMetadata2)} depending on the {@link MediaPlaylistAgent} * implementation. Use media items returned here for other playlist agent APIs such as * {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)}. * * @return playlist * @see MediaPlaylistAgent#getPlaylist() * @see SessionCallback#onPlaylistChanged( * MediaSession2, MediaPlaylistAgent, List, MediaMetadata2) */
public List<MediaItem2> getPlaylist() { return mProvider.getPlaylist_impl(); }
Sets a list of MediaItem2 to the MediaPlaylistAgent. Ensure uniqueness of each MediaItem2 in the playlist so the session can uniquely identity individual items.

This may be an asynchronous call, and MediaPlaylistAgent may keep the copy of the list. Wait for SessionCallback.onPlaylistChanged(MediaSession2, MediaPlaylistAgent, List<MediaItem2>, MediaMetadata2) to know the operation finishes.

You may specify a MediaItem2 without DataSourceDesc. In that case, MediaPlaylistAgent has responsibility to dynamically query DataSourceDesc when such media item is ready for preparation or play. Default implementation needs OnDataSourceMissingHelper for such case.

Params:
  • list – A list of MediaItem2 objects to set as a play list.
Throws:
See Also:
/** * Sets a list of {@link MediaItem2} to the {@link MediaPlaylistAgent}. Ensure uniqueness of * each {@link MediaItem2} in the playlist so the session can uniquely identity individual * items. * <p> * This may be an asynchronous call, and {@link MediaPlaylistAgent} may keep the copy of the * list. Wait for {@link SessionCallback#onPlaylistChanged(MediaSession2, MediaPlaylistAgent, * List, MediaMetadata2)} to know the operation finishes. * <p> * You may specify a {@link MediaItem2} without {@link DataSourceDesc}. In that case, * {@link MediaPlaylistAgent} has responsibility to dynamically query {@link DataSourceDesc} * when such media item is ready for preparation or play. Default implementation needs * {@link OnDataSourceMissingHelper} for such case. * * @param list A list of {@link MediaItem2} objects to set as a play list. * @throws IllegalArgumentException if given list is {@code null}, or has duplicated media * items. * @see MediaPlaylistAgent#setPlaylist(List, MediaMetadata2) * @see SessionCallback#onPlaylistChanged( * MediaSession2, MediaPlaylistAgent, List, MediaMetadata2) * @see #setOnDataSourceMissingHelper */
public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) { mProvider.setPlaylist_impl(list, metadata); }
Skips to the item in the playlist.

This calls MediaPlaylistAgent.skipToPlaylistItem(MediaItem2) and the behavior depends on the playlist agent implementation, especially with the shuffle/repeat mode.

Params:
  • item – The item in the playlist you want to play
See Also:
/** * Skips to the item in the playlist. * <p> * This calls {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)} and the behavior depends * on the playlist agent implementation, especially with the shuffle/repeat mode. * * @param item The item in the playlist you want to play * @see #getShuffleMode() * @see #getRepeatMode() */
public void skipToPlaylistItem(@NonNull MediaItem2 item) { mProvider.skipToPlaylistItem_impl(item); }
Skips to the previous item.

This calls MediaPlaylistAgent.skipToPreviousItem() and the behavior depends on the playlist agent implementation, especially with the shuffle/repeat mode.

See Also:
/** * Skips to the previous item. * <p> * This calls {@link MediaPlaylistAgent#skipToPreviousItem()} and the behavior depends on the * playlist agent implementation, especially with the shuffle/repeat mode. * * @see #getShuffleMode() * @see #getRepeatMode() **/
public void skipToPreviousItem() { mProvider.skipToPreviousItem_impl(); }
Skips to the next item.

This calls MediaPlaylistAgent.skipToNextItem() and the behavior depends on the playlist agent implementation, especially with the shuffle/repeat mode.

See Also:
/** * Skips to the next item. * <p> * This calls {@link MediaPlaylistAgent#skipToNextItem()} and the behavior depends on the * playlist agent implementation, especially with the shuffle/repeat mode. * * @see #getShuffleMode() * @see #getRepeatMode() */
public void skipToNextItem() { mProvider.skipToNextItem_impl(); }
Gets the playlist metadata from the MediaPlaylistAgent.
Returns:the playlist metadata
/** * Gets the playlist metadata from the {@link MediaPlaylistAgent}. * * @return the playlist metadata */
public MediaMetadata2 getPlaylistMetadata() { return mProvider.getPlaylistMetadata_impl(); }
Adds the media item to the playlist at position index. Index equals or greater than the current playlist size will add the item at the end of the playlist.

This will not change the currently playing media item. If index is less than or equal to the current index of the play list, the current index of the play list will be incremented correspondingly.

Params:
  • index – the index you want to add
  • item – the media item you want to add
/** * Adds the media item to the playlist at position index. Index equals or greater than * the current playlist size will add the item at the end of the playlist. * <p> * This will not change the currently playing media item. * If index is less than or equal to the current index of the play list, * the current index of the play list will be incremented correspondingly. * * @param index the index you want to add * @param item the media item you want to add */
public void addPlaylistItem(int index, @NonNull MediaItem2 item) { mProvider.addPlaylistItem_impl(index, item); }
Removes the media item in the playlist.

If the item is the currently playing item of the playlist, current playback will be stopped and playback moves to next source in the list.

Params:
  • item – the media item you want to add
/** * Removes the media item in the playlist. * <p> * If the item is the currently playing item of the playlist, current playback * will be stopped and playback moves to next source in the list. * * @param item the media item you want to add */
public void removePlaylistItem(@NonNull MediaItem2 item) { mProvider.removePlaylistItem_impl(item); }
Replaces the media item at index in the playlist. This can be also used to update metadata of an item.
Params:
  • index – the index of the item to replace
  • item – the new item
/** * Replaces the media item at index in the playlist. This can be also used to update metadata of * an item. * * @param index the index of the item to replace * @param item the new item */
public void replacePlaylistItem(int index, @NonNull MediaItem2 item) { mProvider.replacePlaylistItem_impl(index, item); }
Return currently playing media item.
Returns:currently playing media item
/** * Return currently playing media item. * * @return currently playing media item */
public MediaItem2 getCurrentMediaItem() { // TODO(jaewan): Rename provider, and implement (b/74316764) return mProvider.getCurrentPlaylistItem_impl(); }
Updates the playlist metadata to the MediaPlaylistAgent.
Params:
  • metadata – metadata of the playlist
/** * Updates the playlist metadata to the {@link MediaPlaylistAgent}. * * @param metadata metadata of the playlist */
public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) { mProvider.updatePlaylistMetadata_impl(metadata); }
Gets the repeat mode from the MediaPlaylistAgent.
See Also:
Returns:repeat mode
/** * Gets the repeat mode from the {@link MediaPlaylistAgent}. * * @return repeat mode * @see MediaPlaylistAgent#REPEAT_MODE_NONE * @see MediaPlaylistAgent#REPEAT_MODE_ONE * @see MediaPlaylistAgent#REPEAT_MODE_ALL * @see MediaPlaylistAgent#REPEAT_MODE_GROUP */
public @RepeatMode int getRepeatMode() { return mProvider.getRepeatMode_impl(); }
Sets the repeat mode to the MediaPlaylistAgent.
Params:
  • repeatMode – repeat mode
See Also:
/** * Sets the repeat mode to the {@link MediaPlaylistAgent}. * * @param repeatMode repeat mode * @see MediaPlaylistAgent#REPEAT_MODE_NONE * @see MediaPlaylistAgent#REPEAT_MODE_ONE * @see MediaPlaylistAgent#REPEAT_MODE_ALL * @see MediaPlaylistAgent#REPEAT_MODE_GROUP */
public void setRepeatMode(@RepeatMode int repeatMode) { mProvider.setRepeatMode_impl(repeatMode); }
Gets the shuffle mode from the MediaPlaylistAgent.
See Also:
Returns:The shuffle mode
/** * Gets the shuffle mode from the {@link MediaPlaylistAgent}. * * @return The shuffle mode * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP */
public @ShuffleMode int getShuffleMode() { return mProvider.getShuffleMode_impl(); }
Sets the shuffle mode to the MediaPlaylistAgent.
Params:
  • shuffleMode – The shuffle mode
See Also:
/** * Sets the shuffle mode to the {@link MediaPlaylistAgent}. * * @param shuffleMode The shuffle mode * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP */
public void setShuffleMode(@ShuffleMode int shuffleMode) { mProvider.setShuffleMode_impl(shuffleMode); } }