456 Commits

Author SHA1 Message Date
bachinger
cbc0ee369f Use connection hints when connecting to MediaBrowserService
Minor improvement to allow an Media3 browser to pass extras
when connecting the initial browser in `MediaControllerImplLegacy`.
Before this change an empty bundle was sent. After this change
the connection hints of the `Media3 browser is used as root hints
of the initial browser that connects when the Media3 browser is
built in `MediaBrowser.buildAsync`.

#cherrypick

PiperOrigin-RevId: 684372552
2024-10-10 03:11:52 -07:00
bachinger
c4ff07e229 Don't advertise commands that are not available
When calling `MediaController.getCommandButtonForMediaItem(MediaItem)`
command buttons with custom commands that are not available
shouldn't be advertised to the controller when connected to
a Media3 session.

In contrast, when connected to a legacy session, available commands
are not enforced when advertising commands. Similarly, when sending
a custom commands that is referenced by a command button for media
items, sending is permitted without the command being available.

This is required because available commands match to custom actions
in `PlaybackStateCompat` of the legacy session. Adding commands for
media items to custom action of the `PlaybackStateCompat` would
interfere with other use cases.

Issue: androidx/media#1474
#cherrypick
PiperOrigin-RevId: 683717723
2024-10-08 12:14:34 -07:00
tonihei
bd192c17ca Restrict CommandButton.iconUri to content Uris
These Uris are not widely supported yet and were only meant to be
used with content Uris. Restricting this more tightly allows
controllers to use these Uris more easily as they have a stricter
guarentee on what it's needed to load these Uris. Media session
apps with different types of Uris can convert them by setting up
a ContentProvider if needed.

Issue: androidx/media#1783
PiperOrigin-RevId: 683539747
2024-10-08 02:53:49 -07:00
bachinger
287f353c87 Move tests relying on unreleased robolectric changes
#cherrypick

PiperOrigin-RevId: 679589647
2024-09-27 07:57:39 -07:00
bachinger
c6434a8276 Add @CanIgnoreReturnValue to MediaSession.BuilderBase
PiperOrigin-RevId: 679536456
2024-09-27 04:32:55 -07:00
tonihei
f4eef88089 Ensure Media3 play calls get FGS exemption
When a Media3 controller calls play on a Media3 session, the call
is currently not routed through the platform session at all.
This means the usual exemption to start a FGS for media controller
interactions is not triggered.

We can manually ensure this exemption is given by sending a custom
platform command to the session. The Media3 session will never
receive this command as it's not a known Media3 custom command.
Sessions will see a single onConnect call with a platform controller
from the sender app though. We can prevent this on newer versions of
the code by dropping the onCommand call early.

PiperOrigin-RevId: 679115247
2024-09-26 05:57:40 -07:00
bachinger
65962dcb37 Add Builder.setMaxCommandsForMediaItems for browser and controller
The max number of commands for media items of a browser or controller
can be configured with `setMaxCommandsForMediaItems(int)` on
`MediaController.Builder` and `MediaBrowser.Builder`. An app that has
only limited space for displaying commands can hint this limit to the
session.

A session can receive the value of a connected browser or controller
through `getMaxCommandsForMediaItems()` of a `ControllerInfo` that
is passed into every callback method. The session can then pick the most
sensible commands instead of making the browser app truncating the commands
rather randomly.

When a `MediaBrowser` is connected against a legacy `MediaBrowserServiceCompat`,
the max number of commands is automatically added to the root hints. Conversely,
the value passed in with the root hints to `MediaLibraryService` by a legacy
`MediaBrowserCompat`, is read into `ControllerInfo` like for a Media3 browser.

Issue: androidx/media#1474

#cherrypick

PiperOrigin-RevId: 679076506
2024-09-26 03:33:01 -07:00
bachinger
b8ec6b836b Add interoperability for media item commands
See https://developer.android.com/training/cars/media#custom_browse_actions

- `MediaMetadata.supportedCommands` is converted to an array list of
  strings into the extras of `MediaDescriptionCompat` with `DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST` and vice versa.

- The set of media item command buttons of a session is passed in the
root hints to a legacy browser that connects. A Media3 browser connected
to a legacy service, gets the set of all commands after calling
`getLibraryRoot()`.

#cherrypick

PiperOrigin-RevId: 678807473
2024-09-25 12:40:22 -07:00
bachinger
686c3fe7f5 Add media item command buttons for Media3 controllers
Note that unlike the legacy implementation, custom media items
commands can be used for any media items with Media3 API. This
includes `MediaItem` instances that are received from sources
different to `MediaLibraryService` methods.

Hence when connected against a Media3 session these custom commands
can be used with a `MediaController` as well as with a `MediaBrowser`.

Interoperability with `MediaBrowserServiceCompat` will
be added in a follow up CL.

Issue: androidx/media#1474
#cherrypick
PiperOrigin-RevId: 678782860
2024-09-25 11:36:11 -07:00
tonihei
8b7c8ffb86 Misc cleanup for session token
Improved string representation for legacy token and
import for unambigious class name.

PiperOrigin-RevId: 678256188
2024-09-24 08:16:08 -07:00
tonihei
43765b7567 Add platform token to Media3 SessionToken
Access is package-private and it will allow the media controller logic
to interact with the underlying platform session directly if needed.

Interop: When a MediaController connects to an older session (before this
change), it won't get the platform token from the session directly.
Many controllers will be set up with a platform or compat token though
and we can simply keep the already known token and use it. The only
cases where we still don't have a platform token in the MediaController
are the cases where the controller is created with a SessionToken based
on a ComponentName.
PiperOrigin-RevId: 678230977
2024-09-24 07:01:39 -07:00
bachinger
b884d7ee9b Handle IllegalArgumentException when setting broadcast receiver
Some devices seem to throw an `IllegalArgumentException` when
attempting to set a valid media button broadcast receiver
for playback resumption. This change handles this exception
as a no-op to avoid crashing the app. As a result, playback
resumption with media keys isn't going to work on these
devices.

This change needs to be reverted once the root cause on these
devices has been fixed (see internal bug ref in source).

Issue: androidx/media#1730
PiperOrigin-RevId: 677904243
2024-09-23 12:53:37 -07:00
bachinger
6bda0da6be Fix sending custom commands with a media browser
When sending a custom command with `browser.sendCustomCommand` when
connected to a legacy browser service, the custom command was delivered to `MediaSessionCompat.Callback.onCustomAction` instead of the service method
`onCustomAction`. The difference is that the service version can return an
async response with a bundle, while the session callback version doesn't
have a return value.

Hence, the service method was never called and it wasn't possible to send
a reponse or signal an error back to the browser. The resulting
`ListanableFuture` simply always immediately resolved to a success.

This change overrides `ListenableFuture<SessionResult> sendCustomCommand(SessionCommand command, Bundle args)` in
`MediaBrowserImplLegacy` to use the `MediaBrowserCompat` method to send
instead of the `MediaControlleCompat` method that was used by the subclass
`MediaControllerImplLegacy`. This involves the service callback instead of the
session callback and enables `MediaBrowser` to get the actual return value
from the legacy service.

Issue: androidx/media#1474
#cherrypick
PiperOrigin-RevId: 676519314
2024-09-19 12:35:42 -07:00
ibaker
3e8ecbf564 Remove @DoNotInline annotations
This is no longer needed now our `compileSdk` implies a new-enough AGP
which does this out-lining automatically via R8. See also
https://issuetracker.google.com/345472586#comment7

There's no plan to remove the `ApiXXX` classes, but no new ones need
to be added.

PiperOrigin-RevId: 675940634
2024-09-18 04:47:39 -07:00
hoisie
dc66c9160c Update some APIs to Use real types in ShadowNotificationManager
NotificationChannel and NotificationChannelGroup are public APIs that were
added in Android O, so at this point it is okay to have them appear in API
signatures.

PiperOrigin-RevId: 675756005
2024-09-17 16:47:36 -07:00
ibaker
c48c051ce2 Handle HEADSETHOOK as 'play' in MediaButtonReceiver.onReceive
Issue: androidx/media#1581

#cherrypick

PiperOrigin-RevId: 662515428
2024-08-13 07:53:04 -07:00
Gaëtan Muller
ed15ab012f Revert changes to androidx.media3.session.legacy 2024-07-24 16:17:02 +01:00
Gaëtan Muller
eefb37a0ba Simplify VolumeProviderCompat.getVolumeProvider() 2024-07-24 16:17:01 +01:00
Gaëtan Muller
0593b36dad Remove MediaSessionImplBase, MediaSessionImplApi18, and MediaSessionImplApi19 2024-07-24 16:17:01 +01:00
Gaëtan Muller
b84a63d318 Fix deprecation message 2024-07-24 16:17:01 +01:00
Gaëtan Muller
7406b78fbc Update javadoc 2024-07-24 16:17:01 +01:00
Gaëtan Muller
28edfcbb69 Remove unnecessary SDK_INT checks 2024-07-24 16:17:01 +01:00
Gaëtan Muller
7289764a65 Remove unnecessary @RequiresApi 2024-07-24 16:17:00 +01:00
bachinger
225ad482b1 Add EXTRAS_KEY_DOWNLOAD_STATUS to MediaContants
This was used in media1 `MediaItemDescription` to indicate the download
status of a media item. When connected to a legacy
`MediaBrowserServiceCompat` the Media3 browsers converts the legacy
media item to a Media3 `MediaItem` and converts the extras of
`MediaDescriptionCompat.extras` to `MediaMetadata.extras`.

#cherrypick

PiperOrigin-RevId: 654625502
2024-07-21 23:41:37 -07:00
ibaker
76db936d68 Enable lint errors in session tests
Also resolve some failures.

Lint checks [aren't enabled in tests by default](http://groups.google.com/g/lint-dev/c/rtjVpqHmY0Y).

This change suppresses `NewApi` failures in Robolectric tests because
these tests only run at 'target SDK' by default (currently 30), but the
lint doesn't understand this and so flags spurious issues with API
usages below this.

PiperOrigin-RevId: 653172059
2024-07-17 03:50:05 -07:00
ibaker
268c8cf6a2 Remove dead code from MediaStyleNotificationHelper now minSdk is 21
Tested using session demo app on API 21 emulator, and checked
notification layout looked correct.

PiperOrigin-RevId: 652403407
2024-07-15 01:56:37 -07:00
ibaker
6a9ff95bf0 Bump minSdk to 21 and remove resulting simple dead code
All other AndroidX libraries have already increased their min SDK to
21.

This change renames private symbols to remove `V21` suffixes and
similar, but doesn't change public or protected symbols with similar
names, to avoid needless breakages/churn on users of the library.

Some of the dead code removal is more complex, so I've split it out
into follow-up changes to make it easier to review.

PiperOrigin-RevId: 651776556
2024-07-12 08:11:01 -07:00
ibaker
2c7f2686b7 Remove stray parenthesis from MediaSession.ControllerInfo.toString()
#cherrypick

PiperOrigin-RevId: 651760391
2024-07-12 06:58:33 -07:00
ibaker
c64dacf3df Transform double-tap of HEADSETHOOK to skip-to-next
As reported in Issue: androidx/media#1493 we already use `HEADSETHOOK` to start
waiting for a double-tap, but we don't consider it for the second tap.

Similarly, we previously considered `PLAY` for the second tap, but not the first.
Only `HEADSETHOOK` and `PLAY_PAUSE` are
[documented](https://developer.android.com/reference/androidx/media3/session/MediaSession#media-key-events-mapping)
to transform double-tap to `seekToNext`. So this change removes the
`PLAY` detection from the second tap.

#cherrypick

PiperOrigin-RevId: 651017522
2024-07-10 07:52:18 -07:00
bachinger
06d61ffaaa Allow an app to decide to not start the service
Once a service is started as a foreground service, it must
be started into the foreground. This means an app can not
suppress a play command arriving from the `MediaButtonReceiver`
once the receiver has started the service.

This change adds a method to the `MediaButtonReceiver` that
allows app to suppress starting the service to not get into
this situation of wanting to suppress the play command after
the service is already started.

Issue: androidx/media#1528
PiperOrigin-RevId: 650280025
2024-07-08 09:44:30 -07:00
bachinger
70c063905c Improve automatic error replication for legacy browsers
This change extends the error replication to a given set of
error codes (not only authentication error), but only
replicates an error if the caller of the service `Callback`
is a legacy controller. It also makes error replication
configurable so that apps can opt-out and report errors
manually instead, or define the error codes for which
replication is enabled.

The change also removes the restriction of `sendError` only
being available for Media3 controllers. Instead, sending an
error to a legacy controller updates the platform playback
state in the same way as sending the error to the media
notification controller.

#cherrypick

PiperOrigin-RevId: 648399237
2024-07-01 09:47:25 -07:00
tianyifeng
6bf2461f80 Update translations
#cherrypick

PiperOrigin-RevId: 648385733
2024-07-01 09:02:21 -07:00
ktrajkovski
e4d4a776c3 Remove deprecated hasPreviousWindow() and hasPrevious() methods.
Use Player.hasPreviousMediaItem() and Player.seekToPreviousMediaItem() instead.

PiperOrigin-RevId: 647664991
2024-06-28 07:02:33 -07:00
ktrajkovski
47b1ca18ed Remove deprecated Player#hasPrevious() method.
Use Player#hasPreviousMediaItem() instead.

#cherrypick

PiperOrigin-RevId: 647336042
2024-06-27 09:04:21 -07:00
tonihei
1d26d1891e Clarify that onPlayWhenReadyChanged can be called again with new reason
Sometimes the reason for the current state may change. If we don't
report this again, users have no way of knowing that the reason
changed.

Also adjust ExoPlayerImpl and MediaControllerImplBase accordingly.
SimpleBasePlayer already adheres to this logic.

#cherrypick

PiperOrigin-RevId: 644970236
2024-06-20 03:58:05 -07:00
bachinger
6cc6444dd9 Use a localized fallback message for known error codes
In the case of a legacy session app providing an error
code different to `ERROR_UNKNOWN` without an error
message, a localized fallback message is provided
instead of ignoring the error.

#cherrypick

PiperOrigin-RevId: 644704680
2024-06-19 04:28:20 -07:00
bachinger
856d394c28 Allow session activity to be set per controller
#cherrypick

PiperOrigin-RevId: 644693533
2024-06-19 03:37:02 -07:00
kimvde
d27549d29a Skip 4K export test on Pixel 3a
PiperOrigin-RevId: 644659699
2024-06-19 01:18:05 -07:00
tonihei
cd2250b5fa Formatting fixes and additional plumbin in legacy controller 2024-06-14 17:47:03 +01:00
Gaëtan Muller
63103978be Make MediaControllerImplLegacy.getMaxSeekToPreviousPosition() return the correct value 2024-06-14 16:21:31 +01:00
bachinger
011ed909c0 Sync and map fatal and non-fatal errors from and to the legacy session
A fatal `PlaybackException` is mapped to a legacy playback state
in state `STATE_ERROR` with error code, message and extras. A
non-fatal error sent to controllers with `MediaSession.sendError`
is synced to the legacy session by setting error code and message
and merging the extras while preserving the rest of the state in
sync with the session player.

Vice versa, a `MediaController` connected to a legacy session receives
fatal errors through `Player.onPlayerErrorChanged()` and non-fatal errors
through `MediaController.Listener.onError()`.

Error codes are mapped in `LegacyConversions`. Values of error codes
in `@SessionError.ErrorCode` come from `@PlaybackExceptino.ErrorCode`
with the exception of `@SessionError.ERROR_IO` and
`@SessionError.ERROR_UNKNOWN`. These already exist in
`@PlaybackException.ErrorCode` and are mapped accordingly to avoid
semantic duplicates.

PiperOrigin-RevId: 642595517
2024-06-12 06:26:00 -07:00
ibaker
2456669398 Propagate media3 session extras to media1 PlaybackStateCompat
PiperOrigin-RevId: 642299178
2024-06-11 09:44:22 -07:00
ibaker
b145a96c79 Clean up unecessary zero-arg toBundle() methods
These are no longer needed now that the `Bundleable` interface has been
removed. Public methods are deprecated, package-private ones are
removed. Callers are migrated in both cases (except where tests
explicitly exist for the deprecated method).

PiperOrigin-RevId: 642294451
2024-06-11 09:28:23 -07:00
ibaker
f554c12099 Remove Bundleable type & Bundleable.Creator<Foo> CREATOR fields
This interface is not used in the library. Callers can use the
`Bundle toBundle()` and `static Foo fromBundle(Bundle)` methods
defined directly on each type instead.

PiperOrigin-RevId: 642271609
2024-06-11 08:05:32 -07:00
bachinger
efff1ee2f1 Add SessionError and use it in service results
This change adds `SessionError` and uses it in `SessionResult`
and `LibraryResult` to report errors to callers.

Constructors and factory method that used a simple `errorCode` to
construct error variants of `SessionResult` and `LibraryResult`
have been overloaded with a variant that uses a `SessionError`
instead. While these methods and constructors are supposed to be
deprecated, they aren't yet deprecated until the newly added
alternative is stabilized.

PiperOrigin-RevId: 642254336
2024-06-11 06:53:42 -07:00
tonihei
acb6a89ff6 Add MediaSession.Callback.onPlayerInteractionFinished
This callback is useful for advanced use cases that care about
which Player calls are batched together. It can be implemented
by triggering this new callback every time a batch of Player
interactions from a controller finished executing.

PiperOrigin-RevId: 642189491
2024-06-11 02:15:20 -07:00
ibaker
b1c6d9ff04 Mark PlayerWrapper as final
This package-private class isn't currently extended, so this change
makes it not possible to be extended in future.

PiperOrigin-RevId: 641270464
2024-06-07 09:23:56 -07:00
tonihei
9547828468 Add missing null check
PiperOrigin-RevId: 640555113
2024-06-05 09:45:28 -07:00
michaelkatz
0ed08a5204 Import string translations for session module
#minor-release

PiperOrigin-RevId: 638224207
2024-05-29 03:39:07 -07:00
tonihei
08006651fa Update session module registration
PiperOrigin-RevId: 636482934
2024-05-23 03:11:51 -07:00