Skip to content

fix(ble): stop BLE scan on background and downgrade connection priority#5644

Merged
jamesarich merged 2 commits into
mainfrom
jamesarich/special-doodle
May 28, 2026
Merged

fix(ble): stop BLE scan on background and downgrade connection priority#5644
jamesarich merged 2 commits into
mainfrom
jamesarich/special-doodle

Conversation

@jamesarich

Copy link
Copy Markdown
Collaborator

Summary

Reports of increased battery drain prompted an investigation into the BLE scanning and connection lifecycle. Two compounding issues were identified and fixed:

1. BLE scan continues when app is backgrounded

The Connections screen used DisposableEffect(Unit) to stop scanning on composable disposal, but this only fires when the composable leaves composition (tab switch). When the user backgrounds the app while on the Connections tab with auto-scan enabled, the composable stays composed and the infinite-duration BLE scan continues in the background indefinitely.

Fix: Replace DisposableEffect + LaunchedEffect with LifecycleStartEffect, which stops scanning on ON_STOP (app backgrounded) and restarts on ON_START. The same pattern is applied to network (NSD) scanning.

2. High BLE connection priority never downgrades

Since #5222 (April 22), BleRadioTransport requests Priority.High (~7.5 ms connection interval) on connect for faster initial config drain, but never downgrades back to Balanced (~30-50 ms). This increases battery draw on both the phone and the radio for the entire connection lifetime.

Fix: Launch a delayed coroutine that downgrades to Priority.Balanced 30 seconds after the handshake completes. This gives ample time for the initial config burst while avoiding sustained high-frequency radio wakeups.

Changes

  • ConnectionsScreen -- lifecycle-aware scan start/stop via LifecycleStartEffect
  • BleConnection -- new requestBalancedConnectionPriority() interface method
  • KablePlatformSetup (Android/JVM/iOS) -- requestBalancedConnectionPriority() expect/actual implementations
  • BleRadioTransport -- delayed priority downgrade after onConnect()

Two battery-drain fixes:

1. ConnectionsScreen: Replace DisposableEffect + LaunchedEffect with
   LifecycleStartEffect for both BLE and network scanning. Scans now
   stop on ON_STOP (app backgrounded) and restart on ON_START, preventing
   continuous background BLE radio usage when the user leaves the app
   while on the Connections tab with auto-scan enabled.

2. BleRadioTransport: Downgrade from High to Balanced BLE connection
   priority 10 seconds after the initial handshake completes. High
   priority (~7.5 ms connection interval) is only needed for the
   initial config drain burst; sustaining it indefinitely drains
   battery on both phone and radio.

Adds requestBalancedConnectionPriority() to the BleConnection interface
with platform implementations (Android actual, JVM/iOS no-op stubs).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added the bugfix PR tag label May 28, 2026
@github-actions

github-actions Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

🖼️ Preview staleness check — advisory

This PR modifies UI composables but does not update any *Previews.kt files.

Previews power screenshot tests and in-app docs screenshots. Keeping them current ensures visual regression coverage stays accurate.

Changed UI files:

feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/ConnectionsScreen.kt

What to check:

Pattern Preview file convention
feature/{name}/…/ui/ or component/ feature/{name}/…/*Previews.kt
core/ui/…/ core/ui/…/ (previews colocated)

Adding previews checklist:

  1. Create or update a *Previews.kt file in the same module with @PreviewLightDark
  2. Add @Suppress("PreviewPublic") if the preview is consumed by screenshot-tests
  3. Add corresponding @PreviewTest function in screenshot-tests/src/screenshotTest/
  4. Run ./gradlew :screenshot-tests:updateDebugScreenshotTest to generate reference images

If this PR does not require preview updates (e.g., logic-only change, non-visual refactor), add the skip-preview-check label to dismiss.

@github-actions

github-actions Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

📄 Docs staleness check — advisory

This PR modifies user-facing UI source files but does not update any page under docs/en/user/ or docs/en/developer/.

⚠️ Doc changes propagate to 3 consumers: in-app docs browser, Jekyll site (GitHub Pages), and meshtastic.org (Docusaurus sync). Updating a page in docs/en/ automatically flows to all three.

Changed source files:

feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/ConnectionsScreen.kt

What to check:

Changed area Likely doc page
feature/messaging/ docs/en/user/messages-and-channels.md
feature/node/ docs/en/user/nodes.md or docs/en/user/node-metrics.md
feature/map/ docs/en/user/map-and-waypoints.md
feature/connections/ docs/en/user/connections.md
feature/settings/ docs/en/user/settings-radio-user.md or docs/en/user/settings-module-admin.md
feature/firmware/ docs/en/user/firmware.md
feature/intro/ docs/en/user/onboarding.md
feature/discovery/ docs/en/user/discovery.md
feature/docs/ Internal docs infrastructure
core/ui/ docs/en/developer/codebase.md or component-specific user pages

New page checklist (if adding a new doc page):

  1. Create the .md file in docs/en/user/ or docs/en/developer/ with last_updated frontmatter
  2. Register in DocBundleLoader.kt with string resources (in-app browser)
  3. Jekyll and Docusaurus sync pick up new pages automatically — no config change needed

If this PR does not require a doc update (e.g., internal refactor, bug fix, test change), add the skip-docs-check label to dismiss this check.

Cross-platform note: This check is advisory while doc coverage matures. Both Android and Apple repos use the same skip-docs-check label and advisory severity. See meshtastic/design standards for shared conventions.

Extract requestHighPriorityAndScheduleDowngrade() from
discoverServicesAndSetupCharacteristics() to bring function length
back under the 60-line detekt threshold.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jamesarich jamesarich added this pull request to the merge queue May 28, 2026
Merged via the queue into main with commit 1d221e2 May 28, 2026
18 checks passed
@jamesarich jamesarich deleted the jamesarich/special-doodle branch May 28, 2026 19:22
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.

1 participant