Files
pluriwave/openspec/changes/android-auto-local-music-phase2/specs/android-auto-media/spec.md
T
FreeTLab 352eb9fc37 feat(auto): real metadata, quality sort and name buckets for local music [size:exception]
Local tracks now show embedded title/artist/album art (via native
MediaMetadataRetriever, cached through the existing FileProvider)
instead of the raw filename, falling back gracefully when a file
has no usable tags. Adds two navigable entry points per folder: sort
by audio quality (bitrate, capped at 150 tracks per folder to bound
worst-case latency) and alphabetical name buckets -- the closest
realistic form of "filtering" given Android Auto has no text-search
UI in this integration.

Metadata resolves only for the page actually being browsed (same
slice-cheap-then-map discipline as the paging change), backed by a
flat 256-entry LRU session cache that survives across pages. No new
permission, no new pub dependency, no l10n changes (car-tree labels
stay hardcoded Spanish, matching every existing label in the tree).
2026-07-19 23:52:08 +02:00

99 lines
6.0 KiB
Markdown

# Delta for Android Auto Media
## MODIFIED Requirements
### Requirement: Local Music Browsable Tree
The Android Auto browse tree MUST expose a new non-playable local-music root folder alongside the existing station folders. Browsing that root and any nested subfolder MUST recursively mirror the picked SAF folder's structure: subfolders as non-playable `carpeta_local:<id>` items and audio files as playable `pista:<id>` items resolving to `PistaLocal` instances. When embedded metadata (title and/or album art) can be resolved for a track on the requested page, the displayed title and art MUST reflect that metadata instead of the raw filename and generic placeholder art. When metadata is unavailable, unparseable, or resolution otherwise fails, the item MUST fall back to the raw filename as title and the existing generic placeholder art, exactly as in Phase 1.
(Previously: always used the raw filename as the displayed title, with no metadata resolution.)
#### Scenario: Car browses the local-music root
- GIVEN a local music root folder was picked and its permission is valid
- WHEN `getChildren` is called with the local-music root folder id
- THEN it returns the root's immediate subfolders as `carpeta_local:<id>` items and audio files as `pista:<id>` playable items
- AND each playable item's title reflects resolved metadata when available, else the file's raw filename
#### Scenario: Car browses a nested subfolder
- GIVEN a `carpeta_local:<id>` folder returned from a prior browse call
- WHEN `getChildren` is called with that folder id
- THEN it returns that subfolder's own contents (nested folders and/or tracks), recursively mirroring the on-device structure
- AND browsing an empty subfolder returns an empty list, not an error
#### Scenario: Track has embedded metadata
- GIVEN an audio file on the requested page has parseable embedded title and/or album art
- WHEN it is mapped to a playable `pista:<id>` `MediaItem`
- THEN its `title` and `artUri` reflect the resolved metadata, not the raw filename or generic placeholder
#### Scenario: Metadata unavailable or resolution fails (graceful fallback)
- GIVEN an audio file's embedded metadata is absent, corrupt, in an unsupported format, or blocked by a permission edge case
- WHEN it is mapped to a playable `pista:<id>` `MediaItem`
- THEN its title falls back to the raw filename and its art falls back to the generic placeholder, exactly as in Phase 1
- AND no exception propagates from metadata resolution, and the rest of that page's items are still returned
## ADDED Requirements
### Requirement: Local Music Sort Mode Navigation
The local-music browse tree MUST expose sort mode as navigable, non-playable browse-tree entries (at least "by name" and "by audio quality") for a folder's tracks, since the underlying legacy browse surface cannot re-sort an already-rendered folder in place. Selecting a sort-mode entry MUST return that folder's tracks ordered accordingly: name sort orders by filename; quality sort orders by bitrate descending, reusing the existing `ordenarEmisoras(..., OrdenEmisoras.calidad)` comparator shape.
#### Scenario: Sort-mode entries are available for a folder
- GIVEN the user is browsing a local-music folder containing tracks
- WHEN that folder's sort-mode navigation is requested
- THEN at least a "by name" and a "by audio quality" navigable entry are returned
#### Scenario: User selects sort by quality
- GIVEN the user selects the "by audio quality" entry for a folder
- WHEN its children are resolved
- THEN the folder's tracks are returned ordered by bitrate descending
- AND tracks with unknown bitrate are ordered consistently, without throwing
#### Scenario: User selects sort by name
- GIVEN the user selects the "by name" entry for a folder
- WHEN its children are resolved
- THEN the folder's tracks are returned ordered by filename
### Requirement: Local Music Alphabetical Name Buckets
The local-music browse tree MUST expose alphabetical name-bucket entries (e.g. A-F, G-M, ...) as navigable, non-playable folders for a folder's tracks, as the Phase 2 realization of name-based filtering — the underlying legacy `MediaBrowserService` surface does not support a live text-search box.
#### Scenario: User browses name buckets for a folder
- GIVEN a local-music folder contains tracks spanning multiple starting letters
- WHEN the user browses that folder's name-bucket navigation level
- THEN each returned bucket is a non-playable folder covering a contiguous letter range
- AND selecting a bucket returns only the tracks whose name falls within that range
#### Scenario: Bucket with no matching tracks
- GIVEN a name-bucket range that currently matches zero tracks in a folder
- WHEN that bucket is browsed
- THEN it returns an empty list, not an error
### Requirement: Local Track Embedded Album Art Display
A playable `pista:<id>` `MediaItem` MUST display embedded album art via `artUri` when the track's embedded picture can be resolved and served as a static URI. When embedded art is absent or cannot be resolved (per the browse tree's metadata-resolution fallback), the item MUST fall back to Phase 1's existing generic rotating placeholder art (`station_art_*` rotation). The car head unit MUST NOT display an empty or broken art tile for any local track.
#### Scenario: Track has embedded album art
- GIVEN an audio file on the requested page has a resolvable embedded picture
- WHEN it is mapped to a playable `MediaItem`
- THEN `artUri` points at the resolved embedded art, served as a static URI
#### Scenario: Track has no or unresolvable embedded art
- GIVEN an audio file has no embedded picture, or it cannot be parsed or served
- WHEN it is mapped to a playable `MediaItem`
- THEN `artUri` falls back to the same rotating placeholder used in Phase 1
- AND no broken, empty, or indefinitely-loading art tile is shown
## Out of Scope (Phase 2)
The following are explicitly deferred and MUST NOT be treated as Phase 2 requirements: local-folder subfolder-scoping refinements, shuffle playback, live text search, and voice search (`audio_service.onSearch`). These remain candidates for Phase 3 or later.