feat(eq): android auto custom equalizer and robust device detection
- MainActivity: onListen re-emits the current active device and registers the audio device callback idempotently, so recreated activities resync instead of freezing the active-device id on a disconnected device. - servicio_dispositivo_audio: resubscribir() re-opens the event channel; estado_ecualizador exposes refrescarDispositivoActual() with an in-flight guard, invoked on app resume and when opening advanced EQ options, clearing stale green-dot device selections. - navegacion_auto/servicio_audio: new 'Personalizado' browse tree in Android Auto (5 band folders, 13 gain steps each) applied live via setBanda; preset and gain taps persist at device level when multi-device EQ is active and respect station/matrix overrides, with apply-before-persist ordering and children-changed notifications. - l10n: regenerate stale generated localizations; add rxdart as direct dependency for the subscribeToChildren override.
This commit is contained in:
@@ -26,12 +26,6 @@ import '../servicios/servicio_ecualizador.dart';
|
||||
/// When the toggle is false, resolution falls back to the original 2-level
|
||||
/// hierarchy (station → global) — zero behavioral change vs. prior releases.
|
||||
class EstadoEcualizador extends ChangeNotifier {
|
||||
/// Composite-placeholder id prefix (bt-device-identity ADR-6): marks a
|
||||
/// device whose real Bluetooth MAC is not yet known (BLUETOOTH_CONNECT
|
||||
/// denied or unresolved). Devices with this prefix still update the
|
||||
/// platform-name cache but never auto-create a `presetsDispositivo` entry.
|
||||
static const _prefijoPlaceholderCompuesto = 'bt_a2dp:name:';
|
||||
|
||||
EstadoEcualizador({
|
||||
required this.audio,
|
||||
ServicioEcualizador? servicio,
|
||||
@@ -73,6 +67,7 @@ class EstadoEcualizador extends ChangeNotifier {
|
||||
bool _eqMultiDeviceEnabled = false;
|
||||
String? _dispositivoActualId;
|
||||
StreamSubscription<DispositivoAudio>? _deviceSub;
|
||||
Future<void>? _refrescoEnCurso;
|
||||
|
||||
PresetEcualizador get presetActual => _presetActual;
|
||||
PresetEcualizador get presetPrincipal => _presetPrincipal;
|
||||
@@ -208,6 +203,38 @@ class EstadoEcualizador extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// Re-syncs the active device after a possibly-missed native resync
|
||||
/// (activity recreation over the cached engine, return to foreground,
|
||||
/// opening the settings section): re-subscribes the platform event channel
|
||||
/// via [ServicioDispositivoAudio.resubscribir] — re-registering the native
|
||||
/// callback on the CURRENT activity — and re-seeds [_dispositivoActualId]
|
||||
/// with a fresh query. No-op when the multi-device toggle is off or no
|
||||
/// device service is injected; safe to call repeatedly. Concurrent calls
|
||||
/// (app-resume observer + settings initState) share the same in-flight
|
||||
/// refresh instead of racing [ServicioDispositivoAudio.resubscribir],
|
||||
/// which would leak a native AudioDeviceCallback.
|
||||
Future<void> refrescarDispositivoActual() {
|
||||
final enCurso = _refrescoEnCurso;
|
||||
if (enCurso != null) return enCurso;
|
||||
final refresco = _refrescarDispositivoActual().whenComplete(() {
|
||||
_refrescoEnCurso = null;
|
||||
});
|
||||
_refrescoEnCurso = refresco;
|
||||
return refresco;
|
||||
}
|
||||
|
||||
Future<void> _refrescarDispositivoActual() async {
|
||||
if (!_eqMultiDeviceEnabled) return;
|
||||
final svc = _dispositivoAudio;
|
||||
if (svc == null) return;
|
||||
try {
|
||||
await svc.resubscribir();
|
||||
} catch (_) {
|
||||
// A failed resubscribe must never block the fresh-query re-seed below.
|
||||
}
|
||||
await _sembrarDispositivoActual();
|
||||
}
|
||||
|
||||
/// Subscribes to the device change stream if multi-device is enabled.
|
||||
void _configurarSuscripcionDispositivo() {
|
||||
_deviceSub?.cancel();
|
||||
@@ -239,7 +266,7 @@ class EstadoEcualizador extends ChangeNotifier {
|
||||
// resolves to the eventual real-MAC id.
|
||||
final esBase = dispositivo.tipo == TipoDispositivo.altavozInterno;
|
||||
final esPlaceholderCompuesto = dispositivo.id.startsWith(
|
||||
_prefijoPlaceholderCompuesto,
|
||||
prefijoPlaceholderBtName,
|
||||
);
|
||||
if (!esBase &&
|
||||
!esPlaceholderCompuesto &&
|
||||
|
||||
Reference in New Issue
Block a user