10

Before GATT, createRfcommSocketToServiceRecord, createInsecureRfcommSocketToServiceRecord

methods can make paired device,

but GATT has no option about paired device, only use BluetoothDevice.connectGatt(...)

I want to make a paired device if it's connected already.

thx.

IgorGanapolsky
  • 26,189
  • 23
  • 116
  • 147
user3563211
  • 101
  • 1
  • 1
  • 3

1 Answers1

26

As far as I know, to initiate a pairing procedure in BLE there are two ways:

1) From API 19 and up you can start the pairing by calling the mBluetoothDevice.createBond(). You don't need to be connected with the remote BLE device to start the pairing process.

2) When you try to do a Gatt operation, let's take for example the method

mBluetoothGatt.readCharacteristic(characteristic)

If the remote BLE device needs to be bonded to do any communication then when the callback

onCharacteristicRead( BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)

gets called its status parameter value will be equal to either GATT_INSUFFICIENT_AUTHENTICATION or GATT_INSUFFICIENT_ENCRYPTION, and not equal to GATT_SUCCESS. If this happens then the pairing procedure will start automatically.

Here is an example to find out when it fails once the onCharacteristicRead callback gets called

@Override
public void onCharacteristicRead(
        BluetoothGatt gatt,
        BluetoothGattCharacteristic characteristic,
        int status)
{

    if(BluetoothGatt.GATT_SUCCESS == status)
    {
        // characteristic was read successful
    }
    else if(BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION == status ||
            BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION == status)
    {
        /*
         * failed to complete the operation because of encryption issues,
         * this means we need to bond with the device
         */

        /*
         * registering Bluetooth BroadcastReceiver to be notified
         * for any bonding messages
         */
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        mActivity.registerReceiver(mReceiver, filter);
    }
    else
    {
        // operation failed for some other reason
    }
}

Other people mentioning that this operation starts the pairing procedure automatically: Android Bluetooth Low Energy Pairing

And this is how the receiver can be implemented

private final BroadcastReceiver mReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        final String action = intent.getAction();

        if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED))
        {
            final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);

            switch(state){
                case BluetoothDevice.BOND_BONDING:
                    // Bonding...
                    break;

                case BluetoothDevice.BOND_BONDED:
                    // Bonded...
                    mActivity.unregisterReceiver(mReceiver);
                    break;

                case BluetoothDevice.BOND_NONE:
                    // Not bonded...
                    break;
            }
        }
    }
};
Community
  • 1
  • 1
KikiTheMonk
  • 985
  • 10
  • 24
  • 1
    This answer was a big help for me! I was having issues with Android 6.0+ doing pairing notifications that the user wouldn't even see (older Android did nice dialogs, which I wanted for all cases). One thing I did differently than you was to just call createBond() from the get-go (ie even before connecting to the device), if the device.getBondState() == BluetoothDevice.BOND_NONE. This was because I wasn't getting "GATT_INSUFFICIENT_AUTHENTICATION" when reading the characteristic; the OS would hold it while it sent a notification to pair the device. – cclogg Feb 23 '17 at 02:55
  • What if my **onCharacteristicRead()** never gets called? – IgorGanapolsky Mar 29 '17 at 17:31
  • 1
    @IgorGanapolsky If you are 100% sure that you are calling this method mBluetoothGatt.readCharacteristic(characteristic) then the callback will be called unless maybe there is an issue with the remote device be it code related or maybe connection was lost (if this is the case you should get a different callback but i don't remember the name at the moment). If someone knows different do let us know. – KikiTheMonk Apr 02 '17 at 07:38
  • 1
    @Kyriakos Is the `createBond()` method still necessary, or can we just call `readCharacteristic()`? – IgorGanapolsky Apr 05 '17 at 13:43
  • @IgorGanapolsky i think that really depends on the remote BLE device you are trying to connect to. If that device requires a connection from you to retrieve the data then i assume that you will need to call `createBond()` otherwise you can directly call `readCharacteristic()`. I am not entirely sure about this, if someone knows different let us know. – KikiTheMonk Apr 06 '17 at 11:52
  • If the operation can't continue because of `GATT_INSUFFICIENT_ENCRYPTION` or `GATT_INSUFFICIENT_AUTHENTICATION`, it would be necessary to implement a retry on the receiver's `BOND_BONDED` event, right? – User May 02 '19 at 22:03
  • @Ixx from what I remember yes that is the case – KikiTheMonk May 13 '19 at 19:45