Transform double-tap of HEADSETHOOK to skip-to-next

As reported in Issue: androidx/media#1493 we already use `HEADSETHOOK` to start
waiting for a double-tap, but we don't consider it for the second tap.

Similarly, we previously considered `PLAY` for the second tap, but not the first.
Only `HEADSETHOOK` and `PLAY_PAUSE` are
[documented](https://developer.android.com/reference/androidx/media3/session/MediaSession#media-key-events-mapping)
to transform double-tap to `seekToNext`. So this change removes the
`PLAY` detection from the second tap.

#cherrypick

PiperOrigin-RevId: 651017522
This commit is contained in:
ibaker 2024-07-10 07:49:17 -07:00 committed by Copybara-Service
parent e8778d77fa
commit c64dacf3df
3 changed files with 21 additions and 2 deletions

View File

@ -64,6 +64,10 @@
playback can't be suppressed without the system crashing the service
with a `ForegroundServiceDidNotStartInTimeException`
([#1528](https://github.com/google/ExoPlayer/issues/1528)).
* Transform a double-tap of `KEYCODE_HEADSETHOOK` into a 'seek to next'
action, as
[documented](https://developer.android.com/reference/androidx/media3/session/MediaSession#media-key-events-mapping)
([#1493](https://github.com/androidx/media/issues/1493)).
* UI:
* Downloads:
* OkHttp Extension:

View File

@ -1242,7 +1242,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
if (!isMediaNotificationControllerConnected()) {
if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE && doubleTapCompleted) {
if ((keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_HEADSETHOOK)
&& doubleTapCompleted) {
// Double tap completion for legacy when media notification controller is disabled.
sessionLegacyStub.onSkipToNext();
return true;
@ -1262,7 +1263,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
ControllerInfo controllerInfo = checkNotNull(instance.getMediaNotificationControllerInfo());
Runnable command;
int keyCode = keyEvent.getKeyCode();
if ((keyCode == KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KEYCODE_MEDIA_PLAY)
if ((keyCode == KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_HEADSETHOOK)
&& doubleTapCompleted) {
keyCode = KEYCODE_MEDIA_NEXT;
}

View File

@ -346,6 +346,20 @@ public class MediaSessionKeyEventTest {
player.awaitMethodCalled(MockPlayer.METHOD_SEEK_TO_NEXT, TIMEOUT_MS);
}
@Test
public void playPauseKeyEvent_doubleTapOnHeadsetHook_seekNext() throws Exception {
Assume.assumeTrue(Util.SDK_INT >= 21); // TODO: b/199064299 - Lower minSdk to 19.
handler.postAndSync(
() -> {
player.playWhenReady = true;
player.playbackState = Player.STATE_READY;
});
dispatchMediaKeyEvent(KeyEvent.KEYCODE_HEADSETHOOK, /* doubleTap= */ true);
player.awaitMethodCalled(MockPlayer.METHOD_SEEK_TO_NEXT, TIMEOUT_MS);
}
private MediaController connectMediaNotificationController() throws Exception {
return threadTestRule
.getHandler()