Skip to content

Device: Show a Connect button when AirPods are not connected to this phone#489

Merged
d4rken merged 1 commit into
mainfrom
feat/device-settings-not-connected-card
Apr 8, 2026
Merged

Device: Show a Connect button when AirPods are not connected to this phone#489
d4rken merged 1 commit into
mainfrom
feat/device-settings-not-connected-card

Conversation

@d4rken

@d4rken d4rken commented Apr 8, 2026

Copy link
Copy Markdown
Member

What changed

When your AirPods are paired to multiple phones and audio is currently playing on a different phone, this phone can still see the AirPods nearby but can't access their settings. Until now the Device Settings screen just showed the basic info card and an empty body — confusing, with no explanation.

Now, in that state, a "Not connected" card appears below the device info with a Connect button. Tapping it asks Android to nudge a connection to the AirPods. If that's not available on your phone, the button instead opens the system Bluetooth settings so you can connect manually. Once the connection goes through, the card disappears and all AAP settings and controls become available as normal.

Technical Context

  • Why the card only appears when device.ble != null && !device.isAapConnected && device.address != null: BLE advertisements being live means the AirPods are actually nearby (the existing BlePodMonitor ~20s eviction handles freshness). No AAP state (aap == null) means there's no BR/EDR classic socket — this automatically excludes the cold-start synthesis window where aap != null but state is CONNECTING/HANDSHAKING. Requiring a bonded address excludes anonymous unpaired pods.
  • Nudge vs. settings fallback: BluetoothManager2.nudgeConnection() uses the hidden BluetoothHeadset.connect() reflection API. On phones where this is blocked (missing MODIFY_PHONE_STATE), isNudgeAvailable flips to false and the button label/behavior switches to opening Bluetooth settings. All exception paths (SecurityException from missing BLUETOOTH_CONNECT on API 31+, null adapter, reflection throws) fall through to the same settings-intent fallback so the button can never crash.
  • Drive-by fix in BluetoothManager2.nudgeConnection(): the existing implementation discarded Method.invoke()'s return value and always reported success. BluetoothHeadset.connect() actually returns a Boolean indicating whether the request was accepted; we now propagate it. This makes AutoConnect's log message accurate and makes the new "did the nudge get accepted?" check in the VM actually meaningful.
  • Concurrent tap protection: forceConnect() uses MutableStateFlow<Boolean>.compareAndSet as a one-in-flight guard, and the button is disabled while isForceConnecting is true — rapid double-taps can't spawn parallel connect attempts or duplicate settings-intent launches.
  • Review guidance: the most interesting file is DeviceSettingsViewModel.forceConnect() — all the exception containment and fallback logic lives there. The 7 new unit tests in DeviceSettingsViewModelTest cover each branch, including a CompletableDeferred-gated test that verifies the in-flight guard actually blocks a concurrent call.

@d4rken d4rken added enhancement Add a new feature of improve an existing feature coms/AAP Uses Apples AirPod Protocol. Requires Android ROM with fixed L2CAP support on the Bluetooth sockets. labels Apr 8, 2026
@d4rken d4rken merged commit ccd95a0 into main Apr 8, 2026
10 checks passed
@d4rken d4rken deleted the feat/device-settings-not-connected-card branch April 8, 2026 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

coms/AAP Uses Apples AirPod Protocol. Requires Android ROM with fixed L2CAP support on the Bluetooth sockets. enhancement Add a new feature of improve an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant