Skip to content

fix(onboarding): arm pairing help when bluetooth blocks discovery - #21586

Merged
kodjima33 merged 2 commits into
BasedHardware:mainfrom
apoorvdarshan:fix/onboarding-bluetooth-permission-recovery
Oct 15, 2026
Merged

kodjima33 merged 2 commits into
BasedHardware:mainfrom
apoorvdarshan:fix/onboarding-bluetooth-permission-recovery

Conversation

@apoorvdarshan

Copy link
Copy Markdown
Collaborator

What changed and why

Fixes #17851

On current main, part of the issue is already fixed: a denied Bluetooth permission now goes through the shared BluetoothGuidanceListener prompt with Open Settings (#18436), and the blocked reason shows at once as a pairing card (#21426).

The remaining bug: OnboardingProvider.scanDevices still returns early on a blocked search (Bluetooth permission denied, location missing on Android 11 and older, adapter not ready) before the ten-second "No Omi Found" timer is armed. Once the user dismisses the blocked card, or when no card applies (for example, readiness reports unauthorized while the cached permission flag is still true), the page shows "Searching for devices" forever. No scan is running, and Scan Again, How to Pair and Contact Support never appear.

Every blocked return now arms the same delayed help through a small _armInstructionsTimer helper. It also cancels any earlier timer, so only one is ever pending. A blocked search does not report Device Scan Empty, because discovery never ran and Device Pairing Blocked was already sent. A scan that actually starts still reports it as before.

Not in this PR: resuming discovery automatically when Bluetooth is turned on outside the app. The card's Try Again restarts it.

Product invariants affected

none

How it was verified

  • Read the current scanDevices, FindDevicesPage, FoundDevices, PairingFailureCard and BluetoothReadiness code on main to confirm the early returns and how the page gates the help (deviceList.isEmpty && enableInstructions && pairingFailureReason == null).
  • dart format --line-length 120 on the changed Dart files: no changes.
  • I did not run the tests locally. The new tests are written to fail without the fix: enableInstructions stays false and "No Omi Found" never appears. They run, along with the full app suite, analyzer and iOS/Android compiles, in Omi's CI with ci:full.

Tests

app/test/providers/onboarding_provider_pairing_presentation_test.dart pumps the real ConnectDevicePage/FindDevicesPage with a real OnboardingProvider, the same way the existing empty-scan test does:

  • Bluetooth off still arms the delayed help: the mocked adapter reports off.
  • denied Bluetooth permission still arms the delayed help: the mocked permission_handler request returns denied.

Each test checks that the blocked card shows, waits ten seconds, dismisses the card, and expects "No Omi Found" with Scan Again and Contact Support instead of "Searching for devices". It also checks that Device Pairing Blocked was sent and Device Scan Empty was not.

UI evidence

UI-Evidence: none -- no simulator or device is available here; the change only arms an existing timer and reuses the existing "No Omi Found" state, which the widget tests above render

Failure class (fixes)

Failure-Class: FC-waiting-copy-ignores-pipeline-state

🤖 Generated with Claude Code

scanDevices returned early when Bluetooth permission, location (Android
11 and older) or adapter readiness blocked discovery, before the
ten-second "No Omi Found" timer was armed. Once the blocked card was
dismissed (or when no card applied), the page sat on "Searching for
devices" with no scan running and no Scan Again, How to Pair or Contact
Support. Arm the same delayed help on every blocked path; only a scan
that actually started still reports Device Scan Empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@apoorvdarshan apoorvdarshan added the ci:full Maintainer-granted: run full CI on this fork PR label Oct 14, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@Git-on-my-level Git-on-my-level 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.

Reviewed the remaining #17851 residue against main — every blocked early-return in scanDevices now arms the delayed help. Approved.

app/lib/providers/onboarding_provider.dart — all three blocked paths (Bluetooth permission denied, location missing on Android <=11, adapter not ready in BluetoothReadiness.ensureReady) call _armInstructionsTimer(epoch, scanStarted: false) before returning, and the successful path arms with scanStarted: true right before initiateConnection. The helper cancels any prior timer so only one is ever pending, keeps the epoch/_isDisposed guards, and gates Device Scan Empty on scanStarted so a blocked search (which already reported Device Pairing Blocked) no longer double-counts in the funnel. cancelActiveScan/dispose/onDevices cancel sites are unchanged — no leak or stale-fire path found.

app/test/providers/onboarding_provider_pairing_presentation_test.dart — expectDelayedHelpAfterBlockedScan exercises the real regression end-to-end (blocked card shows, timer fires, dismiss leads to 'No Omi Found' with Scan Again and Contact Support) and asserts Device Pairing Blocked fires while Device Scan Empty does not; the two new testWidgets cover the adapter-off and permission-denied variants.

app/changelog/unreleased/20261015-pairing-blocked-help.json — accurate user-facing fragment.

Dart Analyze & Tests is green on this head. Clean, well-scoped fix — thank you.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

@Git-on-my-level Git-on-my-level added the flutter flutter work label Oct 14, 2026
@kodjima33
kodjima33 merged commit 7a9744f into BasedHardware:main Oct 15, 2026
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:full Maintainer-granted: run full CI on this fork PR flutter flutter work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mobile pairing onboarding bypasses shared Bluetooth permission recovery and skips blocked-state help

3 participants