Android-BLE-Library
Android-BLE-Library copied to clipboard
Lose notifications for some reasons
Hello everybody,
First of all, thanks for your amazing work on this library.
I encounter a strange behavior with notifications and would like to understand what I'm doing wrong. I've 2 android devices, one Gatt Server, one Gatt Client. From the client I write a characteristic to the server to tell him that I want to get a file from him. Then the server send me his file as bytes[] by notifying the client that data is available.
Let's consider this part of the server side that send me data :
public void sendTracks(BluetoothGattCharacteristic characteristic) throws IOException {
// Begin here
byte[] bytes = readFileToBytes(DatabaseSettings.getDatabasePathFileName());
// First Packet
byte[] size = ByteBuffer.allocate(4).putInt(bytes.length).array(); // Total size of file
Log.i(TAG, "sendTracksDataBase SIZE : " + bytes.length);
Log.i(TAG, "sendTracksDataBase MTU Negotiated : " + this.getMtu());
int nbPacketInt = (int)Math.ceil((double)bytes.length / this.getMtu()); // Nb packets rounded up
byte[] nbPackets = ByteBuffer.allocate(4).putInt(nbPacketInt).array();
Log.i(TAG, "sendTracksDataBase NBPACKETS : " + nbPacketInt);
Checksum crc = new CRC32(); // CRC
crc.update(bytes, 0, bytes.length);
byte[] crcBytes = ByteBuffer.allocate(8).putLong(crc.getValue()).array(); // CRC
Log.i(TAG, "sendTracksDataBase CRC : " + crc.getValue());
String ext = FileSystemUtils.getExtension(DatabaseSettings.getDatabasePathFileName());
byte[] extension = ext.getBytes(StandardCharsets.UTF_8);
Log.i(TAG, "sendTracksDataBase EXTENSION : " + ext);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// Send first packet
outputStream.write(size);
outputStream.write(nbPackets);
outputStream.write(crcBytes);
outputStream.write(extension);
this.waitUntilNotificationsEnabled(characteristic).enqueue();
this.sendNotification(characteristic, outputStream.toByteArray(), 0, outputStream.toByteArray().length)
.then(new AfterCallback() {
@Override
public void onRequestFinished(BluetoothDevice device) {
int t = 1;
}
}).enqueue();
// Send everything here
this.sendNotification(characteristic, bytes, 0, bytes.length)
.split()
.fail(new FailCallback() {
@Override
public void onRequestFailed(BluetoothDevice device, int status) {
Log.e(TAG, "SendNotification failed with status : " + status);
}
})
.done(new SuccessCallback() {
@Override
public void onRequestCompleted(BluetoothDevice device) {
Log.i(TAG, "SendNotification success : ");
}
})
.then(new AfterCallback() {
@Override
public void onRequestFinished(BluetoothDevice device) {
}
})
.enqueue();
As you can see, i send a first packet containing meta data of the file, and then i send the notification for the whole array of bytes, with the split function.
On the client side, I've enable the notifications and added a notification callBack to the characteristic the server is notifying.
setNotificationCallback(this.dataCharacteristic)
.with(new DataReceivedCallback() {
@Override
public void onDataReceived(BluetoothDevice device, Data data) {
try {
Log.i(TAG, "onDataReceived");
recomputeDownload(device, data, deviceActionStatusListener);
if (deviceActionStatusListener != null) {
deviceActionStatusListener.onActionProgress(BleTrackerService.DOWNLOAD_PROGRESS);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
enableNotifications(this.dataCharacteristic)
.fail(new FailCallback() {
@Override
public void onRequestFailed(BluetoothDevice device, int status) {
int t = 1;
}
})
.done(new SuccessCallback() {
@Override
public void onRequestCompleted(BluetoothDevice device) {
int t = 1 ;
}
})
.enqueue();
The first time I launch the command, everything is going well as i'm receiving all the notifications. in the background i get the different array of bytes and rebuild my file.
But i can stop this command and relaunch it if i wish. When i stop the command, i disconnect my client from the server. In my clientManager i 'have this piece of code :
@Override
protected void onServicesInvalidated() {
// This method is called when the services get invalidated, i.e. when the device
// disconnects.
// References to characteristics should be nullified here.
this.removeNotificationCallback(this.dataCharacteristic);
this.disableNotifications(this.dataCharacteristic).enqueue();
this.commandCharacteristic = null;
this.dataCharacteristic = null;
this.iotDevice = null;
this.deviceActionStatusListener = null;
// Refresh device
this.refreshDeviceCache().enqueue();
}
Then i re-launch the command. But this time i only get one notification in my Notification CallBack, but the server did the same and should have send me a lot of other notifications.
I cannot understand why my client is not notified anymore ...
Thanks for your help.
Update : If I close and create a new instance of Server Manager that extends BleServerManager between 2 commands, it works well.
Have you tried to just reconnect to the server? What ConnectionState are you in when this error happens?
Hi, sorry for the late response.
I have 2 hints:
- You don't have to do:
The notification callback is cleared automatically and thethis.removeNotificationCallback(this.dataCharacteristic); this.disableNotifications(this.dataCharacteristic).enqueue();dataCharacteristicis no longer valid, as the device has disconnected. - You also don't have to call:
instead you may use extend this method and return true: https://github.com/NordicSemiconductor/Android-BLE-Library/blob/fa970a356454a5a2f164e62219e8c988707e5dfc/ble/src/main/java/no/nordicsemi/android/ble/BleManager.java#L613-L615// Refresh device this.refreshDeviceCache().enqueue();