Before this change, the bitmap loading result with mainHandler, in which we set the metadata to `MediaSessionCompat`. However, the `MediaSessionCompat` is not thread safe, all calls should be made from the same thread. In the other calls to `MediaSessionCompat`, we ensure that they are on the application thread (which may be or may not be main thread), so we should do the same for `setMetadata` when bitmap arrives.
Also removes a comment in `DefaultMediaNotificationProvider` as bitmap request caching is already moved to CacheBitmapLoader.
PiperOrigin-RevId: 490524209
(cherry picked from commit 80927260fd46413b7d1efafed72360b10049af2a)
This change includes a change in the `IMediaController.aidl` file and needs
to provide backwards compatibility for when a client connects that is of an older or
newer version of the current service implementation.
This CL proposes to create a new AIDL method `onPlayerInfoChangedWithExtensions`
that is easier to extend in the future because it does use an `Bundle` rather than
primitives. A `Bundle` can be changed in a backward/forwards compatible way
in case we need further changes.
The compatibility handling is provided in `MediaSessionStub` and `MediaControllerStub`. The approach is not based on specific AIDL/Binder features but implemented fully in application code.
Issue: androidx/media#102
#minor-release
PiperOrigin-RevId: 490483068
(cherry picked from commit 3d8c52f28d5d3ef04c14868e15036563a9fc662d)
This avoids that apps have to depend on the legacy compat support
library when they want to make this conversion.
Also add a version to both helper methods that takes a Looper to
give apps the option to use an existing Looper, which should be
much faster than spinning up a new thread for every method call.
Issue: androidx/media#171
PiperOrigin-RevId: 490441913
(cherry picked from commit 03f0b53cf823bb4878f884c055b550b52b9b57ab)
When receiving the `onTimelineChanged` callback, we convert the timeline to the list of `QueueItem`s, where decoding a bitmap is needed for building each of the `QueueItem`s. The strategy is similar to what we did in <unknown commit> for list of `MediaBrowserCompat.MediaItem` - set the queue item list until the bitmaps decoding for all the `MediaItem`s are completed.
PiperOrigin-RevId: 490283587
(cherry picked from commit 8ce1213ddddb98e0483610cfeaeba3daa5ad9a78)
The only reason this is required at the moment is to set the
process UID field in the token, that is supposed to make it easier
for controller apps to identify the session. However, if this
visibility is not provided, it shouldn't stop us from creating
the controller for this session.
Also docuement more clearly what UID means in this context.
PiperOrigin-RevId: 490184508
(cherry picked from commit c41a5c842080a7e75b9d92acc06d583bd20c7abb)
When we currently call SessionToken.createSessionToken with a legacy
token, we call the package manager to get the process UID. This
requires visiblity to the target package, which may not be available
unless the target runs a service known to the controller app.
However, when connecting to a Media3, this UID doesn't have to be
known, so we can move the call closer to where it's needed to
avoid the unncessary visibility check.
In addition, a legacy session may reply with unknown result code
to the session token request, which we should handle as well.
One of the constructor can be removed since it was only used from
a test.
PiperOrigin-RevId: 489917706
(cherry picked from commit 2fd4aac310787d1a57207b5142a0ab08d5e1a2a5)
They are called from the system only and don't need to be exported
to be visible to other apps.
PiperOrigin-RevId: 489210264
(cherry picked from commit 22ccc1a1286803868970fb2b1eafe63e9c669a5c)
* Transforms the `ListenableFuture<LibraryResult<MediaItem>>` and `ListenableFuture<LibraryResult<List<MediaItem>>>` to `ListenableFuture<MediaBrowserCompat.MediaItem>` and `ListenableFuture<List<MediaBrowserCompat.MediaItem>>`, and the result will be sent out when `ListenableFuture` the `MediaBrowserCompat.MediaItem` (or the list of it) is fulfilled.
* Add `artworkData` to the tests in `MediaBrowserCompatWithMediaLibraryServiceTest`.
PiperOrigin-RevId: 489205547
(cherry picked from commit 4ce171a3cfef7ce1f533fdc0b7366d7b18ef44d1)
The exclusion will be used in a follow-up CL when sending PlayerInfo updates.
#minor-release
PiperOrigin-RevId: 488939258
(cherry picked from commit bae509009bd62554876ecb7485708e50af4eaa2a)
This better matches the callback name (onSurfaceSizeChanged) and
probably cause less confusion with getVideoSize.
PiperOrigin-RevId: 488669786
(cherry picked from commit 1143edc59ac96ec8524e8203d9445dbb0f006630)
The MediaControllerImplBase listener invocations currently use the
class member state that can change if one of the listener method
implementations changes the state recursively.
Updating the listener invocations to use a final local variable
ensures all listeners get consistent updates.
PiperOrigin-RevId: 487503373
(cherry picked from commit 33bea391d42cb5669e6d2c97c0553f3c0c63467b)
Creating the PlaybackStateCompat from a media3 Player state is done
already by the MediaSessionConnector (and used widely). The media3
session module should set the same states under the same circumstances
to ensure compatiblity and consistency.
PlaybackStateCompat changes made in media3 session:
- Use STATE_STOPPED when player is ended instead of STATE_PAUSED
- Use STATE_PLAYING when playback is suppressed temporarily.
- Set the playback speed to 0 if the player is not playing.
- Add extras for mediaId and user-set playback speed.
Part of the problem was that Player.isPlaying() was used to check
the state. Unfortunately, MockPlayer.isPlaying() is implemented in
a way that makes it hard to test these changes, because the value
is set independently of playbackState, playWhenReady and suppression
reason. To be able to write consistent, logical tests, this change
also removes the independent setting of isPlaying in MockPlayer to
align it better with a real player. This requires to update some
other tests to use alternative methods.
PiperOrigin-RevId: 487500859
(cherry picked from commit c5e071e556931331cc780fda5177d556d51ff3da)
The connection to a legacy MediaSession may receive additional
onSessionReady callbacks that are treated as additional state updates.
We currently also set the "notifyConnected" flag for these updates
even though we are connected already, causing an IllegalStateException.
Fix the exception by not setting this flag.
We can also remove the wording about "locked" updates since this class
operates everything on a single application thread.
Issue: androidx/media#49
PiperOrigin-RevId: 487487286
(cherry picked from commit b24161a6f6af184840d9eae7a63276b73a4a4d80)
Accepting a PlayerInfo while the MediaController is masking its state
means we are reverting all masking changes we've made earlier. This
only makes sense if the update already contains the masked operation.
If multiple operations are in flight (or are sent from the session
while they are in flight), we need to wait until all of them are
handled before accepting new updates.
In cases where a new update from the session excludes the Timeline
and the masked state is incompatible with the new update, we also
risk an exception if we accept the update too early.
PiperOrigin-RevId: 487266899
(cherry picked from commit 0b4ba3e3a6130253b801ddc231501168efce8901)
This is the follow-up commit where the onEvents callback
raised by MediaController contains the missing events, for the
case where MediaController is connected to a legacy MediaSession.
#minor-release
PiperOrigin-RevId: 487231996
(cherry picked from commit c403b4ce7ce9a2964ff754bb394782cc36fb882d)
The method getCurrentPosition() may return a lesser position during pause than the previous retrieved value due to ipc call delay in playerInfo update. Users see track position jump backwards at pause. Fixed to return last estimated position while paused if have not received updated playerInfo. Code is deduped to point getContentPosition() to getCurrentPosition() when !isPlayingAd.
PiperOrigin-RevId: 486617341
(cherry picked from commit 9336b95bf4355c4b1e43f95879d9af45cf90cd19)
Notification buttons for next/previous should change based on the new index of the currently played media item after another media item is added or removed from a playlist.
Issue: androidx/media#130
PiperOrigin-RevId: 485869144
(cherry picked from commit 2633f37a2f95ff38bede573ede83cfa123cb5eb9)
Remove static imports to constants and imports to intdefs, to make the
code more readable.
PiperOrigin-RevId: 485592288
(cherry picked from commit 8db6b71805c817f8fc868139199329529975df6e)
* Add `Listener` in `MediaSession` with method `onNotificationRefreshRequired(MediaSession)`.
* Add `MediaSessionService` as the listener of the `MediaSession` when `MediaSession` is added to `MediaSessionService`
* Load bitmap when update metadata in `MediaSessionLegacyStub` and call `onNotificationRefreshRequired` when bitmap asynchronously arrives.
PiperOrigin-RevId: 485376145
(cherry picked from commit 77fedd8d7d511ff97b0441aa9136d0f1aaecef4b)
This root extra needs to be set by apps manually in media1 and we
can do that automatically in Media3 based on the available session
commands.
#minor-release
PiperOrigin-RevId: 484286833
(cherry picked from commit 4c9ca8fad1c4d4c475a0baee243c099204bc23af)
In Media3 there is the useful concept of connection hints that a
client can set when building the session and that are sent to the
service and passed to the `Callback.onConnect()` method when the
browser connects.
These connection hints are then included in the `ControllerInfo`
object that later will be passed to every callback method and the
implementor can then take decisions specific to these connection
hints.
These connection hints are not available in media1. However, when
an app creates a `MediaBrowserCompat` object, the constructor takes
a rootHint object that is sent to
`MediaBrowserServiceCompat.onGetRoot()`.
This change uses the browser rootHints as the connection hints when
creating the `ControllerInfo` for legacy browsers and makes them
available to the `MediaLibrarySession.Callback` domain methods in
the same way as connection hints of a Media3 browser.
PiperOrigin-RevId: 484220748
(cherry picked from commit 21022c77be44fefeaa25ef9fb72be7d48e51a0bc)
* Add `BitmapLoader` in `MediaSession.Builder` and `MediaLibrarySession.Builder`.
* Pass `BitmapLoader` into the constructor of `MediaSession`, `MediaSessionImpl`, `MediaLibrarySession` and `MediaLibrarySessionImpl`.
* Add an interface method `loadBitmapFromMetadata(MediaMetadata)` in `BitmapLoader`.
* Remove the reference of `BitmapLoader` in `DefaultMediaNotificationProvider`.
PiperOrigin-RevId: 483654596
(cherry picked from commit 3f69df72db7a4aa481dd315f008375148f548805)
The inner class avoids a verification failure, which can lead to slower
execution at runtime.
PiperOrigin-RevId: 483639417
(cherry picked from commit 026aea7d3d85406ef9acf4e65cfffbc5e683a762)
* Add `CacheBitmapLoader`.
* Add `CacheBitmapLoaderTest`.
* Remove the `BitmapLoadRequest` and some bitmap caching logic in `DefaultMediaNotificationProvider` since we moved all of them in `CacheBitmapLoader`.
* Modify `DefaultMediaNotificationProviderTest`.
PiperOrigin-RevId: 482787445
(cherry picked from commit ca4edff1fd61c58ce5c56f9bbd9ff80ce8a6670c)
The MediaNotficationManager stops the service from the foreground
calling Service.stopForeground(boolean) which is deprecated in API 33.
This change calls Service.stopForeground(int), which was added in API
24.
#minor-release
PiperOrigin-RevId: 482190332
(cherry picked from commit 601eaba7a6dcce963d5a3547d939ea41404ad3fe)
This is the first commit out of two. This change adds the missing event
flags for the onEvents() callback when MediaController is connected to a
media3 session (see MediaControllerImplBase). I updated the
MediaControllerListenerTest and MediaControllerStateMaskingTest with
assertions that on onEvents() is called alongside individual
Player.Listener callbacks.
There will be a follow-up change for the case where a MediaController is
connected to a legacy MediaSession (MediaControllerImplLegacy). I've
split this in two separate changes to make the size of the commit
manageable for reviewing.
#minor-release
PiperOrigin-RevId: 481933437
(cherry picked from commit 46d5a0e33bd562cd9e6420b342a68bf112847f83)
Adds root extras and metadata extras to MockMediaLibraryService and MockMediaBrowserCompatService and completed test cases for asserting
interoperability with a media1 or Media3 browser.
PiperOrigin-RevId: 480854842
(cherry picked from commit 006a519a0e83d5b9e4262a5bbc228c02b3c9cf5f)
Remove static imports to constants and imports to intdefs, to make the
code more readable.
PiperOrigin-RevId: 479594144
(cherry picked from commit 36e12fbadb7b274f770a5904675493300c8fa89c)
When a media service currently produces multiple media sessions, the notification of the second session overwrites the notification of the first one, because all sessions use the same notification ID. When we use different notification IDs for different sessions, multiple media notifications can be up at the same time, which means that they can both be controlled at the same time.
PiperOrigin-RevId: 478709069
(cherry picked from commit 7783c6e4f71943b543ddb569b120bdbbab362b96)
`PlaybackStateCompat.toKeyCode(command)` was replaced by our
own implementation of `toKeyCode()`. The legacy implementation used PLAY and PAUSE, while the new implementation uses PLAY_PAUSE. This made `pause` a pending intent that attempt to start the service in the foreground, but `service.startForeground()` won't be called in `MediaNotificationManager.updateNotificationInternal` when paused.
PiperOrigin-RevId: 476895752
(cherry picked from commit acd9e581c494b18f6347f5abb2cf9fc82344c723)
Calling maybeUpdateLegacyErrorState potentially creates a new legacy playback
state which involves calling player methods. This change makes sure that the call
sites of `maybeUpdateLegacyErrorState` are called on the app thread as enforced by
the library.
PiperOrigin-RevId: 476406282
(cherry picked from commit 74124f48ea838fcdb436726ba8337e82abc7552e)
The exception fires when intent resolution fails to find a service which declares an appropriate intent-filter. The existing message is confusing; it's trying to say that the service couldn't be found but the double negative renders it incorrect.
#cleanup
#minor-release
PiperOrigin-RevId: 472736740
(cherry picked from commit 15d3d74e16bf9830e5ae32d0a8edf691474d0b4e)
* Non-standard parameter comment; prefer `/* paramName= */ arg`
(see http://go/bugpattern/ParameterComment) (2 times)
* This catch block catches an exception and re-throws another, but swallows the caught exception rather than setting it as a cause. This can make debugging harder.
(see http://go/bugpattern/UnusedException)
* This comment contains Javadoc or HTML tags, but isn't started with a double asterisk (/**); is it meant to be Javadoc?
(see http://go/bugpattern/AlmostJavadoc)
This CL looks good? Just LGTM and Approve it!
This CL doesn’t look good? This is what you can do:
* Revert this CL, by replying "REVERT: <provide reason>"
* File a bug under go/error-prone-bug for category ErrorProneStyle if there's an issue with the CL content.
* File a bug under go/rosie-bug if there's an issue with how the CL was managed.
* Revert this CL and not get a CL that cleans up these paths in the future by
replying "BLOCKLIST: <provide reason>". This is not reversible! We recommend to
opt out the respective paths in your CL Robot configuration instead:
go/clrobot-opt-out.
This CL was generated by CL Robot - a tool that cleans up code findings
(go/clrobot). The affected code paths have been enabled for CL Robot in //depot/google3/java/com/google/android/libraries/media/METADATA which is reachable following include_presubmits from //depot/google3/third_party/java_src/android_libs/media/METADATA.
Anything wrong with the signup? File a bug at go/clrobot-bug.
#codehealth
Tested:
Local presubmit tests passed.
PiperOrigin-RevId: 472255768
(cherry picked from commit 3a2e0d37177034b3012204ac16cf7b3d4e3436b9)
The assertion asserts against a `Period` and an `AdPlaybackState` which actually
asserts against a resolved ad which is what `ExoPlayerImplInternal` does later and
what gives us a `SEEK_ADJUSTMENT`. However, this assertion is not required at the
moment of masking, because we are sure that the resolved seek results in a content
period and never an ad period.
#minor-release
Issue: androidx/media#122
PiperOrigin-RevId: 471827072
(cherry picked from commit 73f86682e94024c780564dbc287f06d47dfeca26)
`contentTitle` and `contentText` can now be overridden.
Issue: androidx/media#150
PiperOrigin-RevId: 471287701
(cherry picked from commit a45df2fdcb5c0d1e8c6eb8ab23e421e8d9233e68)
Native multidex can only be used for binaries with minSdkVersion of 21 or higher, but minSdkVersion was specified to 16.
PiperOrigin-RevId: 470003836
(cherry picked from commit 5b3f32023063c90a63a5e30eeefab161b0a7f824)
We create an empty CueGroup in many places as default or
where none is needed. Instead, we can define a constant
for this purpose and reuse it.
PiperOrigin-RevId: 467944841
(cherry picked from commit 59895646e03ee15aed5e80fb8e60b7f98a7afe5f)
When the player finishes playback and reaches the STATE_ENDED,
the notification remains visible with a pause button and the
service is kept in the foreground. This is a bug.
With this change, when the player reaches the STATE_ENDED, the
service is stopped from the foreground and a notification is shown
with a play button. If the play icon is tapped, the player will restart
playback of the last played item. Playing the last played item again
is the existing behavior when play/pause commands are received from
the legacy MediaSession (e.g. BT headset buttons).
#minor-release
Issue: google/ExoPlayer#112
PiperOrigin-RevId: 467231509
(cherry picked from commit 7a7e1eb23b4bbf7d0c6c15b2f484434e65cd2c68)