Skip to content

fix(ble): Avoid duplicate bonding retries after pairing failure#5969

Merged
jamesarich merged 4 commits into
meshtastic:mainfrom
jeremiah-k:bugfix/ble-avoid-duplicate-bonding
Jun 26, 2026
Merged

fix(ble): Avoid duplicate bonding retries after pairing failure#5969
jamesarich merged 4 commits into
meshtastic:mainfrom
jeremiah-k:bugfix/ble-avoid-duplicate-bonding

Conversation

@jeremiah-k

@jeremiah-k jeremiah-k commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Overview

This pull request prevents the app from immediately starting a second bonding attempt after the user-facing Android pairing flow fails.

Earlier behavior armed the BLE transport after a generic bonding failure so interrupted bonding could still progress through the transport path. In practice, that also allowed the transport to immediately call bond() again when the device was still not bonded. On Android, that can produce a second PIN dialog or hit platform bonding cooldown/throttling after a cancelled, rejected, or timed-out pairing attempt.

This follows the bonding timeout hardening in #5967. That PR makes Android bonding attempts finite, checks for completed bonding even when the terminal broadcast is missed, and re-checks the final platform bond state before failing.

With that in place, this PR changes the UI-side failure behavior so an incomplete pairing attempt surfaces a retry warning instead of immediately arming the transport and triggering another bond() call.

If Android records the device as bonded even though the app-side bond call reports an error, the ViewModel still proceeds with selecting the device.

The related transport-side follow-up in PR #5973 handles the remaining lower-level case: if transport-side bonding fails and Android still reports the device as not bonded, the BLE transport stops that connection attempt before entering GATT setup.

Key Changes

  • Preserved successful pairing behavior: completed bonding still selects the device.
  • Preserved Bluetooth permission failure behavior.
  • Preserved coroutine cancellation behavior.
  • Stopped arming the BLE transport after generic bonding failure when the device is still not bonded.
  • Still selects the device when Android reports it bonded after a late or flaky bonding result.
  • Avoided immediate transport-side re-bonding after a failed UI pairing attempt.
  • Added user-facing retry copy for incomplete pairing.
  • Updated Android ViewModel bonding tests to cover the explicit-retry, late-bonded, and cancellation behavior.

Testing

  • Updated AndroidScannerViewModelBondingTest coverage proving successful bonding still selects the device.
  • Updated coverage proving permission failures do not arm the transport.
  • Updated coverage proving generic bonding failures do not call changeDeviceAddress() and surface a retry warning.
  • Added coverage proving a late bonded result still selects the device.
  • Added coverage proving CancellationException is not treated as a generic bonding failure.
  • Updated the test setup so each test gets isolated ViewModel harness state.

Migration Notes

  • No user data migration is required.
  • Existing BLE addresses and OS bonds are unchanged.
  • Users can retry pairing explicitly after a failed or cancelled pairing attempt.

@github-actions github-actions Bot added the bugfix PR tag label Jun 26, 2026
@jeremiah-k jeremiah-k force-pushed the bugfix/ble-avoid-duplicate-bonding branch from 86c3ae1 to 5f42093 Compare June 26, 2026 16:38
jeremiah-k added a commit to jeremiah-k/Meshtastic-Android that referenced this pull request Jun 26, 2026
When BleRadioTransport bonds before connecting and bond() throws,
re-check isBonded before continuing into GATT setup:
- bond() succeeds: continue (unchanged)
- bond() throws + isBonded true: continue (late/flaky terminal bond)
- bond() throws + isBonded false: fail fast with RadioNotConnectedException,
  let BleReconnectPolicy own retry/backoff instead of hitting cryptic
  GATT status 5/133 later

CancellationException is preserved (rethrown before the generic catch).

Follow-up to meshtastic#5967 (bounded bond wait) and meshtastic#5969 (UI retry path).
@jeremiah-k jeremiah-k marked this pull request as ready for review June 26, 2026 17:02
@jeremiah-k jeremiah-k marked this pull request as draft June 26, 2026 17:28
Stop arming the BLE transport after a generic Android pairing failure so the transport does not immediately call bond() again and trigger duplicate PIN prompts or platform bonding cooldown.

This supersedes the earlier interrupted-bonding fallback behavior now that Android bonding waits are timeout-hardened. Successful bonding and permission failures keep their existing semantics, while ordinary pairing failures now surface a retry warning and wait for explicit user action.
Handle the Android edge case where bond() reports an error even though the platform has already recorded the device as bonded.

Before treating a generic bonding error as terminal, re-check the repository bond state. If Android now reports the device bonded, select the device and arm the transport because pairing actually succeeded despite the app-side signal loss.

Add fake repository support for recording a bond before throwing so the ViewModel behavior is covered without depending on Android framework timing.
Tighten the generic bonding failure test so it asserts the exact retry warning instead of only checking for any non-null error.

Keep the fake bonding implementation deterministic by recording the eventual error and throwing once after outcome handling. This preserves the same external behavior while keeping the fake easier to extend for bonding edge cases.
Cover the requestBonding cancellation path so CancellationException cannot be swallowed by the generic bonding failure handler.

The regression check verifies that a cancelled bond attempt does not arm the BLE transport and does not surface the retry warning intended for ordinary pairing failures.
@jeremiah-k jeremiah-k force-pushed the bugfix/ble-avoid-duplicate-bonding branch from 5f42093 to ba1750e Compare June 26, 2026 18:04
@jeremiah-k jeremiah-k marked this pull request as ready for review June 26, 2026 18:27

@jamesarich jamesarich left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@jamesarich jamesarich added this pull request to the merge queue Jun 26, 2026
Merged via the queue into meshtastic:main with commit 5c83333 Jun 26, 2026
22 checks passed
@jeremiah-k jeremiah-k deleted the bugfix/ble-avoid-duplicate-bonding branch June 26, 2026 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix PR tag

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants