From 35bb18061292c9689250b97edb7c9d43bf323bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Bautista=20Fern=C3=A1ndez?= Date: Thu, 16 Jul 2026 16:28:44 +0200 Subject: [PATCH] feat(auto): browsable Android Auto media tree with play-by-id [size:exception] Expose PluriWave to Android Auto (projected) as a media app: - Declare car media support (automotive_app_desc.xml + manifest meta-data) so Android Auto discovers the existing MediaBrowserService. - New navegacion_auto.dart: ConstructorArbolAuto builds the browse tree (Favoritos / Todas las emisoras / Mis emisoras, 50-item cap, stable emisora: media ids), reproducirPorMediaId routes a car tap to the existing playMediaItem pipeline, FuenteEmisorasAutoLocal serves the tree cold-start-safe (local favorites/custom stations before Flutter UI runs). - PluriWaveAudioHandler overrides getChildren/getMediaItem/playFromMediaId as thin delegations; playback pipeline untouched. - EstadoRadio pushes live station snapshots to the browse source and reconciles the selected station when playback starts from the car. - Every playable item ships title + artUri; stations without logo fall back to a bundled default art (android.resource://). Tests: 52/52 green (10 new navegacion_auto, 2 new estado_radio, plus audio safety-net suites). Handler overrides and native XML are static-review-only (no Android build env). Size exception approved for a single reviewable commit. --- android/app/src/main/AndroidManifest.xml | 5 + .../main/res/drawable/default_station_art.png | Bin 0 -> 85707 bytes .../src/main/res/xml/automotive_app_desc.xml | 3 + lib/app.dart | 10 +- lib/estado/estado_radio.dart | 28 +- lib/main.dart | 14 +- lib/servicios/navegacion_auto.dart | 265 ++++++++++++++++++ lib/servicios/servicio_audio.dart | 91 ++++++ test/estado/estado_radio_test.dart | 115 ++++++++ test/servicios/navegacion_auto_test.dart | 226 +++++++++++++++ 10 files changed, 754 insertions(+), 3 deletions(-) create mode 100644 android/app/src/main/res/drawable/default_station_art.png create mode 100644 android/app/src/main/res/xml/automotive_app_desc.xml create mode 100644 lib/servicios/navegacion_auto.dart create mode 100644 test/servicios/navegacion_auto_test.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 00285e1..0579d5d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -107,6 +107,11 @@ + + + diff --git a/android/app/src/main/res/drawable/default_station_art.png b/android/app/src/main/res/drawable/default_station_art.png new file mode 100644 index 0000000000000000000000000000000000000000..56ef9efbf483ad81df157b33c996b833c31cf832 GIT binary patch literal 85707 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

gdQ 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�qA^A0PdGdZC@A44<{L#ZQ% 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 + + diff --git a/lib/app.dart b/lib/app.dart index 28671b8..29099ff 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -24,16 +24,23 @@ import 'widgets/pluri_layout.dart'; import 'widgets/pluri_onboarding_dialog.dart'; import 'widgets/pluri_wave_scaffold.dart'; import 'package:pluriwave/widgets/mini_reproductor.dart'; +import 'servicios/navegacion_auto.dart'; import 'servicios/servicio_alarmas_android.dart'; import 'servicios/servicio_dispositivo_audio.dart'; class PluriWaveApp extends StatelessWidget { - const PluriWaveApp({super.key, this.prefs}); + const PluriWaveApp({super.key, this.prefs, this.fuenteAuto}); /// Single SharedPreferences instance resolved in main() (S3-R4) and /// injected into every state/service. final SharedPreferences? prefs; + /// Android Auto browse source (Design "Data Flow" — cold-bind local read + /// available before EstadoRadio builds). Optional: defaults to `null`, + /// same as every other existing caller/test that constructs + /// [PluriWaveApp] without it. + final FuenteEmisorasAuto? fuenteAuto; + @override Widget build(BuildContext context) { return MultiProvider( @@ -43,6 +50,7 @@ class PluriWaveApp extends StatelessWidget { (_) => EstadoRadio( prefs: prefs, dispositivoAudio: ServicioDispositivoAudioReal(), + fuenteAuto: fuenteAuto, ), ), // Domain notifiers (S4-R1/R2/R3). Created and disposed by EstadoRadio diff --git a/lib/estado/estado_radio.dart b/lib/estado/estado_radio.dart index d052a22..24df246 100644 --- a/lib/estado/estado_radio.dart +++ b/lib/estado/estado_radio.dart @@ -16,6 +16,7 @@ import 'estado_busqueda.dart'; import 'estado_ecualizador.dart'; import 'estado_grabacion.dart'; import 'orden_emisoras.dart'; +import '../servicios/navegacion_auto.dart'; import '../servicios/persistencia_tolerante.dart'; import '../servicios/servicio_audio.dart'; import '../servicios/servicio_dispositivo_audio.dart'; @@ -44,6 +45,7 @@ class EstadoRadio extends ChangeNotifier { ServicioGrabacionRadio? servicioGrabacion, SharedPreferences? prefs, Future Function()? resolverArchivoCustom, + FuenteEmisorasAuto? fuenteAuto, bool iniciarAutomaticamente = true, }) : audio = audio ?? ServicioAudio(), favoritos = favoritos ?? ServicioFavoritos(), @@ -52,7 +54,8 @@ class EstadoRadio extends ChangeNotifier { servicioEcualizador ?? ServicioEcualizador(prefs: prefs), _dispositivoAudio = dispositivoAudio, _prefs = prefs, - _resolverArchivoCustom = resolverArchivoCustom { + _resolverArchivoCustom = resolverArchivoCustom, + _fuenteAuto = fuenteAuto { ecualizador = EstadoEcualizador( audio: this.audio, servicio: this.servicioEcualizador, @@ -96,6 +99,13 @@ class EstadoRadio extends ChangeNotifier { final SharedPreferences? _prefs; final Future Function()? _resolverArchivoCustom; + /// Android Auto browse source (Design "live snapshot the source + /// prefers"). Optional and unused by default — wired from main.dart via + /// the [FuenteEmisorasAutoLocal] instance registered into the handler. + /// When set, this instance's in-memory lists are pushed on every mutation + /// so the car sees the same data as the phone without a duplicate read. + final FuenteEmisorasAuto? _fuenteAuto; + /// Single startup instance injected from main() (S3-R4); falls back to /// getInstance() only when nothing was injected (tests, legacy callers). Future _resolverPrefs() async => @@ -292,6 +302,14 @@ class EstadoRadio extends ChangeNotifier { grabacion.activa) { unawaited(grabacion.detener()); } + // Design "playback coherence with EstadoRadio": a car-initiated + // selection (Android Auto's playFromMediaId) changes audio.emisoraActual + // directly, bypassing reproducir(). Without this, _emisoraSeleccionada + // would keep shadowing the car's station on emisoraActual's getter. + final actual = audio.emisoraActual; + if (actual != null && actual.uuid != _emisoraSeleccionada?.uuid) { + _emisoraSeleccionada = actual; + } notifyListeners(); }); } @@ -311,6 +329,9 @@ class EstadoRadio extends ChangeNotifier { _errorCarga = _textos.radioApiConnectionError; } finally { _cargandoPopulares = false; + // Design "live snapshot the source prefers": Android Auto's `Todas` + // folder mirrors the same populares list the phone just loaded. + _fuenteAuto?.actualizarSnapshot(todas: _populares); notifyListeners(); } } @@ -318,6 +339,7 @@ class EstadoRadio extends ChangeNotifier { Future cargarFavoritos() async { _listaFavoritos = await favoritos.obtenerTodos(); await _normalizarEmisoraPreferida(); + _fuenteAuto?.actualizarSnapshot(favoritos: _listaFavoritos); notifyListeners(); } @@ -542,6 +564,7 @@ class EstadoRadio extends ChangeNotifier { detalle: 'resolucion de ruta', razon: e.toString(), ); + _fuenteAuto?.actualizarSnapshot(misEmisoras: _emisorasCustom); notifyListeners(); return; } @@ -567,6 +590,7 @@ class EstadoRadio extends ChangeNotifier { razon: e.toString(), ); } + _fuenteAuto?.actualizarSnapshot(misEmisoras: _emisorasCustom); notifyListeners(); } @@ -582,6 +606,7 @@ class EstadoRadio extends ChangeNotifier { if (!await archivo.exists()) { _emisorasCustom = []; _customDegradado = false; + _fuenteAuto?.actualizarSnapshot(misEmisoras: _emisorasCustom); notifyListeners(); return null; } @@ -594,6 +619,7 @@ class EstadoRadio extends ChangeNotifier { detalle: archivo.path, razon: e.toString(), ); + _fuenteAuto?.actualizarSnapshot(misEmisoras: _emisorasCustom); notifyListeners(); return null; } diff --git a/lib/main.dart b/lib/main.dart index b9c67cc..5d189cc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'app.dart'; +import 'servicios/navegacion_auto.dart'; import 'servicios/servicio_audio.dart'; import 'servicios/servicio_audio_session.dart'; import 'tema/pluriwave_tokens.dart'; @@ -41,12 +42,23 @@ Future main() async { ); registrarHandler(handler); + // Android Auto browse source (Design "getChildren data source, cold-start + // safe") — registered before EstadoRadio builds so a headless Auto bind + // (main() runs but the lazily-created Provider tree may never build) can + // still serve favourites/custom stations from local reads. + final fuenteAuto = FuenteEmisorasAutoLocal(); + registrarFuenteNavegacion(fuenteAuto); + // S3-R1: audio focus — phone calls / transient losses pause or duck the // radio; headphones unplugged pauses it. final sesionAudio = ServicioAudioSession(objetivo: handler); unawaited(sesionAudio.configurar()); - runApp(_OrientacionResponsiveApp(child: PluriWaveApp(prefs: prefs))); + runApp( + _OrientacionResponsiveApp( + child: PluriWaveApp(prefs: prefs, fuenteAuto: fuenteAuto), + ), + ); } Future _aplicarPoliticaOrientacion([ui.Display? display]) async { diff --git a/lib/servicios/navegacion_auto.dart b/lib/servicios/navegacion_auto.dart new file mode 100644 index 0000000..8213d8d --- /dev/null +++ b/lib/servicios/navegacion_auto.dart @@ -0,0 +1,265 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:audio_service/audio_service.dart'; +import 'package:path_provider/path_provider.dart'; + +import '../estado/orden_emisoras.dart'; +import '../modelos/emisora.dart'; +import 'persistencia_tolerante.dart'; +import 'servicio_favoritos.dart'; + +/// URI of the bundled default station artwork, served from +/// `android/app/src/main/res/drawable` via `android.resource://` (Design +/// "default artwork delivery" — no per-URI grant needed, works offline, and +/// cannot 404 unlike a FileProvider content URI or a remote placeholder). +const String _defaultArtUri = + 'android.resource://es.freetimelab.pluriwave/drawable/default_station_art'; + +const _prefijoEmisora = 'emisora:'; + +/// Browse-source abstraction for the Android Auto media tree (Design +/// "getChildren data source, cold-start safe"). Kept separate from +/// `EstadoRadio` so a headless Auto bind (`main()` runs but the widget tree +/// — and therefore the lazily-created `EstadoRadio` — never builds) still +/// gets a valid, non-throwing tree. +abstract class FuenteEmisorasAuto { + Future> favoritos(); + Future> misEmisoras(); + + /// `populares` snapshot; may be empty on a cold bind (Design "which + /// stations surface & ordering"). + Future> todas(); + Future porUuid(String uuid); + + /// Live-snapshot push (Design "live snapshot the source prefers"): + /// `EstadoRadio`, when alive, calls this unconditionally on every + /// favorites/custom/populares mutation so a car and phone that are both + /// live see identical lists. Default no-op — only implementations that + /// actually buffer a snapshot (e.g. [FuenteEmisorasAutoLocal]) need to + /// override it; a null field on `EstadoRadio` skips the call entirely via + /// `?.`. + void actualizarSnapshot({ + List? favoritos, + List? misEmisoras, + List? todas, + }) {} +} + +/// Pure builder for the Android Auto browse tree: folders, leaf items, id +/// resolution. No platform dependency — fully testable without a running +/// car or a real `AudioHandler`. +class ConstructorArbolAuto { + /// Root folder ids (Design "media-id scheme"). The tree root itself is + /// identified by [AudioService.browsableRootId], not by a constant here — + /// the handler compares against it directly before calling [raiz]. + static const idFavoritos = 'favoritos'; + static const idTodas = 'todas'; + static const idMisEmisoras = 'mis_emisoras'; + + static const _idsCarpetas = {idFavoritos, idTodas, idMisEmisoras}; + static const _maxItemsPorCarpeta = 50; + + /// Content-style extras (Design "content style", optional polish): list + /// (1) for the root's folders, grid (2) for playable station items. + static const _contentStyleLista = { + 'android.media.browse.CONTENT_STYLE_BROWSABLE_HINT': 1, + 'android.media.browse.CONTENT_STYLE_PLAYABLE_HINT': 1, + }; + static const _contentStyleGrid = { + 'android.media.browse.CONTENT_STYLE_PLAYABLE_HINT': 2, + }; + + /// The 3 root folders (Favoritos, Todas las emisoras, Mis emisoras), all + /// non-playable. + List raiz() => [ + _carpeta(idFavoritos, 'Favoritos'), + _carpeta(idTodas, 'Todas las emisoras'), + _carpeta(idMisEmisoras, 'Mis emisoras'), + ]; + + MediaItem _carpeta(String id, String titulo) => MediaItem( + id: id, + title: titulo, + playable: false, + extras: _contentStyleLista, + ); + + /// Leaf items for [parentId], sorted via [ordenarEmisoras] and capped at + /// [_maxItemsPorCarpeta] (Design "which stations surface & ordering" — + /// avoids driver distraction and Auto list limits). Unknown [parentId] + /// (or an empty [emisoras]) returns an empty list instead of throwing. + List hijos(String parentId, {required List emisoras}) { + if (!_idsCarpetas.contains(parentId)) return const []; + if (emisoras.isEmpty) return const []; + final ordenadas = ordenarEmisoras(emisoras, OrdenEmisoras.calidad); + return ordenadas.take(_maxItemsPorCarpeta).map(itemEmisora).toList(); + } + + /// Maps a single [Emisora] to a playable `MediaItem`: id `emisora:` + /// (Design "media-id scheme"), title, and artUri with the default-art + /// fallback (Design "default artwork delivery"). + MediaItem itemEmisora(Emisora e) => MediaItem( + id: '$_prefijoEmisora${e.uuid}', + title: e.nombre, + playable: true, + artUri: Uri.parse(_artUriPara(e)), + extras: _contentStyleGrid, + ); + + String _artUriPara(Emisora e) { + final favicon = e.favicon; + return (favicon != null && favicon.isNotEmpty) ? favicon : _defaultArtUri; + } + + /// Resolves `emisora:` ids to the matching [Emisora] in [universo]. + /// Any other shape (no prefix, empty uuid, unmatched uuid) returns `null` + /// instead of throwing (Spec "Media Item Resolution by ID"). + Emisora? resolver(String id, List universo) { + if (!id.startsWith(_prefijoEmisora)) return null; + final uuid = id.substring(_prefijoEmisora.length); + if (uuid.isEmpty) return null; + for (final emisora in universo) { + if (emisora.uuid == uuid) return emisora; + } + return null; + } +} + +/// Routing seam between a car-tapped `emisora:` media id and the +/// existing internal playback path (Design "playback coherence" — reuse +/// over duplication). Resolves the uuid via [fuente], builds the same +/// phone-shaped `MediaItem` (`id` = station url, `extras['uuid']`) that +/// [ServicioAudio.reproducir] builds, and delegates to [reproducir]. +/// +/// A stale/unknown id (or a malformed one) is a no-op: [reproducir] is +/// never called and no exception propagates (Spec "Unknown or stale media +/// id"). +Future reproducirPorMediaId( + String id, { + required FuenteEmisorasAuto fuente, + required Future Function(MediaItem) reproducir, +}) async { + if (!id.startsWith(_prefijoEmisora)) return; + final uuid = id.substring(_prefijoEmisora.length); + if (uuid.isEmpty) return; + + final emisora = await fuente.porUuid(uuid); + if (emisora == null) return; + + final item = MediaItem( + id: emisora.url, + title: emisora.nombre, + artist: emisora.pais ?? '', + album: 'PluriWave', + artUri: + emisora.favicon != null && emisora.favicon!.isNotEmpty + ? Uri.tryParse(emisora.favicon!) + : null, + extras: {'uuid': emisora.uuid}, + ); + await reproducir(item); +} + +/// Local, cold-start-safe implementation of [FuenteEmisorasAuto] (Design +/// "getChildren data source"). Reads favourites from SQLite and custom +/// stations from the tolerant JSON file directly — both loadable without +/// the network or a built widget tree, unlike `EstadoRadio._init()` (which +/// is lazy-created by `ChangeNotifierProvider.create:` and may never run on +/// a headless Auto bind). `EstadoRadio`, when alive, overrides these reads +/// with a live snapshot via [actualizarSnapshot]. +class FuenteEmisorasAutoLocal implements FuenteEmisorasAuto { + FuenteEmisorasAutoLocal({ + ServicioFavoritos? favoritosServicio, + Future Function()? resolverRutaCustom, + }) : _favoritosServicio = favoritosServicio ?? ServicioFavoritos(), + _resolverRutaCustom = resolverRutaCustom; + + final ServicioFavoritos _favoritosServicio; + final Future Function()? _resolverRutaCustom; + + List? _snapshotFavoritos; + List? _snapshotMisEmisoras; + List? _snapshotTodas; + + /// Overrides the next reads with `EstadoRadio`'s live in-memory lists + /// (Design "live snapshot the source prefers"). Passing `null` for a + /// field leaves its current override (or local read) untouched. + @override + void actualizarSnapshot({ + List? favoritos, + List? misEmisoras, + List? todas, + }) { + if (favoritos != null) _snapshotFavoritos = favoritos; + if (misEmisoras != null) _snapshotMisEmisoras = misEmisoras; + if (todas != null) _snapshotTodas = todas; + } + + @override + Future> favoritos() async { + final snapshot = _snapshotFavoritos; + if (snapshot != null) return snapshot; + try { + return await _favoritosServicio.obtenerTodos(); + } catch (_) { + // Cold-start safety (Spec "Browse requested before app state is + // loaded"): never throw out of a browse call. + return const []; + } + } + + @override + Future> misEmisoras() async { + final snapshot = _snapshotMisEmisoras; + if (snapshot != null) return snapshot; + return _leerEmisorasCustom(); + } + + @override + Future> todas() async { + // No live network snapshot on a cold bind — populated only once + // EstadoRadio pushes its populares list (Design "which stations + // surface & ordering": degrades gracefully to empty-but-valid). + return _snapshotTodas ?? const []; + } + + @override + Future porUuid(String uuid) async { + final listas = await Future.wait([favoritos(), misEmisoras(), todas()]); + for (final lista in listas) { + for (final emisora in lista) { + if (emisora.uuid == uuid) return emisora; + } + } + return null; + } + + /// Mirrors `EstadoRadio._cargarEmisorasCustom()`'s tolerant JSON read: + /// missing/corrupt files never throw, they degrade to an empty list. + Future> _leerEmisorasCustom() async { + try { + final ruta = await _rutaArchivoCustom(); + final archivo = File(ruta); + if (!await archivo.exists()) return const []; + final contenido = await archivo.readAsString(); + final data = jsonDecode(contenido) as List; + final resultado = parseListaTolerante( + data, + Emisora.fromMap, + subsistema: 'emisoras_custom_auto', + coleccion: 'emisoras_custom', + ); + return resultado.validas; + } catch (_) { + return const []; + } + } + + Future _rutaArchivoCustom() async { + final resolver = _resolverRutaCustom; + if (resolver != null) return resolver(); + final dir = await getApplicationDocumentsDirectory(); + return '${dir.path}/emisoras_custom.json'; + } +} diff --git a/lib/servicios/servicio_audio.dart b/lib/servicios/servicio_audio.dart index 0b9eccb..63871c0 100644 --- a/lib/servicios/servicio_audio.dart +++ b/lib/servicios/servicio_audio.dart @@ -11,6 +11,7 @@ import '../l10n/gen/app_localizations.dart'; import '../modelos/emisora.dart'; import '../modelos/preset_ecualizador.dart'; import 'controlador_reconexion.dart'; +import 'navegacion_auto.dart'; import 'servicio_audio_session.dart'; /// Estado de reproducción expuesto al UI. @@ -35,6 +36,16 @@ void registrarHandler(PluriWaveAudioHandler handler) { _handlerGlobal = handler; } +// ───────────────────────────────────────────────────────────────────────────── +// Android Auto browse source — registered from main.dart, mirrors +// registrarHandler above (Design "getChildren data source registration"). +// ───────────────────────────────────────────────────────────────────────────── +FuenteEmisorasAuto? _fuenteNavegacionGlobal; + +void registrarFuenteNavegacion(FuenteEmisorasAuto fuente) { + _fuenteNavegacionGlobal = fuente; +} + /// Wrapper de alto nivel para el UI. class ServicioAudio { PluriWaveAudioHandler get _handler { @@ -712,4 +723,84 @@ class PluriWaveAudioHandler extends BaseAudioHandler favicon: mediaItem.artUri?.toString(), ); } + + // ── Android Auto browsing (thin delegation to navegacion_auto.dart's + // already-tested pure logic — Design "getChildren data source") ───────── + + @override + Future> getChildren( + String parentMediaId, [ + Map? options, + ]) async { + try { + final constructor = ConstructorArbolAuto(); + if (parentMediaId == AudioService.browsableRootId) { + return constructor.raiz(); + } + final fuente = _fuenteNavegacionGlobal; + if (fuente == null) return const []; + final emisoras = await _listaParaCarpeta(fuente, parentMediaId); + return constructor.hijos(parentMediaId, emisoras: emisoras); + } catch (_) { + // Spec "Browse requested before app state is loaded": never throw out + // of a browse call, even on an unexpected failure. + return const []; + } + } + + @override + Future getMediaItem(String mediaId) async { + try { + final fuente = _fuenteNavegacionGlobal; + if (fuente == null) return null; + final universo = await _universoCompleto(fuente); + final constructor = ConstructorArbolAuto(); + final emisora = constructor.resolver(mediaId, universo); + return emisora == null ? null : constructor.itemEmisora(emisora); + } catch (_) { + return null; + } + } + + @override + Future playFromMediaId( + String mediaId, [ + Map? extras, + ]) async { + final fuente = _fuenteNavegacionGlobal; + if (fuente == null) return; + try { + await reproducirPorMediaId( + mediaId, + fuente: fuente, + reproducir: playMediaItem, + ); + } catch (e) { + // Spec "Unknown or stale media id": never propagate from the handler. + developer.log( + '[PluriWave] Error en playFromMediaId($mediaId): $e', + name: 'ServicioAudio', + level: 900, + ); + } + } + + Future> _listaParaCarpeta( + FuenteEmisorasAuto fuente, + String parentId, + ) => switch (parentId) { + ConstructorArbolAuto.idFavoritos => fuente.favoritos(), + ConstructorArbolAuto.idMisEmisoras => fuente.misEmisoras(), + ConstructorArbolAuto.idTodas => fuente.todas(), + _ => Future.value(const []), + }; + + Future> _universoCompleto(FuenteEmisorasAuto fuente) async { + final listas = await Future.wait([ + fuente.favoritos(), + fuente.misEmisoras(), + fuente.todas(), + ]); + return listas.expand((lista) => lista).toList(); + } } diff --git a/test/estado/estado_radio_test.dart b/test/estado/estado_radio_test.dart index 977d165..27089fc 100644 --- a/test/estado/estado_radio_test.dart +++ b/test/estado/estado_radio_test.dart @@ -6,6 +6,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:pluriwave/estado/estado_radio.dart'; import 'package:pluriwave/modelos/emisora.dart'; import 'package:pluriwave/modelos/preset_ecualizador.dart'; +import 'package:pluriwave/servicios/navegacion_auto.dart'; import 'package:pluriwave/servicios/servicio_audio.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -547,6 +548,111 @@ void main() { ); }, ); + + group( + 'EstadoRadio — Android Auto: snapshot en vivo y reconciliación ' + '(android-auto-media)', + () { + test( + 'empuja un snapshot actualizado a la fuente registrada cuando ' + 'cambian favoritos/custom/populares', + () async { + final fuenteAuto = _FuenteEmisorasAutoEspia(); + final archivo = await _crearArchivoCustom([ + emisoraDemo(uuid: 'custom-auto-1', nombre: 'Custom Auto'), + ]); + final emisoraFav = emisoraDemo(uuid: 'fav-auto-1', nombre: 'Fav Auto'); + final estado = EstadoRadio( + audio: FakeServicioAudio(), + favoritos: FakeServicioFavoritos(), + radio: FakeServicioRadio( + populares: [emisoraDemo(uuid: 'pop-auto-1', nombre: 'Pop Auto')], + ), + servicioEcualizador: FakeServicioEcualizador(), + resolverArchivoCustom: () async => archivo, + fuenteAuto: fuenteAuto, + iniciarAutomaticamente: false, + ); + + await estado.inicializar(); + + expect( + fuenteAuto.ultimoMisEmisoras?.map((e) => e.uuid), + contains('custom-auto-1'), + ); + expect( + fuenteAuto.ultimoTodas?.map((e) => e.uuid), + contains('pop-auto-1'), + ); + + await estado.toggleFavorito(emisoraFav); + + expect( + fuenteAuto.ultimoFavoritos?.map((e) => e.uuid), + contains('fav-auto-1'), + ); + }, + ); + + test( + 'reconcilia _emisoraSeleccionada cuando la selección viene desde ' + 'el auto (no via reproducir())', + () async { + final audio = _AudioControlado(); + final estado = EstadoRadio( + audio: audio, + favoritos: FakeServicioFavoritos(), + radio: FakeServicioRadio(), + servicioEcualizador: FakeServicioEcualizador(), + resolverArchivoCustom: _archivoCustomVacio, + iniciarAutomaticamente: false, + ); + await estado.inicializar(); + final desdeCoche = emisoraDemo( + uuid: 'auto-selected', + nombre: 'Desde el auto', + ); + + audio.seleccionarDesdeAuto(desdeCoche); + await Future.delayed(Duration.zero); + + expect(estado.emisoraActual?.uuid, desdeCoche.uuid); + }, + ); + }, + ); +} + +/// Spy [FuenteEmisorasAuto] that only records the last snapshot pushed by +/// [EstadoRadio] via [actualizarSnapshot] — used to assert the live-snapshot +/// wiring (Design "live snapshot the source prefers") without touching the +/// real local data source. +class _FuenteEmisorasAutoEspia implements FuenteEmisorasAuto { + List? ultimoFavoritos; + List? ultimoMisEmisoras; + List? ultimoTodas; + + void actualizarSnapshot({ + List? favoritos, + List? misEmisoras, + List? todas, + }) { + if (favoritos != null) ultimoFavoritos = favoritos; + if (misEmisoras != null) ultimoMisEmisoras = misEmisoras; + if (todas != null) ultimoTodas = todas; + } + + @override + Future> favoritos() async => ultimoFavoritos ?? const []; + + @override + Future> misEmisoras() async => ultimoMisEmisoras ?? const []; + + @override + Future> todas() async => ultimoTodas ?? const []; + + @override + Future porUuid(String uuid) async => null; } /// [File] spy: only the members `_cargarEmisorasCustom`/ @@ -630,6 +736,15 @@ class _AudioControlado extends ServicioAudio { _pendientes.remove(uuid)?.complete(); } + /// Simulates a car-initiated selection (android-auto-media task 4.3): + /// changes [emisoraActual] WITHOUT going through [reproducir], then pushes + /// an `estadoStream` event, exactly like the real handler would after + /// `playFromMediaId` bypasses `EstadoRadio.reproducir()`. + void seleccionarDesdeAuto(Emisora emisora) { + _actual = emisora; + _estadoController.add(EstadoReproduccion.reproduciendo); + } + @override Future aplicarPreset(PresetEcualizador preset) async {} diff --git a/test/servicios/navegacion_auto_test.dart b/test/servicios/navegacion_auto_test.dart new file mode 100644 index 0000000..fb93387 --- /dev/null +++ b/test/servicios/navegacion_auto_test.dart @@ -0,0 +1,226 @@ +import 'package:audio_service/audio_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pluriwave/modelos/emisora.dart'; +import 'package:pluriwave/servicios/navegacion_auto.dart'; + +void main() { + group('ConstructorArbolAuto.raiz', () { + test('devuelve exactamente 3 carpetas no reproducibles con los ids ' + 'esperados', () { + final raiz = ConstructorArbolAuto().raiz(); + + expect(raiz, hasLength(3)); + final ids = raiz.map((item) => item.id).toSet(); + expect( + ids, + equals({ + ConstructorArbolAuto.idFavoritos, + ConstructorArbolAuto.idTodas, + ConstructorArbolAuto.idMisEmisoras, + }), + ); + for (final item in raiz) { + expect(item.playable, isFalse); + expect(item.title, isNotEmpty); + } + }); + }); + + group('ConstructorArbolAuto.itemEmisora', () { + test('usa el favicon remoto como artUri cuando existe', () { + final emisora = _emisora( + uuid: 'uuid-logo', + nombre: 'Radio Con Logo', + favicon: 'https://cdn.example.com/logo.png', + ); + + final item = ConstructorArbolAuto().itemEmisora(emisora); + + expect(item.id, 'emisora:${emisora.uuid}'); + expect(item.title, emisora.nombre); + expect(item.artUri.toString(), emisora.favicon); + expect(item.playable, isTrue); + }); + + test('cae al arte por defecto cuando el favicon es null o vacío', () { + final sinFavicon = _emisora( + uuid: 'uuid-null', + nombre: 'Radio Sin Logo', + favicon: null, + ); + final faviconVacio = _emisora( + uuid: 'uuid-vacio', + nombre: 'Radio Logo Vacio', + favicon: '', + ); + const esperado = + 'android.resource://es.freetimelab.pluriwave/drawable/default_station_art'; + + final builder = ConstructorArbolAuto(); + + expect(builder.itemEmisora(sinFavicon).artUri.toString(), esperado); + expect(builder.itemEmisora(faviconVacio).artUri.toString(), esperado); + }); + }); + + group('ConstructorArbolAuto.hijos', () { + test('limita a 50 items y respeta el orden de ordenarEmisoras', () { + final emisoras = List.generate( + 60, + (i) => _emisora(uuid: 'uuid-$i', nombre: 'Radio $i', bitrate: i), + ); + + final hijos = ConstructorArbolAuto().hijos( + ConstructorArbolAuto.idFavoritos, + emisoras: emisoras, + ); + + expect(hijos, hasLength(50)); + // ordenarEmisoras por calidad ordena por bitrate descendente: el + // primer item debe ser el de mayor bitrate (59) y el ultimo (el #50) + // el de bitrate 10 (59..10 son 50 valores). + expect(hijos.first.id, 'emisora:uuid-59'); + expect(hijos.last.id, 'emisora:uuid-10'); + }); + + test('lista vacía cuando no hay emisoras, sin lanzar', () { + final hijos = ConstructorArbolAuto().hijos( + ConstructorArbolAuto.idFavoritos, + emisoras: const [], + ); + + expect(hijos, isEmpty); + }); + + test('parentId desconocido devuelve lista vacía', () { + final emisoras = [_emisora(uuid: 'uuid-1', nombre: 'Radio 1')]; + + final hijos = ConstructorArbolAuto().hijos( + 'carpeta-inexistente', + emisoras: emisoras, + ); + + expect(hijos, isEmpty); + }); + }); + + group('ConstructorArbolAuto.resolver', () { + test('resuelve un uuid conocido a su Emisora', () { + final emisora = _emisora(uuid: 'uuid-conocido', nombre: 'Conocida'); + final universo = [emisora, _emisora(uuid: 'otra', nombre: 'Otra')]; + + final resultado = ConstructorArbolAuto().resolver( + 'emisora:uuid-conocido', + universo, + ); + + expect(resultado, equals(emisora)); + }); + + test( + 'devuelve null para id sin prefijo, id malformado o uuid sin match, ' + 'sin lanzar', + () { + final universo = [_emisora(uuid: 'uuid-conocido', nombre: 'Conocida')]; + final builder = ConstructorArbolAuto(); + + expect(builder.resolver('favoritos', universo), isNull); + expect(builder.resolver('emisora:', universo), isNull); + expect( + builder.resolver('emisora:uuid-desconocido', universo), + isNull, + ); + }, + ); + }); + + group('reproducirPorMediaId', () { + test( + 'resuelve el id y delega a reproducir con un MediaItem con forma de ' + 'telefono (id=url, extras.uuid)', + () async { + final emisora = _emisora( + uuid: 'uuid-play', + nombre: 'Radio a reproducir', + url: 'https://stream.demo/play', + ); + final fuente = _FakeFuenteEmisorasAuto( + porUuidResultado: {emisora.uuid: emisora}, + ); + MediaItem? recibido; + + await reproducirPorMediaId( + 'emisora:${emisora.uuid}', + fuente: fuente, + reproducir: (item) async { + recibido = item; + }, + ); + + expect(recibido, isNotNull); + expect(recibido!.id, emisora.url); + expect(recibido!.extras?['uuid'], emisora.uuid); + }, + ); + + test( + 'id obsoleto/desconocido no llama a reproducir ni lanza excepción', + () async { + final fuente = _FakeFuenteEmisorasAuto(porUuidResultado: const {}); + var llamadas = 0; + + await reproducirPorMediaId( + 'emisora:uuid-fantasma', + fuente: fuente, + reproducir: (item) async { + llamadas++; + }, + ); + + expect(llamadas, 0); + }, + ); + }); +} + +Emisora _emisora({ + required String uuid, + required String nombre, + String url = 'https://stream.demo/radio', + String? favicon, + int? bitrate, +}) { + return Emisora( + uuid: uuid, + nombre: nombre, + url: url, + favicon: favicon, + bitrate: bitrate, + ); +} + +class _FakeFuenteEmisorasAuto implements FuenteEmisorasAuto { + _FakeFuenteEmisorasAuto({required Map porUuidResultado}) + : _porUuidResultado = porUuidResultado; + + final Map _porUuidResultado; + + @override + Future> favoritos() async => const []; + + @override + Future> misEmisoras() async => const []; + + @override + Future> todas() async => const []; + + @override + Future porUuid(String uuid) async => _porUuidResultado[uuid]; + + @override + void actualizarSnapshot({ + List? favoritos, + List? misEmisoras, + List? todas, + }) {} +}