@@ -1127,7 +1127,9 @@ protected MediaSessionServiceLegacyStub getLegacyBrowserService() {
11271127 * @param controller The controller requesting to play.
11281128 */
11291129 /* package */ ListenableFuture <SessionResult > handleMediaControllerPlayRequest (
1130- ControllerInfo controller , boolean callOnPlayerInteractionFinished ) {
1130+ ControllerInfo controller ,
1131+ boolean callOnPlayerInteractionFinished ,
1132+ boolean mustStartForegroundService ) {
11311133 SettableFuture <SessionResult > sessionFuture = SettableFuture .create ();
11321134 ListenableFuture <Boolean > playRequestedFuture = onPlayRequested ();
11331135 playRequestedFuture .addListener (
@@ -1181,6 +1183,26 @@ public void onSuccess(MediaItemsWithStartPosition mediaItemsWithStartPosition) {
11811183 callWithControllerForCurrentRequestSet (
11821184 controllerForRequest ,
11831185 () -> {
1186+ if (mediaItemsWithStartPosition .mediaItems .isEmpty ()) {
1187+ if (mustStartForegroundService ) {
1188+ applicationHandler .postAtFrontOfQueue (
1189+ () -> {
1190+ throw new IllegalArgumentException (
1191+ "Callback.onPlaybackResumption must return non-empty"
1192+ + " MediaItemsWithStartPosition if started from a"
1193+ + " media button receiver. If there is nothing to"
1194+ + " resume playback with, override"
1195+ + " MediaButtonReceiver.shouldStartForegroundService()"
1196+ + " and return false." );
1197+ });
1198+ return ;
1199+ }
1200+ Log .w (
1201+ TAG ,
1202+ "onPlaybackResumption() is trying to resume with empty"
1203+ + " playlist, this will make the resumption notification"
1204+ + " appear broken." );
1205+ }
11841206 MediaUtils .setMediaItemsWithStartIndexAndPosition (
11851207 playerWrapper , mediaItemsWithStartPosition );
11861208 Util .handlePlayButtonAction (playerWrapper );
@@ -1195,21 +1217,33 @@ public void onSuccess(MediaItemsWithStartPosition mediaItemsWithStartPosition) {
11951217
11961218 @ Override
11971219 public void onFailure (Throwable t ) {
1220+ RuntimeException e ;
11981221 if (t instanceof UnsupportedOperationException ) {
1199- Log . w (
1200- TAG ,
1201- "UnsupportedOperationException: Make sure to implement"
1202- + " MediaSession.Callback.onPlaybackResumption() if you add a media"
1203- + " button receiver to your manifest or if you implement the recent "
1204- + " media item contract with your MediaLibraryService." ,
1205- t );
1222+ e =
1223+ new UnsupportedOperationException (
1224+ " Make sure to implement MediaSession.Callback.onPlaybackResumption() "
1225+ + " if you add a media button receiver to your manifest or if you "
1226+ + " implement the recent media item contract with your "
1227+ + " MediaLibraryService." ,
1228+ t );
12061229 } else {
1207- Log .e (
1208- TAG ,
1209- "Failure calling MediaSession.Callback.onPlaybackResumption(): "
1210- + t .getMessage (),
1211- t );
1230+ e =
1231+ new IllegalStateException (
1232+ "Failure calling MediaSession.Callback.onPlaybackResumption(): "
1233+ + t .getMessage (),
1234+ t );
1235+ }
1236+ if (mustStartForegroundService ) {
1237+ // MediaButtonReceiver already called startForegroundService(). If we do not
1238+ // crash ourselves, ForegroundServiceDidNotStartInTimeException will do it
1239+ // for us. Let's at least get a useful stack trace out there.
1240+ applicationHandler .postAtFrontOfQueue (
1241+ () -> {
1242+ throw e ;
1243+ });
1244+ return ;
12121245 }
1246+ Log .e (TAG , Objects .requireNonNull (Log .getThrowableString (e )));
12131247 // Play as requested even if playback resumption fails.
12141248 Util .handlePlayButtonAction (playerWrapper );
12151249 sessionFuture .set (new SessionResult (SessionResult .RESULT_SUCCESS ));
@@ -1467,13 +1501,13 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
14671501 // Double tap detection.
14681502 int keyCode = keyEvent .getKeyCode ();
14691503 boolean isTvApp = context .getPackageManager ().hasSystemFeature (PackageManager .FEATURE_LEANBACK );
1504+ boolean isEventSourceMediaButtonReceiver =
1505+ callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION ;
14701506 boolean doubleTapCompleted = false ;
14711507 switch (keyCode ) {
14721508 case KeyEvent .KEYCODE_MEDIA_PLAY_PAUSE :
14731509 case KeyEvent .KEYCODE_HEADSETHOOK :
1474- if (isTvApp
1475- || callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION
1476- || keyEvent .getRepeatCount () != 0 ) {
1510+ if (isTvApp || isEventSourceMediaButtonReceiver || keyEvent .getRepeatCount () != 0 ) {
14771511 // Double tap detection is only for mobile apps that receive a media button event from
14781512 // external sources (for instance Bluetooth) and excluding long press (repeatCount > 0).
14791513 mediaPlayPauseKeyHandler .flush ();
@@ -1513,11 +1547,18 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
15131547 intent .getBooleanExtra (
15141548 MediaNotification .NOTIFICATION_DISMISSED_EVENT_KEY , /* defaultValue= */ false );
15151549 return keyEvent .getRepeatCount () > 0
1516- || applyMediaButtonKeyEvent (keyEvent , doubleTapCompleted , isDismissNotificationEvent );
1550+ || applyMediaButtonKeyEvent (
1551+ keyEvent ,
1552+ doubleTapCompleted ,
1553+ isDismissNotificationEvent ,
1554+ isEventSourceMediaButtonReceiver );
15171555 }
15181556
15191557 private boolean applyMediaButtonKeyEvent (
1520- KeyEvent keyEvent , boolean doubleTapCompleted , boolean isDismissNotificationEvent ) {
1558+ KeyEvent keyEvent ,
1559+ boolean doubleTapCompleted ,
1560+ boolean isDismissNotificationEvent ,
1561+ boolean mustStartForegroundService ) {
15211562 ControllerInfo controllerInfo = checkNotNull (instance .getMediaNotificationControllerInfo ());
15221563 Runnable command ;
15231564 int keyCode = keyEvent .getKeyCode ();
@@ -1530,10 +1571,15 @@ private boolean applyMediaButtonKeyEvent(
15301571 command =
15311572 getPlayerWrapper ().getPlayWhenReady ()
15321573 ? () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER )
1533- : () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1574+ : () ->
1575+ sessionStub .playForControllerInfo (
1576+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
15341577 break ;
15351578 case KEYCODE_MEDIA_PLAY :
1536- command = () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1579+ command =
1580+ () ->
1581+ sessionStub .playForControllerInfo (
1582+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
15371583 break ;
15381584 case KEYCODE_MEDIA_PAUSE :
15391585 command = () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
@@ -2115,7 +2161,8 @@ public void setPendingPlayPauseTask(ControllerInfo controllerInfo, KeyEvent keyE
21152161 applyMediaButtonKeyEvent (
21162162 keyEvent ,
21172163 /* doubleTapCompleted= */ false ,
2118- /* isDismissNotificationEvent= */ false );
2164+ /* isDismissNotificationEvent= */ false ,
2165+ /* mustStartForegroundService= */ false );
21192166 } else {
21202167 sessionLegacyStub .handleMediaPlayPauseOnHandler (
21212168 checkNotNull (controllerInfo .getRemoteUserInfo ()));
0 commit comments