# Proposal: Android Auto Media Art & Quality Polish ## Intent Fast-follow to `android-auto-media`, closing 3 gaps that parent's verify-report flagged (PASS WITH WARNINGS) plus one requested capability. In the car head unit today: (1) stations whose favicon URL is present but dead render broken/blank art — Android Auto resolves `artUri` OUTSIDE the Flutter engine, so the phone's `CachedNetworkImage.errorWidget` fallback never runs (only empty-favicon Case A is handled); (2) the fallback art is a byte-for-byte copy of the launcher icon, reading as a bug; (3) browse items expose no audio-quality hint even though `Emisora.codec`/`bitrate` already exist. This picks up the "fallback artwork for stations without favicons" work deferred in engram #2290. ## Scope ### In Scope - **A** — Degrade Android Auto art gracefully when favicon is present but unreachable (Case B), not only empty (Case A). - **B** — Replace launcher-icon placeholder with the 4 on-brand `station_art_*` assets, reusing `_fallbackArtFor`'s deterministic per-station hash-by-uuid rotation for phone/car parity. Requires native Android drawable copies of the 4 PNGs (same `android.resource://` technique as existing `default_station_art.png`). - **C** — Surface `codec` + `bitrate` (e.g. "128 kbps · MP3") via `MediaItem.displaySubtitle` on browse items; omit gracefully when unknown (never "null kbps"). - Strict-TDD Dart tests for rotation selection, subtitle formatting, and Case-B fallback path. ### Out of Scope - Commissioning brand-new custom artwork (no image-gen tooling here, #2290; reuse existing approved assets — external follow-up may add custom art later). - iOS CarPlay; voice search; phone-UI art changes (already correct). - `flutter build`/`analyze`/`gen-l10n` (hang in this environment). ## Capabilities ### New Capabilities - None. ### Modified Capabilities - `android-auto-media`: browse-item requirements extended — artwork MUST degrade gracefully for both empty AND unreachable favicons using on-brand rotating placeholders, and playable items SHOULD carry an audio-quality subtitle. ## Approach Reuse, don't rebuild — mirror the phone UI. Port `_fallbackArtFor`'s uuid-hash rotation into `navegacion_auto.dart` so `_artUriPara()` picks one of 4 native drawables. Add `displaySubtitle` in `itemEmisora()` from existing `codec`/`bitrate`. **Deferred to design.md — the real open question:** HOW to detect Case B (dead URL) with no Flutter image widget in the OS browser loop. Design must weigh proactive reachability check + cache (network cost, staleness, invalidation) vs. piggybacking the phone's `CachedNetworkImage` error signal (misses car-first-open stations) vs. documenting the gap as a known limitation this iteration. ## Affected Areas | Area | Impact | Description | |------|--------|-------------| | `lib/servicios/navegacion_auto.dart` | Modified | `_artUriPara()` rotation + Case-B fallback; `itemEmisora()` subtitle | | `android/app/src/main/res/drawable/station_art_*.png` | New | 4 native copies of brand assets | | `android/app/src/main/res/drawable/default_station_art.png` | Removed/Kept | Retire launcher-icon copy (design confirms) | | `test/` (Dart) | New | Rotation, subtitle, fallback tests | ## Risks | Risk | Likelihood | Mitigation | |------|------------|------------| | Case-B detection adds unbounded network cost | Med | Design phase decides; may accept as documented gap | | Native drawable / asset drift over time | Low | Comment linking copies to `assets/images/` source | | Malformed codec/bitrate → ugly subtitle | Low | Format guard; omit when either is unknown | ## Split Judgment Keep as ONE change: A+B+C all touch `navegacion_auto.dart` browse-item construction and share tests. If design finds Case-B reachability checking too costly/complex, split A into its own follow-up and ship B+C (pure, low-risk parity + subtitle) first. ## Rollback Plan Additive. Revert PR: restore `_artUriPara()`, drop `displaySubtitle`, delete the 4 native drawables (and restore `default_station_art.png` if retired), remove new tests. Phone UI and audio pipeline untouched — zero residual state. ## Dependencies - `audio_service ^0.18.18` (present; `MediaItem.displaySubtitle`). - Existing `assets/images/station_art_*.png` (source for native copies). ## Success Criteria - [ ] Unreachable favicon shows on-brand art in car, not broken/blank (or gap documented). - [ ] Fallback uses rotating `station_art_*`, matching phone per-station selection. - [ ] Launcher-icon-as-art no longer appears. - [ ] Browse items show quality subtitle; unknown quality omits cleanly. - [ ] Dart tests pass under `flutter test`.