@@ -1128,7 +1128,9 @@ protected MediaSessionServiceLegacyStub getLegacyBrowserService() {
11281128 * @param controller The controller requesting to play.
11291129 */
11301130 /* package */ ListenableFuture <SessionResult > handleMediaControllerPlayRequest (
1131- ControllerInfo controller , boolean callOnPlayerInteractionFinished ) {
1131+ ControllerInfo controller ,
1132+ boolean callOnPlayerInteractionFinished ,
1133+ boolean mustStartForegroundService ) {
11321134 SettableFuture <SessionResult > sessionFuture = SettableFuture .create ();
11331135 ListenableFuture <Boolean > playRequestedFuture = onPlayRequested ();
11341136 playRequestedFuture .addListener (
@@ -1182,6 +1184,26 @@ public void onSuccess(MediaItemsWithStartPosition mediaItemsWithStartPosition) {
11821184 callWithControllerForCurrentRequestSet (
11831185 controllerForRequest ,
11841186 () -> {
1187+ if (mediaItemsWithStartPosition .mediaItems .isEmpty ()) {
1188+ if (mustStartForegroundService ) {
1189+ applicationHandler .postAtFrontOfQueue (
1190+ () -> {
1191+ throw new IllegalArgumentException (
1192+ "Callback.onPlaybackResumption must return non-empty"
1193+ + " MediaItemsWithStartPosition if started from a"
1194+ + " media button receiver. If there is nothing to"
1195+ + " resume playback with, override"
1196+ + " MediaButtonReceiver.shouldStartForegroundService()"
1197+ + " and return false." );
1198+ });
1199+ return ;
1200+ }
1201+ Log .w (
1202+ TAG ,
1203+ "onPlaybackResumption() is trying to resume with empty"
1204+ + " playlist, this will make the resumption notification"
1205+ + " appear broken." );
1206+ }
11851207 MediaUtils .setMediaItemsWithStartIndexAndPosition (
11861208 playerWrapper , mediaItemsWithStartPosition );
11871209 Util .handlePlayButtonAction (playerWrapper );
@@ -1196,21 +1218,33 @@ public void onSuccess(MediaItemsWithStartPosition mediaItemsWithStartPosition) {
11961218
11971219 @ Override
11981220 public void onFailure (Throwable t ) {
1221+ RuntimeException e ;
11991222 if (t instanceof UnsupportedOperationException ) {
1200- Log . w (
1201- TAG ,
1202- "UnsupportedOperationException: Make sure to implement"
1203- + " MediaSession.Callback.onPlaybackResumption() if you add a media"
1204- + " button receiver to your manifest or if you implement the recent "
1205- + " media item contract with your MediaLibraryService." ,
1206- t );
1223+ e =
1224+ new UnsupportedOperationException (
1225+ " Make sure to implement MediaSession.Callback.onPlaybackResumption() "
1226+ + " if you add a media button receiver to your manifest or if you "
1227+ + " implement the recent media item contract with your "
1228+ + " MediaLibraryService." ,
1229+ t );
12071230 } else {
1208- Log .e (
1209- TAG ,
1210- "Failure calling MediaSession.Callback.onPlaybackResumption(): "
1211- + t .getMessage (),
1212- t );
1231+ e =
1232+ new IllegalStateException (
1233+ "Failure calling MediaSession.Callback.onPlaybackResumption(): "
1234+ + t .getMessage (),
1235+ t );
1236+ }
1237+ if (mustStartForegroundService ) {
1238+ // MediaButtonReceiver already called startForegroundService(). If we do not
1239+ // crash ourselves, ForegroundServiceDidNotStartInTimeException will do it
1240+ // for us. Let's at least get a useful stack trace out there.
1241+ applicationHandler .postAtFrontOfQueue (
1242+ () -> {
1243+ throw e ;
1244+ });
1245+ return ;
12131246 }
1247+ Log .e (TAG , Objects .requireNonNull (Log .getThrowableString (e )));
12141248 // Play as requested even if playback resumption fails.
12151249 Util .handlePlayButtonAction (playerWrapper );
12161250 sessionFuture .set (new SessionResult (SessionResult .RESULT_SUCCESS ));
@@ -1448,13 +1482,13 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
14481482 // Double tap detection.
14491483 int keyCode = keyEvent .getKeyCode ();
14501484 boolean isTvApp = context .getPackageManager ().hasSystemFeature (PackageManager .FEATURE_LEANBACK );
1485+ boolean isEventSourceMediaButtonReceiver =
1486+ callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION ;
14511487 boolean doubleTapCompleted = false ;
14521488 switch (keyCode ) {
14531489 case KeyEvent .KEYCODE_MEDIA_PLAY_PAUSE :
14541490 case KeyEvent .KEYCODE_HEADSETHOOK :
1455- if (isTvApp
1456- || callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION
1457- || keyEvent .getRepeatCount () != 0 ) {
1491+ if (isTvApp || isEventSourceMediaButtonReceiver || keyEvent .getRepeatCount () != 0 ) {
14581492 // Double tap detection is only for mobile apps that receive a media button event from
14591493 // external sources (for instance Bluetooth) and excluding long press (repeatCount > 0).
14601494 mediaPlayPauseKeyHandler .flush ();
@@ -1493,11 +1527,15 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
14931527 boolean isDismissNotificationEvent =
14941528 intent .getBooleanExtra (
14951529 MediaNotification .NOTIFICATION_DISMISSED_EVENT_KEY , /* defaultValue= */ false );
1496- return applyMediaButtonKeyEvent (keyEvent , doubleTapCompleted , isDismissNotificationEvent );
1530+ return applyMediaButtonKeyEvent (
1531+ keyEvent , doubleTapCompleted , isDismissNotificationEvent , isEventSourceMediaButtonReceiver );
14971532 }
14981533
14991534 private boolean applyMediaButtonKeyEvent (
1500- KeyEvent keyEvent , boolean doubleTapCompleted , boolean isDismissNotificationEvent ) {
1535+ KeyEvent keyEvent ,
1536+ boolean doubleTapCompleted ,
1537+ boolean isDismissNotificationEvent ,
1538+ boolean mustStartForegroundService ) {
15011539 ControllerInfo controllerInfo = checkNotNull (instance .getMediaNotificationControllerInfo ());
15021540 Runnable command ;
15031541 int keyCode = keyEvent .getKeyCode ();
@@ -1510,10 +1548,15 @@ private boolean applyMediaButtonKeyEvent(
15101548 command =
15111549 getPlayerWrapper ().getPlayWhenReady ()
15121550 ? () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER )
1513- : () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1551+ : () ->
1552+ sessionStub .playForControllerInfo (
1553+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
15141554 break ;
15151555 case KEYCODE_MEDIA_PLAY :
1516- command = () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1556+ command =
1557+ () ->
1558+ sessionStub .playForControllerInfo (
1559+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
15171560 break ;
15181561 case KEYCODE_MEDIA_PAUSE :
15191562 command = () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
@@ -2095,7 +2138,8 @@ public void setPendingPlayPauseTask(ControllerInfo controllerInfo, KeyEvent keyE
20952138 applyMediaButtonKeyEvent (
20962139 keyEvent ,
20972140 /* doubleTapCompleted= */ false ,
2098- /* isDismissNotificationEvent= */ false );
2141+ /* isDismissNotificationEvent= */ false ,
2142+ /* mustStartForegroundService= */ false );
20992143 } else {
21002144 sessionLegacyStub .handleMediaPlayPauseOnHandler (
21012145 checkNotNull (controllerInfo .getRemoteUserInfo ()));
0 commit comments