From a1a4708b57f283abf66a965320738fb17f6e9ca4 Mon Sep 17 00:00:00 2001 From: nift4 Date: Sun, 27 Jul 2025 17:16:48 +0200 Subject: [PATCH] Allow to opt into System UI and bluetooth playback resumption seperately This is a step towards Issue: https://github.com/androidx/media/issues/770 --- .../media3/session/MediaLibraryService.java | 33 ++++++++++++--- .../session/MediaLibrarySessionImpl.java | 6 ++- .../androidx/media3/session/MediaSession.java | 42 ++++++++++++++++--- .../media3/session/MediaSessionImpl.java | 9 +++- 4 files changed, 76 insertions(+), 14 deletions(-) diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaLibraryService.java b/libraries/session/src/main/java/androidx/media3/session/MediaLibraryService.java index 3b00a47376e..4af8d8bdf1b 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaLibraryService.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaLibraryService.java @@ -606,6 +606,24 @@ public Builder setMediaButtonPreferences(List mediaButtonPreferen return super.setMediaButtonPreferences(mediaButtonPreferences); } + /** + * Sets whether to opt into the System UI playback resumption. If this is set to {@code true}, + * {@link MediaSession.Callback#onPlaybackResumption(MediaSession, ControllerInfo, boolean)} + * must be implemented. + * + *

The default is {@code null}. + * + * @param systemUiPlaybackResumptionOptIn Whether to opt into System UI playback resumption + * notification, or {@code null} to determine based on the presence of a {@link + * MediaButtonReceiver} in the manifest. + */ + @UnstableApi + @Override + public Builder setSystemUiPlaybackResumptionOptIn( + @Nullable Boolean systemUiPlaybackResumptionOptIn) { + return super.setSystemUiPlaybackResumptionOptIn(systemUiPlaybackResumptionOptIn); + } + /** * Sets whether a play button is shown if playback is {@linkplain * Player#getPlaybackSuppressionReason() suppressed}. @@ -705,7 +723,8 @@ public MediaLibrarySession build() { checkNotNull(bitmapLoader), playIfSuppressed, isPeriodicPositionUpdateEnabled, - libraryErrorReplicationMode); + libraryErrorReplicationMode, + systemUiPlaybackResumptionOptIn); } } @@ -723,7 +742,8 @@ public MediaLibrarySession build() { BitmapLoader bitmapLoader, boolean playIfSuppressed, boolean isPeriodicPositionUpdateEnabled, - @LibraryErrorReplicationMode int libraryErrorReplicationMode) { + @LibraryErrorReplicationMode int libraryErrorReplicationMode, + @Nullable Boolean systemUiPlaybackResumptionOptIn) { super( context, id, @@ -738,7 +758,8 @@ public MediaLibrarySession build() { bitmapLoader, playIfSuppressed, isPeriodicPositionUpdateEnabled, - libraryErrorReplicationMode); + libraryErrorReplicationMode, + systemUiPlaybackResumptionOptIn); } @Override @@ -756,7 +777,8 @@ public MediaLibrarySession build() { BitmapLoader bitmapLoader, boolean playIfSuppressed, boolean isPeriodicPositionUpdateEnabled, - @LibraryErrorReplicationMode int libraryErrorReplicationMode) { + @LibraryErrorReplicationMode int libraryErrorReplicationMode, + @Nullable Boolean systemUiPlaybackResumptionOptIn) { return new MediaLibrarySessionImpl( this, context, @@ -772,7 +794,8 @@ public MediaLibrarySession build() { bitmapLoader, playIfSuppressed, isPeriodicPositionUpdateEnabled, - libraryErrorReplicationMode); + libraryErrorReplicationMode, + systemUiPlaybackResumptionOptIn); } @Override diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaLibrarySessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaLibrarySessionImpl.java index fde7447f508..25e287707fd 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaLibrarySessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaLibrarySessionImpl.java @@ -81,7 +81,8 @@ public MediaLibrarySessionImpl( BitmapLoader bitmapLoader, boolean playIfSuppressed, boolean isPeriodicPositionUpdateEnabled, - @MediaLibrarySession.LibraryErrorReplicationMode int libraryErrorReplicationMode) { + @MediaLibrarySession.LibraryErrorReplicationMode int libraryErrorReplicationMode, + @Nullable Boolean systemUiPlaybackResumptionOptIn) { super( instance, context, @@ -96,7 +97,8 @@ public MediaLibrarySessionImpl( sessionExtras, bitmapLoader, playIfSuppressed, - isPeriodicPositionUpdateEnabled); + isPeriodicPositionUpdateEnabled, + systemUiPlaybackResumptionOptIn); this.instance = instance; this.callback = callback; this.libraryErrorReplicationMode = libraryErrorReplicationMode; diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java index d9e1a3c8af0..308ea7147e3 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java @@ -461,6 +461,24 @@ public Builder setShowPlayButtonIfPlaybackIsSuppressed( return super.setShowPlayButtonIfPlaybackIsSuppressed(showPlayButtonIfPlaybackIsSuppressed); } + /** + * Sets whether to opt into the System UI playback resumption. If this is set to {@code true}, + * {@link MediaSession.Callback#onPlaybackResumption(MediaSession, ControllerInfo, boolean)} + * must be implemented. + * + *

The default is {@code null}. + * + * @param systemUiPlaybackResumptionOptIn Whether to opt into System UI playback resumption + * notification, or {@code null} to determine based on the presence of a {@link + * MediaButtonReceiver} in the manifest. + */ + @UnstableApi + @Override + public Builder setSystemUiPlaybackResumptionOptIn( + @Nullable Boolean systemUiPlaybackResumptionOptIn) { + return super.setSystemUiPlaybackResumptionOptIn(systemUiPlaybackResumptionOptIn); + } + /** * Sets {@link CommandButton command buttons} that can be added as {@linkplain * MediaMetadata.Builder#setSupportedCommands(List) supported media item commands}. @@ -499,7 +517,8 @@ public MediaSession build() { checkNotNull(bitmapLoader), playIfSuppressed, isPeriodicPositionUpdateEnabled, - MediaLibrarySession.LIBRARY_ERROR_REPLICATION_MODE_NONE); + MediaLibrarySession.LIBRARY_ERROR_REPLICATION_MODE_NONE, + systemUiPlaybackResumptionOptIn); } } @@ -730,7 +749,8 @@ public static ControllerInfo createTestOnlyControllerInfo( BitmapLoader bitmapLoader, boolean playIfSuppressed, boolean isPeriodicPositionUpdateEnabled, - @MediaLibrarySession.LibraryErrorReplicationMode int libraryErrorReplicationMode) { + @MediaLibrarySession.LibraryErrorReplicationMode int libraryErrorReplicationMode, + @Nullable Boolean systemUiPlaybackResumptionOptIn) { synchronized (STATIC_LOCK) { if (SESSION_ID_TO_SESSION_MAP.containsKey(id)) { throw new IllegalStateException("Session ID must be unique. ID=" + id); @@ -752,7 +772,8 @@ public static ControllerInfo createTestOnlyControllerInfo( bitmapLoader, playIfSuppressed, isPeriodicPositionUpdateEnabled, - libraryErrorReplicationMode); + libraryErrorReplicationMode, + systemUiPlaybackResumptionOptIn); } /* package */ MediaSessionImpl createImpl( @@ -769,7 +790,8 @@ public static ControllerInfo createTestOnlyControllerInfo( BitmapLoader bitmapLoader, boolean playIfSuppressed, boolean isPeriodicPositionUpdateEnabled, - @MediaLibrarySession.LibraryErrorReplicationMode int libraryErrorReplicationMode) { + @MediaLibrarySession.LibraryErrorReplicationMode int libraryErrorReplicationMode, + @Nullable Boolean systemUiPlaybackResumptionOptIn) { return new MediaSessionImpl( this, context, @@ -784,7 +806,8 @@ public static ControllerInfo createTestOnlyControllerInfo( sessionExtras, bitmapLoader, playIfSuppressed, - isPeriodicPositionUpdateEnabled); + isPeriodicPositionUpdateEnabled, + systemUiPlaybackResumptionOptIn); } /* package */ MediaSessionImpl getImpl() { @@ -2421,6 +2444,7 @@ default void onError(int seq, SessionError sessionError) throws RemoteException /* package */ ImmutableList mediaButtonPreferences; /* package */ ImmutableList commandButtonsForMediaItems; /* package */ boolean isPeriodicPositionUpdateEnabled; + /* package */ @Nullable Boolean systemUiPlaybackResumptionOptIn; public BuilderBase(Context context, Player player, CallbackT callback) { this.context = checkNotNull(context); @@ -2496,6 +2520,14 @@ public BuilderT setMediaButtonPreferences(List mediaButtonPrefere return (BuilderT) this; } + @CanIgnoreReturnValue + @SuppressWarnings("unchecked") + public BuilderT setSystemUiPlaybackResumptionOptIn( + @Nullable Boolean systemUiPlaybackResumptionOptIn) { + this.systemUiPlaybackResumptionOptIn = systemUiPlaybackResumptionOptIn; + return (BuilderT) this; + } + @CanIgnoreReturnValue @SuppressWarnings("unchecked") public BuilderT setShowPlayButtonIfPlaybackIsSuppressed( diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java index c9c2226b2fd..fdc449a650c 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java @@ -153,6 +153,7 @@ private ImmutableList mediaButtonPreferences; private Bundle sessionExtras; @Nullable private PlaybackException playbackException; + private final @Nullable Boolean systemUiPlaybackResumptionOptIn; @SuppressWarnings("argument.type.incompatible") // Using this in System.identityHashCode public MediaSessionImpl( @@ -169,7 +170,8 @@ public MediaSessionImpl( Bundle sessionExtras, BitmapLoader bitmapLoader, boolean playIfSuppressed, - boolean isPeriodicPositionUpdateEnabled) { + boolean isPeriodicPositionUpdateEnabled, + @Nullable Boolean systemUiPlaybackResumptionOptIn) { Log.i( TAG, "Init " @@ -191,6 +193,7 @@ public MediaSessionImpl( this.bitmapLoader = bitmapLoader; this.playIfSuppressed = playIfSuppressed; this.isPeriodicPositionUpdateEnabled = isPeriodicPositionUpdateEnabled; + this.systemUiPlaybackResumptionOptIn = systemUiPlaybackResumptionOptIn; @SuppressWarnings("nullness:assignment") @Initialized @@ -1079,7 +1082,9 @@ protected MediaSessionServiceLegacyStub getLegacyBrowserService() { } /* package */ boolean canResumePlaybackOnStart() { - return sessionLegacyStub.canResumePlaybackOnStart(); + return systemUiPlaybackResumptionOptIn != null + ? systemUiPlaybackResumptionOptIn + : sessionLegacyStub.canResumePlaybackOnStart(); } /* package */ void setMediaSessionListener(MediaSession.Listener listener) {