Skip to content

Fix AAOS steering-wheel skip buttons after Android 14 update#5318

Closed
joashrajin wants to merge 1 commit into
Automattic:mainfrom
joashrajin:fix/pcdroid-560-aaos-steering-wheel-skip
Closed

Fix AAOS steering-wheel skip buttons after Android 14 update#5318
joashrajin wants to merge 1 commit into
Automattic:mainfrom
joashrajin:fix/pcdroid-560-aaos-steering-wheel-skip

Conversation

@joashrajin

Copy link
Copy Markdown
Contributor

Description

Fixes https://linear.app/a8c/issue/PCDROID-560/aaos-steering-wheel-skip-forwardback-buttons-unresponsive-in-pocket

After the Media3 migration, the AAOS Pocket Casts session stopped advertising COMMAND_SEEK_TO_NEXT / COMMAND_SEEK_TO_PREVIOUS, and the onMediaButtonEvent handler didn't recognise KEYCODE_MEDIA_FAST_FORWARD, KEYCODE_MEDIA_REWIND, or the fallback KEYCODE_MEDIA_STOP that GM's car-media service sends when no skip action is reachable. After the Android 14 vehicle-OS rollout on Chevrolet Equinox EV (and likely other AAOS platforms), the steering-wheel skip-forward / skip-back buttons became completely unresponsive — the user reported Media3 media button event: keyCode=86 (KEYCODE_MEDIA_STOP) in their log when pressing skip. Spotify and Amazon Music kept working because they advertise the skip commands.

Changes

  • PocketCastsForwardingPlayer.getAvailableCommands() — expose COMMAND_SEEK_TO_NEXT and COMMAND_SEEK_TO_PREVIOUS. The existing seekToNext() / seekToPrevious() overrides already route to onSkipForward / onSkipBack (→ PlaybackManager.skipForwardSuspend / skipBackwardSuspend), so no wiring change is needed.
  • Media3SessionCallback.TRANSPORT_PLAYER_COMMANDS — same two commands added so connecting Media3 controllers (AAOS, MediaController test clients) see skip support.
  • Media3SessionCallback.onMediaButtonEvent — handle KEYCODE_MEDIA_FAST_FORWARD and KEYCODE_MEDIA_REWIND as direct skip-forward / skip-back (defence-in-depth for controllers that still dispatch raw key events).
  • Media3SessionCallback.onMediaButtonEvent — on Android Automotive OS, bypass the headphone multi-tap queue for KEYCODE_MEDIA_NEXT and KEYCODE_MEDIA_PREVIOUS. The 250 ms multi-tap window is correct for Pixel Buds but wrong for a steering-wheel button, which fires once per press.

Testing Instructions

Automated tests

  1. ./gradlew :modules:services:repositories:testDebugUnitTest --tests "au.com.shiftyjelly.pocketcasts.repositories.playback.Media3SessionCallbackTest"
  2. ./gradlew :modules:services:repositories:testDebugUnitTest --tests "au.com.shiftyjelly.pocketcasts.repositories.playback.PocketCastsForwardingPlayerTest"
  3. ✅ Verify the new tests pass:
    • KEYCODE_MEDIA_FAST_FORWARD calls skipForwardSuspend directly
    • KEYCODE_MEDIA_REWIND calls skipBackwardSuspend directly
    • on automotive, KEYCODE_MEDIA_NEXT skips forward immediately
    • on automotive, KEYCODE_MEDIA_PREVIOUS skips backward immediately
  4. ✅ Verify the updated commands-exposure tests still pass on both the session callback and the forwarding player.

Manual — AAOS emulator

  1. Build the automotive variant: ./gradlew :automotive:assembleDebug.
  2. Install and launch Pocket Casts on the AAOS emulator (or a physical Android 14 AAOS vehicle if available).
  3. Start playback of any episode.
  4. Send a KEYCODE_MEDIA_NEXT key event via adb shell input keyevent 87 (and 88 for previous, 90 for fast-forward, 89 for rewind).
  5. ✅ Verify each invocation triggers a skip forward / skip backward in the playback position immediately (no 250 ms delay), and that no Media3: stop → pause log line is emitted.
  6. ✅ Verify on-screen playback controls within the app still work normally.

Manual — mobile regression check

  1. Run the mobile debug variant.
  2. Connect Pixel Buds (or any BT headset with multi-tap), play an episode, and use double-tap / triple-tap.
  3. ✅ Verify multi-tap still resolves to the user's configured headphoneControlsNextAction / headphoneControlsPreviousAction after the 250 ms window — the automotive bypass only applies when Util.isAutomotive(context) is true.

Checklist

  • Ensure the linter passes (./gradlew spotlessApply to automatically apply formatting/linting)
  • I have considered whether it makes sense to add tests for my changes
  • If this is a user-facing change, I have added an entry in CHANGELOG.md
  • All strings that need to be localized are in modules/services/localization/src/main/res/values/strings.xml (no string changes)
  • Any jetpack compose components I added or changed are covered by compose previews (no Compose changes)
  • I have updated (or requested that someone edit) the spreadsheet to reflect any new or changed analytics. (no analytics changes)

Note

Tests were not executed locally — the current main branch pulls in a crashlogging:6.0.8 dependency compiled to Java 21 class files, but libs.versions.toml still pins java = "17". Without a local JDK 21 install, :modules:services:crashlogging:compileDebugJavaWithJavac fails before any test code runs. Pre-existing issue, not caused by this PR — relying on CI for verification.

After the Media3 migration, the player no longer advertised
COMMAND_SEEK_TO_NEXT / COMMAND_SEEK_TO_PREVIOUS, and the
onMediaButtonEvent handler did not recognise KEYCODE_MEDIA_FAST_FORWARD,
KEYCODE_MEDIA_REWIND, or the Android 14 AAOS fallback KEYCODE_MEDIA_STOP
that GM's car-media service sends when no skip action is reachable. As a
result, steering-wheel skip buttons on Chevrolet Equinox EV (and likely
other AAOS vehicles after the Android 14 vehicle-OS update) did nothing.

Expose SEEK_TO_NEXT / SEEK_TO_PREVIOUS on both TRANSPORT_PLAYER_COMMANDS
and PocketCastsForwardingPlayer.getAvailableCommands() so AAOS routes
the steering-wheel skip buttons through seekToNext()/seekToPrevious()
(already wired to PlaybackManager.skipForwardSuspend /
skipBackwardSuspend via onSkipForward / onSkipBack). Add explicit
handlers for KEYCODE_MEDIA_FAST_FORWARD / KEYCODE_MEDIA_REWIND as a
defence-in-depth for controllers that still dispatch raw key events.
On automotive, bypass the headphone multi-tap queue for
KEYCODE_MEDIA_NEXT / KEYCODE_MEDIA_PREVIOUS so a single press of the
steering-wheel skip button triggers an immediate skip rather than
waiting on the 250 ms multi-tap timeout.
Copilot AI review requested due to automatic review settings May 19, 2026 16:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes AAOS steering-wheel skip controls becoming unresponsive after the Media3 migration / Android 14 AAOS rollout by ensuring Media3 controllers can discover and dispatch skip actions, and by handling additional automotive-specific key event behaviors.

Changes:

  • Advertise COMMAND_SEEK_TO_NEXT / COMMAND_SEEK_TO_PREVIOUS from both PocketCastsForwardingPlayer and Media3SessionCallback so AAOS routes steering-wheel skip buttons to seekToNext() / seekToPrevious() instead of falling back to STOP.
  • Handle KEYCODE_MEDIA_FAST_FORWARD / KEYCODE_MEDIA_REWIND as direct skip-forward/skip-back in onMediaButtonEvent.
  • On Automotive, bypass the headphone multi-tap queue for KEYCODE_MEDIA_NEXT / KEYCODE_MEDIA_PREVIOUS to avoid the 250ms delay and ensure immediate response.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/playback/PocketCastsForwardingPlayer.kt Exposes seek-to-next/previous commands to make skip reachable for external controllers (AAOS).
modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/playback/Media3SessionCallback.kt Expands advertised transport commands and improves media-button handling for AAOS keycodes and automotive latency expectations.
modules/services/repositories/src/test/java/au/com/shiftyjelly/pocketcasts/repositories/playback/PocketCastsForwardingPlayerTest.kt Updates command-exposure expectations to include seek-to-next/previous (including after swapPlayer).
modules/services/repositories/src/test/java/au/com/shiftyjelly/pocketcasts/repositories/playback/Media3SessionCallbackTest.kt Adds coverage for FAST_FORWARD/REWIND handling and the Automotive multi-tap bypass for NEXT/PREVIOUS.

@joashrajin joashrajin marked this pull request as ready for review May 19, 2026 16:48
@joashrajin joashrajin requested a review from a team as a code owner May 19, 2026 16:48
@joashrajin joashrajin requested review from geekygecko and removed request for a team May 19, 2026 16:48
@geekygecko geekygecko requested review from sztomek and removed request for geekygecko May 19, 2026 23:25
@geekygecko

Copy link
Copy Markdown
Member

@sztomek would you mind reviewing this as it's related to Media 3.

@joashrajin

Copy link
Copy Markdown
Contributor Author

Moving this off my fork to get Buildkite CI to run — superseded by #5328.

@joashrajin joashrajin closed this May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants