Skip to content

Commit 61dcb44

Browse files
committed
Formal API to allow apps to handle playback resumption themselves
This could previously be achieved by inspecting stack trace of onPlaybackResumption() and then returning settable future that will never be set, but this API adds a cleaner way and makes the caveats of this clearer. Issue: #1764
1 parent 2ac334e commit 61dcb44

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

libraries/session/src/main/java/androidx/media3/session/MediaLibrarySessionImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ private void postOrRunOnApplicationHandler(Runnable runnable) {
470470
? checkNotNull(getMediaNotificationControllerInfo())
471471
: controller;
472472
ListenableFuture<MediaSession.MediaItemsWithStartPosition> future =
473-
callback.onPlaybackResumption(instance, controller);
473+
callback.onPlaybackResumption(instance, controller, false);
474474
Futures.addCallback(
475475
future,
476476
new FutureCallback<MediaSession.MediaItemsWithStartPosition>() {

libraries/session/src/main/java/androidx/media3/session/MediaSession.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,6 +1729,17 @@ default ListenableFuture<MediaItemsWithStartPosition> onSetMediaItems(
17291729
new MediaItemsWithStartPosition(mediaItemList, startIndex, startPositionMs)));
17301730
}
17311731

1732+
/**
1733+
* @deprecated Override {@link MediaSession.Callback#onPlaybackResumption(MediaSession,
1734+
* ControllerInfo, boolean)} instead.
1735+
*/
1736+
@Deprecated
1737+
@UnstableApi
1738+
default ListenableFuture<MediaItemsWithStartPosition> onPlaybackResumption(
1739+
MediaSession mediaSession, ControllerInfo controller) {
1740+
return Futures.immediateFailedFuture(new UnsupportedOperationException());
1741+
}
1742+
17321743
/**
17331744
* Returns the playlist with which the player should be prepared when a controller requests to
17341745
* play without a current {@link MediaItem}.
@@ -1750,16 +1761,24 @@ default ListenableFuture<MediaItemsWithStartPosition> onSetMediaItems(
17501761
* Player#COMMAND_GET_CURRENT_MEDIA_ITEM} and either {@link Player#COMMAND_SET_MEDIA_ITEM} or
17511762
* {@link Player#COMMAND_CHANGE_MEDIA_ITEMS} available.
17521763
*
1764+
* <p>If {@code isForPlayback} is true, {@link ManuallyHandlePlaybackResumption} may be set on
1765+
* the future to manually handle playback resumption. Refer to the {@link
1766+
* ManuallyHandlePlaybackResumption} javadoc for more details.
1767+
*
17531768
* @param mediaSession The media session for which playback resumption is requested.
17541769
* @param controller The {@linkplain ControllerInfo controller} that requests the playback
17551770
* resumption. This may be a short living controller created only for issuing a play command
17561771
* for resuming playback.
1772+
* @param isForPlayback Whether playback is going to be started as a result of the future being
1773+
* completed. If false, SystemUI is querying for media item data in order to build and
1774+
* display the resumption notification at boot time.
17571775
* @return The {@linkplain MediaItemsWithStartPosition playlist} to resume playback with.
17581776
*/
17591777
@UnstableApi
1778+
@SuppressWarnings("deprecation") // calling deprecated API for backwards compatibility
17601779
default ListenableFuture<MediaItemsWithStartPosition> onPlaybackResumption(
1761-
MediaSession mediaSession, ControllerInfo controller) {
1762-
return Futures.immediateFailedFuture(new UnsupportedOperationException());
1780+
MediaSession mediaSession, ControllerInfo controller, boolean isForPlayback) {
1781+
return onPlaybackResumption(mediaSession, controller);
17631782
}
17641783

17651784
/**
@@ -1875,6 +1894,25 @@ public int hashCode() {
18751894
}
18761895
}
18771896

1897+
/**
1898+
* Exception that may be set to the future in {@link
1899+
* MediaSession.Callback#onPlaybackResumption(MediaSession, ControllerInfo, boolean)} if the
1900+
* parameter {@code isForPlayback} is true, in order to signal that the app wishes to handle this
1901+
* resumption itself. This means the app is responsible for restoring a playlist, setting it to
1902+
* the player, and starting playback.
1903+
*
1904+
* <p>Do note this has various pitfalls and needs to be used carefully:<br>
1905+
* - {@link MediaSession.Callback#onPlayerInteractionFinished(MediaSession, ControllerInfo,
1906+
* Player.Commands)} will NOT be called for the resumption command.<br>
1907+
* - If playback is not actually resumed in this method, the resumption notification will end up
1908+
* non-functional, but will keep being displayed. This is not a suitable way to disable playback
1909+
* resumption, do not attempt to disable it this way.<br>
1910+
* - If the app takes too long to go into foreground, the grant to go into foreground may have
1911+
* expired.
1912+
*/
1913+
@UnstableApi
1914+
public static class ManuallyHandlePlaybackResumption extends Exception {}
1915+
18781916
/**
18791917
* A result for {@link Callback#onConnect(MediaSession, ControllerInfo)} to denote the set of
18801918
* available commands and the media button preferences for a {@link ControllerInfo controller}.

libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1121,7 +1121,7 @@ protected MediaSessionServiceLegacyStub getLegacyBrowserService() {
11211121
@Nullable
11221122
ListenableFuture<MediaItemsWithStartPosition> future =
11231123
checkNotNull(
1124-
callback.onPlaybackResumption(instance, controllerForRequest),
1124+
callback.onPlaybackResumption(instance, controllerForRequest, true),
11251125
"Callback.onPlaybackResumption must return a non-null future");
11261126
Futures.addCallback(
11271127
future,
@@ -1151,6 +1151,9 @@ public void onFailure(Throwable t) {
11511151
+ " media button receiver to your manifest or if you implement the recent"
11521152
+ " media item contract with your MediaLibraryService.",
11531153
t);
1154+
} else if (t instanceof MediaSession.ManuallyHandlePlaybackResumption) {
1155+
// See ManuallyHandlePlaybackResumption javadoc for details.
1156+
return;
11541157
} else {
11551158
Log.e(
11561159
TAG,

0 commit comments

Comments
 (0)