jamprad
jamprad

Reputation: 55

Android Lollipop BLE Peripheral: calling BluetoothLeAdvertiser.stopAdvertising(AdvertiseCallback) disconnects from connected central

I wish to stop advertising when a central connects (and subscribes to a specific characteristic):

private final BluetoothGattServerCallback bleCallbacks = new BluetoothGattServerCallback() {
    @Override
    public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value){
        Log.v(DEBUG_TAG, "onDescriptorWriteRequest()...");

        BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
        Log.v(DEBUG_TAG, "----- characteristic: " + characteristic.getUuid().toString());

        if (characteristic.equals(peripheralCharacteristic)){
            descriptor.setValue(value);
            if (bluetoothGattServer.sendResponse(device,
                    requestId,
                    BluetoothGatt.GATT_SUCCESS,
                    offset,
                    value)){
                central = device;
                stopAdvertising(); //causes disconnection
                return;
            }
        }

        bluetoothGattServer.sendResponse(device,
                requestId,
                BluetoothGatt.GATT_WRITE_NOT_PERMITTED,
                0,
                null);
    }
...
}

private void stopAdvertising(){
    if (bluetoothLeAdvertiser != null) {
        bluetoothLeAdvertiser.stopAdvertising(advertiseCallback);
    }
}

Upon calling stopAdvertising(), the central and peripheral disconnect from logcat:

04-01 11:26:06.179 7068-7085/package.Class﹕ onDescriptorWriteRequest()...

04-01 11:26:06.179 7068-7085/package.Class﹕ ----- characteristic: 80a1a1a5-8b5b-e88b-9d24-2e609654b852

04-01 11:26:06.207 7068-7085/package D/BluetoothGattServer﹕ onServerConnectionState() - status=0 serverIf=5 device=00:07:80:2F:0F:A2

With stopAdvertising() commented, connection (and communication) with the central continues.

Has anyone encountered this issue with Android's BLE Peripheral Implementation? In iOS, there is no such issue.

Upvotes: 2

Views: 1591

Answers (2)

Gus Fernandez
Gus Fernandez

Reputation: 1

Bogdan's answer applies to Bluetooth LE 4.0. However 4.1 peripherals can connect to more than 1 central, so it makes sense for a peripheral to decide whether or not it wants to stop advertising once a connection is made without immediately losing that connection. This looks like a bug in Android L as recently as 5.1.1

Upvotes: 0

Bogdan Alexandru
Bogdan Alexandru

Reputation: 5542

You do not need to call stopAdvertising after entering a connection.

The Link Layer from the LE Controller has 5 states: "Idle", "Advertising", "Scanning", "Initiating" and "Connected".

When you advertise, you're in "Advertising" state. When it connects, it goes into "Connected" state.

Most likely, the stopAdvertising method assumes you are in "Advertising" state at the time of calling and, without checking this, does what it's supposed to do when you call it in "Advertising": it goes to "Idle" state.

So when you call it, the LL goes into "Idle" regardless of current state.

This seems like a bug in the BLE Host Stack from Android. The correct behaviour when you call stopAdvertising in a "Connected" state should be to return an error code (e.g. "Invalid state for this command") or simply ignore.

Upvotes: 1

Related Questions