fix(eq): stop the phone speaker from impersonating a Bluetooth device
deviceToMap handed the builtin_speaker id to EVERY output type its `when` did not name. A car stereo on LE Audio (TYPE_BLE_HEADSET) or an automotive bus (TYPE_BUS) therefore arrived in Dart under the phone speaker's own id, carrying a type that maps to `desconocido` -- which slipped past the type-only esBase guard and persisted a device entry keyed builtin_speaker. From that moment on, every playback through the phone's own speaker matched that entry, so the green active-output dot stayed pinned to whatever the user had renamed it to (a car, in the reported case) whether or not anything was connected. The dot was never wrong; the row was poisoned. Give unnamed output types their own `other:<type>:<address>` id namespace, and match esBase by id as well as by type so no future native regression can re-create the collision. A guarded one-time migration purges what the collision already persisted from all three device-keyed maps. Fix the ranking too: builtin_speaker sat inside the priority list as a peer, so any type absent from that list sorted BELOW the always-present speaker and could never win. The speaker is now the explicit last resort, externally connected outputs outrank it, and virtual or call-only sinks (earpiece, telephony, remote submix, SCO) are ranked below it so they can never be reported as where music is playing. Route every AudioDeviceInfo.getAddress read through a version-guarded helper. It is API 28 with minSdk 24, and two pre-existing unguarded calls in this same method were latent NoSuchMethodError crashes on Android 7-8.1. Android lint for :app goes from 8 errors to 6. Also lets the user manage the list, which is how they recover from a bad entry without waiting for a release: a remove action clears a device's preset, name and matrix entries, unnamed rows show their transport and address tail instead of a raw bt_a2dp:AA:BB:... id, and the green dot finally carries a tooltip and a semantics label saying what it means. Device QA pending for wired and USB outputs: no jack or adapter available to exercise those paths. Their detection is unchanged by this commit.
This commit is contained in:
@@ -196,11 +196,9 @@ void main() {
|
||||
// known devices.
|
||||
expect(find.text('Known audio devices'), findsOneWidget);
|
||||
|
||||
// The device ID should appear in the list.
|
||||
expect(
|
||||
find.textContaining('bt_a2dp:AA:BB:CC:DD:EE:FF'),
|
||||
findsOneWidget,
|
||||
);
|
||||
// The device row is listed. An unnamed device shows its transport plus
|
||||
// the tail of its address, not the raw id.
|
||||
expect(find.text('Bluetooth · EE:FF'), findsOneWidget);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -444,9 +442,10 @@ void main() {
|
||||
expect(find.text('AirPods Pro'), findsNothing);
|
||||
});
|
||||
|
||||
// 4.5 — approval test (regression-lock): a device never seen on the
|
||||
// stream has no cached platform name, so legacy raw-id fallback holds.
|
||||
testWidgets('4.5 no platform name yet falls back to raw id', (
|
||||
// 4.5 — a device never seen on the stream has no cached platform name, so
|
||||
// the row falls back to a humanized transport + address tail instead of the
|
||||
// raw id, which told the user nothing.
|
||||
testWidgets('4.5 no platform name yet shows a humanized transport label', (
|
||||
tester,
|
||||
) async {
|
||||
setLargeSurface(tester);
|
||||
@@ -467,7 +466,8 @@ void main() {
|
||||
);
|
||||
await pumpStable(tester);
|
||||
|
||||
expect(find.text(deviceId), findsOneWidget);
|
||||
expect(find.text('Bluetooth · EE:FF'), findsOneWidget);
|
||||
expect(find.text(deviceId), findsNothing);
|
||||
});
|
||||
|
||||
// 4.6 — permission trigger point: turning the toggle ON requests
|
||||
|
||||
Reference in New Issue
Block a user