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:
@@ -4,6 +4,14 @@ import 'package:flutter/services.dart';
|
||||
|
||||
import '../modelos/dispositivo_audio.dart';
|
||||
|
||||
/// Composite-placeholder id prefix (bt-device-identity ADR-6): marks a BT
|
||||
/// device whose real MAC is not yet known (BLUETOOTH_CONNECT denied or
|
||||
/// unresolved). Single source of truth for the marker shared by
|
||||
/// `EstadoEcualizador` and the Auto EQ persistence-targeting logic: ids with
|
||||
/// this prefix are transient and must never receive a device-level preset
|
||||
/// entry.
|
||||
const prefijoPlaceholderBtName = 'bt_a2dp:name:';
|
||||
|
||||
/// Abstract service for audio device detection.
|
||||
///
|
||||
/// Implementations:
|
||||
@@ -21,6 +29,16 @@ abstract class ServicioDispositivoAudio {
|
||||
/// (method channel round-trip). Returns the cached value if already known.
|
||||
Future<DispositivoAudio> obtenerDispositivoActual();
|
||||
|
||||
/// Cancels the current device-change subscription and subscribes again.
|
||||
///
|
||||
/// Sends the platform `cancel`+`listen` control messages, which re-triggers
|
||||
/// `onListen` on the CURRENT activity's stream handler and re-registers the
|
||||
/// native `AudioDeviceCallback`. Needed because the Flutter engine outlives
|
||||
/// the Activity (`AudioServiceActivity`): after an activity recreation the
|
||||
/// new handler never saw a `listen`, so its event sink stays null and
|
||||
/// device events stop reaching Dart until this resync runs.
|
||||
Future<void> resubscribir();
|
||||
|
||||
/// Requests the `BLUETOOTH_CONNECT` runtime permission (API 31+) at the
|
||||
/// point the device-management UI is opened (bt-device-identity ADR-1).
|
||||
/// Returns true when granted or not required (SDK < 31, iOS); false when
|
||||
@@ -88,6 +106,12 @@ class ServicioDispositivoAudioReal extends ServicioDispositivoAudio {
|
||||
return device;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> resubscribir() async {
|
||||
await _eventSub?.cancel();
|
||||
_subscribeToEvents();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> solicitarPermisoBluetooth() async {
|
||||
final granted = await _methodChannel.invokeMethod<bool>(
|
||||
@@ -102,6 +126,15 @@ class ServicioDispositivoAudioReal extends ServicioDispositivoAudio {
|
||||
await _controller.close();
|
||||
}
|
||||
|
||||
/// Builds a [DispositivoAudio] from the raw platform-channel map shape.
|
||||
///
|
||||
/// Public so headless consumers (the Android Auto handler's one-shot
|
||||
/// `getActiveDevice` query) reuse the exact same mapping without opening a
|
||||
/// second event-channel subscription, which would steal this service's
|
||||
/// stream handler on the Dart side.
|
||||
static DispositivoAudio dispositivoDesdeMapa(Map<String, dynamic> map) =>
|
||||
_mapToDispositivo(map);
|
||||
|
||||
static DispositivoAudio _mapToDispositivo(Map<String, dynamic> map) {
|
||||
final id = map['id'] as String? ?? 'builtin_speaker';
|
||||
final type = map['type'] as int? ?? 2;
|
||||
|
||||
Reference in New Issue
Block a user