Search code examples
androidbluetooth-lowenergy

Bluetooth Low Energy (BLE) - How to get UUIDs of Service, Characteristic and Descriptor separately


Struggling quite a lot with an issue regarding Bluetooth Low Energy protocol. For example, a device has a Service, and this service contains a Characteristic which contains a Descriptor. UUIDs of the Service, Characteristic and Descriptor are not known in advance. My question is how to get UUIDs of them in a way that we know that this certain UUID is a type of Service/Charactersitic/Descriptor?

BluetoothGatt.getServices() doesn't help, because it returns all UUIDs together and we don't know which one belongs to the service. I'm sure there is a way to split the UUIDs. At least nRF Connect app (you can find it in the Play Store) can do this.


Solution

  • The only way for me to resolve the issue was to use ScanRecord which is retrieved from ScanResult. ScanRecord stores some information about each scanned device including services' UUIDs. We can have access to ScanRecord object once the scanning is started by initScanning() method and returned any result in onScanResult():

    List<UUID> serviceUUIDsList        = new ArrayList<>();
    List<UUID> characteristicUUIDsList = new ArrayList<>();
    List<UUID> descriptorUUIDsList     = new ArrayList<>();
    
    private void initScanning(BluetoothLeScannerCompat bleScanner)
    {
        bleScanner.startScan(getScanCallback());
    }
    
    private ScanCallback getScanCallback()
    {
        return new ScanCallback()
        {
            @Override
            public void onScanResult(int callbackType, ScanResult scanResult)
            {
                super.onScanResult(callbackType, scanResult);
                serviceUUIDsList = getServiceUUIDsList(scanResult);
            }
        };
    }
    
    private List<UUID> getServiceUUIDsList(ScanResult scanResult)
    {
        List<ParcelUuid> parcelUuids = scanResult.getScanRecord().getServiceUuids();
    
        List<UUID> serviceList = new ArrayList<>();
    
        for (int i = 0; i < parcelUuids.size(); i++)
        {
            UUID serviceUUID = parcelUuids.get(i).getUuid();
    
            if (!serviceList.contains(serviceUUID))
                serviceList.add(serviceUUID);
        }
    
        return serviceList;
    }
    

    Thus, when we know service UUIDs, we can get UUIDs of Characteristics and Descriptors:

    private void defineCharAndDescrUUIDs(BluetoothGatt bluetoothGatt)
    {
        List<BluetoothGattService> servicesList = bluetoothGatt.getServices();
    
        for (int i = 0; i < servicesList.size(); i++)
        {
            BluetoothGattService bluetoothGattService = servicesList.get(i);
    
            if (serviceUUIDsList.contains(bluetoothGattService.getUuid()))
            {
                List<BluetoothGattCharacteristic> bluetoothGattCharacteristicList = bluetoothGattService.getCharacteristics();
    
                for (BluetoothGattCharacteristic bluetoothGattCharacteristic : bluetoothGattCharacteristicList)
                {
                    characteristicUUIDsList.add(bluetoothGattCharacteristic.getUuid());
                    List<BluetoothGattDescriptor> bluetoothGattDescriptorsList = bluetoothGattCharacteristic.getDescriptors();
    
                    for (BluetoothGattDescriptor bluetoothGattDescriptor : bluetoothGattDescriptorsList)
                    {
                        descriptorUUIDsList.add(bluetoothGattDescriptor.getUuid());
                    }
                }
            }
        }
    }
    

    I hope, I can help also others which will struggle with the similar issue.