@@ -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 ));
@@ -1468,13 +1502,13 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
14681502 // Double tap detection.
14691503 int keyCode = keyEvent .getKeyCode ();
14701504 boolean isTvApp = context .getPackageManager ().hasSystemFeature (PackageManager .FEATURE_LEANBACK );
1505+ boolean isEventSourceMediaButtonReceiver =
1506+ callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION ;
14711507 boolean doubleTapCompleted = false ;
14721508 switch (keyCode ) {
14731509 case KeyEvent .KEYCODE_MEDIA_PLAY_PAUSE :
14741510 case KeyEvent .KEYCODE_HEADSETHOOK :
1475- if (isTvApp
1476- || callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION
1477- || keyEvent .getRepeatCount () != 0 ) {
1511+ if (isTvApp || isEventSourceMediaButtonReceiver || keyEvent .getRepeatCount () != 0 ) {
14781512 // Double tap detection is only for mobile apps that receive a media button event from
14791513 // external sources (for instance Bluetooth) and excluding long press (repeatCount > 0).
14801514 mediaPlayPauseKeyHandler .flush ();
@@ -1514,11 +1548,18 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
15141548 intent .getBooleanExtra (
15151549 MediaNotification .NOTIFICATION_DISMISSED_EVENT_KEY , /* defaultValue= */ false );
15161550 return keyEvent .getRepeatCount () > 0
1517- || applyMediaButtonKeyEvent (keyEvent , doubleTapCompleted , isDismissNotificationEvent );
1551+ || applyMediaButtonKeyEvent (
1552+ keyEvent ,
1553+ doubleTapCompleted ,
1554+ isDismissNotificationEvent ,
1555+ isEventSourceMediaButtonReceiver );
15181556 }
15191557
15201558 private boolean applyMediaButtonKeyEvent (
1521- KeyEvent keyEvent , boolean doubleTapCompleted , boolean isDismissNotificationEvent ) {
1559+ KeyEvent keyEvent ,
1560+ boolean doubleTapCompleted ,
1561+ boolean isDismissNotificationEvent ,
1562+ boolean mustStartForegroundService ) {
15221563 ControllerInfo controllerInfo = checkNotNull (instance .getMediaNotificationControllerInfo ());
15231564 Runnable command ;
15241565 int keyCode = keyEvent .getKeyCode ();
@@ -1531,10 +1572,15 @@ private boolean applyMediaButtonKeyEvent(
15311572 command =
15321573 getPlayerWrapper ().getPlayWhenReady ()
15331574 ? () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER )
1534- : () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1575+ : () ->
1576+ sessionStub .playForControllerInfo (
1577+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
15351578 break ;
15361579 case KEYCODE_MEDIA_PLAY :
1537- command = () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1580+ command =
1581+ () ->
1582+ sessionStub .playForControllerInfo (
1583+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
15381584 break ;
15391585 case KEYCODE_MEDIA_PAUSE :
15401586 command = () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
@@ -2116,7 +2162,8 @@ public void setPendingPlayPauseTask(ControllerInfo controllerInfo, KeyEvent keyE
21162162 applyMediaButtonKeyEvent (
21172163 keyEvent ,
21182164 /* doubleTapCompleted= */ false ,
2119- /* isDismissNotificationEvent= */ false );
2165+ /* isDismissNotificationEvent= */ false ,
2166+ /* mustStartForegroundService= */ false );
21202167 } else {
21212168 sessionLegacyStub .handleMediaPlayPauseOnHandler (
21222169 checkNotNull (controllerInfo .getRemoteUserInfo ()));
0 commit comments