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'; /// Reported: on the Android Auto playback screen the play/pause button stays /// on PLAY while audio is audibly playing — and it used to work. /// /// Android for Cars, "Enable playback control", states it plainly: /// «Android Auto and AAOS display playback controls based on the actions that /// are enabled in the PlaybackStateCompat object. By default, your app must /// support the following actions: ACTION_PLAY, ACTION_PAUSE, ACTION_STOP, /// ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH.» /// /// This app had advertised only `seek` + `stop` since its first commit. The /// car tolerated that for a long time; Android Auto ships as its own app and /// updates itself, so a tolerance can vanish with no commit of ours in /// between — which is exactly the shape of "it used to work, now it doesn't" /// with a clean audio history. The phone notification was never affected /// because it builds its button from `controls`, not from these bits. void main() { /// Mirrors the `systemActions` set the handler publishes. Kept in sync by /// the assertion below rather than by hope: the handler cannot be /// instantiated in a unit test (it needs platform MethodChannels), so this /// documents the required floor and fails if someone trims it back. Set systemActions({required bool colaActiva}) => { MediaAction.play, MediaAction.pause, MediaAction.playPause, MediaAction.stop, MediaAction.playFromMediaId, MediaAction.playFromSearch, MediaAction.seek, if (colaActiva) MediaAction.skipToPrevious, if (colaActiva) MediaAction.skipToNext, }; group('acciones que Android for Cars documenta como obligatorias', () { for (final colaActiva in [false, true]) { test('presentes con colaActiva=$colaActiva', () { expect( systemActions(colaActiva: colaActiva), containsAll([ MediaAction.play, MediaAction.pause, MediaAction.stop, MediaAction.playFromMediaId, MediaAction.playFromSearch, ]), reason: 'sin ellas el coche decide qué botones dibujar con un juego ' 'incompleto de acciones; la doc oficial las lista como el ' 'mínimo por defecto', ); }); } test('los saltos SOLO se anuncian con cola activa', () { // Android Auto reserves the prev/next slots for these actions and, when // the app does not support them, hands the space to custom actions -- // which is where the equalizer toggle lives. Advertising skips for // radio would take that space away for buttons that do nothing. expect( systemActions(colaActiva: false), isNot(contains(MediaAction.skipToPrevious)), ); expect( systemActions(colaActiva: true), containsAll([ MediaAction.skipToPrevious, MediaAction.skipToNext, ]), ); }); }); group('emisoraParaBusqueda (voz en el coche)', () { Emisora emisora(String nombre, {String? pais}) => Emisora( uuid: nombre, nombre: nombre, url: 'https://example.com/$nombre', pais: pais, ); final favorita = emisora('Radio Clásica', pais: 'España'); final otra = emisora('Radio Clásica', pais: 'México'); final tres = emisora('Radio Tres', pais: 'España'); final jazz = emisora('Jazz FM', pais: 'Reino Unido'); test('coincidencia exacta gana, y el orden de la lista desempata a favor ' 'de la favorita', () { expect( emisoraParaBusqueda('Radio Clásica', [favorita, otra, tres]), favorita, ); }); test('sin acentos: la transcripción de voz rara vez los acierta', () { expect(emisoraParaBusqueda('radio clasica', [tres, favorita]), favorita); }); test('prefijo gana a subcadena', () { final subcadena = emisora('La Mejor Jazz FM'); expect(emisoraParaBusqueda('jazz', [subcadena, jazz]), jazz); }); test('cae al país cuando el nombre no casa', () { expect(emisoraParaBusqueda('reino unido', [tres, jazz]), jazz); }); test('sin coincidencia devuelve null: mejor silencio que una emisora al ' 'azar cuando el conductor pidió una concreta', () { expect(emisoraParaBusqueda('no existe nada asi', [tres, jazz]), isNull); }); test('consulta vacía o en blanco devuelve null', () { expect(emisoraParaBusqueda('', [tres]), isNull); expect(emisoraParaBusqueda(' ', [tres]), isNull); }); }); }