Skip to content

fix: Android API compat, location permission, characteristic guards#6319

Merged
mdmohsin7 merged 7 commits into
mainfrom
fix/android-api-compat
Apr 4, 2026
Merged

fix: Android API compat, location permission, characteristic guards#6319
mdmohsin7 merged 7 commits into
mainfrom
fix/android-api-compat

Conversation

@mdmohsin7
Copy link
Copy Markdown
Member

@mdmohsin7 mdmohsin7 commented Apr 4, 2026

Summary

  • CompanionDeviceManager API compat for Android < 13associate(), myAssociations, and startObservingDevicePresence() use API 33+ signatures. Use legacy APIs on older versions to prevent NoSuchMethodError crashes.
  • Location permission for BLE scanning on Android 11 and below — Android 11 and below require ACCESS_FINE_LOCATION for BLE scan results. Request it alongside Bluetooth permissions, check actual OS status on each scan attempt, and show a clear dialog directing the user to enable it in settings.
  • SecurityException catch on connectGatt — When CompanionDeviceService starts the ForegroundService after process death, BLUETOOTH_CONNECT permission may not be available. Catch SecurityException and notify Dart with permission_denied error instead of crashing.
  • writeCharacteristic silently returns when characteristic is missing — Previously threw an exception that bubbled up as a Crashlytics fatal error (e.g. battery timer fires after device disconnects). Now logs and returns, consistent with readCharacteristic behavior.

Test plan

  • Connect device on Android 12 — no NoSuchMethodError crash on CompanionDeviceManager
  • Connect device on Android 11 — location permission prompted, devices discovered after granting
  • Connect device on Android 13+ — still works
  • Revoke Bluetooth permission mid-session — no crash, error sent to Dart

🤖 Generated with Claude Code

associate(), myAssociations, and startObservingDevicePresence use
API 33+ signatures. Use legacy APIs on older versions to prevent
NoSuchMethodError crashes.
…elow

Android 11 and below require ACCESS_FINE_LOCATION for BLE scan results.
Request it alongside Bluetooth permissions, and check actual OS status
on each scan attempt so returning from settings is handled correctly.
When location permission is missing on older Android, show a clear
dialog directing the user to enable it in settings.
…NECT

When CompanionDeviceService starts the ForegroundService after process
death, BLUETOOTH_CONNECT permission may not be available. Catch the
SecurityException and notify Dart with permission_denied error instead
of crashing.
Log and return silently instead of throwing. The caller handles
missing responses via timeout. Prevents Crashlytics fatal errors
when battery timer fires after device disconnects.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 4, 2026

Greptile Summary

This PR fixes four Android BLE reliability issues: API 33+ CompanionDeviceManager calls are now version-guarded to avoid NoSuchMethodError on older devices, BLUETOOTH_CONNECT SecurityException is caught to notify Dart instead of crashing, writeCharacteristic silently returns on missing characteristics instead of throwing, and Android 11 and below now request ACCESS_FINE_LOCATION for BLE scanning.

  • P1 — PlatformException risk: askForBluetoothPermissions() calls DeviceInfoPlugin().androidInfo inside the else (non-iOS) branch without a Platform.isAndroid guard; scanDevices() correctly uses this guard but the new code in askForBluetoothPermissions() does not, and will throw on macOS/desktop targets.

Confidence Score: 4/5

Safe to merge after fixing the missing Platform.isAndroid guard in askForBluetoothPermissions().

One P1 defect: DeviceInfoPlugin().androidInfo is called without a Platform.isAndroid guard in askForBluetoothPermissions(), which throws a PlatformException on non-Android platforms. The same pattern is correctly guarded in scanDevices(). The remaining finding is a P2 l10n violation. All other changes (SecurityException catch, API version guards, writeCharacteristic silent-return) are correct and well-structured.

app/lib/providers/onboarding_provider.dart (missing Platform.isAndroid guard around androidInfo call)

Important Files Changed

Filename Overview
app/android/app/src/main/kotlin/com/friend/ios/OmiBleForegroundService.kt Wraps connectGatt in a SecurityException catch and properly notifies Dart with permission_denied; correctly refactors the null-check for the returned GATT object.
app/android/app/src/main/kotlin/com/friend/ios/OmiCompanionManager.kt API-version-guarded associate() (API 33 vs. legacy Handler-based), getMacAddresses(), and startObserving()/stopObserving() correctly bifurcate on SDK version; launchChooser is cleanly extracted to remove duplication.
app/lib/providers/onboarding_provider.dart Adds Android 11 location-permission logic in both askForBluetoothPermissions() and scanDevices(); the scanDevices() call is correctly guarded with Platform.isAndroid, but askForBluetoothPermissions() calls DeviceInfoPlugin().androidInfo without that guard, risking PlatformException on non-Android platforms.
app/lib/pages/onboarding/find_device/page.dart Wires onShowLocationDialog to the new provider callback; dialog strings are hardcoded in English instead of using l10n keys.
app/lib/services/devices/transports/native_ble_transport.dart Changes writeCharacteristic to log-and-return when the characteristic is missing, consistent with readCharacteristic; eliminates the Crashlytics fatal from battery timer firing post-disconnect.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[scanDevices called] --> B{hasBluetoothPermission?}
    B -- No --> C[askForBluetoothPermissions]
    C --> D{Platform.isIOS?}
    D -- Yes --> E[Request bluetooth permission]
    D -- No --> F[Request bluetoothScan + bluetoothConnect]
    F --> G{Platform.isAndroid AND sdkInt <= 30?}
    G -- Yes --> H[Request locationWhenInUse]
    G -- No --> I[Skip location]
    H --> J[updateLocationPermission]
    B -- Yes --> K{Platform.isAndroid?}
    C --> K
    K -- Yes --> L{sdkInt <= 30?}
    K -- No --> M[Start BLE scan]
    L -- Yes --> N{locationWhenInUse.isGranted?}
    L -- No --> M
    N -- Yes --> M
    N -- No --> O[onShowLocationDialog → open Settings]
    O --> P[return early]
    M --> Q[subscribe + initiateConnection]
Loading

Reviews (1): Last reviewed commit: "bump ver 806" | Re-trigger Greptile

Comment thread app/lib/providers/onboarding_provider.dart Outdated
Comment thread app/lib/pages/onboarding/find_device/page.dart Outdated
- Wrap DeviceInfoPlugin().androidInfo in PlatformService.isAndroid
  check to prevent crash on non-Android platforms
- Add enableLocationTitle and enableLocationDescription l10n keys
- Replace hardcoded strings with context.l10n references
@mdmohsin7 mdmohsin7 merged commit 0e2d11b into main Apr 4, 2026
2 checks passed
@mdmohsin7 mdmohsin7 deleted the fix/android-api-compat branch April 4, 2026 15:11
Glucksberg pushed a commit to Glucksberg/omi-local that referenced this pull request Apr 28, 2026
…asedHardware#6319)

## Summary

- **CompanionDeviceManager API compat for Android < 13** —
`associate()`, `myAssociations`, and `startObservingDevicePresence()`
use API 33+ signatures. Use legacy APIs on older versions to prevent
`NoSuchMethodError` crashes.
- **Location permission for BLE scanning on Android 11 and below** —
Android 11 and below require `ACCESS_FINE_LOCATION` for BLE scan
results. Request it alongside Bluetooth permissions, check actual OS
status on each scan attempt, and show a clear dialog directing the user
to enable it in settings.
- **SecurityException catch on connectGatt** — When
CompanionDeviceService starts the ForegroundService after process death,
`BLUETOOTH_CONNECT` permission may not be available. Catch
`SecurityException` and notify Dart with `permission_denied` error
instead of crashing.
- **writeCharacteristic silently returns when characteristic is
missing** — Previously threw an exception that bubbled up as a
Crashlytics fatal error (e.g. battery timer fires after device
disconnects). Now logs and returns, consistent with `readCharacteristic`
behavior.

## Test plan

- [x] Connect device on Android 12 — no `NoSuchMethodError` crash on
CompanionDeviceManager
- [x] Connect device on Android 11 — location permission prompted,
devices discovered after granting
- [x] Connect device on Android 13+ — still works
- [ ] Revoke Bluetooth permission mid-session — no crash, error sent to
Dart

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant