From 92e05c511645eefedce45ece255c57b1410087f2 Mon Sep 17 00:00:00 2001 From: Marco Sinigaglia Date: Mon, 9 Dec 2024 11:26:25 +0100 Subject: [PATCH 1/3] Removed unwanted retrieve services on connect Ref 5c92dcfbe3b8c38021403329d54c69f31b94ca09 --- .../src/main/java/it/innove/Peripheral.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/android/src/main/java/it/innove/Peripheral.java b/android/src/main/java/it/innove/Peripheral.java index 8bba6b4d..a1a11ee9 100644 --- a/android/src/main/java/it/innove/Peripheral.java +++ b/android/src/main/java/it/innove/Peripheral.java @@ -76,7 +76,6 @@ public class Peripheral extends BluetoothGattCallback { private final Queue commandQueue = new ConcurrentLinkedQueue<>(); private final Handler mainHandler = new Handler(Looper.getMainLooper()); - private Runnable discoverServicesRunnable; private boolean commandQueueBusy = false; private List writeQueue = new ArrayList<>(); @@ -320,21 +319,6 @@ public void onConnectionStateChange(BluetoothGatt gatta, int status, final int n if (newState == BluetoothProfile.STATE_CONNECTED && status == BluetoothGatt.GATT_SUCCESS) { connected = true; - discoverServicesRunnable = new Runnable() { - @Override - public void run() { - try { - gatt.discoverServices(); - } catch (NullPointerException e) { - Log.d(BleManager.LOG_TAG, - "onConnectionStateChange connected but gatt of Run method was null"); - } - discoverServicesRunnable = null; - } - }; - - mainHandler.post(discoverServicesRunnable); - sendConnectionEvent(device, "BleManagerConnectPeripheral", status); Log.d(BleManager.LOG_TAG, "Connected to: " + device.getAddress()); @@ -345,11 +329,6 @@ public void run() { } else if (newState == BluetoothProfile.STATE_DISCONNECTED || status != BluetoothGatt.GATT_SUCCESS) { - if (discoverServicesRunnable != null) { - mainHandler.removeCallbacks(discoverServicesRunnable); - discoverServicesRunnable = null; - } - for (Callback writeCallback : writeCallbacks) { writeCallback.invoke("Device disconnected"); } @@ -400,8 +379,6 @@ public void run() { commandQueueBusy = false; connected = false; clearBuffers(); - commandQueue.clear(); - commandQueueBusy = false; gatt.disconnect(); gatt.close(); From 76a460b74b46a8db459e5558cbb95e560318a573 Mon Sep 17 00:00:00 2001 From: Ville Hakulinen Date: Tue, 21 Jan 2025 13:21:39 +0200 Subject: [PATCH 2/3] backport innoveit/react-native-ble-manager#1297 Backport #1297 for v11 --- .../src/main/java/it/innove/BleManager.java | 2 + .../java/it/innove/DefaultScanManager.java | 9 +- .../src/main/java/it/innove/Peripheral.java | 157 ++++++++++-------- 3 files changed, 101 insertions(+), 67 deletions(-) diff --git a/android/src/main/java/it/innove/BleManager.java b/android/src/main/java/it/innove/BleManager.java index 9116e6b3..4862563a 100644 --- a/android/src/main/java/it/innove/BleManager.java +++ b/android/src/main/java/it/innove/BleManager.java @@ -720,6 +720,8 @@ private void disconnectPeripherals() { if (peripheral.isConnected()) { peripheral.disconnect(null, true); } + peripheral.errorAndClearAllCallbacks("disconnected by BleManager"); + peripheral.resetQueuesAndBuffers(); } } } diff --git a/android/src/main/java/it/innove/DefaultScanManager.java b/android/src/main/java/it/innove/DefaultScanManager.java index d7dc5c32..4f5a9616 100644 --- a/android/src/main/java/it/innove/DefaultScanManager.java +++ b/android/src/main/java/it/innove/DefaultScanManager.java @@ -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; @@ -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(); } @@ -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; } diff --git a/android/src/main/java/it/innove/Peripheral.java b/android/src/main/java/it/innove/Peripheral.java index a1a11ee9..c2940f38 100644 --- a/android/src/main/java/it/innove/Peripheral.java +++ b/android/src/main/java/it/innove/Peripheral.java @@ -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; @@ -156,14 +157,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 { @@ -293,15 +289,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) { @@ -311,7 +375,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(); } @@ -329,59 +393,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; sendConnectionEvent(device, "BleManagerDisconnectPeripheral", BluetoothGatt.GATT_SUCCESS); @@ -888,7 +906,9 @@ private byte[] copyOf(byte[] source) { } private boolean enqueue(Runnable command) { + final boolean result = commandQueue.add(command); + if (result) { nextCommand(); } else { @@ -918,9 +938,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; } @@ -968,6 +988,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); @@ -1215,6 +1239,9 @@ private BluetoothGattCharacteristic findWritableCharacteristic(BluetoothGattServ writeProperty = BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE; } + if (service == null) { + throw new Exception("Service is null."); + } List characteristics = service.getCharacteristics(); for (BluetoothGattCharacteristic characteristic : characteristics) { if ((characteristic.getProperties() & writeProperty) != 0 From c51dd42ae5c24113858a8642a32a85035292e446 Mon Sep 17 00:00:00 2001 From: Ville Hakulinen Date: Thu, 30 Jan 2025 10:34:34 +0200 Subject: [PATCH 3/3] backport innoveit/react-native-ble-manager#1305 --- .../src/main/java/it/innove/BleManager.java | 90 +++++++++++++------ 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/android/src/main/java/it/innove/BleManager.java b/android/src/main/java/it/innove/BleManager.java index 4862563a..d55eccad 100644 --- a/android/src/main/java/it/innove/BleManager.java +++ b/android/src/main/java/it/innove/BleManager.java @@ -368,8 +368,12 @@ public void startNotification(String deviceUUID, String serviceUUID, String char } Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral != null) { - peripheral.registerNotify(UUIDHelper.uuidFromString(serviceUUID), - UUIDHelper.uuidFromString(characteristicUUID), 1, callback); + if (peripheral.isConnected()) { + peripheral.registerNotify(UUIDHelper.uuidFromString(serviceUUID), + UUIDHelper.uuidFromString(characteristicUUID), 1, callback); + } else { + callback.invoke("Peripheral not connected", null); + } } else callback.invoke("Peripheral not found"); } @@ -383,8 +387,12 @@ public void stopNotification(String deviceUUID, String serviceUUID, String chara } Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral != null) { - peripheral.removeNotify(UUIDHelper.uuidFromString(serviceUUID), - UUIDHelper.uuidFromString(characteristicUUID), callback); + if (peripheral.isConnected()) { + peripheral.removeNotify(UUIDHelper.uuidFromString(serviceUUID), + UUIDHelper.uuidFromString(characteristicUUID), callback); + } else { + callback.invoke("Peripheral not connected", null); + } } else callback.invoke("Peripheral not found"); } @@ -399,13 +407,17 @@ public void write(String deviceUUID, String serviceUUID, String characteristicUU } Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral != null) { - byte[] decoded = new byte[message.size()]; - for (int i = 0; i < message.size(); i++) { - decoded[i] = Integer.valueOf(message.getInt(i)).byteValue(); + if (peripheral.isConnected()) { + byte[] decoded = new byte[message.size()]; + for (int i = 0; i < message.size(); i++) { + decoded[i] = Integer.valueOf(message.getInt(i)).byteValue(); + } + Log.d(LOG_TAG, "Message(" + decoded.length + "): " + bytesToHex(decoded)); + peripheral.write(UUIDHelper.uuidFromString(serviceUUID), UUIDHelper.uuidFromString(characteristicUUID), + decoded, maxByteSize, null, callback, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); + } else { + callback.invoke("Peripheral not connected", null); } - Log.d(LOG_TAG, "Message(" + decoded.length + "): " + bytesToHex(decoded)); - peripheral.write(UUIDHelper.uuidFromString(serviceUUID), UUIDHelper.uuidFromString(characteristicUUID), - decoded, maxByteSize, null, callback, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); } else callback.invoke("Peripheral not found"); } @@ -420,13 +432,17 @@ public void writeWithoutResponse(String deviceUUID, String serviceUUID, String c } Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral != null) { - byte[] decoded = new byte[message.size()]; - for (int i = 0; i < message.size(); i++) { - decoded[i] = Integer.valueOf(message.getInt(i)).byteValue(); + if (peripheral.isConnected()) { + byte[] decoded = new byte[message.size()]; + for (int i = 0; i < message.size(); i++) { + decoded[i] = Integer.valueOf(message.getInt(i)).byteValue(); + } + Log.d(LOG_TAG, "Message(" + decoded.length + "): " + bytesToHex(decoded)); + peripheral.write(UUIDHelper.uuidFromString(serviceUUID), UUIDHelper.uuidFromString(characteristicUUID), + decoded, maxByteSize, queueSleepTime, callback, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); + } else { + callback.invoke("Peripheral not connected", null); } - Log.d(LOG_TAG, "Message(" + decoded.length + "): " + bytesToHex(decoded)); - peripheral.write(UUIDHelper.uuidFromString(serviceUUID), UUIDHelper.uuidFromString(characteristicUUID), - decoded, maxByteSize, queueSleepTime, callback, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); } else callback.invoke("Peripheral not found"); } @@ -440,8 +456,12 @@ public void read(String deviceUUID, String serviceUUID, String characteristicUUI } Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral != null) { - peripheral.read(UUIDHelper.uuidFromString(serviceUUID), UUIDHelper.uuidFromString(characteristicUUID), - callback); + if (peripheral.isConnected()) { + peripheral.read(UUIDHelper.uuidFromString(serviceUUID), UUIDHelper.uuidFromString(characteristicUUID), + callback); + } else { + callback.invoke("Peripheral not connected", null); + } } else callback.invoke("Peripheral not found", null); } @@ -457,13 +477,15 @@ public void readDescriptor(String deviceUUID, String serviceUUID, String charact Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral == null) { callback.invoke("Peripheral not found", null); + } else if (!peripheral.isConnected()) { + callback.invoke("Peripheral not connected", null); + } else { + peripheral.readDescriptor( + UUIDHelper.uuidFromString(serviceUUID), + UUIDHelper.uuidFromString(characteristicUUID), + UUIDHelper.uuidFromString(descriptorUUID), + callback); } - - peripheral.readDescriptor( - UUIDHelper.uuidFromString(serviceUUID), - UUIDHelper.uuidFromString(characteristicUUID), - UUIDHelper.uuidFromString(descriptorUUID), - callback); } @ReactMethod @@ -477,6 +499,8 @@ public void writeDescriptor(String deviceUUID, String serviceUUID, String charac Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral == null) { callback.invoke("Peripheral not found", null); + } else if (!peripheral.isConnected()) { + callback.invoke("Peripheral not connected", null); } else { byte[] decoded = new byte[message.size()]; for (int i = 0; i < message.size(); i++) { @@ -492,7 +516,11 @@ public void retrieveServices(String deviceUUID, ReadableArray services, Callback Log.d(LOG_TAG, "Retrieve services from: " + deviceUUID); Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral != null) { - peripheral.retrieveServices(callback); + if (peripheral.isConnected()) { + peripheral.retrieveServices(callback); + } else { + callback.invoke("Peripheral not connected", null); + } } else callback.invoke("Peripheral not found", null); } @@ -502,7 +530,11 @@ public void refreshCache(String deviceUUID, Callback callback) { Log.d(LOG_TAG, "Refreshing cache for: " + deviceUUID); Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral != null) { - peripheral.refreshCache(callback); + if (peripheral.isConnected()) { + peripheral.refreshCache(callback); + } else { + callback.invoke("Peripheral not connected", null); + } } else callback.invoke("Peripheral not found"); } @@ -512,7 +544,11 @@ public void readRSSI(String deviceUUID, Callback callback) { Log.d(LOG_TAG, "Read RSSI from: " + deviceUUID); Peripheral peripheral = peripherals.get(deviceUUID); if (peripheral != null) { - peripheral.readRSSI(callback); + if (peripheral.isConnected()) { + peripheral.readRSSI(callback); + } else { + callback.invoke("Peripheral not connected", null); + } } else callback.invoke("Peripheral not found", null); }