394 Commits

Author SHA1 Message Date
tonihei
db86932781 Use DataSourceBitmapLoader by default
This replaces the SimpleBitmapLoader that can now be deprecated
as it's fully unused and doesn't provide any additional functionality.

#minor-release

PiperOrigin-RevId: 574454636
2023-10-18 06:18:32 -07:00
Googler
ff330bd8e9 Rollback of 4ebe630a80
PiperOrigin-RevId: 574308136
2023-10-17 17:16:01 -07:00
Googler
1a43aa3602 Rollback of 64bd3bcad3
PiperOrigin-RevId: 574290408
2023-10-17 16:01:10 -07:00
bachinger
64bd3bcad3 Send media button events from service directly using MediaSessionImpl
Media button event coming from the `MediaSessionService` are delegated
to the `MediaSessionImpl` and then sent to the session by using the
`MediaSessionStub` directly instead of using the `MediaController`
API.

Splitting the `MediaController.Listener` and `Player.Listener` in
`MediaNotificationManager` got reverted, and both listener are set to the
controller as before. This reverts the change that introduced a
different timing behaviour. It still holds, that a listener
registered on a `MediaController` that calls a method like `play()` is
called immediately and before the call has arrived at the player. This
change works around this behaviour from the library side by calling
`MediaSessionStub` directly with a `ControllerInfo`.

#minor-release

PiperOrigin-RevId: 573918850
2023-10-16 13:52:30 -07:00
bachinger
d5f093f43c Send ConnectionState as in-process bundle if possible
#minor-release

PiperOrigin-RevId: 573849858
2023-10-16 10:15:34 -07:00
bachinger
f53e1bc6f6 Only set the queue when COMMAND_GET_TIMELINE is available
Android Auto shows a queue button when the queue is not empty.
Apps were able to remove this queue button with the legacy API
by not setting the queue of the session.

After this change, removing `COMMAND_GET_TIMELINE` from the commands
of the media notification controller or the session player sets the
queue in the platform session to null.

#minor-release
Issue: androidx/media#339
PiperOrigin-RevId: 573813558
2023-10-16 08:14:38 -07:00
tonihei
d1fc15f207 Avoid bundling PlayerInfo for in-process calls
PlayerInfo bundling is costly and we can add a shortcut for
in-process binder calls where we store the direct object
reference in a live Binder object that can be written to the
Bundle instead of the individual data fields.

#minor-release

PiperOrigin-RevId: 572816784
2023-10-12 01:16:27 -07:00
tonihei
4ebe630a80 Split available command filtering and bundling
A few methods in PlayerInfo and related classes combine filtering
information with bundling in one method. This makes it impossible
to use just the filtering for example and it's also easier to reason
about than two dedicated methods. This change splits these methods
into two parts accordingly.

PiperOrigin-RevId: 572592458
2023-10-11 09:09:11 -07:00
bachinger
7fdc5b22ba Check whether a session is still managed before removing
When the controller of the `MediaNotificationManager` is disconnected,
the session is removed from the service without checking whether the
session hasn't already been removed. This caused flakiness in `MediaSessionServiceTest.addSession()`.

Because there is a public API `MediaSessionService.removeSession()`,
the controller can't make an assumption whether the session is still
contained in the service when being disconnected.

#minor-release

PiperOrigin-RevId: 572568350
2023-10-11 07:27:50 -07:00
bachinger
4dc3db4da3 Add MediaSession.Builder().setPeriodicPositionUpdateEnabled()
This allows to disable periodic position updates when building
the session.

#minor-release

PiperOrigin-RevId: 572531837
2023-10-11 04:10:03 -07:00
tonihei
846117399f Do not interrupt controller thread without a good reason
Interrupting the main thread in particular may be dangerous
as the flag is not cleared after handling the current message.

#minor-release

PiperOrigin-RevId: 572259422
2023-10-10 08:36:40 -07:00
tonihei
fe7c62afe0 Add missing Future cancellation checks
Future.isDone and getDone doesn't imply the Future was successful
and it may have been cancelled or failed.

In case where we handle failure, we should also handle cancellation
to avoid CancellationException to bubble up unchecked.

In demo app code where we use isDone for field initialization, we
want to crash in the failure case (usually security exception where
the connection is disallowed), but we want to gracefully handle
cancellation. Cancellation of these variables usually happens in
Activity.onDestroy/onStop, but methods may be called after this point.

#minor-release

PiperOrigin-RevId: 572178018
2023-10-10 02:14:24 -07:00
bachinger
0b0d02c3e4 Add isAutomotiveController and isAutoCompanionController
Issue: androidx/media#561
Issue: androidx/media#644
Issue: androidx/media#645
PiperOrigin-RevId: 568948230
2023-09-27 13:45:17 -07:00
bachinger
99086b4007 Add default implementation of Callback.onSubscribe
The library already maintains the subscribed controllers internally. This
change adds `MediaLibrarySession.getSubscribedControllers(mediaId)` to
access subscribed controllers for a given media ID.

To accept a subscription, `MediaLibraryService.Callback.onSubscribe` is
required to return `RESULT_SUCCESS`. So far, this isn't the case for the
default implementation of the library.

This change implements `Callback.onSubscribe` to conditionally
provide `RESULT_SUCCESS`. The default calls `Callback.onGetItem(mediaId)` to
assess the availability of the media item. If the app retruns `RESULT_SUCCESS`
with a browsable item, the subscription is accepted. If receiving a valid item
fails, the subscription is rejected.

Issue: androidx/media#561
PiperOrigin-RevId: 568925079
2023-09-27 12:19:34 -07:00
tonihei
77ba0292ad Add position interpolation to MediaControllerImplLegacy
Without this, the position won't udpate until the session sends
a new playback state.

PiperOrigin-RevId: 568889286
2023-09-27 10:23:27 -07:00
bachinger
ffd7bb5639 Resolve and dispatch media button events within Media3
Before this change, media button events are routed from `onStartCommand`
of the `MediaSessionService` to  the `MediaSessionCompat`, resolved by
the legacy library to a session command called on
`MediaSessionCompat.Callback` from where the command is delegated back
to the Media3 session.

With this change the keycode is resolved directly to a Media3 command
that is sent to the session through the media notification controller
of the session.

After this change, a playback or custom command sent to the session
from a notification, either as a pending intent (before API 33) or as
a legacy session command, look the same and the caller is the
media notification controller on all API levels.

PiperOrigin-RevId: 568224123
2023-09-25 08:19:33 -07:00
bachinger
5e05e2ec22 Pass down ControllerInfo from service to session when connecting
With this change, the `ControllerInfo` passed to
`MediaSessionService.onGetSession(ControllerInfo)`
is the same instance that is passed later to all
callback methods of `MediaSession.Callback`.

PiperOrigin-RevId: 568216855
2023-09-25 07:50:12 -07:00
bachinger
742410d517 Use proxy controller to maintain platform session and notification
With this change, the notification controller that is connected by
`MediaNotificationManager`, is used as a proxy controller of the
System UI controller. An app can use the proxy at connection time
and during the lifetime of the session for configuration of the
platform session and the media notification on all API levels.

This includes using custom layout and available player and session
commands of the proxy to maintain the platform session (actions,
custom actions, session extras) and the `MediaNotification.Provider`.

The legacy System UI controller is hidden from the public API,
instead the app interacts with the Media3 proxy:

- System UI is hidden from `MediaSession.getConnectedControllers()`.
- Calls from System UI to methods of `MediaSession.Callback`/
  `MediaLibrarySession.Callback` are mapped to the `ControllerInfo`
  of the proxy controller.
- When `getControllerForCurrentRequest()` is called during an operation of
  System UI the proxy `ControllerInfo` is returned.

PiperOrigin-RevId: 567606117
2023-09-22 06:36:22 -07:00
ibaker
e357d9f218 Don't call MediaSession.Callback.onPostConnect if connecting failed
I spotted that this looked wrong while investigating test various
session test failures. However, changing this logic doesn't seem to
affect the tests so I don't know if the change is an improvement or not.

PiperOrigin-RevId: 566655318
2023-09-19 09:29:40 -07:00
jbibik
39c1ac7f3a Move setAudioAttributes from ExoPlayer to Player
PiperOrigin-RevId: 566607528
2023-09-19 06:08:37 -07:00
christosts
c0e11e0edd Move bitmap loader tests in test
These tests were under androidTest because we needed a functional
BitmapFactory. Robolectric now supports decoding bitmaps so moving them
under tests.

PiperOrigin-RevId: 565181239
2023-09-13 15:40:55 -07:00
bachinger
8c0191d0cb Use media button broadcast receiver above Android 31
This change avoids using a framework API that is deprecated since
API 31 and works around difficulties with this deprecated API on
devices from some manufacturers on API 33/34.

Manually tested with BT headphone connected to:

- Samsung SM-G920F (API 24)
- Pixel (API 28)
- Samsung SM-A515W (API 33)
- Pixel 6 Pro (API 33)

(verified manually with devices and adb output of dumpsys)

Issue: androidx/media#167
PiperOrigin-RevId: 562890206
2023-09-05 14:24:06 -07:00
tianyifeng
32e367fabf Set groupKey for media notification in DefaultMediaNotificationProvider
By doing so, the media notification sent from DefaultMediaNotificationProvider won't be auto-grouped (https://developer.android.com/develop/ui/views/notifications/group#automatic-grouping) with the regular notifications sent from the other places in the app. As the result, when the customer attempts to dismiss the regular notifications (by swiping away), the media notification won't be dismissed as being in the same group.

Issue: androidx/media#549
PiperOrigin-RevId: 561047571
2023-08-29 09:10:12 -07:00
bachinger
6bd3e53e8d Set notification foreground service behaviour starting with API 31
When the foreground service type is set to `mediaPlayiback` this shouldn't
be required. However, some reports from users say that setting the
foreground service behavor fixes some problems on some devices. Setting
it explicitely with this change makes sure users don't have to do that
workaround themselves.

Issue: androidx/media#167
PiperOrigin-RevId: 557608577
2023-08-18 15:09:59 +01:00
tonihei
597de8706d Show play button during playback suppression by default
This changes the default logic of shouldShowPlayButton to show a play
button while the playback is temporarily suppressed. This helps to
provide better UI feedback to the fact that playback stopped and
provides a quick way for users to override the suppression and attempt
to restart playback.

Some apps may want to keep the legacy behavior depending on their app's
needs. Hence, we also add a config parameter to set this behavior both
in MediaSession and our default UI components.

Issue: google/ExoPlayer#11213
PiperOrigin-RevId: 557129171
2023-08-15 17:15:38 +01:00
jbibik
dedccc596e Fix PlayerWrapper's creation of VolumeProviderCompat
When hardware buttons are used to control the volume of the remote device, the call propagates to `MediaSessionCompat.setPlaybackToRemote(volumeProviderCompat)`. However, `volumeProviderCompat` was created incorrectly when the new device volume commands were present (COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS and COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS), i.e. with volumeControlType = `VOLUME_CONTROL_FIXED`. This resulted in `VolumeProviderCompat` which doesn't call `onSetVolumeTo` or `onAdjustVolume` and hence doesn't propagate the calls to the `Player`. Instead, it only worked with the deprecated commands which ensured the volumeControlType was `VOLUME_CONTROL_ABSOLUTE`.

This bug was introduced in c71e4bf1ff (1.0 media 3 release) when `PlayerWrapper`'s call to `createVolumeProviderCompat` was mostly rewritten to handle the new commands, but the two if-statements were not amended. Note: this change fixes the bug only for Android 11 and below. For 12 and above, there is a tracking bug for the regression that was introduced: https://issuetracker.google.com/issues/201546605

http://Issue: androidx/media#554

#minor-release

PiperOrigin-RevId: 554966361
2023-08-10 12:12:09 +00:00
bachinger
17ee5277d5 Only use result.sendError where supported by legacy media library
`MediaLibraryServiceLegacyStub` handles various edge cases by calling
`result.sendError(null)` with the intention to send back an error to
the legacy browser [1].

`MediaBrowserServiceCompat` of the legacy media1 Compat library has an
inner base class `Result` that has a default implementation of
`onErrorSent` that throws an `UnsupportedOperationException` [2].
However, most anonymous inner classes for `Result` created in
`MediaBrowserServiceCompat` do not override `onErrorSent` [3].

Hence Media3 must not call `sendError` in these cases. Instead we call
`sendResult(null)` according to what the default implementation of
the callbacks in `MediaBrowserServiceCompat` do ([4] as an example).

Issue: androidx/media#78
Issue: androidx/media#334

[1] https://github.com/androidx/media/blob/release/libraries/session/src/main/java/androidx/media3/session/MediaLibraryServiceLegacyStub.java#L200
[2] https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java;l=872
[3] https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java;l=578-604?q=MediaBrowserServiceCompat&ss=androidx
[4] https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java;l=1395

PiperOrigin-RevId: 551210137
2023-08-01 14:11:08 +01:00
bachinger
a90ec96425 Use MediaUtils.intersect in MediaControllerImplBase
PiperOrigin-RevId: 550566322
2023-08-01 13:54:11 +01:00
bachinger
2c19399d3e Move command button related helper methods to CommandButton
PiperOrigin-RevId: 550558261
2023-08-01 13:53:09 +01:00
bachinger
d658de5944 Mark media notification controller and filter command buttons
The `MediaNotificationManager` registers an internal controller
to each session. This change marks this controller through its
connection hints and provides an API for apps to hide
implementation details of the marking.

Issue: androidx/media#389
PiperOrigin-RevId: 549712768
2023-08-01 13:44:12 +01:00
tonihei
8064c6df83 Declare foreground service type for DownloadService
This ensures the DownloadService stays functional on Android 14
where defining this type is required. On Android 14 and above,
the app also needs to define the DATA_SYNC permission, which is
added to the demo app as well. In the future, this service type
will no longer be supported and DownloadService needs to be
rewritten with another background scheduling framework.

Issue: google/ExoPlayer#11239
PiperOrigin-RevId: 548994842
2023-07-20 10:23:56 +01:00
Googler
46482e0384 Avoid resetting suppression reason with play/pause on MediaController
Unlike ExoPlayer, when play/pause is called on MediaController, the playback suppression reason is set to default causing a change in it and subsequent callbacks on the Player.Listener.

PiperOrigin-RevId: 548088931
2023-07-20 09:57:51 +01:00
siroberts
ab904bde2d Prevent the creation of CommandButtons without commands.
The setPlayerCommand and setSessionCommand builder methods contain assertions to ensure that at most one of these fields is set, but this left it possible to create a command button with no command by calling build on an empty builder.

PiperOrigin-RevId: 547488248
2023-07-13 15:56:43 +01:00
bachinger
ea21d27a69 Add custom layout to the state of the MediaController
This change also marks the buttons of the custom layout as
enabled/disabled according to available commands in the controller.
Accordingly, `CommandButton.Builder.setEnabled(boolean)` is deprecated
because the value is overridden by the library.

Issue: androidx/media#38

#minor-release

PiperOrigin-RevId: 547272588
2023-07-13 15:47:50 +01:00
ibaker
eed0e42ff8 Remove javadoc @link from non-javadoc comments
Also update type names to match the current names for these types.

PiperOrigin-RevId: 546884049
2023-07-13 15:32:21 +01:00
ibaker
5e96d355e1 Suppress NewApi lint warning on <vector> usage in drawables
PiperOrigin-RevId: 545207308
2023-07-05 09:08:51 +00:00
ibaker
dc311fd0ca Remove IfAny suffix from @Nullable IntDef locals in MCImplBase
We use `@Nullable` for IntDefs in other places and don't use this suffix
elsewhere, so I don't think we need it here either.

PiperOrigin-RevId: 543687285
2023-06-29 22:57:38 +00:00
tonihei
2322462404 Do not trim audio samples by changing their timestamp
MP4 edit lists sometimes ask to start playback between two samples.
If this happens, we currently change the timestamp of the first
sample to zero to trim it (e.g. to display the first frame for a
slightly shorter period of time). However, we can't do this to audio
samples are they have an inherent duration and trimming them this
way is not possible.

#minor-release

PiperOrigin-RevId: 543420218
2023-06-29 22:50:04 +00:00
jbibik
c2d8051662 Cleaner unified PlayerInfo update method in MediaControllerImplBase
`MediaControllerImplBase` has 2 methods for updating listeners about `PlayerInfo` changes - `updatePlayerInfo` (for masking the state) and `onPlayerInfoChanged` (when communicating with the session). There is a set number of listener callbacks related to `PlayerInfo` updates and both methods should go through the same control flow (whether we know that masking will ignore most of them or not).

A unified method `notifyPlayerInfoListenersWithReasons` encapsulates only the shared logic of 2 methods - listeners' callbacks. This ensures that both methods call them in the same order and none are missed out.

PiperOrigin-RevId: 542587879
2023-06-23 16:47:58 +00:00
jbibik
b8ac5b4210 Order MediaControllerImplBase listener callbacks as in ExoPlayerImpl
The callbacks for `PlayerInfo` changes are currently in both `MediaControllerImplBase.updatePlayerInfo` (masking) and `MediaControllerImplBase.onPlayerInfoChanged`. But the order was different between them both and `ExoPlayerImpl.updatePlaybackInfo` which they are trying to mimic.

#minor-release

PiperOrigin-RevId: 542519070
2023-06-22 15:45:21 +00:00
tofunmi
be38670391 Transformer: Decode image in sRGB
The effects pipeline must receive images in the sRGB colorspace due to the color transfers applied in the shaders. Currently the burden to making sure images are in the right colorspaces falls onto apps. This CL ensures that this is not the case anymore.

PiperOrigin-RevId: 542323613
2023-06-22 15:41:55 +00:00
jbibik
b9cc70d9e2 Fixed spelling across various PlayerInfo *ChangeReason fields
PiperOrigin-RevId: 541892788
2023-06-22 15:23:21 +00:00
jbibik
501da109ce Default RepeatMode for conversion is NONE/OFF
Current behaviour causes an app to crash if it receives an unrecognized repeat mode send over the wire. In order to avoid the crash, a sensible default had to be chosen.

For `Player.RepeatMode`, it is `Player.REPEAT_MODE_OFF`, which is the same value we use as default when unbundling `PlayerInfo`.

For `PlaybackStateCompat.RepeatMode`, it is `PlaybackStateCompat.REPEAT_MODE_NONE`, which is what we use in the no-arg `LegacyPlayerInfo` constructor.

Issue: androidx/media#448

#minor-release

PiperOrigin-RevId: 540563792
2023-06-19 16:13:39 +01:00
tonihei
51fb72b00d Replace deprecated NullableType from checkerframework with our own one
The existing NullableType has been deprecated 5 years ago and causes
crashes in Kotlin apps because Kotlin doesn't recognize this annotation
as a nullable type annotation.

While we can't align on a single @Nullable annotation yet, we can at
least replace this one by JSR305's @Nonnull(MAYBE) as it fulfils all
requirements, including full Kotlin compatiblity. To avoid the
cumbersome name, we can redefine it as our own @NullableType
annotation. (We can't use @Nullable to avoid name clashes with the main
@Nullable annotation from AndroidX)

Issue: google/ExoPlayer#6792
PiperOrigin-RevId: 540497469
2023-06-19 16:08:20 +01:00
siroberts
cf21add916 Add missing checkNotNull to bitmapLoader.
#minor-release

PiperOrigin-RevId: 540309118
2023-06-14 20:47:04 +01:00
bachinger
3d674fa2f3 Implement equals/hashCode for CommandButton
#minor-release

PiperOrigin-RevId: 540274932
2023-06-14 20:45:36 +01:00
jbibik
4b5a457790 Notify listeners of error changes when masking in MediaControllerImplBase
Currently, the implementation of `MediaControllerImplBase` differs from `ExoPlayerImpl`. The listeners of the former are notified of player error changes only in `onPlayerInfoChanged` and not `updatePlayerInfo` (masking method). Whereas `ExoPlayerImpl` has one unified method - `updatePlaybackInfo` - which sends the events to all the available listeners.

This change fixes the lack of 2 particular callbacks - `onPlayerErrorChanged` and `onPlayerError`, however, there might be more differences. Ideally, there should be a unified method for oldPlayerInfo/newPlayerInfo comparison-update-notify-listeners flow.

Issue: androidx/media#449

#minor-release

PiperOrigin-RevId: 539961618
2023-06-14 20:32:55 +01:00
tianyifeng
2e2f19351f Add seekPrev and seekNext buttons on the default compact notification
This change is for Android 12 and below, where the buttons are derived from the actions added with the notification. From Android 13 (https://developer.android.com/about/versions/13/behavior-changes-13#playback-controls), the system derives media controls from `PlaybackState` actions.

When adding the actions onto the notification, the logic will iterate all the command buttons. The `COMMAND_KEY_CONPACT_VIEW_INDEX` extra will be checked for each button. If that extra is set for the three buttons on the compact view, then the customized buttons and their order will be used. Otherwise, the compact view will be "seekPrev" (if any), "play/pause" (if any), "seekNext" (if any) buttons (in such order).

Issue: androidx/media#410
PiperOrigin-RevId: 538797874
2023-06-09 13:54:13 +00:00
jbibik
d9764c18ad Allow playback of MediaItems with LocalConfiguration
When initiated by MediaController, it should be possible for `MediaSession` to pass `MediaItems` to the `Player` if they have `LocalConfiguration`. In such case, it is not required to override `MediaSession.Callback.onAddMediaItems`, because the new current default implementation will handle it.

However, in other cases, MediaItem.toBundle() will continue to strip the LocalConfiguration information.

Issue: androidx/media#282

#minor-release

PiperOrigin-RevId: 537993460
2023-06-06 18:08:17 +00:00
ibaker
fa990714fe Remove exoplayer2-specific parts from media3-only files
PiperOrigin-RevId: 537038419
2023-06-02 09:19:32 +00:00