Repository navigation
Conversation
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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Git-on-my-level
left a comment
There was a problem hiding this comment.
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.
What changed and why
Fixes #17851
On current
main, part of the issue is already fixed: a denied Bluetooth permission now goes through the sharedBluetoothGuidanceListenerprompt with Open Settings (#18436), and the blocked reason shows at once as a pairing card (#21426).The remaining bug:
OnboardingProvider.scanDevicesstill 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
_armInstructionsTimerhelper. It also cancels any earlier timer, so only one is ever pending. A blocked search does not reportDevice Scan Empty, because discovery never ran andDevice Pairing Blockedwas 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
scanDevices,FindDevicesPage,FoundDevices,PairingFailureCardandBluetoothReadinesscode onmainto confirm the early returns and how the page gates the help (deviceList.isEmpty && enableInstructions && pairingFailureReason == null).dart format --line-length 120on the changed Dart files: no changes.enableInstructionsstays false and "No Omi Found" never appears. They run, along with the full app suite, analyzer and iOS/Android compiles, in Omi's CI withci:full.Tests
app/test/providers/onboarding_provider_pairing_presentation_test.dartpumps the realConnectDevicePage/FindDevicesPagewith a realOnboardingProvider, the same way the existing empty-scan test does:Bluetooth off still arms the delayed help: the mocked adapter reportsoff.denied Bluetooth permission still arms the delayed help: the mockedpermission_handlerrequest 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 Blockedwas sent andDevice Scan Emptywas 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