Skip to content

feat: add timeout for notifications and detect aborted pairing on android #766

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

gion-andri
Copy link
Contributor

@gion-andri gion-andri commented May 27, 2025

Previously, iOS applied an internal timeout to the startNotifications command, while Android did not. This change:

  • Standardizes timeout behavior across both platforms
  • Exposes an optional timeout parameter for callers to customize as needed
  • Maintains backward compatibility by keeping the parameter optional

And on Android, cancelling the OS pairing prompt for a BLE device did not interrupt the startNotifications call, potentially causing hangs. This update:

  • Detects when the user cancels bonding on Android
  • Aborts the startNotifications call in response
  • Aligns Android’s behaviour with the existing iOS implementation

Fixes #765

@gion-andri gion-andri changed the title feat: add timeout for notifications and detect aborted pairing on android (#765) feat: add timeout for notifications and detect aborted pairing on android May 27, 2025
@peitschie peitschie self-assigned this May 28, 2025
@peitschie
Copy link
Collaborator

At a first pass, this looks excellent to me @gion-andri

I'll test it out locally and report back if I see any quirks 🙂

Thanks for the contribution!

@gion-andri gion-andri force-pushed the timeout-for-notifications branch from fc0e1b7 to d1a624a Compare June 2, 2025 13:43
Previously, iOS applied an internal timeout to the `startNotifications` command, while Android did not. This change:

- Standardizes timeout behavior across both platforms
- Exposes an optional `timeout` parameter for callers to customize as needed
- Maintains backward compatibility by keeping the parameter optional

a

a
@gion-andri gion-andri force-pushed the timeout-for-notifications branch from d1a624a to 01105b2 Compare June 3, 2025 11:14
@peitschie
Copy link
Collaborator

So... sitting down and looking at this patch, I can definitely see why the functionality is needed. Thanks for the effort putting this patch together.

@gion-andri what would be your appetite to make further changes to how the api for the bonding is exposed?

I am not that keen on the fact this is an implicit flow hidden behind the startNotification call. Would you be open to an explicit bond workflow?

I've implemented one like this on a previous plugin (https://github.com/don/cordova-plugin-ble-central/blob/master/src/android/BLECentralPlugin.java#L873). An explicit bond method is exposed to the plugin user, that ensures the device is properly bonded before continuing.

The impact to you here would be that you explicitly call await ble.bond(...) and then await.startNotifications(...) after the bond step succeeds.

The main advantage is it means you can more clearly identify a bonding problem in your app and report accordingly. Of course, the down-side is that this method has no iOS equivalent, so you'd need to conditionally call it when on the Android platform (or try/catch if it fails due to not being supported).

What are your thoughts here?

On Android, cancelling the OS pairing prompt for a BLE device did not interrupt the `startNotifications` call, potentially causing hangs. This update:

- Detects when the user cancels bonding on Android
- Aborts the `startNotifications` call in response
- Aligns Android’s behaviour with the existing iOS implementation
@gion-andri gion-andri force-pushed the timeout-for-notifications branch from 01105b2 to d539bda Compare June 6, 2025 08:18
@gion-andri
Copy link
Contributor Author

gion-andri commented Jun 6, 2025

@peitschie Thanks for taking the time to review this. I’m open to solving the issue in a different way—I just want to make sure I understand your suggestion correctly.

As it stands, there is already an explicit bonding flow. That flow handles everything I added for the notifications case (including a timeout and listening for bonding state changes) already.

The problem I’m trying to address is that Android will automatically initiate bonding when you call .startNotifications() on an encrypted characteristic. If the user cancels the pairing prompt, the plugin’s main queue never resumes, and the complete plugin is stuck.

Even if we encourage consumers to explicitly bond first, the plugin shouldn’t get stuck if someone relies on the implicit bonding that Android triggers.

In regards to the implementation:

I initially tried to reuse createBondStateReceiver() for notifications, but it quickly became a little messy — since we’d need to track different key prefixes and execute different code for both cases on success and error. That’s why I added a separate BroadcastReceiver specifically for the notifications flow.

With a more extensive refactor, we might be able to unify everything under a single BroadcastReceiver. If this is what you suggest, I am open to try that, it will just include some more changes to existing functionality.

Or maybe I misunderstood your comment completely, then please let me know :)

(And: while reviewing my changes, I found that I forgot a check on the deviceId, thats my latest change I pushed).

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.

Android: startNotifications() hangs when pairing prompt is canceled
3 participants