Files
pluriwave/openspec/changes/bt-device-identity/proposal.md
T
FreeTLab 747738d20a
Build & Deploy PluriWave / Análisis de código (push) Successful in 35s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 1m38s
docs(openspec): add SDD artifact trails for bt-device-identity and alarm-volume-ramp-restore
In-progress artifact sets from the current SDD cycles: exploration,
proposal, spec, design, tasks, and verify reports as produced so far.
Also drops a leftover working copy of eq-device-disconnect-revert
whose contents were already committed under changes/archive/.
2026-07-11 00:56:22 +02:00

5.4 KiB

Proposal: Canonical Bluetooth Device Identity

Intent

Renaming a Bluetooth audio device then re-pairing creates a duplicate device in the multi-device EQ list, and devices display raw ids instead of their own Bluetooth name. Two compounding bugs cause this: (1) on Android 12+ the app never requests BLUETOOTH_CONNECT, so getAddress() returns the placeholder 02:00:00:00:00:00 for every BT device and they all collapse onto one id bt_a2dp:02:00:00:00:00:00; (2) any unseen deviceId spawns a new entry, and the rename overlay is keyed separately so a rename never transfers. Fixing identity now unblocks reliable per-device EQ before more devices accumulate corrupted keys.

Scope

In Scope

  • Declare BLUETOOTH_CONNECT in manifest + runtime request flow, mirroring POST_NOTIFICATIONS, triggered on opening the device-management UI.
  • Placeholder detection in deviceToMap(): treat 02:00:00:00:00:00 as absent → fall back to type+productName composite id (id format unchanged).
  • Cache per-device platform names in EstadoEcualizador; fix both nombreVisible() call sites so real BT names feed the fallback chain.
  • One-time destructive migration dropping placeholder-keyed entries from the three EQ persistence keys; keep stable-MAC entries.
  • New user-visible strings (permission rationale, migration notice) in all 13 locales.

Out of Scope

  • iOS changes — stableKey() already implements uid-primary / type+name fallback.
  • Reworking the composite-key format or the 4-level EQ resolution hierarchy.
  • Recovering data lost to the placeholder collision (unrecoverable by design).
  • Auto-switch / autoswitch-UX behavior (separate change).

Capabilities

No standing openspec/specs/* exists for audio devices yet (multi-device-eq shipped as an archived change). These are new capability specs.

New Capabilities

  • bt-device-identity: canonical MAC identity, placeholder detection + composite fallback, BLUETOOTH_CONNECT runtime flow, per-device name caching, and placeholder-key migration.

Modified Capabilities

  • None.

Approach

Restore a stable BT MAC by acquiring BLUETOOTH_CONNECT at the point of intent (device-management UI), and make the id pipeline resilient when it is still absent. Kotlin deviceToMap() gains an explicit placeholder guard so 02:00:00:00:00:00 is treated as blank, producing a deterministic type:productName id instead of a colliding one. EstadoEcualizador caches each device's reported platform name so nombreVisible() prefers the device's own Bluetooth name over the raw id. A guarded one-time migration purges only placeholder-keyed entries from the three SharedPreferences maps and surfaces a rename-again notice to affected users. MAC stays canonical wherever available; the colon-delimited key format is preserved intact.

Affected Areas

Area Impact Description
android/app/src/main/AndroidManifest.xml Modified Add BLUETOOTH_CONNECT (maxSdk-scoped as needed).
android/app/.../MainActivity.kt deviceToMap() Modified Placeholder guard → composite fallback; BT runtime-permission flow (mirror POST_NOTIFICATIONS).
lib/estado/estado_ecualizador.dart Modified Cache per-device platform names; feed nombreVisible(); stop spawning entries for placeholder ids.
lib/pantallas/pantalla_ajustes.dart (L769, L846) Modified Pass real platform name to nombreVisible() instead of ''.
lib/servicios/servicio_ecualizador.dart (keys L42-44) Modified Migration purging placeholder-keyed entries from 3 maps.
lib/l10n/*.arb (13 files) Modified Permission-rationale + migration-notice keys.

Risks

Risk Likelihood Mitigation
Migration deletes legitimate data Low Match ONLY exact bt_a2dp:02:00:00:00:00:00; keep all other keys.
BT permission denied → unstable ids Med Composite type:productName fallback keeps app functional; re-prompt on next UI open.
No BT-permission precedent in codebase Med Copy proven POST_NOTIFICATIONS/RECORD_AUDIO flow verbatim.
Composite-key colon-delimiter safety broken Low Id format unchanged; single leading type: segment preserved (ADR-3, multi-device-eq).

Rollback Plan

Changes are additive/guarded and behind a versioned migration. To revert: restore prior MainActivity.kt, estado_ecualizador.dart, pantalla_ajustes.dart, remove the BLUETOOTH_CONNECT declaration and the migration + l10n keys. The migration is one-shot and gated by a run-once flag; already-deleted placeholder-collision entries were unrecoverable regardless, so revert restores behavior, not lost data. No schema/version bump of the persistence keys, so downgrade is clean.

Dependencies

  • permission_handler capability already used for POST_NOTIFICATIONS/RECORD_AUDIO (reuse existing pattern; no new package expected).

Success Criteria

  • With BLUETOOTH_CONNECT granted, distinct BT devices produce distinct MAC-based ids (no 02:00:00:00:00:00).
  • Renaming a device then re-pairing does NOT create a duplicate entry.
  • The device list shows each device's own Bluetooth name by default; custom renames still override.
  • Migration removes only placeholder-keyed entries; stable-MAC EQ/preset/name data is retained.
  • Permission rationale + migration notice render correctly in all 13 locales.
  • flutter analyze clean; existing servicio_ecualizador_test.dart and EQ state tests pass.