@@ -1141,7 +1141,9 @@ protected MediaSessionServiceLegacyStub getLegacyBrowserService() {
11411141 * @param controller The controller requesting to play.
11421142 */
11431143 /* package */ ListenableFuture <SessionResult > handleMediaControllerPlayRequest (
1144- ControllerInfo controller , boolean callOnPlayerInteractionFinished ) {
1144+ ControllerInfo controller ,
1145+ boolean callOnPlayerInteractionFinished ,
1146+ boolean mustStartForegroundService ) {
11451147 SettableFuture <SessionResult > sessionFuture = SettableFuture .create ();
11461148 ListenableFuture <Boolean > playRequestedFuture = onPlayRequested ();
11471149 playRequestedFuture .addListener (
@@ -1195,6 +1197,26 @@ public void onSuccess(MediaItemsWithStartPosition mediaItemsWithStartPosition) {
11951197 callWithControllerForCurrentRequestSet (
11961198 controllerForRequest ,
11971199 () -> {
1200+ if (mediaItemsWithStartPosition .mediaItems .isEmpty ()) {
1201+ if (mustStartForegroundService ) {
1202+ applicationHandler .postAtFrontOfQueue (
1203+ () -> {
1204+ throw new IllegalArgumentException (
1205+ "Callback.onPlaybackResumption must return non-empty"
1206+ + " MediaItemsWithStartPosition if started from a"
1207+ + " media button receiver. If there is nothing to"
1208+ + " resume playback with, override"
1209+ + " MediaButtonReceiver.shouldStartForegroundService()"
1210+ + " and return false." );
1211+ });
1212+ return ;
1213+ }
1214+ Log .w (
1215+ TAG ,
1216+ "onPlaybackResumption() is trying to resume with empty"
1217+ + " playlist, this will make the resumption notification"
1218+ + " appear broken." );
1219+ }
11981220 MediaUtils .setMediaItemsWithStartIndexAndPosition (
11991221 playerWrapper , mediaItemsWithStartPosition );
12001222 Util .handlePlayButtonAction (playerWrapper );
@@ -1209,21 +1231,33 @@ public void onSuccess(MediaItemsWithStartPosition mediaItemsWithStartPosition) {
12091231
12101232 @ Override
12111233 public void onFailure (Throwable t ) {
1234+ RuntimeException e ;
12121235 if (t instanceof UnsupportedOperationException ) {
1213- Log . w (
1214- TAG ,
1215- "UnsupportedOperationException: Make sure to implement"
1216- + " MediaSession.Callback.onPlaybackResumption() if you add a media"
1217- + " button receiver to your manifest or if you implement the recent "
1218- + " media item contract with your MediaLibraryService." ,
1219- t );
1236+ e =
1237+ new UnsupportedOperationException (
1238+ " Make sure to implement MediaSession.Callback.onPlaybackResumption() "
1239+ + " if you add a media button receiver to your manifest or if you "
1240+ + " implement the recent media item contract with your "
1241+ + " MediaLibraryService." ,
1242+ t );
12201243 } else {
1221- Log .e (
1222- TAG ,
1223- "Failure calling MediaSession.Callback.onPlaybackResumption(): "
1224- + t .getMessage (),
1225- t );
1244+ e =
1245+ new IllegalStateException (
1246+ "Failure calling MediaSession.Callback.onPlaybackResumption(): "
1247+ + t .getMessage (),
1248+ t );
1249+ }
1250+ if (mustStartForegroundService ) {
1251+ // MediaButtonReceiver already called startForegroundService(). If we do not
1252+ // crash ourselves, ForegroundServiceDidNotStartInTimeException will do it
1253+ // for us. Let's at least get a useful stack trace out there.
1254+ applicationHandler .postAtFrontOfQueue (
1255+ () -> {
1256+ throw e ;
1257+ });
1258+ return ;
12261259 }
1260+ Log .e (TAG , Objects .requireNonNull (Log .getThrowableString (e )));
12271261 // Play as requested even if playback resumption fails.
12281262 Util .handlePlayButtonAction (playerWrapper );
12291263 sessionFuture .set (new SessionResult (SessionResult .RESULT_SUCCESS ));
@@ -1482,13 +1516,13 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
14821516 // Double tap detection.
14831517 int keyCode = keyEvent .getKeyCode ();
14841518 boolean isTvApp = context .getPackageManager ().hasSystemFeature (PackageManager .FEATURE_LEANBACK );
1519+ boolean isEventSourceMediaButtonReceiver =
1520+ callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION ;
14851521 boolean doubleTapCompleted = false ;
14861522 switch (keyCode ) {
14871523 case KEYCODE_MEDIA_PLAY_PAUSE :
14881524 case KEYCODE_HEADSETHOOK :
1489- if (isTvApp
1490- || callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION
1491- || keyEvent .getRepeatCount () != 0 ) {
1525+ if (isTvApp || isEventSourceMediaButtonReceiver || keyEvent .getRepeatCount () != 0 ) {
14921526 // Double tap detection is only for mobile apps that receive a media button event from
14931527 // external sources (for instance Bluetooth) and excluding long press (repeatCount > 0).
14941528 mediaPlayPauseKeyHandler .flush ();
@@ -1528,11 +1562,18 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
15281562 intent .getBooleanExtra (
15291563 MediaNotification .NOTIFICATION_DISMISSED_EVENT_KEY , /* defaultValue= */ false );
15301564 return keyEvent .getRepeatCount () > 0
1531- || applyMediaButtonKeyEvent (keyEvent , doubleTapCompleted , isDismissNotificationEvent );
1565+ || applyMediaButtonKeyEvent (
1566+ keyEvent ,
1567+ doubleTapCompleted ,
1568+ isDismissNotificationEvent ,
1569+ isEventSourceMediaButtonReceiver );
15321570 }
15331571
15341572 private boolean applyMediaButtonKeyEvent (
1535- KeyEvent keyEvent , boolean doubleTapCompleted , boolean isDismissNotificationEvent ) {
1573+ KeyEvent keyEvent ,
1574+ boolean doubleTapCompleted ,
1575+ boolean isDismissNotificationEvent ,
1576+ boolean mustStartForegroundService ) {
15361577 ControllerInfo controllerInfo = checkNotNull (instance .getMediaNotificationControllerInfo ());
15371578 Runnable command ;
15381579 int keyCode = keyEvent .getKeyCode ();
@@ -1546,10 +1587,15 @@ private boolean applyMediaButtonKeyEvent(
15461587 command =
15471588 getPlayerWrapper ().getPlayWhenReady ()
15481589 ? () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER )
1549- : () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1590+ : () ->
1591+ sessionStub .playForControllerInfo (
1592+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
15501593 break ;
15511594 case KEYCODE_MEDIA_PLAY :
1552- command = () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1595+ command =
1596+ () ->
1597+ sessionStub .playForControllerInfo (
1598+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
15531599 break ;
15541600 case KEYCODE_MEDIA_PAUSE :
15551601 command = () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
@@ -2164,7 +2210,8 @@ public void setPendingPlayPauseTask(ControllerInfo controllerInfo, KeyEvent keyE
21642210 applyMediaButtonKeyEvent (
21652211 keyEvent ,
21662212 /* doubleTapCompleted= */ false ,
2167- /* isDismissNotificationEvent= */ false );
2213+ /* isDismissNotificationEvent= */ false ,
2214+ /* mustStartForegroundService= */ false );
21682215 } else {
21692216 sessionLegacyStub .handleMediaPlayPauseOnHandler (
21702217 checkNotNull (controllerInfo .getRemoteUserInfo ()));
0 commit comments