import 'dart:async'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pluriwave/main.dart'; /// Reported: with Android Auto connected, the car screen sometimes came up /// completely BLACK, and opening the app on the phone then showed a /// completely WHITE screen until it was force-killed and reopened. Never /// without Android Auto. /// /// Cause, verified in the plugin source: /// `AudioServiceActivity.provideFlutterEngine` returns /// `AudioServicePlugin.getFlutterEngine(context)`, which CREATES the engine /// and runs `main()` the first time it is asked — and the car asks first, /// when it binds the MediaBrowserService, so `main()` runs HEADLESS with no /// Activity. `SystemChrome.setPreferredOrientations` travels the /// `flutter/platform` channel, whose handler (`PlatformPlugin`) is installed /// by the Activity. Headless, nobody answers it. /// /// It was the FIRST `await` in `main()`, so that one call took the whole /// startup with it: the Android Auto browse source below it was never /// registered (`getChildren` had no source → black car screen) and `runApp` /// was never reached. Opening the app then reused that same cached, already /// dead engine → white screen. Only a force-kill, which disposes the cached /// engine, recovered it — exactly the workaround that was reported. /// /// The user's own guess was that portrait-only + a landscape phone made the /// app "go a bit crazy". Right file, right trigger, different mechanism: a /// broken layout renders overflow stripes or a red error box, never white. /// White means nothing was ever built. void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('política de orientación', () { test('un móvil se queda en vertical', () { expect(orientacionesPara(411), const [DeviceOrientation.portraitUp]); expect(orientacionesPara(599.9), const [DeviceOrientation.portraitUp]); }); test('una tablet puede girar', () { expect(orientacionesPara(600), DeviceOrientation.values); expect(orientacionesPara(1280), DeviceOrientation.values); }); }); group('nunca puede tumbar el arranque', () { test('un fallo del canal de plataforma se traga, no se propaga', () async { // This is the headless case: no PlatformPlugin, so the call fails. // Before the fix this exception escaped out of main() and killed // startup before runApp and before the Android Auto registration. await expectLater( aplicarPoliticaOrientacion( aplicar: (_) async => throw MissingPluginException( 'No implementation found for method ' 'SystemChrome.setPreferredOrientations on channel ' 'flutter/platform', ), ), completes, ); }); test('un canal que nunca responde tampoco puede colgar a quien llama, ' 'porque main() ya no lo espera', () async { // The structural half of the fix: main() calls this through // `unawaited(...)`. Proven here by starting a call that never settles // and showing the test still finishes -- if startup awaited it, this // future is exactly what would hang forever on the headless engine. var termino = false; unawaited( aplicarPoliticaOrientacion( aplicar: (_) => Completer().future, ).then((_) => termino = true), ); await Future.delayed(Duration.zero); expect(termino, isFalse, reason: 'sigue pendiente, como debe'); // The point is that nothing above depends on it. }); test('el camino feliz sigue aplicando la política de la pantalla', () { // Guard against "fixed" by neutering: the swallow-everything wrapper // must still actually apply something on a healthy engine. late List aplicadas; return aplicarPoliticaOrientacion( aplicar: (o) async => aplicadas = o, ).then((_) { expect(aplicadas, isNotEmpty); expect(aplicadas, orientacionesPara(800 / 1)); }); }); }); }