javaandroidbluetooth-lowenergy

How to know when a BLE device subscribes to a characteristic on Android?


Coming from an iOS dev background, when working with Bluetooth LE acting as a peripheral you can register for a callback when a "central" BLE device subscribes (enables notifications) for a characteristic.

I'm struggling to see how this is achieved on Android. If you're working with Bluetooth LE acting as the central, I can see how you'd subscribe: bluetoothGatt.setCharacteristicNotification(characteristicToSubscribeTo, true);

Which is the same as this on iOS: peripheralDevice.setNotifyValue(true, forCharacteristic characteristicToSubscribeTo)

Now, after calling the above on iOS, on the peripheral side you then get a callback to say the central has subscribed with a method similar to: peripheralManager(manager, central subscribedCentral didSubscribeToCharacteristic characteristic) which then gives you a reference to the device that subscribed/enabled notifications and to what characteristic.

What's the equivalent on Android?

For clarity I'll point out that I don't need to subscribe to a characteristic on Android, the device is acting as the peripheral and needs to be notified when other devices subscribe to characteristics.

Sorry if this is obvious but I can't find it in the docs or elsewhere.


Solution

  • Just after setting the bounty I had an idea, haha should've waited a little more give my brain more time to think ;)

    It seems that iOS has abstracted away a little bit how subscriptions work internally. Under the ios CoreBluetooth hood a certain "Descriptor" of the characteristic is written by the Center, which indicates the center wants to subscribe the characteristic's value.

    Here is the code that you need to add to your BluetoothGattServerCallback subclass:

        @Override
        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
    
            Log.i(TAG, "onDescriptorWriteRequest, uuid: " + descriptor.getUuid());
    
            if (descriptor.getUuid().equals(Descriptor.CLIENT_CHARACTERISTIC_CONFIGURATION) && descriptor.getValue().equals(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) {
                Log.i(TAG, "it's a subscription");
    
                for (int i = 0; i < 30; i++) {
                    descriptor.getCharacteristic().setValue(String.format("new value: %d", i));
                    mGattServer.notifyCharacteristicChanged(device, descriptor.getCharacteristic(), false);
                }
            }
        }
    

    would be best to use https://github.com/movisens/SmartGattLib for the uuid (Descriptor.CLIENT_CHARACTERISTIC_CONFIGURATION but the raw value is 00002902-0000-1000-8000-00805f9b34fb)