# MediaSession

Artifact: [androidx.media3:media3-session](https://developer.android.com/jetpack/androidx/releases/media3) [View Source](https://cs.android.com/search?q=file:androidx/media3/session/MediaSession.java+class:androidx.media3.session.MediaSession)

*** ** * ** ***


```
@DoNotMock
public class MediaSession
```

<br />

Known direct subclasses [MediaLibraryService.MediaLibrarySession](https://developer.android.com/reference/androidx/media3/session/MediaLibraryService.MediaLibrarySession)

|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaLibraryService.MediaLibrarySession` | An extended `https://developer.android.com/reference/androidx/media3/session/MediaSession` for the `https://developer.android.com/reference/androidx/media3/session/MediaLibraryService`. |

*** ** * ** ***

A session that allows a media app to expose its player functionality, information of the playlist and the media item currently being played to other processes including the Android framework and other apps. The common use cases are as follows:

- Receiving and dispatching media key events (for instance Bluetooth/wired headset and remote control devices).
- Publish media playback information and player commands to SystemUI (media notification) and Android Auto/Wear OS.
- Separating UI process and playback process.

A session should be created when an app wants to publish media playback information or handle media key events. In general, an app only needs one session for all playback, though multiple sessions can be created to provide finer grain controls of media. See [Supporting Multiple Sessions](https://developer.android.com/reference/androidx/media3/session/MediaSession#MultipleSessions) for details.

If an app wants to support playback when in the background, using a `https://developer.android.com/reference/androidx/media3/session/MediaSessionService` is the preferred approach. See `https://developer.android.com/reference/androidx/media3/session/MediaSessionService` for details.

Topics covered here:

1. [Session Lifecycle](https://developer.android.com/reference/androidx/media3/session/MediaSession#SessionLifecycle)
2. [Threading Model](https://developer.android.com/reference/androidx/media3/session/MediaSession#ThreadingModel)
3. [Media Key Events Mapping](https://developer.android.com/reference/androidx/media3/session/MediaSession#KeyEvents)
4. [Supporting Multiple Sessions](https://developer.android.com/reference/androidx/media3/session/MediaSession#MultipleSessions)
5. [Backward Compatibility with Legacy Session APIs](https://developer.android.com/reference/androidx/media3/session/MediaSession#BackwardCompatibility)
6. [Backward Compatibility with Legacy Controller APIs](https://developer.android.com/reference/androidx/media3/session/MediaSession#CompatibilityController)

## Session Lifecycle

A session can be created by `https://developer.android.com/reference/androidx/media3/session/MediaSession.Builder`. The owner of the session may pass its `https://developer.android.com/reference/androidx/media3/session/MediaSession#getToken()` to other processes to allow them to create a `https://developer.android.com/reference/androidx/media3/session/MediaController` to interact with the session.

When a session receives playback commands, the session calls corresponding methods directly on the underlying player set by `https://developer.android.com/reference/androidx/media3/session/MediaSession.Builder#Builder(android.content.Context,androidx.media3.common.Player)` or `https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlayer(androidx.media3.common.Player)`.

When an app is finished performing playback it must call `https://developer.android.com/reference/androidx/media3/session/MediaSession#release()` to clean up the session and notify any controllers. The app is responsible for releasing the underlying player after releasing the session.

## Threading Model

The instances are thread safe, but must be used on a thread with a looper.

`https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback` methods will be called on the application thread associated with the `https://developer.android.com/reference/androidx/media3/common/Player#getApplicationLooper()` of the underlying player. When a new player is set by `https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlayer(androidx.media3.common.Player)`, the player must use the same application looper as the previous one.

The session listens to player events via `https://developer.android.com/reference/androidx/media3/common/Player.Listener` and expects the callback methods to be called on the application thread. If the player violates the threading contract, an `https://developer.android.com/reference/java/lang/IllegalStateException.html` will be thrown.

## Media Key Events Mapping

When the session receives media key events they are mapped to a method call on the underlying player. The following table shows the mapping between the event key code and the `https://developer.android.com/reference/androidx/media3/common/Player` method which is called.

| Key code | Player API |
|---|---|
| `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_PLAY` | `https://developer.android.com/reference/androidx/media3/common/Player#play()` |
| `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_PAUSE` | `https://developer.android.com/reference/androidx/media3/common/Player#pause()` |
| - `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_PLAY_PAUSE` - `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_HEADSETHOOK` | - For a single tap, - `https://developer.android.com/reference/androidx/media3/common/Player#pause()` if `https://developer.android.com/reference/androidx/media3/common/Player#getPlayWhenReady()` is `true` - `https://developer.android.com/reference/androidx/media3/common/Player#play()` otherwise - In case the media key events are coming from another package ID than the package ID of the media app (events coming for instance from Bluetooth), a double tap generating two key events within a brief amount of time, is converted to `https://developer.android.com/reference/androidx/media3/common/Player#seekToNext()` |
| `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_NEXT` | `https://developer.android.com/reference/androidx/media3/common/Player#seekToNext()` |
| `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_PREVIOUS` | `https://developer.android.com/reference/androidx/media3/common/Player#seekToPrevious()` |
| `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_STOP` | `https://developer.android.com/reference/androidx/media3/common/Player#stop()` |
| `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_FAST_FORWARD` | `https://developer.android.com/reference/androidx/media3/common/Player#seekForward()` |
| `https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MEDIA_REWIND` | `https://developer.android.com/reference/androidx/media3/common/Player#seekBack()` |
[Key code and corresponding Player API]

## Supporting Multiple Sessions

Generally, multiple sessions aren't necessary for most media apps. One exception is if your app can play multiple media content at the same time, but only for the playback of video-only media or remote playback, since the [audio focus policy](https://developer.android.com/media/optimize/audio-focus) recommends not playing multiple audio content at the same time. Also, keep in mind that multiple media sessions would make Android Auto and Bluetooth devices with display to show your app multiple times, because they list up media sessions, not media apps.

## Backward compatibility with platform and legacy session APIs

An active `https://developer.android.com/reference/android/media/session/MediaSession.html` is internally created with the session for backwards compatibility. It's used to handle incoming connections and commands from `https://developer.android.com/reference/android/media/session/MediaController.html` and legacy `
android.support.v4.media.session.MediaControllerCompat` instances.

While Media3 allows setting controller-specific configurations (such as available commands, custom layout, media button preferences, session activity, session extras, and playback exceptions) for each connected `https://developer.android.com/reference/androidx/media3/session/MediaController`, all platform and legacy controllers interact with this single, shared platform session.

Because all platform and legacy controllers share this one platform session, controller-specific settings cannot be pushed to individual platform or legacy controllers (calls to controller-specific setters with a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()` are ignored). Instead, to dynamically configure the shared platform session, apps can:

- Use `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` as the target controller in controller-specific methods (such as `https://developer.android.com/reference/androidx/media3/session/MediaSession#setAvailableCommands(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.session.SessionCommands,androidx.media3.common.Player.Commands)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(androidx.media3.session.MediaSession.ControllerInfo,java.util.List<androidx.media3.session.CommandButton>)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setCustomLayout(androidx.media3.session.MediaSession.ControllerInfo,java.util.List<androidx.media3.session.CommandButton>)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionActivity(androidx.media3.session.MediaSession.ControllerInfo,android.app.PendingIntent)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionExtras(androidx.media3.session.MediaSession.ControllerInfo,android.os.Bundle)`, or `https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlaybackException(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.common.PlaybackException)`). When a media notification controller is connected, settings applied to it are routed directly to the shared platform session and reflected across all platform controllers.
- Use session-wide methods such as `https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(java.util.List<androidx.media3.session.CommandButton>)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setCustomLayout(java.util.List<androidx.media3.session.CommandButton>)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionExtras(android.os.Bundle)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionActivity(android.app.PendingIntent)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlaybackException(androidx.media3.common.PlaybackException)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#sendError(androidx.media3.session.SessionError)`, and `https://developer.android.com/reference/androidx/media3/session/MediaSession#broadcastCustomCommand(androidx.media3.session.SessionCommand,android.os.Bundle)`.
- Configure initial commands, media button preferences, custom layout, session extras, or session activity for the platform session when the media notification controller connects in `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onConnect(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)` or `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onConnectAsync(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)` via `https://developer.android.com/reference/androidx/media3/session/MediaSession.ConnectionResult.AcceptedResultBuilder`.

## Backward compatibility with platform and legacy controller APIs

In addition to `https://developer.android.com/reference/androidx/media3/session/MediaController`, the session also supports connections from the platform and legacy controller APIs - `https://developer.android.com/reference/android/media/session/MediaController.html` and `
android.support.v4.media.session.MediaControllerCompat`. However, `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` may not be precise for these controllers. See `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` for the details.

Neither an unknown package name nor an unknown UID mean that you should disallow a connection or commands per se. For SDK levels where such issues happen, session tokens can only be obtained by trusted controllers (e.g. Bluetooth, Auto, ...). This means only trusted controllers can connect and an app can accept such controllers in the same way as with legacy sessions.

## Summary

| ### Nested types |
|---|
| `public final class https://developer.android.com/reference/androidx/media3/session/MediaSession.Builder` A builder for `https://developer.android.com/reference/androidx/media3/session/MediaSession`. |
| `public interface https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback` A callback to handle incoming commands from `https://developer.android.com/reference/androidx/media3/session/MediaController`. |
| `public final class https://developer.android.com/reference/androidx/media3/session/MediaSession.ConnectionResult` A result for `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onConnectAsync(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)` to denote the set of available commands and the media button preferences for a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo`. |
| `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi public class https://developer.android.com/reference/androidx/media3/session/MediaSession.ConnectionResult.AcceptedResultBuilder` A builder for `https://developer.android.com/reference/androidx/media3/session/MediaSession.ConnectionResult` instances to accept a connection. |
| `public final class https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` Information of a `https://developer.android.com/reference/androidx/media3/session/MediaController` or a `https://developer.android.com/reference/androidx/media3/session/MediaBrowser`. |
| `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi public final class https://developer.android.com/reference/androidx/media3/session/MediaSession.MediaItemsWithStartPosition` Representation of a list of `https://developer.android.com/reference/androidx/media3/common/MediaItem` and where to start playing. |
| `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi public interface https://developer.android.com/reference/androidx/media3/session/MediaSession.ProgressReporter` A progress reporter to report progress for a custom command sent by a controller. |

| ### Public methods |
|---|---|
| `final void` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#broadcastCustomCommand(androidx.media3.session.SessionCommand,android.os.Bundle)(https://developer.android.com/reference/androidx/media3/session/SessionCommand command, https://developer.android.com/reference/android/os/Bundle.html args)` Broadcasts a custom command to all connected controllers. |
| `static int` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#getBitmapDimensionLimit(android.content.Context)(https://developer.android.com/reference/android/content/Context.html context)` Returns the bitmap dimension limit in pixels. |
| `final https://developer.android.com/reference/androidx/media3/common/util/BitmapLoader` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#getBitmapLoader()()` Returns the `https://developer.android.com/reference/androidx/media3/common/util/BitmapLoader`. |
| `final https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo>` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#getConnectedControllers()()` Returns the list of connected controllers. |
| `final @https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#getControllerForCurrentRequest()()` Returns the `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` for the controller that sent the current request for a `https://developer.android.com/reference/androidx/media3/common/Player` method. |
| `https://guava.dev/releases/snapshot-android/api/docs/com/google/common/collect/ImmutableList.html<https://developer.android.com/reference/androidx/media3/session/CommandButton>` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#getCustomLayout()()` Returns the custom layout of the session. |
| `final https://developer.android.com/reference/java/lang/String.html` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#getId()()` Returns the session ID. |
| `https://guava.dev/releases/snapshot-android/api/docs/com/google/common/collect/ImmutableList.html<https://developer.android.com/reference/androidx/media3/session/CommandButton>` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaButtonPreferences()()` Returns the media button preferences of the session. |
| `@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()()` Returns the `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` of the media notification controller. |
| `final https://developer.android.com/reference/android/media/session/MediaSession.Token.html` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#getPlatformToken()()` Returns the platform `https://developer.android.com/reference/android/media/session/MediaSession.Token.html` of the `https://developer.android.com/reference/android/media/session/MediaSession.html` created internally by this session. |
| `final https://developer.android.com/reference/androidx/media3/common/Player` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#getPlayer()()` Returns the underlying `https://developer.android.com/reference/androidx/media3/common/Player`. |
| `final @https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/android/app/PendingIntent.html` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#getSessionActivity()()` Returns the `https://developer.android.com/reference/android/app/PendingIntent.html` to launch `https://developer.android.com/reference/androidx/media3/session/MediaSession.Builder#setSessionActivity(android.app.PendingIntent)` or null if not set. |
| `https://developer.android.com/reference/android/os/Bundle.html` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#getSessionExtras()()` Returns the session extras. |
| `final boolean` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#getShowPlayButtonIfPlaybackIsSuppressed()()` Returns whether a play button is shown if playback is `https://developer.android.com/reference/androidx/media3/common/Player#getPlaybackSuppressionReason()`. |
| `final https://developer.android.com/reference/androidx/media3/session/SessionToken` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#getToken()()` Returns the `https://developer.android.com/reference/androidx/media3/session/SessionToken` for creating `https://developer.android.com/reference/androidx/media3/session/MediaController` instances. |
| `final boolean` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#isAutoCompanionController(androidx.media3.session.MediaSession.ControllerInfo)(https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo)` Returns whether the given `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` belongs to an Android Auto companion app controller. |
| `final boolean` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#isAutomotiveController(androidx.media3.session.MediaSession.ControllerInfo)(https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo)` Returns whether the given `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` belongs to an Automotive OS controller. |
| `boolean` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#isMediaNotificationController(androidx.media3.session.MediaSession.ControllerInfo)( https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo )` Returns whether the given media controller info belongs to the media notification controller. |
| `final void` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#release()()` Releases the session and disconnects all connected controllers. |
| `final https://guava.dev/releases/snapshot-android/api/docs/com/google/common/util/concurrent/ListenableFuture.html<https://developer.android.com/reference/androidx/media3/session/SessionResult>` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#sendCustomCommand(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.session.SessionCommand,android.os.Bundle)( https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller, https://developer.android.com/reference/androidx/media3/session/SessionCommand command, https://developer.android.com/reference/android/os/Bundle.html args )` Sends a custom command to a specific controller. |
| `final void` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#sendError(androidx.media3.session.SessionError)(https://developer.android.com/reference/androidx/media3/session/SessionError sessionError)` Sends a non-fatal error to all connected controllers. |
| `final void` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#sendError(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.session.SessionError)( https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo, https://developer.android.com/reference/androidx/media3/session/SessionError sessionError )` Sends a non-fatal error to the given controller. |
| `final void` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#setAvailableCommands(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.session.SessionCommands,androidx.media3.common.Player.Commands)( https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller, https://developer.android.com/reference/androidx/media3/session/SessionCommands sessionCommands, https://developer.android.com/reference/androidx/media3/common/Player.Commands playerCommands )` Sets the new available commands for the controller. |
| `final void` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#setCustomLayout(java.util.List<androidx.media3.session.CommandButton>)(https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/session/CommandButton> layout)` Sets the custom layout for all controllers. |
| `final https://guava.dev/releases/snapshot-android/api/docs/com/google/common/util/concurrent/ListenableFuture.html<https://developer.android.com/reference/androidx/media3/session/SessionResult>` | `@https://checkerframework.org/api/com/google/errorprone/annotations/CanIgnoreReturnValue.html https://developer.android.com/reference/androidx/media3/session/MediaSession#setCustomLayout(androidx.media3.session.MediaSession.ControllerInfo,java.util.List<androidx.media3.session.CommandButton>)( https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller, https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/session/CommandButton> layout )` Sets the custom layout for the given controller. |
| `final void` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(java.util.List<androidx.media3.session.CommandButton>)(https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/session/CommandButton> mediaButtonPreferences)` Sets the media button preferences for all controllers. |
| `final https://guava.dev/releases/snapshot-android/api/docs/com/google/common/util/concurrent/ListenableFuture.html<https://developer.android.com/reference/androidx/media3/session/SessionResult>` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi @https://checkerframework.org/api/com/google/errorprone/annotations/CanIgnoreReturnValue.html https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(androidx.media3.session.MediaSession.ControllerInfo,java.util.List<androidx.media3.session.CommandButton>)( https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller, https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/session/CommandButton> mediaButtonPreferences )` Sets the media button preferences for the given controller. |
| `final void` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlaybackException(androidx.media3.common.PlaybackException)(@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/common/PlaybackException playbackException)` Sets the playback exception for all connected controllers. |
| `final void` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlaybackException(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.common.PlaybackException)( https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo, @https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/common/PlaybackException playbackException )` Sets the playback exception for the given controller. |
| `final void` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlayer(androidx.media3.common.Player)(https://developer.android.com/reference/androidx/media3/common/Player player)` Sets the underlying `https://developer.android.com/reference/androidx/media3/common/Player` for this session to dispatch incoming events to. |
| `final void` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionActivity(android.app.PendingIntent)(@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/android/app/PendingIntent.html activityPendingIntent)` Updates the session activity that was set when `https://developer.android.com/reference/androidx/media3/session/MediaSession.Builder#setSessionActivity(android.app.PendingIntent)`. |
| `final void` | `@https://developer.android.com/reference/androidx/media3/common/util/UnstableApi https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionActivity(androidx.media3.session.MediaSession.ControllerInfo,android.app.PendingIntent)( https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller, @https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/android/app/PendingIntent.html activityPendingIntent )` Sends the session activity to the connected controller. |
| `final void` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionExtras(android.os.Bundle)(https://developer.android.com/reference/android/os/Bundle.html sessionExtras)` Sets the `https://developer.android.com/reference/androidx/media3/session/MediaSession#getSessionExtras()` and sends them to connected controllers. |
| `final void` | `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionExtras(androidx.media3.session.MediaSession.ControllerInfo,android.os.Bundle)( https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller, https://developer.android.com/reference/android/os/Bundle.html sessionExtras )` Sends the session extras to the connected controller. |

## Public methods

### broadcastCustomCommand

```
public final void broadcastCustomCommand(SessionCommand command, Bundle args)
```

Broadcasts a custom command to all connected controllers.

This call immediately returns and doesn't wait for a result from the controller.

A command is not accepted if it is not a custom command.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/SessionCommand command` | A custom command. |
| `https://developer.android.com/reference/android/os/Bundle.html args` | A `https://developer.android.com/reference/android/os/Bundle.html` for additional arguments. May be empty. |

| See also |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession#sendCustomCommand(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.session.SessionCommand,android.os.Bundle)` |   |

### getBitmapDimensionLimit

```
public static int getBitmapDimensionLimit(Context context)
```

Returns the bitmap dimension limit in pixels. Bitmaps with width or height larger than this will be scaled down to fit within the limit.

| Parameters |
|---|---|
| `https://developer.android.com/reference/android/content/Context.html context` | The context in which the bitmap dimension limit is defined. |

| Returns |
|---|---|
| `int` | The bitmap dimension limit in pixels. |

### getBitmapLoader

```
@UnstableApi
public final BitmapLoader getBitmapLoader()
```

Returns the `https://developer.android.com/reference/androidx/media3/common/util/BitmapLoader`.

### getConnectedControllers

```
public final List<MediaSession.ControllerInfo> getConnectedControllers()
```

Returns the list of connected controllers.

Interoperability: The returned list includes connected platform or legacy controllers (where `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#getControllerVersion()` equals `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`). Note that when the media notification controller is connected, requests from System UI are attributed to `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` and System UI is not included in this list.

This method must be called from the thread associated with the `https://developer.android.com/reference/androidx/media3/common/Player#getApplicationLooper()`.

### getControllerForCurrentRequest

```
public final @Nullable MediaSession.ControllerInfo getControllerForCurrentRequest()
```

Returns the `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` for the controller that sent the current request for a `https://developer.android.com/reference/androidx/media3/common/Player` method.

This method will return a non-null value while `https://developer.android.com/reference/androidx/media3/common/Player` methods triggered by a controller are executed.

Note: If you want to prevent a controller from calling a method, specify the `https://developer.android.com/reference/androidx/media3/session/MediaSession.ConnectionResult#availablePlayerCommands()` in `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onConnectAsync(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)` or set them via `https://developer.android.com/reference/androidx/media3/session/MediaSession#setAvailableCommands(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.session.SessionCommands,androidx.media3.common.Player.Commands)`.

Interoperability: For requests originating from System UI, this method returns the `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` of `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` when the notification controller is connected.

This method must be called on the `https://developer.android.com/reference/androidx/media3/common/Player#getApplicationLooper()` of the underlying player.

| Returns |
|---|---|
| `@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` | The `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` of the controller that sent the current request, or ` null` if not applicable. |

### getCustomLayout

```
@UnstableApi
public ImmutableList<CommandButton> getCustomLayout()
```

Returns the custom layout of the session.

This method will be deprecated, prefer to use `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaButtonPreferences()` instead. Note that the media button preferences use `https://developer.android.com/reference/androidx/media3/session/CommandButton#slots()` to define the allowed button placement.

For informational purpose only. Mutations on the `https://developer.android.com/reference/android/os/Bundle.html` of either a `https://developer.android.com/reference/androidx/media3/session/CommandButton` or a `https://developer.android.com/reference/androidx/media3/session/SessionCommand` do not have effect. To change the custom layout use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setCustomLayout(java.util.List<androidx.media3.session.CommandButton>)` or `https://developer.android.com/reference/androidx/media3/session/MediaSession#setCustomLayout(androidx.media3.session.MediaSession.ControllerInfo,java.util.List<androidx.media3.session.CommandButton>)`.

This method must be called from the thread associated with the `https://developer.android.com/reference/androidx/media3/common/Player#getApplicationLooper()`.

### getId

```
public final String getId()
```

Returns the session ID.

### getMediaButtonPreferences

```
@UnstableApi
public ImmutableList<CommandButton> getMediaButtonPreferences()
```

Returns the media button preferences of the session.

For informational purpose only. Mutations on the `https://developer.android.com/reference/android/os/Bundle.html` of either a `https://developer.android.com/reference/androidx/media3/session/CommandButton` or a `https://developer.android.com/reference/androidx/media3/session/SessionCommand` do not have effect. To change the media button preferences use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(androidx.media3.session.MediaSession.ControllerInfo,java.util.List<androidx.media3.session.CommandButton>)`.

This method must be called from the thread associated with the `https://developer.android.com/reference/androidx/media3/common/Player#getApplicationLooper()`.

### getMediaNotificationControllerInfo

```
@UnstableApi
public @Nullable MediaSession.ControllerInfo getMediaNotificationControllerInfo()
```

Returns the `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` of the media notification controller.

Use this controller info to set `https://developer.android.com/reference/androidx/media3/session/MediaSession#setAvailableCommands(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.session.SessionCommands,androidx.media3.common.Player.Commands)` and `https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(androidx.media3.session.MediaSession.ControllerInfo,java.util.List<androidx.media3.session.CommandButton>)` that are consistently applied to the media notification on all API levels.

Available `https://developer.android.com/reference/androidx/media3/session/SessionCommands` of the media notification controller are used to enable or disable buttons of the media button preferences before they are passed to the `https://developer.android.com/reference/androidx/media3/session/MediaNotification.Provider#createNotification(androidx.media3.session.MediaSession,com.google.common.collect.ImmutableList<androidx.media3.session.CommandButton>,androidx.media3.session.MediaNotification.ActionFactory,androidx.media3.session.MediaNotification.Provider.Callback)`. Disabled command buttons are not converted to notification actions when using `https://developer.android.com/reference/androidx/media3/session/DefaultMediaNotificationProvider`. This affects the media notification displayed by System UI below API 33.

The available session commands of the media notification controller are used to maintain custom actions of the platform session (see `PlaybackStateCompat.getCustomActions()`). Command buttons of the media button preferences are disabled or enabled according to the available session commands. Disabled command buttons are not converted to custom actions of the platform session. This affects the media notification displayed by System UI [starting with API 33](https://developer.android.com/about/versions/13/behavior-changes-13#playback-controls).

The available `https://developer.android.com/reference/androidx/media3/common/Player.Commands` are intersected with the actual available commands of the underlying player to determine the playback actions of the platform session (see `PlaybackStateCompat.getActions()`).

In addition to available commands and media button preferences, this controller info serves as the designated target to dynamically configure the single shared platform session for `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionActivity(androidx.media3.session.MediaSession.ControllerInfo,android.app.PendingIntent)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionExtras(androidx.media3.session.MediaSession.ControllerInfo,android.os.Bundle)`, `https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlaybackException(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.common.PlaybackException)`, and `https://developer.android.com/reference/androidx/media3/session/MediaSession#setCustomLayout(androidx.media3.session.MediaSession.ControllerInfo,java.util.List<androidx.media3.session.CommandButton>)`. Configurations applied to this controller info update the shared platform session and reflect across all connected platform controllers.

This method must be called from the thread associated with the `https://developer.android.com/reference/androidx/media3/common/Player#getApplicationLooper()`.

### getPlatformToken

```
@UnstableApi
public final MediaSession.Token getPlatformToken()
```

Returns the platform `https://developer.android.com/reference/android/media/session/MediaSession.Token.html` of the `https://developer.android.com/reference/android/media/session/MediaSession.html` created internally by this session.

### getPlayer

```
public final Player getPlayer()
```

Returns the underlying `https://developer.android.com/reference/androidx/media3/common/Player`.

This method must be called from the thread associated with the `https://developer.android.com/reference/androidx/media3/common/Player#getApplicationLooper()`.

### getSessionActivity

```
public final @Nullable PendingIntent getSessionActivity()
```

Returns the `https://developer.android.com/reference/android/app/PendingIntent.html` to launch `https://developer.android.com/reference/androidx/media3/session/MediaSession.Builder#setSessionActivity(android.app.PendingIntent)` or null if not set.

This method must be called from the thread associated with the `https://developer.android.com/reference/androidx/media3/common/Player#getApplicationLooper()`.

| Returns |
|---|---|
| `@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/android/app/PendingIntent.html` | The `https://developer.android.com/reference/android/app/PendingIntent.html` to launch an activity belonging to the session. |

### getSessionExtras

```
public Bundle getSessionExtras()
```

Returns the session extras.

For informational purpose only. Mutations on the `https://developer.android.com/reference/android/os/Bundle.html` do not have immediate effect. To change the session extras use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionExtras(android.os.Bundle)` or `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionExtras(androidx.media3.session.MediaSession.ControllerInfo,android.os.Bundle)`.

This method must be called from the thread associated with the `https://developer.android.com/reference/androidx/media3/common/Player#getApplicationLooper()`.

### getShowPlayButtonIfPlaybackIsSuppressed

```
@UnstableApi
public final boolean getShowPlayButtonIfPlaybackIsSuppressed()
```

Returns whether a play button is shown if playback is `https://developer.android.com/reference/androidx/media3/common/Player#getPlaybackSuppressionReason()`.

### getToken

```
public final SessionToken getToken()
```

Returns the `https://developer.android.com/reference/androidx/media3/session/SessionToken` for creating `https://developer.android.com/reference/androidx/media3/session/MediaController` instances.

### isAutoCompanionController

```
@UnstableApi
public final boolean isAutoCompanionController(MediaSession.ControllerInfo controllerInfo)
```

Returns whether the given `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` belongs to an Android Auto companion app controller.

Note: This is not a security validation.

Interoperability: If an Android Auto companion app controller connects as a platform or legacy controller (see `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`), it interacts via the shared platform session. In this case, controller-specific settings (such as custom layout or media button preferences) cannot be set directly for the controller; configure the shared platform session instead (e.g. via `https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(java.util.List<androidx.media3.session.CommandButton>)` or `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()`).

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo` | The controller info of the connected controller. |

| Returns |
|---|---|
| `boolean` | True if the controller into belongs to a connected Auto companion client app. |

### isAutomotiveController

```
@UnstableApi
public final boolean isAutomotiveController(MediaSession.ControllerInfo controllerInfo)
```

Returns whether the given `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo` belongs to an Automotive OS controller.

Note: This is not a security validation.

Interoperability: If an Automotive OS controller connects as a platform or legacy controller (see `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`), it interacts via the shared platform session. In this case, controller-specific settings (such as custom layout or media button preferences) cannot be set directly for the controller; configure the shared platform session instead (e.g. via `https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(java.util.List<androidx.media3.session.CommandButton>)` or `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()`).

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo` | The controller info of the connected controller. |

| Returns |
|---|---|
| `boolean` | True if the controller into belongs to a connected Automotive OS controller. |

### isMediaNotificationController

```
@UnstableApi
public boolean isMediaNotificationController(
    MediaSession.ControllerInfo controllerInfo
)
```

Returns whether the given media controller info belongs to the media notification controller.

See `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo` | The controller info. |

| Returns |
|---|---|
| `boolean` | Whether the controller info belongs to the media notification controller. |

### release

```
public final void release()
```

Releases the session and disconnects all connected controllers.

The session must not be used after calling this method.

Releasing the session removes the session's listeners from the player but does not `https://developer.android.com/reference/androidx/media3/common/Player#stop()` or `https://developer.android.com/reference/androidx/media3/common/Player#release()` the player. An app can further use the player after the session is released and needs to make sure to eventually release the player.

### sendCustomCommand

```
public final ListenableFuture<SessionResult> sendCustomCommand(
    MediaSession.ControllerInfo controller,
    SessionCommand command,
    Bundle args
)
```

Sends a custom command to a specific controller.

The result from `https://developer.android.com/reference/androidx/media3/session/MediaController.Listener#onCustomCommand(androidx.media3.session.MediaController,androidx.media3.session.SessionCommand,android.os.Bundle)` will be returned.

A command is not accepted if it is not a custom command.

Interoperability: This call has no effect when called for a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller` | The controller to send the custom command to. |
| `https://developer.android.com/reference/androidx/media3/session/SessionCommand command` | A custom command. |
| `https://developer.android.com/reference/android/os/Bundle.html args` | A `https://developer.android.com/reference/android/os/Bundle.html` for additional arguments. May be empty. |

| Returns |
|---|---|
| `https://guava.dev/releases/snapshot-android/api/docs/com/google/common/util/concurrent/ListenableFuture.html<https://developer.android.com/reference/androidx/media3/session/SessionResult>` | A `https://guava.dev/releases/snapshot-android/api/docs/com/google/common/util/concurrent/ListenableFuture.html` of `https://developer.android.com/reference/androidx/media3/session/SessionResult` from the controller. |

| See also |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession#broadcastCustomCommand(androidx.media3.session.SessionCommand,android.os.Bundle)` |   |

### sendError

```
@UnstableApi
public final void sendError(SessionError sessionError)
```

Sends a non-fatal error to all connected controllers.

See `https://developer.android.com/reference/androidx/media3/session/MediaSession#sendError(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.session.SessionError)` for sending an error to a specific controller only.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/SessionError sessionError` | The session error. |

### sendError

```
@UnstableApi
public final void sendError(
    MediaSession.ControllerInfo controllerInfo,
    SessionError sessionError
)
```

Sends a non-fatal error to the given controller.

This will call `https://developer.android.com/reference/androidx/media3/session/MediaController.Listener#onError(androidx.media3.session.MediaController,androidx.media3.session.SessionError)` of the given connected controller.

When an error is sent to `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` or a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`, the error of the `https://developer.android.com/reference/android/media/session/PlaybackState.html` of the platform session is updated accordingly.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo` | The controller to send the error to. |
| `https://developer.android.com/reference/androidx/media3/session/SessionError sessionError` | The session error. |

### setAvailableCommands

```
public final void setAvailableCommands(
    MediaSession.ControllerInfo controller,
    SessionCommands sessionCommands,
    Player.Commands playerCommands
)
```

Sets the new available commands for the controller.

This is a synchronous call. Changes in the available commands take effect immediately regardless of the controller notified about the change through `https://developer.android.com/reference/androidx/media3/common/Player.Listener#onAvailableCommandsChanged(androidx.media3.common.Player.Commands)` and `https://developer.android.com/reference/androidx/media3/session/MediaController.Listener#onAvailableSessionCommandsChanged(androidx.media3.session.MediaController,androidx.media3.session.SessionCommands)`.

Note that `playerCommands` will be intersected with the `https://developer.android.com/reference/androidx/media3/common/Player#getAvailableCommands()` of the underlying `https://developer.android.com/reference/androidx/media3/common/Player` and the controller will only be able to call the commonly available commands.

Interoperability: Calling this method for a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()` updates internal command permissions for that controller, but does not alter the visible playback actions or custom actions of the shared platform session. To update the available commands and actions of the shared platform session, use `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` as the target controller.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller` | The controller to change allowed commands. |
| `https://developer.android.com/reference/androidx/media3/session/SessionCommands sessionCommands` | The new available session commands. |
| `https://developer.android.com/reference/androidx/media3/common/Player.Commands playerCommands` | The new available player commands. |

### setCustomLayout

```
public final void setCustomLayout(List<CommandButton> layout)
```

Sets the custom layout for all controllers.

This method will be deprecated, prefer to use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(java.util.List<androidx.media3.session.CommandButton>)`. Note that the media button preferences use `https://developer.android.com/reference/androidx/media3/session/CommandButton#slots()` to define the allowed button placement.

Calling this method broadcasts the custom layout to all connected Media3 controllers, including the `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()`.

On the controller side, the `https://developer.android.com/reference/androidx/media3/session/CommandButton#isEnabled()` flag is set to `false` if the available commands of a controller do not allow to use a button.

`https://developer.android.com/reference/androidx/media3/session/MediaController.Listener#onCustomLayoutChanged(androidx.media3.session.MediaController,java.util.List<androidx.media3.session.CommandButton>)` is only called if the new custom layout is different to the custom layout the `https://developer.android.com/reference/androidx/media3/session/MediaController#getCustomLayout()`. Note that `https://developer.android.com/reference/android/os/Bundle.html` are ignored when comparing `https://developer.android.com/reference/androidx/media3/session/CommandButton`.

Controllers that connect after calling this method will have the new custom layout available with the initial connection result. A custom layout specific to a controller can be set when the controller `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onConnectAsync(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)` by using an `https://developer.android.com/reference/androidx/media3/session/MediaSession.ConnectionResult.AcceptedResultBuilder`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/session/CommandButton> layout` | The ordered list of `https://developer.android.com/reference/androidx/media3/session/CommandButton`. |

### setCustomLayout

```
@CanIgnoreReturnValue
public final ListenableFuture<SessionResult> setCustomLayout(
    MediaSession.ControllerInfo controller,
    List<CommandButton> layout
)
```

Sets the custom layout for the given controller.

This method will be deprecated, prefer to use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(androidx.media3.session.MediaSession.ControllerInfo,java.util.List<androidx.media3.session.CommandButton>)`. Note that the media button preferences use `https://developer.android.com/reference/androidx/media3/session/CommandButton#slots()` to define the allowed button placement.

Make sure to have the session commands of all command buttons of the custom layout `https://developer.android.com/reference/androidx/media3/session/MediaController#getAvailableSessionCommands()`. Include the custom session commands a controller should be able to send in the available commands of the connection result `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onConnectAsync(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)`. The `https://developer.android.com/reference/androidx/media3/session/CommandButton#isEnabled()` flag is set according to the available commands of the controller and overrides a value that may have been set by the app.

On the controller side, `https://developer.android.com/reference/androidx/media3/session/MediaController.Listener#onCustomLayoutChanged(androidx.media3.session.MediaController,java.util.List<androidx.media3.session.CommandButton>)` is only called if the new custom layout is different to the custom layout the `https://developer.android.com/reference/androidx/media3/session/MediaController#getCustomLayout()`. Note that this comparison uses `https://developer.android.com/reference/androidx/media3/session/CommandButton#equals(java.lang.Object)` and therefore ignores `https://developer.android.com/reference/androidx/media3/session/CommandButton#extras()`.

On the controller side, the `https://developer.android.com/reference/androidx/media3/session/CommandButton#isEnabled()` flag is set to `false` if the available commands of the controller do not allow to use a button.

Interoperability: This call has no effect when called for a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`. To set the custom layout of the platform session, use `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` as the target controller or use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setCustomLayout(java.util.List<androidx.media3.session.CommandButton>)`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller` | The controller for which to set the custom layout. |
| `https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/session/CommandButton> layout` | The ordered list of `https://developer.android.com/reference/androidx/media3/session/CommandButton`. |

### setMediaButtonPreferences

```
@UnstableApi
public final void setMediaButtonPreferences(List<CommandButton> mediaButtonPreferences)
```

Sets the media button preferences for all controllers.

Calling this method broadcasts the media button preferences to all connected Media3 controllers, including the `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()`.

On the controller side, the `https://developer.android.com/reference/androidx/media3/session/CommandButton#isEnabled()` flag is set to `false` if the available commands of a controller do not allow to use a button.

`https://developer.android.com/reference/androidx/media3/session/MediaController.Listener#onMediaButtonPreferencesChanged(androidx.media3.session.MediaController,java.util.List<androidx.media3.session.CommandButton>)` is only called if the new media button preferences are different to the media button preferences the `https://developer.android.com/reference/androidx/media3/session/MediaController#getMediaButtonPreferences()`. Note that `https://developer.android.com/reference/android/os/Bundle.html` are ignored when comparing `https://developer.android.com/reference/androidx/media3/session/CommandButton`.

Controllers that connect after calling this method will have the new media button preferences available with the initial connection result. Media button preferences specific to a controller can be set when the controller `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onConnectAsync(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)` by using an `https://developer.android.com/reference/androidx/media3/session/MediaSession.ConnectionResult.AcceptedResultBuilder`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/session/CommandButton> mediaButtonPreferences` | The ordered list of `https://developer.android.com/reference/androidx/media3/session/CommandButton`. |

### setMediaButtonPreferences

```
@UnstableApi
@CanIgnoreReturnValue
public final ListenableFuture<SessionResult> setMediaButtonPreferences(
    MediaSession.ControllerInfo controller,
    List<CommandButton> mediaButtonPreferences
)
```

Sets the media button preferences for the given controller.

Make sure to have the session commands of all command buttons of the media button preferences `https://developer.android.com/reference/androidx/media3/session/MediaController#getAvailableSessionCommands()`. Include the custom session commands a controller should be able to send in the available commands of the connection result `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onConnectAsync(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)`. The `https://developer.android.com/reference/androidx/media3/session/CommandButton#isEnabled()` flag is set according to the available commands of the controller and overrides a value that may have been set by the app.

On the controller side, `https://developer.android.com/reference/androidx/media3/session/MediaController.Listener#onMediaButtonPreferencesChanged(androidx.media3.session.MediaController,java.util.List<androidx.media3.session.CommandButton>)` is only called if the new media button preferences are different to the media button preferences the `https://developer.android.com/reference/androidx/media3/session/MediaController#getMediaButtonPreferences()`. Note that this comparison uses `https://developer.android.com/reference/androidx/media3/session/CommandButton#equals(java.lang.Object)` and therefore ignores `https://developer.android.com/reference/androidx/media3/session/CommandButton#extras()`.

On the controller side, the `https://developer.android.com/reference/androidx/media3/session/CommandButton#isEnabled()` flag is set to `false` if the available commands of the controller do not allow to use a button.

Interoperability: This call has no effect when called for a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`. To set the media button preferences of the platform session, use `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` as the target controller or use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setMediaButtonPreferences(java.util.List<androidx.media3.session.CommandButton>)`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller` | The controller for which to set the media button preferences. |
| `https://developer.android.com/reference/java/util/List.html<https://developer.android.com/reference/androidx/media3/session/CommandButton> mediaButtonPreferences` | The ordered list of `https://developer.android.com/reference/androidx/media3/session/CommandButton`. |

### setPlaybackException

```
@UnstableApi
public final void setPlaybackException(@Nullable PlaybackException playbackException)
```

Sets the playback exception for all connected controllers.

The exception set for controllers can be removed by passing null. This also resets any exception that may have been set for a specific controller with `https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlaybackException(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.common.PlaybackException)`.

| Parameters |
|---|---|
| `@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/common/PlaybackException playbackException` | The `https://developer.android.com/reference/androidx/media3/common/PlaybackException` or null. |

| See also |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlaybackException(androidx.media3.session.MediaSession.ControllerInfo,androidx.media3.common.PlaybackException)` |   |

### setPlaybackException

```
@UnstableApi
public final void setPlaybackException(
    MediaSession.ControllerInfo controllerInfo,
    @Nullable PlaybackException playbackException
)
```

Sets the playback exception for the given controller.

When setting a non-null instance, the original player state is overridden. When the player is not in an error state, the exception is used to modify the player state and send it to the controller. If the player is already in an error state, then this exception replaces the original exception and sends the updated player state to the controller.

An exception set for a given controller can be removed by setting null.

Passing in a playback exception that has `https://developer.android.com/reference/androidx/media3/common/PlaybackException#areErrorInfosEqual(androidx.media3.common.PlaybackException,androidx.media3.common.PlaybackException)` to the previously set exception for the given controller, results in a no-op.

Interoperability: This call has no effect when called for a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`. To set the playback exception of the platform session, use `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` as the target controller or use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setPlaybackException(androidx.media3.common.PlaybackException)`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controllerInfo` | The controller for which to set the playback exception. |
| `@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/androidx/media3/common/PlaybackException playbackException` | The `https://developer.android.com/reference/androidx/media3/common/PlaybackException` or null. |

### setPlayer

```
public final void setPlayer(Player player)
```

Sets the underlying `https://developer.android.com/reference/androidx/media3/common/Player` for this session to dispatch incoming events to.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/common/Player player` | A player that handles actual media playback in your app. |

| Throws |
|---|---|
| `https://developer.android.com/reference/java/lang/IllegalArgumentException.html` | if the new player's application looper differs from the current player's looper, or `https://developer.android.com/reference/androidx/media3/common/Player#canAdvertiseSession()` returns false. |
| `https://developer.android.com/reference/java/lang/IllegalStateException.html` | if the new player's application looper differs from the current looper. |

### setSessionActivity

```
@UnstableApi
public final void setSessionActivity(@Nullable PendingIntent activityPendingIntent)
```

Updates the session activity that was set when `https://developer.android.com/reference/androidx/media3/session/MediaSession.Builder#setSessionActivity(android.app.PendingIntent)`.

Note: When a controller is connected to the session that has a version smaller than 1.6.0, then setting the session activity to null has no effect on the controller side.

Interoperability: Setting the session activity also updates the session activity of the shared platform session.

| Parameters |
|---|---|
| `@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/android/app/PendingIntent.html activityPendingIntent` | The pending intent to start the session activity or null. |

| Throws |
|---|---|
| `https://developer.android.com/reference/java/lang/IllegalArgumentException.html` | if the `https://developer.android.com/reference/android/app/PendingIntent.html` passed into this method is `https://developer.android.com/reference/android/app/PendingIntent.html#getActivity(android.content.Context, int, android.content.Intent, int)`. |

### setSessionActivity

```
@UnstableApi
public final void setSessionActivity(
    MediaSession.ControllerInfo controller,
    @Nullable PendingIntent activityPendingIntent
)
```

Sends the session activity to the connected controller.

This call immediately returns and doesn't wait for a result from the controller.

Interoperability: This call has no effect when called for a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`. To set the session activity of the platform session, use `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` as the target controller or use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionActivity(android.app.PendingIntent)`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller` | The controller to send the session activity to. |
| `@https://developer.android.com/reference/androidx/annotation/Nullable https://developer.android.com/reference/android/app/PendingIntent.html activityPendingIntent` | The pending intent to start the session activity. |

| Throws |
|---|---|
| `https://developer.android.com/reference/java/lang/IllegalArgumentException.html` | if the `https://developer.android.com/reference/android/app/PendingIntent.html` passed into this method is `https://developer.android.com/reference/android/app/PendingIntent.html#getActivity(android.content.Context, int, android.content.Intent, int)`. |

### setSessionExtras

```
public final void setSessionExtras(Bundle sessionExtras)
```

Sets the `https://developer.android.com/reference/androidx/media3/session/MediaSession#getSessionExtras()` and sends them to connected controllers.

The initial extras can be set `https://developer.android.com/reference/androidx/media3/session/MediaSession.Builder#setSessionExtras(android.os.Bundle)`.

This call immediately returns and doesn't wait for a result from the controller.

| Parameters |
|---|---|
| `https://developer.android.com/reference/android/os/Bundle.html sessionExtras` | The session extras. |

### setSessionExtras

```
public final void setSessionExtras(
    MediaSession.ControllerInfo controller,
    Bundle sessionExtras
)
```

Sends the session extras to the connected controller.

The initial extras for a specific controller can be set in `https://developer.android.com/reference/androidx/media3/session/MediaSession.Callback#onConnectAsync(androidx.media3.session.MediaSession,androidx.media3.session.MediaSession.ControllerInfo)` when `https://developer.android.com/reference/androidx/media3/session/MediaSession.ConnectionResult.AcceptedResultBuilder#setSessionExtras(android.os.Bundle)`.

This call immediately returns and doesn't wait for a result from the controller.

Interoperability: This call has no effect when called for a `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo#LEGACY_CONTROLLER_VERSION()`. To set the session extras of the platform session, use `https://developer.android.com/reference/androidx/media3/session/MediaSession#getMediaNotificationControllerInfo()` as the target controller or use `https://developer.android.com/reference/androidx/media3/session/MediaSession#setSessionExtras(android.os.Bundle)`.

| Parameters |
|---|---|
| `https://developer.android.com/reference/androidx/media3/session/MediaSession.ControllerInfo controller` | The controller to send the extras to. |
| `https://developer.android.com/reference/android/os/Bundle.html sessionExtras` | The session extras. |