Android Auto no longer copies the launcher icon as placeholder art; it rotates through the same 4 on-brand station_art assets the phone UI already uses, keyed by the same per-station hash for visual parity. Malformed or unusable favicon URLs (including a Dart Uri quirk where 'http://' reports hasAuthority=true with an empty host) now fail the validity gate instead of being handed to the OS media browser as-is. Browsable items also show codec/bitrate as a subtitle when known.
4.6 KiB
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 (sameandroid.resource://technique as existingdefault_station_art.png). - C — Surface
codec+bitrate(e.g. "128 kbps · MP3") viaMediaItem.displaySubtitleon 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.