Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Bluetooth Low Energy Pairing

How to pair a Bluetooth Low Energy(BLE) device with Android to read encrypted data.

Using the information in the Android BLE page, I am able to discover the device, connect to it, discover services and read un-encrypted characteristics.

When I try to read an encrypted characteristic (one that will cause iOS to show a popup asking to pair and then complete the read) I am getting an error code 5, which corresponds to Insufficient Authentication.

I am not sure how to get the device paired or how to provide the authentication information for the read to complete.

I toyed with BluetoothGattCharacteristics by trying to add descriptors, but that did not work either.
Any help is appreciated!

like image 330
Zomb Avatar asked Aug 12 '13 22:08

Zomb


People also ask

What is Bluetooth Low Energy in Android?

Android provides built-in platform support for Bluetooth Low Energy (BLE) in the central role and provides APIs that apps can use to discover devices, query for services, and transmit information. Common use cases include the following: Transferring small amounts of data between nearby devices.

How do I turn off Bluetooth Low Energy Android?

Users can disable system-level Bluetooth background scanning by going to Settings > Security & Location > Location > Scanning and disabling the toggle for Bluetooth scanning.

Is Bluetooth Low Energy compatible with Bluetooth?

It is independent of classic Bluetooth and has no compatibility, but Bluetooth Basic Rate/Enhanced Data Rate (BR/EDR) and LE can coexist.


1 Answers

When you get the GATT_INSUFFICIENT_AUTHENTICATION error, the system starts the bonding process for you. In the example below I'm trying to enable notifications and indications on glucose monitor. First I'm enabling the notifications on Glucose Measurement characteristic which can cause the error to appear.

@Override     public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {         if (status == BluetoothGatt.GATT_SUCCESS) {             if (GM_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {                 mCallbacks.onGlucoseMeasurementNotificationEnabled();                  if (mGlucoseMeasurementContextCharacteristic != null) {                     enableGlucoseMeasurementContextNotification(gatt);                 } else {                     enableRecordAccessControlPointIndication(gatt);                 }             }              if (GM_CONTEXT_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {                 mCallbacks.onGlucoseMeasurementContextNotificationEnabled();                 enableRecordAccessControlPointIndication(gatt);             }              if (RACP_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {                 mCallbacks.onRecordAccessControlPointIndicationsEnabled();             }         } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {             // this is where the tricky part comes              if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {                 mCallbacks.onBondingRequired();                  // I'm starting the Broadcast Receiver that will listen for bonding process changes                  final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);                 mContext.registerReceiver(mBondingBroadcastReceiver, filter);             } else {                 // this situation happens when you try to connect for the second time to already bonded device                 // it should never happen, in my opinion                 Logger.e(TAG, "The phone is trying to read from paired device without encryption. Android Bug?");                 // I don't know what to do here                 // This error was found on Nexus 7 with KRT16S build of Andorid 4.4. It does not appear on Samsung S4 with Andorid 4.3.             }         } else {             mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status);         }     }; 

Where the mBondingBroadcastReceiver is:

private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {     @Override     public void onReceive(final Context context, final Intent intent) {         final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);         final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);         final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);          Logger.d(TAG, "Bond state changed for: " + device.getAddress() + " new state: " + bondState + " previous: " + previousBondState);          // skip other devices         if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))             return;          if (bondState == BluetoothDevice.BOND_BONDED) {             // Continue to do what you've started before             enableGlucoseMeasurementNotification(mBluetoothGatt);              mContext.unregisterReceiver(this);             mCallbacks.onBonded();         }     } }; 

Remember to unregister the broadcast receiver when exiting the activity. It may have not been unregistered by the receicver itself.

like image 100
philips77 Avatar answered Oct 09 '22 02:10

philips77