fix(ble): retrigger connection when bonding is interrupted#5849
Merged
Conversation
Selecting an unbonded node gated the connection on a clean bond() success: changeDeviceAddress() (which arms the persistent transport reconnect loop) only ran when bonding completed cleanly. Any bonding hiccup — user-cancel/timeout, an unreliable ACTION_BOND_STATE_CHANGED broadcast, or an OS/GATT-initiated bond already in flight — left the device inert until the user manually re-selected the node. - AndroidScannerViewModel.requestBonding: arm the transport on every outcome except a permissions SecurityException, handing off to the transport's reconnect+backoff loop (which bonds on demand) instead of requiring a manual re-select. - AndroidBluetoothRepository.bond: when createBond() returns false, re-check bondState instead of failing outright — BOND_BONDED resumes immediately, BOND_BONDING keeps waiting on the receiver. Handles the in-flight-bond collision documented in Kable #111. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jeremiah-k
pushed a commit
to jeremiah-k/Meshtastic-Android
that referenced
this pull request
Jun 18, 2026
…eshtastic#5849) (meshtastic#5850) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
jamesarich
added a commit
that referenced
this pull request
Jun 18, 2026
- AndroidScannerViewModel: keep main's armTransport bonding-retry structure; apply the SecurityException + USB string-resource conversions on top; drop the now-moot bonding_failed string (main no longer errors on flaky bonding) - NodeDetailScreens: wrap onRequestPosition/node in rememberUpdatedState for the grant LaunchedEffect (LambdaParameterInRestartableEffect) - spotless: blank lines between multiline when-conditions (TakPermissionUtil, ConnectionsScreen) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Selecting an unbonded node and having the bonding flow get interrupted left the device inert — the user had to re-select the node to retrigger a connection.
Root cause: the transport's reconnect loop is persistent and bonds on demand, but it only starts once
changeDeviceAddress()runs. For an unbonded device that call was gated behind a cleanbond()success, so any bonding hiccup (user-cancel/timeout, an unreliableACTION_BOND_STATE_CHANGEDbroadcast, or an OS/GATT-initiated bond already in flight) skipped it and the persistent reconnect loop was never armed.Changes
🐛 Bug Fixes
AndroidScannerViewModel.requestBonding— arm the transport on every bonding outcome except a permissionsSecurityException. A flaky or interrupted bond now hands off to the transport's reconnect+backoff loop (which bonds on demand and retries) instead of stranding the device until a manual re-select.AndroidBluetoothRepository.bond— whencreateBond()returnsfalse, re-checkbondStateinstead of failing outright:BOND_BONDED→ resume immediatelyBOND_BONDING→ keep waiting on the receiver for the terminal transitionThis handles the in-flight-bond collision and unreliable bond-state broadcast documented upstream in Kable #111.
Reviewer notes
androidMainclasses touchingBluetoothDevice/BroadcastReceiver, and neither module has a Robolectric /androidUnitTestharness today. Standing one up is a larger, separate effort.Validation
./gradlew spotlessApply spotlessCheck— pass./gradlew detekt— passcompileAndroidMainfor:core:bleand:feature:connections(with--rerun-tasks) — pass