Commit graph

200 commits

Author SHA1 Message Date
tianyifeng
9c81f3b011 Add BitmapLoader injection in MediaController
Also clean up the strict mode violations of using `BitmapFactory.convertToByteArray` on the main thread.

PiperOrigin-RevId: 496422355
(cherry picked from commit d848d3358a)
2023-01-25 18:17:16 +00:00
ibaker
fdc59304e6 Remove TODO from ControllerInfo - the existing approach is fine
PiperOrigin-RevId: 496398934
(cherry picked from commit 14947539e5)
2023-01-25 18:17:16 +00:00
tonihei
2186b6d325 Avoid sending periodic position updates while paused and not loading
The period updates were introduced to ensure the buffered position is
updated regularly and that any playback position drift is corrected.

None of these updates need to happen while the player is paused or
not loading and we can avoid the constant binder interactions.

PiperOrigin-RevId: 496329800
(cherry picked from commit 0749b05923)
2023-01-25 18:17:15 +00:00
tonihei
097cdded3f Clarify behavior for out-of-bounds indices and align implementations
Some Player methods operate relative to existing indices in the
playlist (add,remove,move,seek). As these operations may be issued
from a place with a stale playlist (e.g. a controller that sends
a command while the playlist is changing), we have to handle out-
of-bounds indices gracefully. In most cases this is already
documented and implemented correctly. However, some cases are not
documented and the existing player implementations don't handle
these cases consistently (or in some cases not even correctly).

PiperOrigin-RevId: 495856295
(cherry picked from commit a1954f7e0a)
2023-01-25 18:17:15 +00:00
tonihei
80be30f511 Clarify and correct allowed multi-threading for some Player methods
Some Player methods like getting the Looper and adding listeners
were always allowed to be called from any thread, but this is
undocumented. This change makes the threading rules of these
methods more explicit.

Removing listeners was never meant to be called from another thread
and we also don't support it safely because final callbacks may
be triggered from the wrong thread. To find potential issues, we
can assert the correct thread when releasing listeners.

Finally, there is a potential race condition when calling addListener
from a different thread at the same time as release, which may lead to
a registered listener that could receive callbacks after the player is
released.

PiperOrigin-RevId: 493843981
(cherry picked from commit 927b2d6a43)
2023-01-25 18:17:14 +00:00
tonihei
71a1254514 Replace MediaMetadata folderType by isBrowsable
The folder type has a mix of information about the item. It shows
whether the item is browsable (type != FOLDER_TYPE_NONE) and
which Bluetooth folder type to set for legacy session information.

It's a lot clearer to split this into a boolean isBrowsable and
use the existing mediaType to map back to the bluetooth folder type
where required.

folderType is not marked as deprecated yet as this would be an API
change, which will be done later.

PiperOrigin-RevId: 493544589
(cherry picked from commit ae8000aeca)
2023-01-25 18:17:11 +00:00
tonihei
8618263b99 Write media type with a custom key to legacy components.
This allows legacy media controllers and browsers to access this
information and legacy sessions and browser services to set this
information.

PiperOrigin-RevId: 492414716
(cherry picked from commit ca4c6efdb7)
2023-01-25 17:50:39 +00:00
christosts
1a9b1c4d35 Reduce log output for failing bitmap loads
Do not log the exception stack traces raised by the BitmapLoader when a
bitmap fails to load, e.g. when the artwork's URI scheme is not
supported by the SimpleBitmapLoader. The logs are kept in place but only
a single line is printed.

#minor-release

PiperOrigin-RevId: 492191461
(cherry picked from commit f768ff970c)
2023-01-25 17:50:39 +00:00
Googler
93694b2283 Decomission ControllerInfoProxy in favor of ControllerInfo.
This CL makes it possible to create a media3 ControllerInfo in test code, which is needed to test several aspects of a media3-based media app. It does this by exposing a test-only static factory method. This is a hacky low-effort approach; a better solution could be to split ControllerInfo up into a public interface that was exposed to client logic, and that they could extend, and a package-private implementation with internal fields like the callback. That's a much bigger change, however.

PiperOrigin-RevId: 491978830
(cherry picked from commit 69093db7f5)
2023-01-25 17:49:34 +00:00
bachinger
665f04d70a Use the artist as the subtitle of the legacy media description
The Bluetooth AVRCP service expects the metadata of the item currently
being played to be in sync with the corresponding media description in
the active item of the queue. The comparison expects the metadata values
of `METADATA_KEY_TITLE` and `METADATA_KEY_ARTIST` [1] to be equal to the
`title` and `subtitle` field of the `MediaDescription` [2] of the
corresponding queue item.

Hence we need to populate the media description accordingly to avoid the
BT service to delay the update for two seconds and log an exception.

[1] https://cs.android.com/android/platform/superproject/+/master:packages/modules/Bluetooth/android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java;l=120
[2] https://cs.android.com/android/platform/superproject/+/master:packages/modules/Bluetooth/android/app/src/com/android/bluetooth/audio_util/MediaPlayerWrapper.java;l=258

Issue: androidx/media#148
PiperOrigin-RevId: 491877806
(cherry picked from commit 2a07a0b445)
2023-01-25 17:49:34 +00:00
rohks
4ecbd77442 Add public constructors to DefaultMediaNotificationProvider
Issue: androidx/media#213

Without a public constructor, it is not possible to extend this class and override its method.

PiperOrigin-RevId: 491673111
(cherry picked from commit f3e450e783)
2023-01-25 17:49:34 +00:00
tianyifeng
d58b4fd6a6 Handle the bitmap loading result with applicationHandler
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 80927260fd)
2023-01-25 17:41:00 +00:00
bachinger
8b0c0761f3 Exclude tracks from PlayerInfo if not changed
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 3d8c52f28d)
2023-01-25 17:41:00 +00:00
tonihei
9829ff3d4c Add helper method to convert platform session token to Media3 token
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 03f0b53cf8)
2023-01-25 17:40:56 +00:00
bachinger
782a69e38c Migrate BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS to Media3
PiperOrigin-RevId: 490376734
(cherry picked from commit 1803d1cdb8)
2023-01-25 17:38:34 +00:00
tianyifeng
d3d99f0194 Load bitmaps for MediaSessionCompat.QueueItem.
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 8ce1213ddd)
2023-01-25 17:38:34 +00:00
tonihei
fa6b8fe06d Do not require package visibility when obtaining SessionTokens
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 c41a5c8420)
2023-01-25 17:37:32 +00:00
tonihei
f4f801a809 Do not require package visibility when connecting to a Media3 session
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 2fd4aac310)
2023-01-25 17:37:31 +00:00
tonihei
91c51fe94d Mark broadcast receivers as not exported
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 22ccc1a128)
2023-01-25 17:37:31 +00:00
tianyifeng
f3268ac8ae Load bitmaps for MediaBrowserCompat.
* 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 4ce171a3cf)
2023-01-25 17:37:31 +00:00
bachinger
73d40e1cfc Add bundling exclusions with unit tests
The exclusion will be used in a follow-up CL when sending PlayerInfo updates.

#minor-release

PiperOrigin-RevId: 488939258
(cherry picked from commit bae509009b)
2023-01-25 17:37:31 +00:00
bachinger
4adfb5f50f Add pending sequence before sending the remote session task
#minor-release

PiperOrigin-RevId: 488885069
(cherry picked from commit e1eb8b6dd8)
2022-11-17 10:06:29 +00:00
tonihei
8cc37db8e5 Rename getVideoSurfaceSize to getSurfaceSize
This better matches the callback name (onSurfaceSizeChanged) and
probably cause less confusion with getVideoSize.

PiperOrigin-RevId: 488669786
(cherry picked from commit 1143edc59a)
2022-11-17 10:06:29 +00:00
tonihei
7f17ff6d00 Ensure listener invocations use final state variable.
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 33bea391d4)
2022-11-10 12:56:11 +00:00
tonihei
58d670d941 Align PlaybackStateCompat states with logic in MediaSessionConnector
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 c5e071e556)
2022-11-10 12:40:37 +00:00
tonihei
824cbf405c Avoid notifying connection twice from MediaControllerImplLegacy.
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 b24161a6f6)
2022-11-10 11:10:11 +00:00
tonihei
dddc6026e9 Wait with PlayerInfo updates until all pending operations are done
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 0b4ba3e3a6)
2022-11-09 17:29:31 +00:00
christosts
707c2d894d MediaController: Add missing event flags (2/2)
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 c403b4ce7c)
2022-11-09 14:58:49 +00:00
michaelkatz
8270dd4536 Changed MediaController to return last estimated position while paused
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 9336b95bf4)
2022-11-07 11:36:36 +00:00
Googler
b780635c0b Add 'Player.getVideoSurfaceSize' that returns the size of the surface
on which the video is rendered.

Design Doc: go/aaos-mu-media-dd

PiperOrigin-RevId: 485884772
2022-11-03 15:50:19 +00:00
rohks
5ac4700c9a Update notification when timeline changes
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 2633f37a2f)
2022-11-03 14:37:30 +00:00
christosts
96a25a76a1 Clean imports in MediaControllerImplLegacy
Remove static imports to constants and imports to intdefs, to make the
code more readable.

PiperOrigin-RevId: 485592288
(cherry picked from commit 8db6b71805)
2022-11-02 14:45:12 +00:00
tianyifeng
f5afec955a Load bitmaps for MediaMetadataCompat and handle the metadata updates.
* 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 77fedd8d7d)
2022-11-01 18:43:26 +00:00
andrewlewis
690ebb3dcd Upgrade dackka and fix some generation errors
#minor-release

PiperOrigin-RevId: 484483080
(cherry picked from commit 3069d8130b)
2022-10-28 10:03:56 +00:00
bachinger
dddb4841af Set BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED automatically
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 4c9ca8fad1)
2022-10-27 17:20:06 +00:00
bachinger
1c81587398 Use MediaBrowserCompat.rootHints as connections hints
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 21022c77be)
2022-10-27 11:50:03 +00:00
tianyifeng
88a413b2cb Add injection of BitmapLoader from MediaSession.
* 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 3f69df72db)
2022-10-25 13:21:08 +00:00
ibaker
373c23c11b Create NotificationChannel in DefaultMediaNotificationProvider.Api26
The inner class avoids a verification failure, which can lead to slower
execution at runtime.

PiperOrigin-RevId: 483639417
(cherry picked from commit 026aea7d3d)
2022-10-25 11:54:05 +00:00
microkatz
9fbc464ce3 Merge pull request #141 from tzugen:patch-4
PiperOrigin-RevId: 483395026
(cherry picked from commit e2a77f7be9)
2022-10-31 11:28:21 +00:00
bachinger
adf264c7c0 Minor simplification when setting metadata to platform session
PiperOrigin-RevId: 482805730
(cherry picked from commit a47f530b92)
2022-10-21 15:56:34 +00:00
tianyifeng
1ce13aa721 Add CacheBitmapLoader in the session module
* 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 ca4edff1fd)
2022-10-21 14:28:35 +00:00
christosts
0727b1f6f2 Use Service.stopForeground(int) on API 24+
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 601eaba7a6)
2022-10-19 13:41:26 +00:00
christosts
ba84c2a09c MediaController: Add missing event flags (1/2)
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 46d5a0e33b)
2022-10-18 15:54:54 +00:00
bachinger
fc1089f68a Migrate media constants from androidx.media.util.MediaConstants
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 006a519a0e)
2022-10-13 11:18:46 +00:00
christosts
0ceec3ebb9 MediaControllerImplBase: clean imports
Remove static imports to constants and imports to intdefs, to make the
code more readable.

PiperOrigin-RevId: 479594144
(cherry picked from commit 36e12fbadb)
2022-10-07 16:07:50 +00:00
aquilescanta
506653bbcc Fix typo in MediaController javadoc
PiperOrigin-RevId: 479268879
(cherry picked from commit 0beccb6e14)
2022-10-06 10:21:12 +00:00
christosts
1cfeddc369 Misc fix on DefaultMediaNotificationProviderTest
PiperOrigin-RevId: 479079184
(cherry picked from commit bf948db669)
2022-10-05 17:22:40 +00:00
Googler
9842c273e9 Allow using different notification IDs for different media sessions
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 7783c6e4f7)
2022-10-04 07:38:38 +00:00
bachinger
05ebdb9211 Don't start the service in the foreground with a pause intent
`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 acd9e581c4)
2022-09-26 14:56:00 +00:00
bachinger
cc6c6aa62b Call callback future listeners on app handler
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 74124f48ea)
2022-09-23 17:34:25 +00:00