I'm attempting to build multiple BLE services for my Android peripheral (Fossil Watch), but found that when creating the AdvertiseData you cannot add multiple services one right after another, you must wait for the callback: https://android.googlesource.com/platform/packages/services/Car/+/master/TrustAgent/src/com/android/car/trust/SimpleBleServer.java#139
If this is true for all BLE peripherals in Android (and not specific to whatever that link above is actually for), how can I utilize the AdvertiseData.Builder() with .addServiceUuid() to add my second and third services in the BluetoothGattServerCallback > onServiceAdded?
To put it in other words, how do I wait for the callback to execute and continue adding services? How do I refactor my code to accommodate this?
I tried overriding the callback, and checking if the service coming through in the callback is the first one, to then add the second, etc. I'm getting an error now though (below), so I'm not quite sure to handle the AdvertiseData.Builder() piece outside of the method it was already in (which is included in the code below):
Cannot resolve method 'addServiceUuid(android.os.ParcelUuid)'
I looked through Google and SO and have not found any similar questions.
Callback:
private BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {
@Override
public void onServiceAdded(int status, BluetoothGattService service){
if (service == commandsService){ // if the service added is the first one, add the second
advData.addServiceUuid(new ParcelUuid(CONFIRMS_SERVICE_UUID));
} else if (service == confirmsService){ // if the service is the second, add the third
advData.addServiceUuid(new ParcelUuid(ALERTS_SERVICE_UUID));
} else {
// All three should be added, success!
}
}
Advertising started, where it gives me an error (below) if the following commented out .addServiceUuid() were included:
private void startAdvertising() {
BluetoothAdapter bluetoothAdapter = mBluetoothManager.getAdapter();
mBluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
if (mBluetoothLeAdvertiser == null) {
Log.w(TAG, "Failed to create advertiser");
return;
}
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setConnectable(true)
.setTimeout(1000)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
.build();
advData = new AdvertiseData.Builder()
.setIncludeDeviceName(false)
.setIncludeTxPowerLevel(false)
.addServiceUuid(new ParcelUuid(COMMANDS_SERVICE_UUID))
// .addServiceUuid(new ParcelUuid(CONFIRMS_SERVICE_UUID))
// .addServiceUuid(new ParcelUuid(ALERTS_SERVICE_UUID))
.build();
mBluetoothLeAdvertiser
.startAdvertising(settings, advData, mAdvertiseCallback);
}
If the two lines were uncommented, this error occurs:
W/GattServer: LE Advertise Failed: 1
W/Binder: Caught a RuntimeException from the binder stub implementation.
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
at java.util.ArrayList.get(ArrayList.java:437)
at android.bluetooth.BluetoothGattServer$1.onServiceAdded(BluetoothGattServer.java:129)
at android.bluetooth.IBluetoothGattServerCallback$Stub.onTransact(IBluetoothGattServerCallback.java:85)
at android.os.Binder.execTransact(Binder.java:697)
I hope to find out how to utilize the AdvertiseData.Builder and add multiple services, using the callback to add one at a time. I don't understand how to use the callback and the builder together, and what the right way is to wait for the callback to add the next service.
Resource - I used this project as an example to get started: http://nilhcem.com/android-things/bluetooth-low-energy