Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unfullfilled callbacks when gatt is null #1297

Merged
merged 11 commits into from
Jan 16, 2025
2 changes: 2 additions & 0 deletions android/src/main/java/it/innove/BleManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,8 @@ private void disconnectPeripherals() {
if (peripheral.isConnected()) {
peripheral.disconnect(null, true);
}
peripheral.errorAndClearAllCallbacks("disconnected by BleManager");
peripheral.resetQueuesAndBuffers();
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions android/src/main/java/it/innove/DefaultScanManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanRecord;
Expand Down Expand Up @@ -45,7 +47,9 @@ public void stopScan(Callback callback) {
// update scanSessionId to prevent stopping next scan by running timeout thread
scanSessionId.incrementAndGet();

getBluetoothAdapter().getBluetoothLeScanner().stopScan(mScanCallback);
final BluetoothLeScanner scanner = getBluetoothAdapter().getBluetoothLeScanner();
if (scanner != null)
scanner.stopScan(mScanCallback);
isScanning = false;
callback.invoke();
}
Expand Down Expand Up @@ -173,7 +177,8 @@ public void run() {
// check current scan session was not stopped
if (scanSessionId.intValue() == currentScanSession) {
if (btAdapter.getState() == BluetoothAdapter.STATE_ON) {
btAdapter.getBluetoothLeScanner().stopScan(mScanCallback);
final BluetoothLeScanner scanner = btAdapter.getBluetoothLeScanner();
if (scanner != null) scanner.stopScan(mScanCallback);
isScanning = false;
}

Expand Down
157 changes: 92 additions & 65 deletions android/src/main/java/it/innove/Peripheral.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothStatusCodes;

import android.content.Context;
import android.os.Build;
import android.os.Handler;
Expand Down Expand Up @@ -160,14 +161,9 @@ public void connect(final Callback callback, Activity activity, ReadableMap opti

public void disconnect(final Callback callback, final boolean force) {
mainHandler.post(() -> {
for (Callback connectCallback : connectCallbacks) {
connectCallback.invoke("Disconnect called before connect callback invoked");
}
connectCallbacks.clear();
errorAndClearAllCallbacks("Disconnect called before the command completed");
resetQueuesAndBuffers();
connected = false;
clearBuffers();
commandQueue.clear();
commandQueueBusy = false;

if (gatt != null) {
try {
Expand Down Expand Up @@ -297,15 +293,83 @@ public BluetoothDevice getDevice() {
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
mainHandler.post(() -> {
for (Callback retrieveServicesCallback : retrieveServicesCallbacks) {
WritableMap map = this.asWritableMap(gatt);
retrieveServicesCallback.invoke(null, map);
if (gatt == null) {
for (Callback retrieveServicesCallback : retrieveServicesCallbacks) {
retrieveServicesCallback.invoke("Error during service retrieval: gatt is null");
}
}
else if (status == BluetoothGatt.GATT_SUCCESS)
{
for (Callback retrieveServicesCallback : retrieveServicesCallbacks) {
WritableMap map = this.asWritableMap(gatt);
retrieveServicesCallback.invoke(null, map);
}
}
else {
for (Callback retrieveServicesCallback : retrieveServicesCallbacks) {
retrieveServicesCallback.invoke("Error during service retrieval.");
}
}
retrieveServicesCallbacks.clear();
completedCommand();
});
}

public void errorAndClearAllCallbacks(final String errorMessage) {

for (Callback writeCallback : writeCallbacks) {
writeCallback.invoke(errorMessage);
}
writeCallbacks.clear();

for (Callback retrieveServicesCallback : retrieveServicesCallbacks) {
retrieveServicesCallback.invoke(errorMessage);
}
retrieveServicesCallbacks.clear();

for (Callback readRSSICallback : readRSSICallbacks) {
readRSSICallback.invoke(errorMessage);
}
readRSSICallbacks.clear();

for (Callback registerNotifyCallback : registerNotifyCallbacks) {
registerNotifyCallback.invoke(errorMessage);
}
registerNotifyCallbacks.clear();

for (Callback requestMTUCallback : requestMTUCallbacks) {
requestMTUCallback.invoke(errorMessage);
}
requestMTUCallbacks.clear();

for (Callback readCallback : readCallbacks) {
readCallback.invoke(errorMessage);
}
readCallbacks.clear();

for (Callback readDescriptorCallback : readDescriptorCallbacks) {
readDescriptorCallback.invoke(errorMessage);
}
readDescriptorCallbacks.clear();

for (Callback callback : writeDescriptorCallbacks) {
callback.invoke(errorMessage);
}
writeDescriptorCallbacks.clear();

for (Callback connectCallback : connectCallbacks) {
connectCallback.invoke(errorMessage);
}
connectCallbacks.clear();
}

public void resetQueuesAndBuffers() {
writeQueue.clear();
commandQueue.clear();
commandQueueBusy = false;
connected = false;
clearBuffers();
}
@Override
public void onConnectionStateChange(BluetoothGatt gatta, int status, final int newState) {

Expand All @@ -315,7 +379,7 @@ public void onConnectionStateChange(BluetoothGatt gatta, int status, final int n
mainHandler.post(() -> {
gatt = gatta;

if (status != BluetoothGatt.GATT_SUCCESS) {
if (gatt != null && status != BluetoothGatt.GATT_SUCCESS) {
gatt.close();
}

Expand All @@ -333,59 +397,13 @@ public void onConnectionStateChange(BluetoothGatt gatta, int status, final int n

} else if (newState == BluetoothProfile.STATE_DISCONNECTED || status != BluetoothGatt.GATT_SUCCESS) {

for (Callback writeCallback : writeCallbacks) {
writeCallback.invoke("Device disconnected");
}
writeCallbacks.clear();

for (Callback retrieveServicesCallback : retrieveServicesCallbacks) {
retrieveServicesCallback.invoke("Device disconnected");
}
retrieveServicesCallbacks.clear();

for (Callback readRSSICallback : readRSSICallbacks) {
readRSSICallback.invoke("Device disconnected");
}
readRSSICallbacks.clear();

for (Callback registerNotifyCallback : registerNotifyCallbacks) {
registerNotifyCallback.invoke("Device disconnected");
}
registerNotifyCallbacks.clear();

for (Callback requestMTUCallback : requestMTUCallbacks) {
requestMTUCallback.invoke("Device disconnected");
}
requestMTUCallbacks.clear();

for (Callback readCallback : readCallbacks) {
readCallback.invoke("Device disconnected");
}
readCallbacks.clear();

for (Callback readDescriptorCallback : readDescriptorCallbacks) {
readDescriptorCallback.invoke("Device disconnected");
}
readDescriptorCallbacks.clear();

for (Callback callback : writeDescriptorCallbacks) {
callback.invoke("Device disconnected");
}
writeDescriptorCallbacks.clear();

for (Callback connectCallback : connectCallbacks) {
connectCallback.invoke("Connection error");
errorAndClearAllCallbacks("Device disconnected");
resetQueuesAndBuffers();
if (gatt != null) {
gatt.disconnect();
gatt.close();
}
connectCallbacks.clear();

writeQueue.clear();
commandQueue.clear();
commandQueueBusy = false;
connected = false;
clearBuffers();

gatt.disconnect();
gatt.close();
gatt = null;
sendDisconnectionEvent(device, BluetoothGatt.GATT_SUCCESS);
}
Expand Down Expand Up @@ -891,7 +909,9 @@ private byte[] copyOf(byte[] source) {
}

private boolean enqueue(Runnable command) {

final boolean result = commandQueue.add(command);

if (result) {
nextCommand();
} else {
Expand Down Expand Up @@ -921,9 +941,9 @@ private void nextCommand() {

// Check if we still have a valid gatt object
if (gatt == null) {
Log.d(BleManager.LOG_TAG, "Error, gatt is null");
commandQueue.clear();
commandQueueBusy = false;
Log.d(BleManager.LOG_TAG, "Error, gatt is null. Fill all callbacks with an error");
errorAndClearAllCallbacks("Gatt is null");
resetQueuesAndBuffers();
return;
}

Expand Down Expand Up @@ -971,6 +991,10 @@ public void readRSSI(final Callback callback) {
public void refreshCache(Callback callback) {
enqueue(() -> {
try {
if (gatt == null) {
throw new Exception("gatt is null");
}

Method localMethod = gatt.getClass().getMethod("refresh", new Class[0]);
boolean res = (Boolean) localMethod.invoke(gatt, new Object[0]);
callback.invoke(null, res);
Expand Down Expand Up @@ -1218,6 +1242,9 @@ private BluetoothGattCharacteristic findWritableCharacteristic(BluetoothGattServ
writeProperty = BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE;
}

if (service == null) {
throw new Exception("Service is null.");
}
List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
if ((characteristic.getProperties() & writeProperty) != 0
Expand Down