@@ -1128,7 +1128,9 @@ protected MediaSessionServiceLegacyStub getLegacyBrowserService() {
1128
1128
* @param controller The controller requesting to play.
1129
1129
*/
1130
1130
/* package */ ListenableFuture <SessionResult > handleMediaControllerPlayRequest (
1131
- ControllerInfo controller , boolean callOnPlayerInteractionFinished ) {
1131
+ ControllerInfo controller ,
1132
+ boolean callOnPlayerInteractionFinished ,
1133
+ boolean mustStartForegroundService ) {
1132
1134
SettableFuture <SessionResult > sessionFuture = SettableFuture .create ();
1133
1135
ListenableFuture <Boolean > playRequestedFuture = onPlayRequested ();
1134
1136
playRequestedFuture .addListener (
@@ -1182,6 +1184,26 @@ public void onSuccess(MediaItemsWithStartPosition mediaItemsWithStartPosition) {
1182
1184
callWithControllerForCurrentRequestSet (
1183
1185
controllerForRequest ,
1184
1186
() -> {
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
+ }
1185
1207
MediaUtils .setMediaItemsWithStartIndexAndPosition (
1186
1208
playerWrapper , mediaItemsWithStartPosition );
1187
1209
Util .handlePlayButtonAction (playerWrapper );
@@ -1196,21 +1218,33 @@ public void onSuccess(MediaItemsWithStartPosition mediaItemsWithStartPosition) {
1196
1218
1197
1219
@ Override
1198
1220
public void onFailure (Throwable t ) {
1221
+ RuntimeException e ;
1199
1222
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 );
1207
1230
} 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 ;
1213
1246
}
1247
+ Log .e (TAG , Objects .requireNonNull (Log .getThrowableString (e )));
1214
1248
// Play as requested even if playback resumption fails.
1215
1249
Util .handlePlayButtonAction (playerWrapper );
1216
1250
sessionFuture .set (new SessionResult (SessionResult .RESULT_SUCCESS ));
@@ -1468,13 +1502,13 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
1468
1502
// Double tap detection.
1469
1503
int keyCode = keyEvent .getKeyCode ();
1470
1504
boolean isTvApp = context .getPackageManager ().hasSystemFeature (PackageManager .FEATURE_LEANBACK );
1505
+ boolean isEventSourceMediaButtonReceiver =
1506
+ callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION ;
1471
1507
boolean doubleTapCompleted = false ;
1472
1508
switch (keyCode ) {
1473
1509
case KeyEvent .KEYCODE_MEDIA_PLAY_PAUSE :
1474
1510
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 ) {
1478
1512
// Double tap detection is only for mobile apps that receive a media button event from
1479
1513
// external sources (for instance Bluetooth) and excluding long press (repeatCount > 0).
1480
1514
mediaPlayPauseKeyHandler .flush ();
@@ -1514,11 +1548,18 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
1514
1548
intent .getBooleanExtra (
1515
1549
MediaNotification .NOTIFICATION_DISMISSED_EVENT_KEY , /* defaultValue= */ false );
1516
1550
return keyEvent .getRepeatCount () > 0
1517
- || applyMediaButtonKeyEvent (keyEvent , doubleTapCompleted , isDismissNotificationEvent );
1551
+ || applyMediaButtonKeyEvent (
1552
+ keyEvent ,
1553
+ doubleTapCompleted ,
1554
+ isDismissNotificationEvent ,
1555
+ isEventSourceMediaButtonReceiver );
1518
1556
}
1519
1557
1520
1558
private boolean applyMediaButtonKeyEvent (
1521
- KeyEvent keyEvent , boolean doubleTapCompleted , boolean isDismissNotificationEvent ) {
1559
+ KeyEvent keyEvent ,
1560
+ boolean doubleTapCompleted ,
1561
+ boolean isDismissNotificationEvent ,
1562
+ boolean mustStartForegroundService ) {
1522
1563
ControllerInfo controllerInfo = checkNotNull (instance .getMediaNotificationControllerInfo ());
1523
1564
Runnable command ;
1524
1565
int keyCode = keyEvent .getKeyCode ();
@@ -1531,10 +1572,15 @@ private boolean applyMediaButtonKeyEvent(
1531
1572
command =
1532
1573
getPlayerWrapper ().getPlayWhenReady ()
1533
1574
? () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER )
1534
- : () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1575
+ : () ->
1576
+ sessionStub .playForControllerInfo (
1577
+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
1535
1578
break ;
1536
1579
case KEYCODE_MEDIA_PLAY :
1537
- command = () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1580
+ command =
1581
+ () ->
1582
+ sessionStub .playForControllerInfo (
1583
+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
1538
1584
break ;
1539
1585
case KEYCODE_MEDIA_PAUSE :
1540
1586
command = () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
@@ -2116,7 +2162,8 @@ public void setPendingPlayPauseTask(ControllerInfo controllerInfo, KeyEvent keyE
2116
2162
applyMediaButtonKeyEvent (
2117
2163
keyEvent ,
2118
2164
/* doubleTapCompleted= */ false ,
2119
- /* isDismissNotificationEvent= */ false );
2165
+ /* isDismissNotificationEvent= */ false ,
2166
+ /* mustStartForegroundService= */ false );
2120
2167
} else {
2121
2168
sessionLegacyStub .handleMediaPlayPauseOnHandler (
2122
2169
checkNotNull (controllerInfo .getRemoteUserInfo ()));
0 commit comments