Don't start the service in the foreground with a pause intent

`PlaybackStateCompat.toKeyCode(command)` was replaced by our
own implementation of `toKeyCode()`. The legacy implementation used PLAY and PAUSE, while the new implementation uses PLAY_PAUSE. This made `pause` a pending intent that attempt to start the service in the foreground, but `service.startForeground()` won't be called in `MediaNotificationManager.updateNotificationInternal` when paused.

PiperOrigin-RevId: 476895752
This commit is contained in:
bachinger 2022-09-26 14:56:00 +00:00 committed by Marc Baechinger
parent 16dca1828c
commit acd9e581c4
3 changed files with 52 additions and 5 deletions

View File

@ -67,6 +67,8 @@
service is stopped from the foreground and a notification with a play service is stopped from the foreground and a notification with a play
button is shown to restart playback of the last media item button is shown to restart playback of the last media item
([#112](https://github.com/androidx/media/issues/112)). ([#112](https://github.com/androidx/media/issues/112)).
* Don't start a foreground service with a pending intent for pause
([#167](https://github.com/androidx/media/issues/167)).
* RTSP: * RTSP:
* Add H263 fragmented packet handling * Add H263 fragmented packet handling
([#119](https://github.com/androidx/media/pull/119)). ([#119](https://github.com/androidx/media/pull/119)).

View File

@ -105,7 +105,9 @@ import androidx.media3.common.util.Util;
intent.setData(mediaSession.getImpl().getUri()); intent.setData(mediaSession.getImpl().getUri());
intent.setComponent(new ComponentName(service, service.getClass())); intent.setComponent(new ComponentName(service, service.getClass()));
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, keyCode)); intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
if (Util.SDK_INT >= 26 && command == COMMAND_PLAY_PAUSE) { if (Util.SDK_INT >= 26
&& command == COMMAND_PLAY_PAUSE
&& !mediaSession.getPlayer().getPlayWhenReady()) {
return Api26.createForegroundServicePendingIntent(service, keyCode, intent); return Api26.createForegroundServicePendingIntent(service, keyCode, intent);
} else { } else {
return PendingIntent.getService( return PendingIntent.getService(

View File

@ -42,18 +42,61 @@ public class DefaultActionFactoryTest {
public void createMediaPendingIntent_intentIsMediaAction() { public void createMediaPendingIntent_intentIsMediaAction() {
DefaultActionFactory actionFactory = DefaultActionFactory actionFactory =
new DefaultActionFactory(Robolectric.setupService(TestService.class)); new DefaultActionFactory(Robolectric.setupService(TestService.class));
MediaSession mockMediaSession = mock(MediaSession.class);
MediaSessionImpl mockMediaSessionImpl = mock(MediaSessionImpl.class);
when(mockMediaSession.getImpl()).thenReturn(mockMediaSessionImpl);
Uri dataUri = Uri.parse("http://example.com"); Uri dataUri = Uri.parse("http://example.com");
MediaSession mockMediaSession = mock(MediaSession.class);
Player mockPlayer = mock(Player.class);
MediaSessionImpl mockMediaSessionImpl = mock(MediaSessionImpl.class);
when(mockMediaSession.getPlayer()).thenReturn(mockPlayer);
when(mockMediaSession.getImpl()).thenReturn(mockMediaSessionImpl);
when(mockMediaSessionImpl.getUri()).thenReturn(dataUri); when(mockMediaSessionImpl.getUri()).thenReturn(dataUri);
PendingIntent pendingIntent =
actionFactory.createMediaActionPendingIntent(mockMediaSession, Player.COMMAND_SEEK_FORWARD);
ShadowPendingIntent shadowPendingIntent = shadowOf(pendingIntent);
assertThat(actionFactory.isMediaAction(shadowPendingIntent.getSavedIntent())).isTrue();
assertThat(shadowPendingIntent.getSavedIntent().getData()).isEqualTo(dataUri);
}
@Test
public void createMediaPendingIntent_commandPlayPauseWhenNotPlayWhenReady_isForegroundService() {
DefaultActionFactory actionFactory =
new DefaultActionFactory(Robolectric.setupService(TestService.class));
Uri dataUri = Uri.parse("http://example.com");
MediaSession mockMediaSession = mock(MediaSession.class);
Player mockPlayer = mock(Player.class);
MediaSessionImpl mockMediaSessionImpl = mock(MediaSessionImpl.class);
when(mockMediaSession.getPlayer()).thenReturn(mockPlayer);
when(mockMediaSession.getImpl()).thenReturn(mockMediaSessionImpl);
when(mockMediaSessionImpl.getUri()).thenReturn(dataUri);
when(mockPlayer.getPlayWhenReady()).thenReturn(false);
PendingIntent pendingIntent =
actionFactory.createMediaActionPendingIntent(mockMediaSession, Player.COMMAND_PLAY_PAUSE);
ShadowPendingIntent shadowPendingIntent = shadowOf(pendingIntent);
assertThat(shadowPendingIntent.isForegroundService()).isTrue();
}
@Test
public void createMediaPendingIntent_commandPlayPauseWhenPlayWhenReady_notAForegroundService() {
DefaultActionFactory actionFactory =
new DefaultActionFactory(Robolectric.setupService(TestService.class));
Uri dataUri = Uri.parse("http://example.com");
MediaSession mockMediaSession = mock(MediaSession.class);
Player mockPlayer = mock(Player.class);
MediaSessionImpl mockMediaSessionImpl = mock(MediaSessionImpl.class);
when(mockMediaSession.getPlayer()).thenReturn(mockPlayer);
when(mockMediaSession.getImpl()).thenReturn(mockMediaSessionImpl);
when(mockMediaSessionImpl.getUri()).thenReturn(dataUri);
when(mockPlayer.getPlayWhenReady()).thenReturn(true);
PendingIntent pendingIntent = PendingIntent pendingIntent =
actionFactory.createMediaActionPendingIntent(mockMediaSession, Player.COMMAND_PLAY_PAUSE); actionFactory.createMediaActionPendingIntent(mockMediaSession, Player.COMMAND_PLAY_PAUSE);
ShadowPendingIntent shadowPendingIntent = shadowOf(pendingIntent); ShadowPendingIntent shadowPendingIntent = shadowOf(pendingIntent);
assertThat(actionFactory.isMediaAction(shadowPendingIntent.getSavedIntent())).isTrue(); assertThat(actionFactory.isMediaAction(shadowPendingIntent.getSavedIntent())).isTrue();
assertThat(shadowPendingIntent.getSavedIntent().getData()).isEqualTo(dataUri); assertThat(shadowPendingIntent.isForegroundService()).isFalse();
} }
@Test @Test