Merges its delta requirements into the android-auto-media base spec. Completes Phase 2; only Phase 3 (subfolder scoping, shuffle) remains. On-device validation of the native metadata path is still an outstanding pre-release gate across all local-music phases shipped today.
5.2 KiB
Proposal: Android Auto Local Music — Phase 2 (Real Metadata, Sort, Name Buckets)
Intent
Phase 1 shipped browsable SAF folders with filename-only titles and generic placeholder art. Phase 2 delivers the deferred polish: real embedded metadata (title/artist/bitrate/sample-rate/album art), sort by name and audio quality, and name-based navigation — without breaking Phase 1's lazy paging philosophy or its pure-SAF, zero-dangerous-permission stance.
Scope
In Scope
- A. Real metadata — resolve embedded title/artist/bitrate/sample-rate + embedded album art for tracks on the page being shown/played, replacing filename title and
station_art_*placeholder. - B. Sort — name (filename, already cheap) and quality (bitrate desc, reusing the
ordenarEmisoras(..., OrdenEmisoras.calidad)comparator shape) exposed as separate navigable sort-mode entries (Android Auto cannot re-sort in place). - C. Name navigation — alphabetical navigable buckets (A–F, etc.) as the realistic, browse-tree-native form of "filter by name".
- New translatable strings (sort-mode labels, "unknown metadata" text) added to ALL 13 ARB files from the start.
Out of Scope
- Phase 3: subfolder scoping, shuffle, transport-control polish.
- Live text-search box (impossible under legacy MediaBrowserService).
- Voice search via
audio_service.onSearch— flagged as Phase 3 candidate.
Capabilities
New Capabilities
- None.
Modified Capabilities
local-music-browse: gains metadata resolution, quality sort, alphabetical buckets (confirm exact spec name inopenspec/specs/during sdd-spec).android-auto-navigation: local branch gains sort-mode + bucket entries.
Approach — Metadata Extraction Decision (the one open technical call)
DECISION: native android.media.MediaMetadataRetriever on the existing pluriwave/file_actions channel. No new pub dependency.
Why, versus the Dart packages:
- Phase 1 tracks are
content://SAF URIs (buildDocumentUriUsingTree), NOT file paths and NOT guaranteed MediaStore-indexed.on_audio_queryis MediaStore-based and would (a) miss files outside standard media folders reached via an arbitrary SAF tree and (b) reintroduceREAD_MEDIA_AUDIO, the dangerous permission Phase 1 deliberately rejected — REJECT. audio_metadata_reader/flutter_media_metadataneed aFile/bytes; SAFcontent://gives neither, so we'd still need native byte-streaming — more complexity, no less native code.MediaMetadataRetriever.setDataSource(context, uri)accepts acontent://URI directly, returns TITLE/ARTIST/BITRATE +getEmbeddedPicture()bytes, reuses the existingcontentResolver, adds zero deps and zero permissions. Consistent with the Phase 1 hand-rolled-channel ADR.
DECISION: parse-on-demand + bounded in-memory session cache. NOT eager-scan-and-cache — eager scan is slow, needs a persistence store, and goes stale when the user adds/removes files. On-demand is always fresh and matches paging. Design formalizes cache bounds/eviction.
Tension to formalize in sdd-design: sort-by-quality needs bitrate for the whole folder, so it must resolve metadata for all tracks in that folder (not just the visible page). Mitigation: name sort stays metadata-free (filename only); quality-sort cost is paid only when the user opts into that entry.
Affected Areas
| Area | Impact | Description |
|---|---|---|
MainActivity.kt (file_actions) |
Modified | New readAudioMetadata(treeUri, documentId) via MediaMetadataRetriever; embedded-art delivery (cache file + existing FileProvider) — static-review-only |
lib/modelos/pista_local.dart |
Modified | Add artist/bitrate/sampleRate/artUri fields |
lib/servicios/musica_local_auto.dart |
Modified | Metadata channel call + session cache |
lib/servicios/navegacion_auto.dart |
Modified | Metadata-backed title/subtitle/art; sort-mode + bucket entries |
lib/l10n/*.arb (13) |
Modified | Sort/metadata labels |
Risks
| Risk | Likelihood | Mitigation |
|---|---|---|
| MMR sample-rate key is API 31+ | High | Degrade gracefully, reuse existing "unknown" handling |
artUri needs a static URI, not bytes |
High | Persist embedded art to cache dir, serve via existing FileProvider |
| Native untestable here (no build/DHU) | High | Static-review-only; keep sort/bucket/mapping logic pure Dart |
| Quality-sort forces full-folder parse | Med | Opt-in cost only when that entry is chosen |
| ARB drift across 13 locales | Med | All 13 in tasks from the start |
Rollback Plan
Additive over Phase 1. Revert by removing readAudioMetadata, restoring filename title + placeholder art, and dropping sort-mode/bucket entries. Phase 1 browse/play untouched.
Dependencies
- None new (native MMR, no pub package).
Success Criteria
- Tracks show embedded title/artist and real album art when present, filename/placeholder fallback otherwise.
- Name and quality sort available as navigable entries; quality orders by bitrate desc.
- Alphabetical buckets navigable within a folder.
- Metadata resolved on-demand only; no eager scan, no persistence staleness.
- All 13 ARB files carry new strings; no regression to Phase 1 or stations; pure Dart unit-tested, native static-reviewed.