Files
pluriwave/openspec/changes/android-auto-media/apply-progress.md
T
Javier Bautista Fernández 07c6e32af0
Build & Deploy PluriWave / Análisis de código (push) Successful in 26s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m22s
docs(auto): android auto research guide and sdd artifacts for android-auto-media
2026-07-16 16:28:54 +02:00

67 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Apply Progress: android-auto-media
**Batch**: 1 of 1 (all 31 tasks attempted in a single batch)
**Mode**: Strict TDD (Dart layers) + static-review-only (Kotlin/manifest/XML/PNG, per tasks.md)
## Summary
All tasks implemented. 31/31 marked `[x]` in `tasks.md`. New/changed test files: 31 targeted tests green (10 in `navegacion_auto_test.dart`, 21 in `estado_radio_test.dart`), plus 21 pre-existing tests in touched sibling files re-verified green as a safety net.
## TDD Cycle Evidence
| Task | Test File | Layer | Safety Net | RED | GREEN | TRIANGULATE | REFACTOR |
|------|-----------|-------|------------|-----|-------|-------------|----------|
| 1.1 | `test/servicios/navegacion_auto_test.dart` | Unit | N/A (new file) | ✅ Written | ✅ Passed | Structural | None needed |
| 1.21.3 | `navegacion_auto_test.dart` (raiz) | Unit | N/A (new) | ✅ Written | ✅ Passed | Single scenario (3-folder shape is fixed) | ✅ Clean |
| 1.41.6 | `navegacion_auto_test.dart` (itemEmisora) | Unit | N/A (new) | ✅ Written | ✅ Passed | ✅ 3 cases (remote favicon, null favicon, empty favicon) | ✅ Clean |
| 1.71.8 | `navegacion_auto_test.dart` (hijos) | Unit | N/A (new) | ✅ Written | ✅ Passed | ✅ 3 cases (60→50 cap+order, empty, unknown parentId) | ✅ Clean |
| 1.91.10 | `navegacion_auto_test.dart` (resolver) | Unit | N/A (new) | ✅ Written | ✅ Passed | ✅ 4 cases (known, no-prefix, empty-uuid, unmatched) | ✅ Clean |
| 1.111.12 | `navegacion_auto_test.dart` (reproducirPorMediaId) | Unit | N/A (new) | ✅ Written | ✅ Passed | ✅ 2 cases (known uuid delegates, unknown uuid no-ops) | ✅ Clean |
| 1.13 | `navegacion_auto_test.dart` (full file) | Unit | ✅ 10/10 before+after | — | — | — | ✅ Naming/doc pass, no duplicated art-fallback logic |
| 2.12.2 | — (static-review-only per tasks.md; covered indirectly by Phase 1 fakes exercising the interface contract) | N/A | N/A | N/A | N/A | N/A | N/A |
| 3.13.4 | — (static-review-only per tasks.md; thin delegation, verified by compiling through `servicio_audio_*_test.dart` safety-net runs) | N/A | ✅ 19/19 before, 19/19 after | N/A | N/A | N/A | N/A |
| 4.14.2 | `test/estado/estado_radio_test.dart` (snapshot push) | Unit | ✅ 19/19 baseline | ✅ Written | ✅ Passed | Single integration scenario across 3 mutation sites (favorites/custom/populares) | ✅ Clean |
| 4.34.4 | `estado_radio_test.dart` (reconcile) | Unit | ✅ 19/19 baseline | ✅ Written | ✅ Passed | Single scenario (car-initiated selection) | ✅ Clean |
| 4.5 | `estado_radio_test.dart` (full file) | Unit | ✅ 21/21 before+after | — | — | — | ✅ Doc comments added, no behavior change |
| 5.1 | — (static-review-only per tasks.md; no `main.dart`/`app.dart` test pattern exists) | N/A | N/A | N/A | N/A | N/A | N/A |
| 6.16.3 | — (static-review-only per tasks.md; no Android build env) | N/A | N/A | N/A | N/A | N/A | N/A |
| 7.1 | Targeted run (see deviation note in tasks.md) | Unit | — | — | ✅ 52/52 combined | — | — |
| 7.2 | Manual static review (see deviation note in tasks.md) | — | — | — | — | — | — |
| 7.3 | This note | — | — | — | — | — | — |
### Test Summary
- **Total tests written**: 12 (10 in `navegacion_auto_test.dart` + 2 in `estado_radio_test.dart`)
- **Total tests passing**: 52 (31 new/touched + 21 pre-existing safety-net, all green)
- **Layers used**: Unit (12 new)
- **Approval tests**: None — no refactoring-of-existing-behavior tasks (4.14.4 add new optional-param behavior, existing callers unaffected: `fuenteAuto` defaults to `null`)
- **Pure functions created**: `ConstructorArbolAuto.raiz/hijos/itemEmisora/resolver`, `reproducirPorMediaId` — all pure or side-effect-isolated via injected callback
## Files Changed
| File | Action | What Was Done |
|------|--------|----------------|
| `lib/servicios/navegacion_auto.dart` | Created | `FuenteEmisorasAuto` interface (+ default no-op `actualizarSnapshot`), `ConstructorArbolAuto` pure builder, `reproducirPorMediaId` routing seam, `FuenteEmisorasAutoLocal` cold-start-safe data source |
| `lib/servicios/servicio_audio.dart` | Modified | `registrarFuenteNavegacion()` + module field (mirrors `registrarHandler`); `PluriWaveAudioHandler` overrides `getChildren`/`getMediaItem`/`playFromMediaId`, all delegating to `navegacion_auto.dart`'s tested pure logic, all swallowing errors per spec |
| `lib/estado/estado_radio.dart` | Modified | Optional `fuenteAuto` ctor param; pushes live snapshot at 5 `notifyListeners()` sites across `cargarPopulares`, `cargarFavoritos`, `_cargarEmisorasCustom`/`_leerContenidoCustom`; reconciles `_emisoraSeleccionada` in `_escucharErroresReproduccion` |
| `lib/main.dart` | Modified | Builds `FuenteEmisorasAutoLocal`, calls `registrarFuenteNavegacion`, passes it to `PluriWaveApp` |
| `lib/app.dart` | Modified | `PluriWaveApp` accepts optional `fuenteAuto`, forwards it to `EstadoRadio` |
| `android/app/src/main/res/xml/automotive_app_desc.xml` | Created | `<automotiveApp><uses name="media"/></automotiveApp>` |
| `android/app/src/main/AndroidManifest.xml` | Modified | Added `com.google.android.gms.car.application` meta-data inside `<application>` |
| `android/app/src/main/res/drawable/default_station_art.png` | Created | 192×192 PNG copied from `mipmap-xxxhdpi/ic_launcher.png` (no Android build env to generate a bespoke asset — see Deviations) |
| `test/servicios/navegacion_auto_test.dart` | Created | 10 tests: raiz, itemEmisora (favicon + fallback), hijos (cap/order/empty/unknown), resolver (known/malformed/unmatched), reproducirPorMediaId (known/unknown) |
| `test/estado/estado_radio_test.dart` | Modified | Added `_FuenteEmisorasAutoEspia` spy, `_AudioControlado.seleccionarDesdeAuto()` helper, 2 new tests (snapshot push, reconciliation) |
## Deviations from Design
1. **`actualizarSnapshot` promoted to the abstract `FuenteEmisorasAuto` interface** (design's code block only listed it as `FuenteEmisorasAutoLocal`-specific). Necessary because task 4.2 requires `EstadoRadio` to call `fuenteAuto?.actualizarSnapshot(...)` through the `FuenteEmisorasAuto?`-typed field — Dart's `implements` contract requires the method on the interface for that call to type-check. Given a default no-op body on the abstract class, this is additive and behavior-neutral for any implementation that doesn't need it.
2. **Default artwork PNG is a placeholder**, not a bespoke "no logo" graphic: copied from the existing `mipmap-xxxhdpi/ic_launcher.png` launcher asset since there is no Android build/design-asset environment available here. Filename/path/dimensions are correct and Android-loadable; the actual pixel content should be swapped for a proper station-art placeholder before shipping (noted in task 6.3 static review).
3. **Content-style extra keys** use the documented Android Auto browse hint keys (`android.media.browse.CONTENT_STYLE_BROWSABLE_HINT` / `..._PLAYABLE_HINT`) since Design left the exact key names unspecified ("Non-blocking polish"); this is standard, well-known Android Auto convention.
## Issues Found
None — all safety-net tests (pre-existing tests in every touched file) stayed green throughout.
## Status
31/31 tasks complete. Ready for `sdd-verify`. A real `flutter analyze` + full `flutter test` + DHU manual verification pass is recommended before merge, per the noted execution-constraint deviations on 7.1/7.2.