androidnotificationsbluetooth-lowenergybluetooth-gattcharacteristics

Receive notifications for multiple characteristics in Android


I have several characteristics (all under one service) that I would like to be notified of in my Android app. When I set the notification descriptor for one of them, it works well. I understand that some sort of a queue or delay must be utilized for receiving notifications for multiple, but I do not understand how to implement it in my code. I also cannot find any examples on this site Android documentation, or otherwise that explain how to implement this.

Here is the code I have attempted to create for setting the service notification:

@Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                for (BluetoothGattCharacteristic characteristic: gatt.getService(UUID.fromString("00001826-0000-1000-8000-00805f9b34fb")).getCharacteristics()) {
                    gatt.setCharacteristicNotification(characteristic, true);
                    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
                    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                    gatt.writeDescriptor(descriptor);
                }

            }
        }

Here is the function I have for setting the text in my app to match the value of the characteristic which has just changed:

 @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            TextView instructionText = getView().findViewById(R.id.instructionText);
            if(showMeasurements) {
                instructionText.setText(characteristic.getStringValue(0));
            }
        }

One other method that I have considered trying is creating a list List<BluetoothGattCharacteristic> chars = new ArrayList<>(); and adding each characteristic I find in this list. Then I could try to write the notification descriptor one by one, but I cannot seem to implement this either.

I am a college student who is not familiar with Android development and such functions. Any help on how to go about resolving this problem would be greatly appreciated. Thank you.


Solution

  • Thanks to this post, I was able to asynchronously apply my notification descriptor to each of my characteristics.

    Although most of the code is the same, there are some slight modifications that are required. It is for this reason that I want to provide a more in depth explanation of what is going on in this code so that future newbie developers like me can take advantage of it.

    Within my gatCallback, I create a list similar to the one I mentioned in my question. I also define some UUIDs which I will utilize later on in my code:

    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
            List<BluetoothGattCharacteristic> chars = new ArrayList<>();
            UUID pitchUUID = UUID.fromString("78c5307a-6715-4040-bd50-d64db33e2e9e");
            UUID rollUUID = UUID.fromString("78c5307b-6715-4040-bd50-d64db33e2e9e");
    

    Once I have discovered services, I iterate through the characteristics I need from my specific service, and I add them to my list. I then jump to a function I have created called subscribeToCharacteristics, passing in my BluetoothGatt object:

    for (BluetoothGattCharacteristic characteristic: gatt.getService(UUID.fromString("00001826-0000-1000-8000-00805f9b34fb")).getCharacteristics()) {
                        chars.add(characteristic);
                    }
                    subscribeToCharacteristics(gatt);
    
    

    It is in this function that I set the characteristic notification. I only do that if there are items in the list; if items are present, that means that there are still descriptors that need to be written!

    private void subscribeToCharacteristics(BluetoothGatt gatt) {
                if(chars.size() == 0) return;
                BluetoothGattCharacteristic characteristic = chars.get(0);
                gatt.setCharacteristicNotification(characteristic, true);
                BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
                if(descriptor != null) {
                    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                    gatt.writeDescriptor(descriptor);
                }
            }
    

    When I override the onDescriptorWrite function, I just remove the first element in my list, and then call my subscribeToCharacteristics function again.

    @Override
            public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
                Log.i("DESCRIPTOR", "WROTE DESCRIPTOR FOR CHARACTERISTIC");
                super.onDescriptorWrite(gatt, descriptor, status);
                chars.remove(0);
                subscribeToCharacteristics(gatt);
            }
    

    Notice that I did not utilize GetCharacteristicsWithNotifications(gatt); as this is not a standard function and was not explained well in the other post.

    I also did not use notifyCharacteristics.get(0); as this was not previously explained or included in the post's code.

    Lastly, I did not use characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); because I already have my services and characteristics defined with the appropriate properties in my Arduino's code. If I were not sure of this, then this code could have been used.

    I hope this (long) explanation will be of value to any future devs!