@@ -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 ));
@@ -1448,13 +1482,13 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
1448
1482
// Double tap detection.
1449
1483
int keyCode = keyEvent .getKeyCode ();
1450
1484
boolean isTvApp = context .getPackageManager ().hasSystemFeature (PackageManager .FEATURE_LEANBACK );
1485
+ boolean isEventSourceMediaButtonReceiver =
1486
+ callerInfo .getControllerVersion () != ControllerInfo .LEGACY_CONTROLLER_VERSION ;
1451
1487
boolean doubleTapCompleted = false ;
1452
1488
switch (keyCode ) {
1453
1489
case KeyEvent .KEYCODE_MEDIA_PLAY_PAUSE :
1454
1490
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 ) {
1458
1492
// Double tap detection is only for mobile apps that receive a media button event from
1459
1493
// external sources (for instance Bluetooth) and excluding long press (repeatCount > 0).
1460
1494
mediaPlayPauseKeyHandler .flush ();
@@ -1493,11 +1527,15 @@ private void handleAvailablePlayerCommandsChanged(Player.Commands availableComma
1493
1527
boolean isDismissNotificationEvent =
1494
1528
intent .getBooleanExtra (
1495
1529
MediaNotification .NOTIFICATION_DISMISSED_EVENT_KEY , /* defaultValue= */ false );
1496
- return applyMediaButtonKeyEvent (keyEvent , doubleTapCompleted , isDismissNotificationEvent );
1530
+ return applyMediaButtonKeyEvent (
1531
+ keyEvent , doubleTapCompleted , isDismissNotificationEvent , isEventSourceMediaButtonReceiver );
1497
1532
}
1498
1533
1499
1534
private boolean applyMediaButtonKeyEvent (
1500
- KeyEvent keyEvent , boolean doubleTapCompleted , boolean isDismissNotificationEvent ) {
1535
+ KeyEvent keyEvent ,
1536
+ boolean doubleTapCompleted ,
1537
+ boolean isDismissNotificationEvent ,
1538
+ boolean mustStartForegroundService ) {
1501
1539
ControllerInfo controllerInfo = checkNotNull (instance .getMediaNotificationControllerInfo ());
1502
1540
Runnable command ;
1503
1541
int keyCode = keyEvent .getKeyCode ();
@@ -1510,10 +1548,15 @@ private boolean applyMediaButtonKeyEvent(
1510
1548
command =
1511
1549
getPlayerWrapper ().getPlayWhenReady ()
1512
1550
? () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER )
1513
- : () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1551
+ : () ->
1552
+ sessionStub .playForControllerInfo (
1553
+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
1514
1554
break ;
1515
1555
case KEYCODE_MEDIA_PLAY :
1516
- command = () -> sessionStub .playForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
1556
+ command =
1557
+ () ->
1558
+ sessionStub .playForControllerInfo (
1559
+ controllerInfo , UNKNOWN_SEQUENCE_NUMBER , mustStartForegroundService );
1517
1560
break ;
1518
1561
case KEYCODE_MEDIA_PAUSE :
1519
1562
command = () -> sessionStub .pauseForControllerInfo (controllerInfo , UNKNOWN_SEQUENCE_NUMBER );
@@ -2095,7 +2138,8 @@ public void setPendingPlayPauseTask(ControllerInfo controllerInfo, KeyEvent keyE
2095
2138
applyMediaButtonKeyEvent (
2096
2139
keyEvent ,
2097
2140
/* doubleTapCompleted= */ false ,
2098
- /* isDismissNotificationEvent= */ false );
2141
+ /* isDismissNotificationEvent= */ false ,
2142
+ /* mustStartForegroundService= */ false );
2099
2143
} else {
2100
2144
sessionLegacyStub .handleMediaPlayPauseOnHandler (
2101
2145
checkNotNull (controllerInfo .getRemoteUserInfo ()));
0 commit comments