1

I'm trying to connect an Android Tablet to an already bonded BLE device via BluetoothDevice::connectGatt(...), but the BluetoothParingDialog gets called again twice.

The BLE device is based on the Nordic nRF5 series.

I created a very simplified Android app (targetSdk 30) to isolate the problem:

Manifest:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature
    android:name="android.hardware.bluetooth_le"
    android:required="true"/>

Scan for the device:

BluetoothManager bluetoothManager = (BluetoothManager)getContext().getSystemService(BLUETOOTH_SERVICE);
bluetoothLeScanner = bluetoothManager.getAdapter().getBluetoothLeScanner();
bluetoothLeScanner.startScan(scanCallback);

Scan callback:

ScanCallback scanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        BluetoothDevice device = result.getDevice();
        if (device != null) {
            String deviceName = device.getName();
                if (deviceName != null) {
                    if (deviceName.startsWith("MY_BLE_DEVICE")) {
                        bluetoothLeScanner.stopScan(scanCallback);
                        bluetoothDevice = device;
                        TryConnect();
                    }
                }
        }
        super.onScanResult(callbackType, result);
    }

    private void TryConnect() {
        if (bluetoothDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
            bluetoothDevice.connectGatt(getContext(), false, new BluetoothGattCallback(){});
        } else {
            bluetoothDevice.createBond();
        }
    }
};

And here the broadcast receiver for connecting after the first bonding:

receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        int state = (int)intent.getExtras().get(BluetoothDevice.EXTRA_BOND_STATE);

        if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action) && !isConnection){
            bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            if (bluetoothDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
                isConnection = true;
                TryConnect();
            }
        }
    }
};

On first time, everything works fine. The device starts bonding via BluetoothDevice::createBond(), the dialog pops-up and after pressing "pair", I can connect to the device. Afterwards, it's also displayed as "Paired" in the Android Bluetooth Settings.

On the second time, the scanner finds the device, and I'm calling directly connectGatt() -> The Paring-Dialog gets displayed again (and once again if I press "Pair"). Also, the device is not paired anymore (see in the logs).

This also happens if I pair the device at first via Android Bluetooth Settings.

Following the logcat output directly after calling connectGatt(..)

2022-07-27 16:37:33.145 21289-21289/com.example.bletestapp I/BluetoothAdapter: STATE_ON
2022-07-27 16:37:33.154 21289-21289/com.example.bletestapp D/BluetoothGatt: connect() - device: DE:D6:D2:33:40:03, auto: false
2022-07-27 16:37:33.155 21289-21289/com.example.bletestapp I/BluetoothAdapter: isSecureModeEnabled
2022-07-27 16:37:33.156 2777-4160/? D/BtConfig.SecureMode: isSecureModeOn:false
2022-07-27 16:37:33.156 21289-21289/com.example.bletestapp D/BluetoothGatt: registerApp()
2022-07-27 16:37:33.160 21289-21289/com.example.bletestapp D/BluetoothGatt: registerApp() - UUID=ca7f6fdc-54b5-4412-9ce8-82044123d264
2022-07-27 16:37:33.163 2777-4160/? D/BtGatt.GattService: registerClient(com.example.bletestapp) - UUID=ca7f6fdc-54b5-4412-9ce8-82044123d264
2022-07-27 16:37:33.165 2777-4160/? D/BtGatt.ContextMap: add() - appUid: 10426, appPid: 21289, appName: com.example.bletestapp
2022-07-27 16:37:33.166 2777-3876/? I/bt_stack: [INFO:gatt_api.cc(950)] GATT_Register ca7f6fdc-54b5-4412-9ce8-82044123d264
2022-07-27 16:37:33.166 2777-3876/? I/bt_stack: [INFO:gatt_api.cc(994)] allocated gatt_if=13
2022-07-27 16:37:33.166 2777-2979/? D/BtGatt.GattService: onClientRegistered() - UUID=ca7f6fdc-54b5-4412-9ce8-82044123d264, clientIf=13
2022-07-27 16:37:33.168 21289-23039/com.example.bletestapp D/BluetoothGatt: onClientRegistered() - status=0 clientIf=13
2022-07-27 16:37:33.218 21289-21289/com.example.bletestapp I/BluetoothAdapter: STATE_ON
2022-07-27 16:37:33.218 21289-21289/com.example.bletestapp D/BluetoothLeScanner: could not find callback wrapper
2022-07-27 16:37:33.223 2777-4160/? D/BtGatt.GattService: clientConnect(com.example.bletestapp) - address = 33:4, isDirect=true transport =0 set own addr = false own addr type:0, clientIf: 13, opportunistic=false, phy: 1
2022-07-27 16:37:33.225 2777-3876/? W/bt_btm: BTM_SecAddBleDevice: dev_type=0x2
2022-07-27 16:37:33.225 2777-3876/? E/bt_stack: [ERROR:gatt_api.cc(1150)] GATT_Connectgatt_if=13, address=de:d6:d2:33:40:03, is_direct=1, opportunistic=0
2022-07-27 16:37:33.226 2777-3876/? W/bt_btm: btm_find_dev_by_identity_addr find pseudo->random match with diff addr type: 1 vs 0
2022-07-27 16:37:33.226 2777-3876/? W/bt_btm: btm_find_dev_by_identity_addr find pseudo->random match with diff addr type: 1 vs 0
2022-07-27 16:37:33.226 2777-3876/? W/bt_btm: btm_ble_enable_resolving_list() rl_state = 0xb, rl_mask = 0x1
2022-07-27 16:37:33.226 773-773/? D/vendor.qti.bluetooth@1.0-ibs_handler: SerialClockVote: vote for UART CLK ON
2022-07-27 16:37:33.227 773-773/? D/vendor.qti.bluetooth@1.0-wake_lock: Acquire wakelock is acquired 
2022-07-27 16:37:33.227 773-773/? I/vendor.qti.bluetooth@1.0-ibs_handler: DeviceWakeUp: Writing IBS_WAKE_IND
2022-07-27 16:37:33.230 773-3872/? I/vendor.qti.bluetooth@1.0-ibs_handler: ProcessIbsCmd: Received IBS_WAKE_ACK: 0xFC
2022-07-27 16:37:33.230 773-3872/? I/vendor.qti.bluetooth@1.0-ibs_handler: ProcessIbsCmd: Signal wack_cond_
2022-07-27 16:37:33.230 773-773/? D/vendor.qti.bluetooth@1.0-ibs_handler: DeviceWakeUp: Unblocked from waiting for FC
2022-07-27 16:37:33.231 773-3872/? I/vendor.qti.bluetooth@1.0-ibs_handler: ProcessIbsCmd: Received IBS_WAKE_IND: 0xFD
2022-07-27 16:37:33.231 773-3872/? I/vendor.qti.bluetooth@1.0-ibs_handler: ProcessIbsCmd: Writing IBS_WAKE_ACK
2022-07-27 16:37:33.258 2805-2805/? I/ViewRootImpl@bceb956[Toast]: Relayout returned: old=(0,36,1200,1920) new=(422,1762,778,1824) req=(356,62)0 dur=13 res=0x7 s={true 500290883584} ch=true fn=-1
2022-07-27 16:37:33.259 2777-3876/? W/bt_l2cap: l2cble_conn_comp: HANDLE=6 addr_type=1 conn_interval=36 slave_latency=0 supervision_tout=500
2022-07-27 16:37:33.259 2777-3876/? W/bt_l2cap: l2cu_initialize_fixed_ccb: don't cancel l2c_lcb_timer
2022-07-27 16:37:33.259 2777-3876/? W/bt_btm: btm_ble_disable_resolving_list() rl_state = 0xb, rl_mask = 0x1, to_resume = 1
2022-07-27 16:37:33.267 2777-3876/? D/IOP_DB_BT: db_query_create: id EnforceMasterRole :: key KEY_BDADDR
2022-07-27 16:37:33.268 2777-3876/? D/IOP_DB_BT: db_query_add_key: key KEY_DIR_ALL
2022-07-27 16:37:33.268 2777-3876/? D/IOP_DB_BT: db_query_execute: result 1
2022-07-27 16:37:33.269 2777-3876/? W/bt_btif: bta_dm_acl_change info: 0x0
2022-07-27 16:37:33.290 2777-2979/? E/BluetoothRemoteDevices: Remote class is UNCATEGORIZED
2022-07-27 16:37:33.290 2777-2979/? I/BluetoothBondStateMachine: bondStateChangeCallback: Status: 0 Address: DE:D6:D2:33:40:03 newState: 1
2022-07-27 16:37:33.294 1210-3535/? D/SecContentProvider: query(), uri = 4 selection = bluetoothLogForRemote
2022-07-27 16:37:33.294 1210-3535/? D/SecContentProvider: called from android.uid.bluetooth:1002
2022-07-27 16:37:33.295 2777-2979/? I/BluetoothBondStateMachine: sspRequestCallback: [B@f395de name: [B@714a3bf cod: 7936 pairingVariant 2 passkey: ******
2022-07-27 16:37:33.296 2777-2979/? E/bt_btif: remote name callback registration fail.
2022-07-27 16:37:33.298 2777-3638/? D/BluetoothAdapterService: updateDataBase() bondstate : 11
2022-07-27 16:37:33.298 2777-3638/? E/BluetoothAdapterService: updateDataBase - newState is bonding. return.

Is there a way to get the reason, why the dialog is shown twice? Since it's hidden in the SDK, I can't get the stack trace to figure it out in detail. Does the BLE device miss something in the handshake / connection procedure which could lead to this behavior? Could it be a timing problem or key exchange failure? If more information of the BLE device is necessary, I can submit it later.

Fabman22
  • 183
  • 12
  • Most likely a bug in Android – Emil Jul 28 '22 at 07:59
  • @Emil thanks for your answer - can you maybe point me to the source where this could lead to a wrong behavior? I assume this depends on the HAL interface, which expects something special of the BLE device (missing parameters, wrong response, etc.). In BluetoothPairingDialog.java, the intent ACTION_PAIRING_REQUEST is the reason for showing this dialog. But showing this dialog is the result of start paring again, since I got unpaired before by Android. What could be a reason for Android to unpair an already bonded device? How I wrote, I cannot exclude some wrong behavior of the BLE device. – Fabman22 Jul 29 '22 at 08:31
  • @Emil it looks like you are right, I tried to connect with the Windows nrf connect app - this works as expected, no wrong connection attempts. Trying it with the official nrf connect Android app leads to the same behavior! May you help me by giving an advice which parameters could be changed for a sufficient result? – Fabman22 Sep 16 '22 at 08:24
  • Tried another phone or tablet? – Emil Sep 16 '22 at 17:06
  • According to this link https://github.com/PhilipsHue/flutter_reactive_ble/issues/507 it's an Android 12 issue. Haven't been able to confirm this myself. – Entreco May 15 '23 at 09:19

0 Answers0