fix(alarmas,auto): guard the last unguarded snooze path, surface car progress
Continuation of7054a4c: the native anchor guard alone did not fix the reported ~1444-minute snooze, because Dart runs AFTERWARDS on the pre-notice path and had no guard at all. 1. Snooze from the pre-notice notification, root cause. app.dart dispatches AFTER the receiver's postponeNext already ran and after startActivity, and EstadoAlarmas.posponerProximaDesdePreaviso took whatever occurrence it was handed on faith, then persisted and rescheduled from it -- the last snooze path in the codebase with no occurrence guard. The occurrence itself is not trustworthy either: app.dart falls back to alarma.proximaEjecucion when the native event carries none, and that field can already point at tomorrow. _ocurrenciaSonando is generalized into _ocurrenciaValida with a caller- supplied forward allowance and an externally-proposed occurrence that still has to survive the same check. The pre-notice path gets a ventanaPreaviso (30 min, matching AlarmScheduler.PRE_NOTICE_MILLIS) -- unlike the ringing-screen guard, this occurrence legitimately has not happened yet, which is exactly why the existing helper could not just be reused here. Also heals state already poisoned by the missing guard: a snoozeHasta parked past a 3-hour ceiling (posponerEjecucion clamps to 120 minutes, so anything beyond that is corruption, not a long real snooze) is dropped on recalculation. Without it, an alarm poisoned on a build before this fix keeps reporting tomorrow after updating, and the user reasonably concludes nothing changed. 2. Android Auto: no progress bar or time labels on a local track. updatePosition was never set anywhere in the handler, so it sat at its Duration.zero default while copyWith refreshed updateTime to now on every push -- the car was told "position 0, as of right now" on every event, a bar pinned at the start regardless of what was actually playing. Now set from _player.position on both the player-state and buffered-position listeners (the latter ticks ~2/s, which is what keeps the car's bar smooth between player-state events). Also stream the MediaItem's duration once the source reports it -- Auto draws no bar at all without one, and radio streams correctly keep reporting none (live audio has no length). 3. Android Auto: drop the Ecualizador browsable folder. Owner decision after driving with it: a browsable six-preset list is more interaction than a driver wants, and on/off from all three player views (already fixed in7054a4cto win the custom-action slot) is the only equalizer control that belongs in the car. Preset selection stays on the phone. This lands back on the redesign mockup's original rule ("sin carpeta de ecualizador"), now for a road-tested reason. getChildren keeps answering the folder's id transitionally, since a head unit can have the old tree cached for a session or two. The two "raiz always includes/ends with Ecualizador" tests are replaced, not regressed -- same move the codebase already made once in the other direction for the same folder. Tests: 1127 -> 1132.
This commit is contained in:
@@ -578,6 +578,7 @@ class PluriWaveAudioHandler extends BaseAudioHandler
|
||||
late AudioPlayer _player = _crearPlayer();
|
||||
StreamSubscription<PlayerState>? _estadoPlayerSub;
|
||||
StreamSubscription<Duration>? _bufferedSub;
|
||||
StreamSubscription<Duration?>? _duracionSub;
|
||||
StreamSubscription<PlaybackEvent>? _eventosSub;
|
||||
StreamSubscription<int?>? _androidAudioSessionIdSub;
|
||||
final _androidAudioSessionIdController = StreamController<int?>.broadcast();
|
||||
@@ -720,6 +721,16 @@ class PluriWaveAudioHandler extends BaseAudioHandler
|
||||
cambiandoFuente: _cambiandoFuente,
|
||||
),
|
||||
playing: playing,
|
||||
// Reported: in Android Auto the progress bar and the time labels of
|
||||
// a local track never move. `updatePosition` was NEVER set anywhere
|
||||
// in this file, so it stayed at its `Duration.zero` default while
|
||||
// `copyWith` refreshed `updateTime` to now on every push
|
||||
// (audio_service.dart:411-413, :256). A client extrapolates
|
||||
// `updatePosition + (now - updateTime) * speed`, so it was told
|
||||
// "position 0, as of right now" over and over — a bar pinned at the
|
||||
// start. The phone UI never noticed because it reads
|
||||
// `_player.positionStream` directly.
|
||||
updatePosition: _player.position,
|
||||
bufferedPosition: _player.bufferedPosition,
|
||||
speed: _player.speed,
|
||||
),
|
||||
@@ -728,7 +739,27 @@ class PluriWaveAudioHandler extends BaseAudioHandler
|
||||
});
|
||||
|
||||
_bufferedSub = _player.bufferedPositionStream.listen((pos) {
|
||||
playbackState.add(playbackState.value.copyWith(bufferedPosition: pos));
|
||||
playbackState.add(
|
||||
playbackState.value.copyWith(
|
||||
bufferedPosition: pos,
|
||||
// Must ride along: `copyWith` stamps a fresh `updateTime` but keeps
|
||||
// the old `updatePosition`, so a push without it actively tells the
|
||||
// client the PREVIOUS position is current NOW — freezing the bar
|
||||
// between player-state events. This stream ticks ~2/s, which is
|
||||
// what keeps the car's bar smooth.
|
||||
updatePosition: _player.position,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
// Duration arrives asynchronously once the source is parsed, and Android
|
||||
// Auto draws no progress bar for a MediaItem without one. Radio streams
|
||||
// report null (correct: live audio has no length) and are left alone.
|
||||
_duracionSub = _player.durationStream.listen((duracion) {
|
||||
final actual = mediaItem.value;
|
||||
if (duracion == null || actual == null) return;
|
||||
if (actual.duration == duracion) return;
|
||||
mediaItem.add(actual.copyWith(duration: duracion));
|
||||
});
|
||||
|
||||
_eventosSub = _player.playbackEventStream.listen(
|
||||
@@ -1180,6 +1211,7 @@ class PluriWaveAudioHandler extends BaseAudioHandler
|
||||
Future<void> _recrearPlayer() async {
|
||||
await _estadoPlayerSub?.cancel();
|
||||
await _bufferedSub?.cancel();
|
||||
await _duracionSub?.cancel();
|
||||
await _eventosSub?.cancel();
|
||||
await _androidAudioSessionIdSub?.cancel();
|
||||
|
||||
@@ -1486,6 +1518,7 @@ class PluriWaveAudioHandler extends BaseAudioHandler
|
||||
await stop();
|
||||
await _estadoPlayerSub?.cancel();
|
||||
await _bufferedSub?.cancel();
|
||||
await _duracionSub?.cancel();
|
||||
await _eventosSub?.cancel();
|
||||
await _androidAudioSessionIdSub?.cancel();
|
||||
await _player.dispose();
|
||||
@@ -1535,6 +1568,13 @@ class PluriWaveAudioHandler extends BaseAudioHandler
|
||||
// external data source, unlike every branch below it -- checked
|
||||
// before the `_fuenteNavegacionGlobal` gate, mirroring how the
|
||||
// local-music branch above is also resolved before that gate.
|
||||
// The Ecualizador folder is no longer offered by `raiz()` (owner
|
||||
// decision: the car keeps only the on/off toggle on the playback
|
||||
// screen). This branch stays as a TRANSITIONAL courtesy: Android Auto
|
||||
// caches browse trees on the head unit, so a stale "Ecualizador" entry
|
||||
// can survive the update for a session or two. Answering it keeps that
|
||||
// leftover working instead of opening an empty dead folder. Delete
|
||||
// once no head unit can still be holding the old tree.
|
||||
if (parentMediaId == ConstructorArbolAuto.idEcualizador) {
|
||||
return itemsEcualizadorAuto(
|
||||
activo: _ecualizadorActivo,
|
||||
|
||||
Reference in New Issue
Block a user