The DefaultMediaNotificationProvider caches the last loaded artwork
bitmap so that the bitmap isn't loaded again when the notification is
updated, e.g., the player is transiting from playing to paused. However,
loading bitmap requests for bitmaps that are already being loaded are
not suppressed. For example, if the notification is updated while the
artwork is still downloading, the same artwork might be downloaded
multiple times.
This change suppresses a bitmap load request if the same artwork is
still being loaded, to avoid additional artwork downloads.
#minor-release
PiperOrigin-RevId: 462572221
We currently clear all pending messages, including the one that flushes
pending commands to the MediaSession. To ensure all commands that have
been called before controller.release() are still sent, we can manually
trigger the flush message from the release call.
Related to handling the final flush because disconnecting the controller,
MediaSessionStub didn't post the removal of the controller to the
session thread, creating a race condition between removing the controller
and actually handling the flush.
Issue: androidx/media#99
PiperOrigin-RevId: 462342860
These constructors are currently very intertwined, passing `this`
references from the constructor of one to the constructor of another
before the first constructor is complete (and so the `this` reference
isn't really valid yet).
This change uses checker framework `@UnderInitialization` and
`@NotOnlyInitialized` annotations to make it more clear that the
references are not available yet. For the one 'direct' access needed
in the second constructor (calling `getApplicationLooper()`) we now
pass the `applicationLooper` directly alongside (to avoid needing to
dereference the reference 'too early').
This change also ensures that where a class hierarchy has a
'dependent' class hierarchy, the 'subclass' instance is always used
(by both subclass and superclass) without casting or manually hiding
the superclass field, by defining an overridable `getFoo()` method
instead and always using it.
#minor-release
PiperOrigin-RevId: 462335043
"seq" is not a well-defined abbreviation and the value is
also an integer, so sequenceNumber is better than just sequence.
PiperOrigin-RevId: 462129581
Add a Builder to constructor DefaultMediaNotificationProvider. The
Builder can also set the provider's:
- notification ID
- notification channel ID
- notification channel name
The change adds an API for apps to set the small icon in notifications.
#minor-release
Issue: androidx/media#104
PiperOrigin-RevId: 462111536
Some commands are run asynchronously and subsequent commands need
to wait until the previous one finished. This can be supported
by returning a Future for each command and using the existing
command execution logic to wait for each Future to complete.
As some MediaSessionStub code is now executed delayed to when it
was originally created, we also need to check if the session is
not released before triggering any actions or sending result codes.
Issue: androidx/media#85
PiperOrigin-RevId: 462101136
The commands currently use a task and a postTask that are chained
together manually. In some cases, e.g. when adding MediaItems,
the postTask is already a chain of commands in itself.
To allow using the entire command handling as a single task
(for simplified queueing), we can change the implementation to
always create a single task. If multiple subtasks need to be
chained together, we can do that by wrapping the method calls.
In case a task is asynchronous, we can also use Futures to
chain them together.
Overall, this is just a refactoring and changes no logic.
Issue: androidx/media#85
PiperOrigin-RevId: 462085724
Some commands may be asynchronous and subsequent commands need to
wait for them to complete before running. This change updates the
queue to use (and listen to) Futures instead of calling Runnables
directly. The commands are currently still added as Runanbles
though, so this change is a no-op.
Also moves the permission check in MediaSessionImpl to before
queueing the command because the permission should be check at
the time of calling the method.
When executing the comamnds in the queue, we need to be careful
to avoid recursion in the same thread (which happens when both
the Future is immediate and running on the correct thread already).
To avoid recursion, we detect this case and loop the commands
instead.
Issue: androidx/media#85
PiperOrigin-RevId: 461827264
After this change the current tracks are sent to the controller as part of
`PlayerInfo` and call `Listener.onTracksChanged()` in case of a change in tracks.
PiperOrigin-RevId: 461578695
This code path is now completely redundant as the same effect can be
achieved by using player.setMediaItem.
#minor-release
PiperOrigin-RevId: 455115567
These calls were not implemented so far as they require a mix of
initial prepareFrom/playFrom calls and addQueueItem. We can also
support clients without queue handling to set single MediaItems.
To make the calls consistent and predictable in the session,
we need to ensure that none of the play/pause/addQueueItem/
removeQueueItem/prepare/playFromXYZ/prepareFromXYZ are called
before the controller is prepared and has media.
#minor-release
PiperOrigin-RevId: 455110246
The service handles three different types of `Intents`. Custom command and media
command Intents created by the library and media button event Intents from other
sources.
Media commands from the library as well as from external sources have the action
set to `android.intent.action.MEDIA_BUTTON`. If the data URI is set and can be
used to identify a session then it is a library Intent. If the Intent is coming
from an external KeyEvent, the service implementation is asked which session to use
by calling `onGetSession(controllerInfo)` with the controller info being an
anonymous legacy controller info.
Intents representing a custom command are always coming from the library and hence
always have a data URI.
Issue: androidx/media#82
PiperOrigin-RevId: 453932972
Some Player implementations have no playlist capability but can still
set a MediaItem for playback. Examples are a MediaController connected
to a legacy MediaSession, ExoPlayer up to 2.12 or MediaPlayer.
To indicate this capability, we need an allowed command in addition
to COMMAND_CHANGE_MEDIA_ITEMS that just allows to set a single item
that replaces everything that is currently played.
#minor-release
PiperOrigin-RevId: 453879626
Use Collections.synchronizedSet() instead of creating a set from a
ConcurrentHashMap because ConcurrentHashMap has a bug in APIs 21/22
that can result in lost updates.
PiperOrigin-RevId: 453696565
These legacy callbacks are currently forwarded to onSetMediaUri which
will be removed in the future.
Also make sure to only call player.prepare/play after the items have
been set.
The calls to onAddQueueItem are also forwarded to onAddMediaItems to
actually allow a session to resolve these items to playable media, which
wasn't possible so far.
PiperOrigin-RevId: 453625204
This provides an (unstable) API for apps to broadcast session extras
Bundle to all connected controllers and set the extras in the legacy
session.
Similar to the custom layout, the extras Bundle is not part of the
Media3 session state. This means that when a Media3 controller
connects to the session after the broadcast, the extras needs to be
sent to that controller in `MediaSession.Callback.onPostConnect(MediaSession session, ControllerInfo controller)`.
PiperOrigin-RevId: 451871731
This value only existed to allow setting media URLs from external sources
(e.g. in a MediaController) so that a player can start playing this item.
Now that we have MediaItem.RequestMetadata.mediaUrl we can remove this value
from MediaMetadata because it's request metadata, not media metadata.
PiperOrigin-RevId: 451857413
The MediaItemFiller is not flexible enough for most realworld usages
because:
- it doesn't allow asynchronous resolution of MediaItems (e.g. to
look up URIs from a database)
- it doesn't allow to batch updates for multiple items or do more
advanced customizations (e.g. expanding a mediaId representing
a playlist to multiple items).
Both issues can be solved by passing in a list of items and
returning a ListenableFuture. The callback itself can also move
into MediaSession.Callback for consistency with the other
callbacks.
PiperOrigin-RevId: 451857319
In some cases it's helpful to have access to the session
(e.g. to get the PlayerWrapper) from within the PostSessionTask
implementations. This change forwards the existing sessionImpl
instance to all these callbacks.
PiperOrigin-RevId: 451857191
Refactors the DefaultMediaNotificationProvider by separating the
selection of actions and building the notification with it.
The custom commands of the custom layout of the session are turned
into notification actions and when received from the notification
converted back to custom session commands that are sent to the
session.
PiperOrigin-RevId: 450404350
We need to pass timestamp for the list of cues so we are defining a new class CueGroup which will store both cues and timestamp.
PiperOrigin-RevId: 449212054
Specifically mention that releasing the session does not release the player and the app needs to take care to release the player.
Issue: androidx/media#73
PiperOrigin-RevId: 448454338
This provides a way for apps to send a custom layout to media3
controllers and legacy controllers by making sure to include custom
actions in the legacy playback state when built in the PlayerWrapper
for broadcasting.
PiperOrigin-RevId: 447967600
A custom action sent by legacy controllers as for instance the System UI mini player arrive at MediaSessionCompat.Callback.onCustomAction() and need to be dispatched to the session callback as a such.
PiperOrigin-RevId: 447486859