Home » Android » bluetooth – Programmatically pairing with a BLE device on Android 4.4+

bluetooth – Programmatically pairing with a BLE device on Android 4.4+

Posted by: admin April 23, 2020 Leave a comment

Questions:

Does anyone have a complete working example of how to programmatically pair with a BLE (not Bluetooth Classic) device that uses passkey entry (i.e. a 6-digit PIN) or Numeric Comparison on Android 4.4 or later? By ‘programmatically’ I mean I tell Android the PIN – the user isn’t prompted.

There are many similar questions about this on SO but they are either a) about Bluetooth Classic, b) old (before setPin() and createBond() were public), or c) unanswered.

My understanding is as follows.

  1. You connect to the device and discover its services.
  2. You try to read a ‘protected’ characteristic.
  3. The device returns an authentication error.
  4. Android somehow initiates pairing and you tell it the PIN.
  5. You can now read the characteristic.

I have created a device using mBed running on the nRF51-DK and given it a single characteristic.

I set up the security parameters like so:

ble.securityManager().init(
    true, // Enable bonding (though I don't really need this)
    true, // Require MitM protection. I assume you don't get a PIN prompt without this, though I'm not 100% sure.
    SecurityManager::IO_CAPS_DISPLAY_ONLY, // This makes it us the Passkey Entry (PIN) pairing method.
    "123456"); // Static PIN

And then in the characteristic I used

requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);

Now when I try to read it with the Nordic Master Control Panel, I get a pairing request notification like this:

pairing request

passkey entry

And I can put this PIN in, and then MCP says I’m bonded, and can read the characteristic.

However, in my app I would like to avoid having the user enter the PIN, since I know it already. Does anyone have a complete recent example of how to do this?

Edit: By the way this is the most relevant question I found on SO, but the answer there doesn’t seem to work.

How to&Answers:

I almost have it working. It pairs programmatically but I can’t get rid of the “Pairing request” notification. Some answers to this question claim to be able to hide it just after it is shown using the hidden method cancelPairingUserInput() but that doesn’t seem to work for me.

Edit: Success!

I eventually resorted to reading the source code of BluetoothPairingRequest and the code that sends the pairing request broadcast and realised I should be intercepting the ACTION_PAIRING_REQUEST. Fortunately it is an ordered intent broadcast so you can intercept it before the system does.

Here’s the procedure.

  1. Register to receive BluetoothDevice.ACTION_PAIRING_REQUEST changed broadcast intents. Use a high priority!
  2. Connect to the device.
  3. Discover services.
  4. If you have disconnected by now, it’s probably because the bond information is incorrect (e.g. the peripheral purged it). In that case, delete the bond information using a hidden method (seriously Google), and reconnect.
  5. Try to read a characteristic that requires encryption MitM protection.
  6. In the ACTION_PAIRING_REQUEST broadcast receiver, check that the pairing type is BluetoothDevice.PAIRING_VARIANT_PIN and if so, call setPin() and abortBroadcast(). Otherwise you can just let the system handle it, or show an error or whatever.

Here is the code.

Answer:

I also faced the same problem and after all the research, I figured out the below solution to pair to a BLE without any manual intervention.

(Tested and working!!!)

I am basically looking for a particular Bluetooth device (I know MAC address) and pair with it once found. The first thing to do is to create pair request using a broadcast receiver and handle the request as below.

You need to write the broadcastReceiver and handle it as below.

Voila! You should be able to pair to Bluetooth device without ANY MANUAL INTERVENTION.

Hope this helps 🙂 Please make it right answer if it works for you.