Skip to content

Migrate Android Auto support to audio_service#223

Draft
mardale90 wants to merge 1 commit into
dddevid:masterfrom
mardale90:dev-android-auto
Draft

Migrate Android Auto support to audio_service#223
mardale90 wants to merge 1 commit into
dddevid:masterfrom
mardale90:dev-android-auto

Conversation

@mardale90

@mardale90 mardale90 commented Jul 15, 2026

Copy link
Copy Markdown

Problem
Android Auto showed no recent items, no search, and playback couldn't be started from the car. Root cause: the custom MusicService (MediaBrowserServiceCompat) held no data of its own — it relied entirely on the Flutter engine being alive to push library data and answer search/playback requests over a MethodChannel/EventChannel bridge. When Android Auto starts the service directly (app never opened on the phone), MainActivity never runs, so the plugin's event sink stays null and every request from the car is silently dropped. On top of that, a callback registration bug (PlayerProvider was overwriting LibraryProvider's working onRequestLibraryData handler with a no-op) meant the browse tree could stay empty even with the app open.

Fix
Replaced the custom native MediaBrowserServiceCompat + MethodChannel bridge with audio_service, which already backed the iOS lock-screen integration. audio_service hosts its own MediaBrowserService and, when Android Auto connects with the app closed, spawns a headless Flutter engine and runs main() — so the browse tree, search, and playback commands are served by Dart code directly, with no dependency on the UI having been opened first.

Changes
Dart

  • lib/services/audio_handler.dart: MuslyAudioHandler now implements the full Android Auto surface — getChildren/subscribeToChildren (browse tree: Recent/Albums/Artists/Playlists, same media-id scheme as before), search, playFromMediaId/playFromSearch, and remote volume (UPnP/Cast) via AndroidPlaybackInfo, replacing the old native VolumeProviderCompat. AudioService.init() now runs on Android too (previously iOS-only).
  • lib/providers/library_provider.dart: switched from a push model (send data to native at the "right" moment, which was the actual bug) to a pull model — the handler calls registered getters on demand, ensuring the library is initialized (even from cache) before answering.
  • lib/providers/player_provider.dart: search/playback/volume callbacks wired directly to the handler; removed the duplicate playback-state update path and the broken callback override.
  • lib/main.dart: AuthProvider, PlayerProvider, LibraryProvider are now constructed eagerly instead of lazily via Provider(create: ...), so their Android Auto callbacks are registered as soon as the engine starts — required for the headless cold-start path, since no widget would otherwise ever read these providers.
  • Removed lib/services/android_auto_service.dart (obsolete MethodChannel bridge).

Android (Kotlin)

  • Removed MusicService.kt and AndroidAutoPlugin.kt (~1180 lines of custom bridging code).
  • MainActivity now extends AudioServiceFragmentActivity to share its Flutter engine with the media service.
  • AndroidManifest.xml: declares com.ryanheise.audioservice.AudioService and its MediaButtonReceiver instead of the custom service.
  • Cleaned up now-dead MusicService references in AndroidSystemPlugin, BluetoothMediaHelper, LyricsPlugin.

Testing

  • flutter analyze: no issues.
  • flutter build apk --debug: builds successfully, merged manifest confirms audio_service's MediaBrowserService is registered.
  • Manual verification still needed: Android Auto (or Desktop Head Unit) with the app both open and never-opened, plus a regression pass on the media notification, UPnP volume, and Cast, since those paths were touched.

Summary by CodeRabbit

  • New Features
    • Improved Android Auto integration with library browsing, search, media selection, and remote playback support.
    • Android Auto now works more reliably during background and cold-start scenarios.
    • Enhanced media notifications and playback controls on Android.
  • Bug Fixes
    • Improved offline library fallback and cleanup during logout.
    • Improved synchronization of lyrics, artwork, playback state, and remote volume controls.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Android Auto integration is migrated from custom MusicService and AndroidAutoService bridges to audio_service. MuslyAudioHandler now handles browsing, search, playback, remote volume, and background-service integration, with providers supplying callbacks and library data.

Changes

Audio service Android Auto migration

Layer / File(s) Summary
Audio service platform integration
android/app/src/main/AndroidManifest.xml, android/app/src/main/kotlin/.../MainActivity.kt, lib/services/audio_handler.dart, pubspec.yaml
Android uses audio_service components, MainActivity shares the Flutter engine, and MuslyAudioHandler implements Android Auto browsing, search, playback, remote controls, and background initialization.
Provider callback and library data wiring
lib/main.dart, lib/providers/library_provider.dart, lib/providers/player_provider.dart, lib/services/services.dart
Providers are created eagerly; library callbacks and child notifications move to MuslyAudioHandler, while playback and remote-control routing no longer uses AndroidAutoService.
Native bridge behavior removal
android/app/src/main/kotlin/.../AndroidSystemPlugin.kt, .../BluetoothMediaHelper.kt, .../LyricsPlugin.kt, .../AndroidAutoPlugin.kt, .../MusicService.kt
The custom native Android Auto bridge and MusicService are removed, and native playback, lyrics, remote-playback, and volume updates stop targeting them.
Service lifecycle and API cleanup
lib/providers/auth_provider.dart, lib/services/android_system_service.dart
Logout removes the deleted service disposal, clears offline downloads, disposes integrations, and removes remote-control methods from AndroidSystemService.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AndroidAuto
  participant MuslyAudioHandler
  participant LibraryProvider
  participant PlayerProvider
  AndroidAuto->>MuslyAudioHandler: Browse or playback request
  MuslyAudioHandler->>LibraryProvider: Request library data
  LibraryProvider-->>MuslyAudioHandler: Return media items
  MuslyAudioHandler->>PlayerProvider: Invoke playback callback
  PlayerProvider-->>MuslyAudioHandler: Update playback or remote state
  MuslyAudioHandler-->>AndroidAuto: Publish media-session state
Loading

Possibly related PRs

  • dddevid/Musly#80: Both changes update PlayerProvider handling of UPnP playback state and Android Auto media-session synchronization.
  • dddevid/Musly#128: Both changes modify UPnP/Cast remote playback, volume, and media-session routing.

Suggested reviewers: dddevid

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: migrating Android Auto support to audio_service.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/providers/library_provider.dart`:
- Around line 474-479: Update the server-offline handling in the song, album,
artist, and playlist branches of the relevant provider method: assign each
downloaded-only filtered collection unconditionally, including empty results,
instead of preserving the full catalog. For playlists, retain only playlists
containing at least one downloaded song, using the existing downloaded ID set
and playlist song data.

In `@lib/providers/player_provider.dart`:
- Line 2755: Update _onCastStateChanged() to initialize setRemotePlayback’s
volume from CastService.mediaState.volume instead of the fixed 50, and keep the
Android Auto remote volume synchronized when subsequent Cast-side volume changes
are reported.

In `@lib/services/audio_handler.dart`:
- Around line 528-538: Update the AudioServiceConfig configuration to set
androidStopForegroundOnPause to false, keeping the audio service foregrounded
during pauses and preserving Android Auto cold-start/resume behavior. Do not add
battery-optimization handling or unrelated configuration changes.
- Around line 342-357: Update setRemotePlayback so the isRemote == false branch
emits a local PlaybackState after adding LocalAndroidPlaybackInfo, replacing the
remote playback state immediately; preserve the existing remote-mode update
behavior and construct the local state using the established playback-state
flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ae1f6f8-f0f4-488b-a1f3-034764a64229

📥 Commits

Reviewing files that changed from the base of the PR and between 3e805ef and a5b3138.

⛔ Files ignored due to path filters (2)
  • packages/flutter_chrome_cast/pubspec.lock is excluded by !**/*.lock
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • android/app/src/main/AndroidManifest.xml
  • android/app/src/main/kotlin/com/musly/musly/AndroidAutoPlugin.kt
  • android/app/src/main/kotlin/com/musly/musly/AndroidSystemPlugin.kt
  • android/app/src/main/kotlin/com/musly/musly/BluetoothMediaHelper.kt
  • android/app/src/main/kotlin/com/musly/musly/LyricsPlugin.kt
  • android/app/src/main/kotlin/com/musly/musly/MainActivity.kt
  • android/app/src/main/kotlin/com/musly/musly/MusicService.kt
  • lib/main.dart
  • lib/providers/auth_provider.dart
  • lib/providers/library_provider.dart
  • lib/providers/player_provider.dart
  • lib/services/android_auto_service.dart
  • lib/services/android_system_service.dart
  • lib/services/audio_handler.dart
  • lib/services/services.dart
  • pubspec.yaml
💤 Files with no reviewable changes (7)
  • lib/services/services.dart
  • android/app/src/main/kotlin/com/musly/musly/AndroidAutoPlugin.kt
  • lib/services/android_auto_service.dart
  • android/app/src/main/kotlin/com/musly/musly/MusicService.kt
  • lib/services/android_system_service.dart
  • android/app/src/main/kotlin/com/musly/musly/BluetoothMediaHelper.kt
  • lib/providers/auth_provider.dart

Comment thread lib/providers/library_provider.dart
Comment thread lib/providers/player_provider.dart
Comment thread lib/services/audio_handler.dart
Comment thread lib/services/audio_handler.dart
@mardale90 mardale90 marked this pull request as draft July 16, 2026 14:16
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.

2 participants