Tags: BasedHardware/omi
Tags
Show copyable URL as fallback when launchUrl fails If the browser can't be opened (sandboxing, no default browser, etc.), the raw URL is shown as selectable text so the user can copy-paste it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BLE: richer disconnect diagnostics to diagnose reconnect-burst reports ( #6710) ## Why Users report BLE reconnect bursts on both iOS and Android, but our current diagnostics (`BleDisconnectEvent`: timestamp, reason, code, isManual) can't distinguish between: - **range / RF / peripheral-sleep drops** vs. **healthy-signal drops** (need last RSSI) - **brief-link flaps** vs. **long-stable connections that dropped** (need duration) - **foreground** vs. **backgrounded** (iOS suspension, Android service throttling) - **reconnection lag** the user actually perceives as the bug (need time-to-reconnect) - **silent fail-to-connect** vs. **established-then-dropped** (iOS `didFailToConnect` currently persists nothing and never retries) Without this split, a user's 20-disconnect diagnostic is just 20 identical "connection_timeout" rows — we can't tell a bug from expected behaviour. ## What Extends the Pigeon contract and both native implementations to capture: - `event_type` — `disconnect` vs `fail_to_connect` - `last_rssi` — signal at the moment of the drop (-53 dBm = healthy; -85 dBm = range) - `connection_duration_ms` — how long the link was established before dropping - `app_state` — foreground / inactive / background at event time - `time_to_reconnect_ms` — backfilled on the next successful connect (this is likely the real user complaint) - `fail_to_connect_count` — separate top-level counter so silent-failure paths are visible ### iOS side-effect fixes `didFailToConnect` previously dropped the user silently — no retry, no diagnostic. Now it: - Persists a `fail_to_connect` event - Increments `failToConnectCount` - Re-issues `connect()` after 200ms for previously-connected peripherals (mirrors `didDisconnect` behaviour) ### Android event-type resolution `hasEverConnected` is a device-lifetime flag and can't tell a reconnect failure from a link drop once the device has ever connected. Added `currentAttemptEstablished` which resets on each `connectGatt` call and is set when `onGattConnected` fires — this is what actually answers "did this attempt establish?" ## What I deliberately did *not* do - No exponential-backoff change on the reconnect path (was speculation without data) - No firmware supervision-timeout change (separate decision — Apple ADG allows up to 6s vs. our current 4s, but worth shipping telemetry first to know if it moves the needle) - No RSSI-keep-alive timing change (another speculation) The point is to **get signal from affected users** before making behaviour changes that could regress. ## Per-file commits - `pigeon_interfaces.dart` — contract - `pigeon_communicator.g.*` × 3 — regenerated Dart / Swift / Kotlin stubs - `OmiBleManager.swift` — iOS capture + fail-to-connect retry - `OmiBleManager.kt` — per-device `lastRssi` map + `isAppForeground` flag - `OmiBleForegroundService.kt` — Android persistence + per-attempt flag - `MainActivity.kt` — lifecycle hook for `isAppForeground` - `device_diagnostics.dart` — UI row metadata + JSON export ## Test plan - [ ] Flutter dev build, open Device Diagnostics, trigger a manual disconnect → verify `manual` event has `isManual=true`, no `last_rssi` surprise - [ ] Walk out of range until drop → event should show degraded `last_rssi` and a `connection_duration_ms` - [ ] Force-kill app during active connection → event shows `background` app_state - [ ] iOS: unplug device firmware mid-scan to trigger `didFailToConnect` → event shows `event_type=fail_to_connect` with orange pill - [ ] Wait for reconnect, inspect same event → `time_to_reconnect_ms` backfilled - [ ] Export JSON → confirm new fields present in the saved file - [ ] Android: same matrix on a real device ## Next step Once this is in users' hands and we have a fresh diagnostic, decide whether the underlying issue is: - (a) range / RF — firmware timeout bump helps - (b) long reconnect latency — reconnect path needs work - (c) fail-to-connect loops — retry logic needs backoff - (d) something else entirely 🤖 Generated with [Claude Code](https://claude.com/claude-code)
PreviousNext