Files
pluriwave/openspec/changes/archive/2026-07-16-android-auto-media/specs/android-auto-media/spec.md
T
FreeTLab f9003436ea docs(openspec): archive android-auto-media and auto-media-art-quality
Promotes the android-auto-media capability spec to openspec/specs/
and moves both completed changes into openspec/changes/archive/.
2026-07-19 13:22:18 +02:00

4.6 KiB

Android Auto Media Specification

Purpose

PluriWave MUST expose a browsable station tree and play-by-media-id interface to Android Auto (projected) via the existing PluriWaveAudioHandler (audio_service MediaBrowserService/MediaSession), so a driver can browse and play stations from the car head unit without rebuilding the audio pipeline.

Requirements

Requirement: Android Auto Discovery Declaration

The app MUST declare itself as a media app to Android Auto so the car head unit discovers it.

Scenario: Android Auto scans installed apps

  • GIVEN PluriWave is installed on the phone
  • WHEN Android Auto scans installed apps for car-app support
  • THEN it finds res/xml/automotive_app_desc.xml declaring <uses name="media"/>
  • AND the AndroidManifest.xml <application> block declares <meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc"/>
  • AND PluriWave appears in the car's media app list

Requirement: Browsable Media Tree

getChildren MUST return a browsable tree rooted at AudioService.browsableRootId, organized into non-playable folders (Favoritos, Todas las emisoras, Mis emisoras) containing playable station items.

Scenario: Car requests the root

  • GIVEN the car head unit connects and requests the root (AudioService.browsableRootId)
  • WHEN getChildren is called with the root id
  • THEN it returns three folder MediaItems (Favoritos, Todas las emisoras, Mis emisoras), each with playable: false

Scenario: Car requests a folder with no stations

  • GIVEN the user has zero favorite stations
  • WHEN getChildren is called with the Favoritos folder id
  • THEN it returns an empty list, not an error

Scenario: Browse requested before app state is loaded

  • GIVEN the audio handler starts cold and station/favorites Provider state has not finished loading
  • WHEN getChildren is called (root or any folder)
  • THEN it returns a valid, possibly empty, list without throwing and without blocking or crashing the service

Requirement: Playable Item Metadata

Every playable MediaItem (station) MUST include a non-empty title and a loadable artUri; stations without a logo MUST fall back to a bundled default artwork.

  • GIVEN a station has a valid remote logo URL
  • WHEN it is mapped to a MediaItem
  • THEN title is the station name and artUri is the station's logo URL
  • GIVEN a station has no logo (null or empty)
  • WHEN it is mapped to a MediaItem
  • THEN artUri is set to the bundled default artwork asset instead of being empty or null

Requirement: Media Item Resolution by ID

getMediaItem MUST resolve a single station id to its full MediaItem, returning null for unknown ids instead of throwing.

Scenario: Known station id

  • GIVEN a valid station id that exists in current state
  • WHEN getMediaItem(id) is called
  • THEN it returns the corresponding MediaItem with title and artUri populated

Scenario: Unknown station id

  • GIVEN an id that does not match any known station or folder
  • WHEN getMediaItem(id) is called
  • THEN it returns null without throwing

Requirement: Play by Media ID Reuses Existing Playback Path

playFromMediaId MUST resolve the id to an Emisora and invoke the existing internal playMediaItem path; it MUST NOT duplicate playback or reconnection logic.

Scenario: User selects a station in the car

  • GIVEN the user taps a playable station item on the car head unit
  • WHEN playFromMediaId(id) is called
  • THEN the id is resolved to an Emisora via the existing resolution logic (_emisoraDesdeMediaItem)
  • AND playback starts through the existing playMediaItem internal path
  • AND no separate or duplicated playback logic is executed

Scenario: Unknown or stale media id

  • GIVEN playFromMediaId is called with an id that no longer resolves to a known station
  • WHEN resolution fails
  • THEN playback does not start and no unhandled exception propagates from the handler

Requirement: Playback State Synchronization

Play/pause/stop state changes MUST remain synchronized between the car head unit and the phone UI, regardless of which side initiated the change.

Scenario: User pauses from the car

  • GIVEN a station is playing and projected to the car
  • WHEN the user pauses from the car head unit
  • THEN the phone UI reflects the paused state via the shared MediaSession/PlaybackState

Scenario: User pauses from the phone

  • GIVEN a station is playing and projected to the car
  • WHEN the user pauses from the phone UI
  • THEN the car head unit reflects the paused state via the same shared session