react-native-ble-manager 8.4.4 → 8.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -691,12 +691,12 @@ The scanning for peripherals is ended.
691
691
 
692
692
  **Arguments**
693
693
 
694
- - `none`
694
+ - `status` - `Number` - [iOS] the reason for stopping the scan. Error code 10 is used for timeouts, 0 covers everything else. [Android] the reason for stopping the scan (<https://developer.android.com/reference/android/bluetooth/le/ScanCallback#constants_1>). Error code 10 is used for timeouts
695
695
 
696
696
  **Examples**
697
697
 
698
698
  ```js
699
- bleManagerEmitter.addListener("BleManagerStopScan", () => {
699
+ bleManagerEmitter.addListener("BleManagerStopScan", (args) => {
700
700
  // Scanning is stopped
701
701
  });
702
702
  ```
@@ -218,6 +218,7 @@ class BleManager extends ReactContextBaseJavaModule {
218
218
  if (scanManager != null) {
219
219
  scanManager.stopScan(callback);
220
220
  WritableMap map = Arguments.createMap();
221
+ map.putInt("status", 0);
221
222
  sendEvent("BleManagerStopScan", map);
222
223
  }
223
224
  }
@@ -290,8 +291,7 @@ class BleManager extends ReactContextBaseJavaModule {
290
291
 
291
292
  Peripheral peripheral = peripherals.get(peripheralUUID);
292
293
  if (peripheral != null) {
293
- peripheral.disconnect(force);
294
- callback.invoke();
294
+ peripheral.disconnect(callback, force);
295
295
  } else
296
296
  callback.invoke("Peripheral not found");
297
297
  }
@@ -589,7 +589,7 @@ class BleManager extends ReactContextBaseJavaModule {
589
589
  synchronized (peripherals) {
590
590
  for (Peripheral peripheral : peripherals.values()) {
591
591
  if (peripheral.isConnected()) {
592
- peripheral.disconnect(true);
592
+ peripheral.disconnect(null,true);
593
593
  }
594
594
  }
595
595
  }
@@ -80,6 +80,7 @@ public class LegacyScanManager extends ScanManager {
80
80
  btAdapter.stopLeScan(mLeScanCallback);
81
81
  }
82
82
  WritableMap map = Arguments.createMap();
83
+ map.putInt("status", 0);
83
84
  bleManager.sendEvent("BleManagerStopScan", map);
84
85
  }
85
86
  }
@@ -39,7 +39,7 @@ public class LollipopScanManager extends ScanManager {
39
39
  ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder();
40
40
  List<ScanFilter> filters = new ArrayList<>();
41
41
 
42
- if (options.hasKey("legacy")) {
42
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && options.hasKey("legacy")) {
43
43
  scanSettingsBuilder.setLegacy(options.getBoolean("legacy"));
44
44
  }
45
45
 
@@ -101,6 +101,7 @@ public class LollipopScanManager extends ScanManager {
101
101
  btAdapter.getBluetoothLeScanner().stopScan(mScanCallback);
102
102
  }
103
103
  WritableMap map = Arguments.createMap();
104
+ map.putInt("status", 10);
104
105
  bleManager.sendEvent("BleManagerStopScan", map);
105
106
  }
106
107
  }
@@ -145,6 +146,7 @@ public class LollipopScanManager extends ScanManager {
145
146
  @Override
146
147
  public void onScanFailed(final int errorCode) {
147
148
  WritableMap map = Arguments.createMap();
149
+ map.putInt("status", errorCode);
148
150
  bleManager.sendEvent("BleManagerStopScan", map);
149
151
  }
150
152
  };
@@ -28,12 +28,12 @@ import org.json.JSONException;
28
28
  import java.lang.reflect.Method;
29
29
  import java.util.ArrayList;
30
30
  import java.util.Map;
31
- import java.util.HashMap;
32
31
  import java.util.Arrays;
33
32
  import java.util.Iterator;
34
33
  import java.util.List;
35
34
  import java.util.UUID;
36
35
  import java.util.Queue;
36
+ import java.util.concurrent.ConcurrentHashMap;
37
37
  import java.util.concurrent.ConcurrentLinkedQueue;
38
38
 
39
39
  import static android.os.Build.VERSION_CODES.LOLLIPOP;
@@ -50,10 +50,10 @@ public class Peripheral extends BluetoothGattCallback {
50
50
 
51
51
  private final BluetoothDevice device;
52
52
  private final Map<String, NotifyBufferContainer> bufferedCharacteristics;
53
- protected byte[] advertisingDataBytes = new byte[0];
54
- protected int advertisingRSSI;
55
- private boolean connected = false;
56
- private boolean connecting = false;
53
+ protected volatile byte[] advertisingDataBytes = new byte[0];
54
+ protected volatile int advertisingRSSI;
55
+ private volatile boolean connected = false;
56
+ private volatile boolean connecting = false;
57
57
  private ReactContext reactContext;
58
58
 
59
59
  private BluetoothGatt gatt;
@@ -75,7 +75,7 @@ public class Peripheral extends BluetoothGattCallback {
75
75
 
76
76
  public Peripheral(BluetoothDevice device, int advertisingRSSI, byte[] scanRecord, ReactContext reactContext) {
77
77
  this.device = device;
78
- this.bufferedCharacteristics = new HashMap<String, NotifyBufferContainer>();
78
+ this.bufferedCharacteristics = new ConcurrentHashMap<String, NotifyBufferContainer>();
79
79
  this.advertisingRSSI = advertisingRSSI;
80
80
  this.advertisingDataBytes = scanRecord;
81
81
  this.reactContext = reactContext;
@@ -83,12 +83,14 @@ public class Peripheral extends BluetoothGattCallback {
83
83
 
84
84
  public Peripheral(BluetoothDevice device, ReactContext reactContext) {
85
85
  this.device = device;
86
- this.bufferedCharacteristics = new HashMap<String, NotifyBufferContainer>();
86
+ this.bufferedCharacteristics = new ConcurrentHashMap<String, NotifyBufferContainer>();
87
87
  this.reactContext = reactContext;
88
88
  }
89
89
 
90
90
  private void sendEvent(String eventName, @Nullable WritableMap params) {
91
- reactContext.getJSModule(RCTNativeAppEventEmitter.class).emit(eventName, params);
91
+ synchronized (reactContext) {
92
+ reactContext.getJSModule(RCTNativeAppEventEmitter.class).emit(eventName, params);
93
+ }
92
94
  }
93
95
 
94
96
  private void sendConnectionEvent(BluetoothDevice device, String eventName, int status) {
@@ -101,61 +103,67 @@ public class Peripheral extends BluetoothGattCallback {
101
103
  Log.d(BleManager.LOG_TAG, "Peripheral event (" + eventName + "):" + device.getAddress());
102
104
  }
103
105
 
104
- public void connect(Callback callback, Activity activity) {
105
- if (!connected) {
106
- BluetoothDevice device = getDevice();
107
- this.connectCallback = callback;
108
- this.connecting = true;
109
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
110
- Log.d(BleManager.LOG_TAG, " Is Or Greater than M $mBluetoothDevice");
111
- gatt = device.connectGatt(activity, false, this, BluetoothDevice.TRANSPORT_LE);
112
- } else {
113
- Log.d(BleManager.LOG_TAG, " Less than M");
114
- try {
115
- Log.d(BleManager.LOG_TAG, " Trying TRANPORT LE with reflection");
116
- Method m = device.getClass().getDeclaredMethod("connectGatt", Context.class, Boolean.class,
117
- BluetoothGattCallback.class, Integer.class);
118
- m.setAccessible(true);
119
- Integer transport = device.getClass().getDeclaredField("TRANSPORT_LE").getInt(null);
120
- gatt = (BluetoothGatt) m.invoke(device, activity, false, this, transport);
121
- } catch (Exception e) {
122
- e.printStackTrace();
123
- Log.d(TAG, " Catch to call normal connection");
124
- gatt = device.connectGatt(activity, false, this);
106
+ public void connect(final Callback callback, Activity activity) {
107
+ mainHandler.post(() -> {
108
+ if (!connected) {
109
+ BluetoothDevice device = getDevice();
110
+ this.connectCallback = callback;
111
+ this.connecting = true;
112
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
113
+ Log.d(BleManager.LOG_TAG, " Is Or Greater than M $mBluetoothDevice");
114
+ gatt = device.connectGatt(activity, false, this, BluetoothDevice.TRANSPORT_LE);
115
+ } else {
116
+ Log.d(BleManager.LOG_TAG, " Less than M");
117
+ try {
118
+ Log.d(BleManager.LOG_TAG, " Trying TRANPORT LE with reflection");
119
+ Method m = device.getClass().getDeclaredMethod("connectGatt", Context.class, Boolean.class,
120
+ BluetoothGattCallback.class, Integer.class);
121
+ m.setAccessible(true);
122
+ Integer transport = device.getClass().getDeclaredField("TRANSPORT_LE").getInt(null);
123
+ gatt = (BluetoothGatt) m.invoke(device, activity, false, this, transport);
124
+ } catch (Exception e) {
125
+ e.printStackTrace();
126
+ Log.d(TAG, " Catch to call normal connection");
127
+ gatt = device.connectGatt(activity, false, this);
128
+ }
125
129
  }
126
- }
127
- } else {
128
- if (gatt != null) {
129
- callback.invoke();
130
130
  } else {
131
- callback.invoke("BluetoothGatt is null");
131
+ if (gatt != null) {
132
+ callback.invoke();
133
+ } else {
134
+ callback.invoke("BluetoothGatt is null");
135
+ }
132
136
  }
133
- }
137
+ });
134
138
  }
135
139
  // bt_btif : Register with GATT stack failed.
136
140
 
137
- public void disconnect(boolean force) {
138
- connectCallback = null;
139
- connected = false;
140
- clearBuffers();
141
- commandQueue.clear();
142
- commandQueueBusy = false;
141
+ public void disconnect(final Callback callback, final boolean force) {
142
+ mainHandler.post(() -> {
143
+ connectCallback = null;
144
+ connected = false;
145
+ clearBuffers();
146
+ commandQueue.clear();
147
+ commandQueueBusy = false;
143
148
 
144
- if (gatt != null) {
145
- try {
146
- gatt.disconnect();
147
- if (force) {
148
- gatt.close();
149
- gatt = null;
150
- sendConnectionEvent(device, "BleManagerDisconnectPeripheral", BluetoothGatt.GATT_SUCCESS);
149
+ if (gatt != null) {
150
+ try {
151
+ gatt.disconnect();
152
+ if (force) {
153
+ gatt.close();
154
+ gatt = null;
155
+ sendConnectionEvent(device, "BleManagerDisconnectPeripheral", BluetoothGatt.GATT_SUCCESS);
156
+ }
157
+ Log.d(BleManager.LOG_TAG, "Disconnect");
158
+ } catch (Exception e) {
159
+ sendConnectionEvent(device, "BleManagerDisconnectPeripheral", BluetoothGatt.GATT_FAILURE);
160
+ Log.d(BleManager.LOG_TAG, "Error on disconnect", e);
151
161
  }
152
- Log.d(BleManager.LOG_TAG, "Disconnect");
153
- } catch (Exception e) {
154
- sendConnectionEvent(device, "BleManagerDisconnectPeripheral", BluetoothGatt.GATT_FAILURE);
155
- Log.d(BleManager.LOG_TAG, "Error on disconnect", e);
156
- }
157
- } else
158
- Log.d(BleManager.LOG_TAG, "GATT is null");
162
+ } else
163
+ Log.d(BleManager.LOG_TAG, "GATT is null");
164
+ if (callback != null)
165
+ callback.invoke();
166
+ });
159
167
  }
160
168
 
161
169
  public WritableMap asWritableMap() {
@@ -262,97 +270,102 @@ public class Peripheral extends BluetoothGattCallback {
262
270
  return device;
263
271
  }
264
272
 
265
- public Boolean hasService(UUID uuid) {
266
- if (gatt == null) {
267
- return null;
268
- }
269
- return gatt.getService(uuid) != null;
270
- }
271
-
272
273
  @Override
273
274
  public void onServicesDiscovered(BluetoothGatt gatt, int status) {
274
275
  super.onServicesDiscovered(gatt, status);
275
-
276
- if (retrieveServicesCallback != null) {
277
- WritableMap map = this.asWritableMap(gatt);
278
- retrieveServicesCallback.invoke(null, map);
279
- retrieveServicesCallback = null;
280
- }
276
+ mainHandler.post(() -> {
277
+ if (retrieveServicesCallback != null) {
278
+ WritableMap map = this.asWritableMap(gatt);
279
+ retrieveServicesCallback.invoke(null, map);
280
+ retrieveServicesCallback = null;
281
+ }
282
+ completedCommand();
283
+ });
281
284
  }
282
285
 
283
286
  @Override
284
- public void onConnectionStateChange(BluetoothGatt gatta, int status, int newState) {
287
+ public void onConnectionStateChange(BluetoothGatt gatta, int status, final int newState) {
285
288
 
286
289
  Log.d(BleManager.LOG_TAG, "onConnectionStateChange to " + newState + " on peripheral: " + device.getAddress()
287
290
  + " with status " + status);
288
291
 
289
- gatt = gatta;
292
+ mainHandler.post(() -> {
293
+ gatt = gatta;
290
294
 
291
- if (status != BluetoothGatt.GATT_SUCCESS) {
292
- gatt.close();
293
- // change the state to ensure the connection is teared down properly in the code below
294
- newState = BluetoothProfile.STATE_DISCONNECTED;
295
- }
295
+ if (status != BluetoothGatt.GATT_SUCCESS) {
296
+ gatt.close();
297
+ }
296
298
 
297
- connecting = false;
298
- if (newState == BluetoothProfile.STATE_CONNECTED) {
299
- connected = true;
299
+ connecting = false;
300
+ if (newState == BluetoothProfile.STATE_CONNECTED && status == BluetoothGatt.GATT_SUCCESS) {
301
+ connected = true;
300
302
 
301
- discoverServicesRunnable = new Runnable() {
302
- @Override
303
- public void run() {
304
- try {
305
- gatt.discoverServices();
306
- } catch (NullPointerException e) {
307
- Log.d(BleManager.LOG_TAG, "onConnectionStateChange connected but gatt of Run method was null");
303
+ discoverServicesRunnable = new Runnable() {
304
+ @Override
305
+ public void run() {
306
+ try {
307
+ gatt.discoverServices();
308
+ } catch (NullPointerException e) {
309
+ Log.d(BleManager.LOG_TAG, "onConnectionStateChange connected but gatt of Run method was null");
310
+ }
311
+ discoverServicesRunnable = null;
308
312
  }
309
- discoverServicesRunnable = null;
310
- }
311
- };
313
+ };
312
314
 
313
- mainHandler.post(discoverServicesRunnable);
315
+ mainHandler.post(discoverServicesRunnable);
314
316
 
315
- sendConnectionEvent(device, "BleManagerConnectPeripheral", status);
317
+ sendConnectionEvent(device, "BleManagerConnectPeripheral", status);
316
318
 
317
- if (connectCallback != null) {
318
- Log.d(BleManager.LOG_TAG, "Connected to: " + device.getAddress());
319
- connectCallback.invoke();
320
- connectCallback = null;
321
- }
319
+ if (connectCallback != null) {
320
+ Log.d(BleManager.LOG_TAG, "Connected to: " + device.getAddress());
321
+ connectCallback.invoke();
322
+ connectCallback = null;
323
+ }
322
324
 
323
- } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
325
+ } else if (newState == BluetoothProfile.STATE_DISCONNECTED || status != BluetoothGatt.GATT_SUCCESS) {
324
326
 
325
- if (discoverServicesRunnable != null) {
326
- mainHandler.removeCallbacks(discoverServicesRunnable);
327
- discoverServicesRunnable = null;
328
- }
327
+ if (discoverServicesRunnable != null) {
328
+ mainHandler.removeCallbacks(discoverServicesRunnable);
329
+ discoverServicesRunnable = null;
330
+ }
329
331
 
330
- List<Callback> callbacks = Arrays.asList(writeCallback, retrieveServicesCallback, readRSSICallback,
331
- readCallback, registerNotifyCallback, requestMTUCallback);
332
- for (Callback currentCallback : callbacks) {
333
- if (currentCallback != null) {
334
- try {
335
- currentCallback.invoke("Device disconnected");
336
- } catch (Exception e) {
337
- e.printStackTrace();
338
- } }
339
- }
340
- if (connectCallback != null) {
341
- connectCallback.invoke("Connection error");
332
+ List<Callback> callbacks = Arrays.asList(writeCallback, retrieveServicesCallback, readRSSICallback,
333
+ readCallback, registerNotifyCallback, requestMTUCallback);
334
+ for (Callback currentCallback : callbacks) {
335
+ if (currentCallback != null) {
336
+ try {
337
+ currentCallback.invoke("Device disconnected");
338
+ } catch (Exception e) {
339
+ e.printStackTrace();
340
+ } }
341
+ }
342
+ if (connectCallback != null) {
343
+ connectCallback.invoke("Connection error");
344
+ connectCallback = null;
345
+ }
346
+ writeCallback = null;
347
+ writeQueue.clear();
348
+ readCallback = null;
349
+ retrieveServicesCallback = null;
350
+ readRSSICallback = null;
351
+ registerNotifyCallback = null;
352
+ requestMTUCallback = null;
353
+ commandQueue.clear();
354
+ commandQueueBusy = false;
342
355
  connectCallback = null;
356
+ connected = false;
357
+ clearBuffers();
358
+ commandQueue.clear();
359
+ commandQueueBusy = false;
360
+
361
+ gatt.disconnect();
362
+ gatt.close();
363
+ gatt = null;
364
+ sendConnectionEvent(device, "BleManagerDisconnectPeripheral", BluetoothGatt.GATT_SUCCESS);
365
+
343
366
  }
344
- writeCallback = null;
345
- writeQueue.clear();
346
- readCallback = null;
347
- retrieveServicesCallback = null;
348
- readRSSICallback = null;
349
- registerNotifyCallback = null;
350
- requestMTUCallback = null;
351
- commandQueue.clear();
352
- commandQueueBusy = false;
353
367
 
354
- this.disconnect(true);
355
- }
368
+ });
356
369
 
357
370
  }
358
371
 
@@ -382,7 +395,7 @@ public class Peripheral extends BluetoothGattCallback {
382
395
  if (buffer != null) {
383
396
  buffer.put(dataValue);
384
397
  Log.d(BleManager.LOG_TAG, "onCharacteristicChanged-buffering: " +
385
- buffer.size() + " from peripheral: " + device.getAddress());
398
+ buffer.size() + " from peripheral: " + device.getAddress());
386
399
 
387
400
  if (buffer.isBufferFull()) {
388
401
  Log.d(BleManager.LOG_TAG, "onCharacteristicChanged sending buffered data " + buffer.size());
@@ -412,93 +425,87 @@ public class Peripheral extends BluetoothGattCallback {
412
425
  public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
413
426
  super.onCharacteristicRead(gatt, characteristic, status);
414
427
 
415
- if (status != BluetoothGatt.GATT_SUCCESS) {
416
- if (status == GATT_AUTH_FAIL || status == GATT_INSUFFICIENT_AUTHENTICATION) {
417
- Log.d(BleManager.LOG_TAG, "Read needs bonding");
418
- // *not* doing completedCommand()
419
- return;
428
+ mainHandler.post(() -> {
429
+ if (status != BluetoothGatt.GATT_SUCCESS) {
430
+ if (status == GATT_AUTH_FAIL || status == GATT_INSUFFICIENT_AUTHENTICATION) {
431
+ Log.d(BleManager.LOG_TAG, "Read needs bonding");
432
+ }
433
+ readCallback.invoke("Error reading " + characteristic.getUuid() + " status=" + status, null);
434
+ readCallback = null;
435
+ } else if (readCallback != null) {
436
+ final byte[] dataValue = copyOf(characteristic.getValue());
437
+ readCallback.invoke(null, BleManager.bytesToWritableArray(dataValue));
438
+ readCallback = null;
420
439
  }
421
- sendBackrError(readCallback, "Error reading " + characteristic.getUuid() + " status=" + status);
422
- readCallback = null;
423
- } else if (readCallback != null) {
424
- final byte[] dataValue = copyOf(characteristic.getValue());
425
- final Callback callback = readCallback;
426
- readCallback = null;
427
- mainHandler.post(new Runnable() {
428
- @Override
429
- public void run() {
430
- callback.invoke(null, BleManager.bytesToWritableArray(dataValue));
431
- }
432
- });
433
- }
440
+ completedCommand();
441
+ });
434
442
 
435
- completedCommand();
436
443
  }
437
444
 
438
445
  @Override
439
446
  public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
440
447
  super.onCharacteristicWrite(gatt, characteristic, status);
441
448
 
442
- if (writeQueue.size() > 0) {
443
- byte[] data = writeQueue.get(0);
444
- writeQueue.remove(0);
445
- doWrite(characteristic, data, writeCallback);
446
- } else if (status != BluetoothGatt.GATT_SUCCESS) {
447
- if (status == GATT_AUTH_FAIL || status == GATT_INSUFFICIENT_AUTHENTICATION) {
448
- Log.d(BleManager.LOG_TAG, "Write needs bonding");
449
- // *not* doing completedCommand()
450
- return;
449
+ mainHandler.post(() -> {
450
+ if (writeQueue.size() > 0) {
451
+ byte[] data = writeQueue.get(0);
452
+ writeQueue.remove(0);
453
+ doWrite(characteristic, data, writeCallback);
454
+ } else if (status != BluetoothGatt.GATT_SUCCESS) {
455
+ if (status == GATT_AUTH_FAIL || status == GATT_INSUFFICIENT_AUTHENTICATION) {
456
+ Log.d(BleManager.LOG_TAG, "Write needs bonding");
457
+ // *not* doing completedCommand()
458
+ return;
459
+ }
460
+ writeCallback.invoke( "Error writing " + characteristic.getUuid() + " status=" + status, null);
461
+ writeCallback = null;
462
+ } else if (writeCallback != null) {
463
+ writeCallback.invoke();
464
+ writeCallback = null;
451
465
  }
452
- sendBackrError(writeCallback, "Error writing " + characteristic.getUuid() + " status=" + status);
453
- writeCallback = null;
454
- } else if (writeCallback != null) {
455
- final Callback callback = writeCallback;
456
- mainHandler.post(new Runnable() {
457
- @Override
458
- public void run() {
459
- callback.invoke();
460
- }
461
- });
462
- writeCallback = null;
463
- }
464
-
465
- completedCommand();
466
+ completedCommand();
467
+ });
466
468
  }
467
469
 
468
470
  @Override
469
471
  public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
470
- if (registerNotifyCallback != null) {
471
- if (status == BluetoothGatt.GATT_SUCCESS) {
472
- registerNotifyCallback.invoke();
473
- Log.d(BleManager.LOG_TAG, "onDescriptorWrite success");
472
+ mainHandler.post(() -> {
473
+ if (registerNotifyCallback != null) {
474
+ if (status == BluetoothGatt.GATT_SUCCESS) {
475
+ registerNotifyCallback.invoke();
476
+ Log.d(BleManager.LOG_TAG, "onDescriptorWrite success");
477
+ } else {
478
+ registerNotifyCallback.invoke("Error writing descriptor status=" + status, null);
479
+ Log.e(BleManager.LOG_TAG, "Error writing descriptor status=" + status);
480
+ }
481
+
482
+ registerNotifyCallback = null;
474
483
  } else {
475
- registerNotifyCallback.invoke("Error writing descriptor status=" + status, null);
476
- Log.e(BleManager.LOG_TAG, "Error writing descriptor status=" + status);
484
+ Log.e(BleManager.LOG_TAG, "onDescriptorWrite with no callback");
477
485
  }
478
486
 
479
- registerNotifyCallback = null;
480
- } else {
481
- Log.e(BleManager.LOG_TAG, "onDescriptorWrite with no callback");
482
- }
483
-
484
- completedCommand();
487
+ completedCommand();
488
+ });
485
489
  }
486
490
 
487
491
  @Override
488
492
  public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
489
493
  super.onReadRemoteRssi(gatt, rssi, status);
490
- if (readRSSICallback != null) {
491
- if (status == BluetoothGatt.GATT_SUCCESS) {
492
- updateRssi(rssi);
493
- readRSSICallback.invoke(null, rssi);
494
- } else {
495
- readRSSICallback.invoke("Error reading RSSI status=" + status, null);
496
- }
497
494
 
498
- readRSSICallback = null;
499
- }
495
+ mainHandler.post(() -> {
496
+ if (readRSSICallback != null) {
497
+ if (status == BluetoothGatt.GATT_SUCCESS) {
498
+ updateRssi(rssi);
499
+ readRSSICallback.invoke(null, rssi);
500
+ } else {
501
+ readRSSICallback.invoke("Error reading RSSI status=" + status, null);
502
+ }
503
+
504
+ readRSSICallback = null;
505
+ }
500
506
 
501
- completedCommand();
507
+ completedCommand();
508
+ });
502
509
  }
503
510
 
504
511
  private String bufferedCharacteristicsKey(String serviceUUID, String characteristicUUID) {
@@ -513,6 +520,7 @@ public class Peripheral extends BluetoothGattCallback {
513
520
  private void setNotify(UUID serviceUUID, UUID characteristicUUID, final Boolean notify, Callback callback) {
514
521
  if (! isConnected() || gatt == null) {
515
522
  callback.invoke("Device is not connected", null);
523
+ completedCommand();
516
524
  return;
517
525
  }
518
526
 
@@ -520,18 +528,21 @@ public class Peripheral extends BluetoothGattCallback {
520
528
  final BluetoothGattCharacteristic characteristic = findNotifyCharacteristic(service, characteristicUUID);
521
529
 
522
530
  if (characteristic == null) {
523
- callback.invoke("Characteristic " + characteristicUUID + " not found");
531
+ callback.invoke("Characteristic " + characteristicUUID + " not found");
532
+ completedCommand();
524
533
  return;
525
534
  }
526
535
 
527
536
  if (! gatt.setCharacteristicNotification(characteristic, notify)) {
528
537
  callback.invoke("Failed to register notification for " + characteristicUUID);
538
+ completedCommand();
529
539
  return;
530
540
  }
531
541
 
532
542
  final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUIDHelper.uuidFromString(CHARACTERISTIC_NOTIFICATION_CONFIG));
533
543
  if (descriptor == null) {
534
544
  callback.invoke("Set notification failed for " + characteristicUUID);
545
+ completedCommand();
535
546
  return;
536
547
  }
537
548
 
@@ -547,63 +558,56 @@ public class Peripheral extends BluetoothGattCallback {
547
558
  String msg = "Characteristic " + characteristicUUID + " does not have NOTIFY or INDICATE property set";
548
559
  Log.d(BleManager.LOG_TAG, msg);
549
560
  callback.invoke(msg);
561
+ completedCommand();
550
562
  return;
551
563
  }
552
564
  final byte[] finalValue = notify ? value : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
553
565
  final Callback finalCallback = callback;
554
566
 
555
- boolean result = commandQueue.add(new Runnable() {
556
- @Override
557
- public void run() {
558
- if (! isConnected()) {
559
- completedCommand();
560
- return;
561
- }
562
-
563
- boolean result = false;
564
- try {
565
- result = gatt.setCharacteristicNotification(characteristic, notify);
566
- // Then write to descriptor
567
- descriptor.setValue(finalValue);
568
- registerNotifyCallback = finalCallback;
569
- result = gatt.writeDescriptor(descriptor);
570
- } catch(Exception e) {
571
- Log.d(BleManager.LOG_TAG, "Exception in setNotify", e);
572
- }
573
-
574
- if (! result) {
575
- sendBackrError(registerNotifyCallback, "writeDescriptor failed for descriptor: " + descriptor.getUuid());
576
- registerNotifyCallback = null;
577
- completedCommand();
578
- }
579
- }
580
- });
567
+ boolean result = false;
568
+ try {
569
+ result = gatt.setCharacteristicNotification(characteristic, notify);
570
+ // Then write to descriptor
571
+ descriptor.setValue(finalValue);
572
+ registerNotifyCallback = finalCallback;
573
+ result &= gatt.writeDescriptor(descriptor);
574
+ } catch(Exception e) {
575
+ Log.d(BleManager.LOG_TAG, "Exception in setNotify", e);
576
+ }
581
577
 
582
- if (result) {
583
- nextCommand();
584
- } else {
585
- Log.e(BleManager.LOG_TAG, "Could not enqueue setNotify command");
578
+ if (! result) {
579
+ callback.invoke( "writeDescriptor failed for descriptor: " + descriptor.getUuid(), null);
580
+ registerNotifyCallback = null;
581
+ completedCommand();
586
582
  }
587
583
  }
588
584
 
589
585
  public void registerNotify(UUID serviceUUID, UUID characteristicUUID, Integer buffer, Callback callback) {
590
- Log.d(BleManager.LOG_TAG, "registerNotify");
591
- if (buffer > 1) {
592
- Log.d(BleManager.LOG_TAG, "registerNotify using buffer");
593
- String bufferKey = this.bufferedCharacteristicsKey(serviceUUID.toString(), characteristicUUID.toString());
594
- this.bufferedCharacteristics.put(bufferKey, new NotifyBufferContainer(buffer));
586
+ if (!enqueue(() -> {
587
+ Log.d(BleManager.LOG_TAG, "registerNotify");
588
+ if (buffer > 1) {
589
+ Log.d(BleManager.LOG_TAG, "registerNotify using buffer");
590
+ String bufferKey = this.bufferedCharacteristicsKey(serviceUUID.toString(), characteristicUUID.toString());
591
+ this.bufferedCharacteristics.put(bufferKey, new NotifyBufferContainer(buffer));
592
+ }
593
+ this.setNotify(serviceUUID, characteristicUUID, true, callback);
594
+ })) {
595
+ Log.e(BleManager.LOG_TAG, "Could not enqueue setNotify command to register notify");
595
596
  }
596
- this.setNotify(serviceUUID, characteristicUUID, true, callback);
597
597
  }
598
598
 
599
599
  public void removeNotify(UUID serviceUUID, UUID characteristicUUID, Callback callback) {
600
- Log.d(BleManager.LOG_TAG, "removeNotify");
601
- String bufferKey = this.bufferedCharacteristicsKey(serviceUUID.toString(), characteristicUUID.toString());
602
- if (this.bufferedCharacteristics.containsKey(bufferKey)) {
603
- NotifyBufferContainer buffer = this.bufferedCharacteristics.get(bufferKey);
604
- this.bufferedCharacteristics.remove(bufferKey);
600
+ if (!enqueue(() -> {
601
+ Log.d(BleManager.LOG_TAG, "removeNotify");
602
+ String bufferKey = this.bufferedCharacteristicsKey(serviceUUID.toString(), characteristicUUID.toString());
603
+ if (this.bufferedCharacteristics.containsKey(bufferKey)) {
604
+ NotifyBufferContainer buffer = this.bufferedCharacteristics.get(bufferKey);
605
+ this.bufferedCharacteristics.remove(bufferKey);
606
+ }
607
+ this.setNotify(serviceUUID, characteristicUUID, false, callback);
608
+ })) {
609
+ Log.e(BleManager.LOG_TAG, "Could not enqueue setNotify command to remove notify");
605
610
  }
606
- this.setNotify(serviceUUID, characteristicUUID, false, callback);
607
611
  }
608
612
 
609
613
  // Some devices reuse UUIDs across characteristics, so we can't use
@@ -612,7 +616,7 @@ public class Peripheral extends BluetoothGattCallback {
612
616
  // until we find the best match
613
617
  // This function prefers Notify over Indicate
614
618
  private BluetoothGattCharacteristic findNotifyCharacteristic(BluetoothGattService service,
615
- UUID characteristicUUID) {
619
+ UUID characteristicUUID) {
616
620
 
617
621
  try {
618
622
  // Check for Notify first
@@ -641,48 +645,31 @@ public class Peripheral extends BluetoothGattCallback {
641
645
  }
642
646
  }
643
647
 
644
- public void read(UUID serviceUUID, UUID characteristicUUID, Callback callback) {
645
-
646
- if (!isConnected() || gatt == null) {
647
- callback.invoke("Device is not connected", null);
648
- return;
649
- }
650
-
651
- BluetoothGattService service = gatt.getService(serviceUUID);
652
- final BluetoothGattCharacteristic characteristic = findReadableCharacteristic(service, characteristicUUID);
648
+ public void read(UUID serviceUUID, UUID characteristicUUID, final Callback callback) {
649
+ enqueue(() -> {
650
+ if (!isConnected() || gatt == null) {
651
+ callback.invoke("Device is not connected", null);
652
+ completedCommand();
653
+ return;
654
+ }
653
655
 
654
- if (characteristic == null) {
655
- callback.invoke("Characteristic " + characteristicUUID + " not found.", null);
656
- return;
657
- }
656
+ BluetoothGattService service = gatt.getService(serviceUUID);
657
+ final BluetoothGattCharacteristic characteristic = findReadableCharacteristic(service, characteristicUUID);
658
658
 
659
- final Callback reactcb = callback;
660
- boolean result = commandQueue.add(new Runnable() {
661
- @Override
662
- public void run() {
663
- readCallback = reactcb;
664
- if (! gatt.readCharacteristic(characteristic)) {
665
- readCallback = null;
666
- sendBackrError(reactcb, "Read failed");
667
- completedCommand();
668
- }
669
- }
670
- });
659
+ if (characteristic == null) {
660
+ callback.invoke("Characteristic " + characteristicUUID + " not found.", null);
661
+ completedCommand();
662
+ return;
663
+ }
671
664
 
672
- if (result) {
673
- nextCommand();
674
- } else {
675
- Log.d(BleManager.LOG_TAG, "Could not queue read characteristic command");
676
- }
677
- }
665
+ readCallback = callback;
666
+ if (!gatt.readCharacteristic(characteristic)) {
667
+ callback.invoke("Read failed", null);
668
+ readCallback = null;
669
+ completedCommand();
670
+ }
678
671
 
679
- private void sendBackrError(final Callback callback, final String message) {
680
- new Handler(Looper.getMainLooper()).post(new Runnable() {
681
- @Override
682
- public void run() {
683
- callback.invoke(message, null);
684
- }
685
- });
672
+ });
686
673
  }
687
674
 
688
675
  private byte[] copyOf(byte[] source) {
@@ -693,6 +680,16 @@ public class Peripheral extends BluetoothGattCallback {
693
680
  return copy;
694
681
  }
695
682
 
683
+ private boolean enqueue(Runnable command) {
684
+ final boolean result = commandQueue.add(command);
685
+ if (result) {
686
+ nextCommand();
687
+ } else {
688
+ Log.d(BleManager.LOG_TAG, "could not enqueue command");
689
+ }
690
+ return result;
691
+ }
692
+
696
693
  private void completedCommand() {
697
694
  commandQueue.poll();
698
695
  commandQueueBusy = false;
@@ -723,78 +720,76 @@ public class Peripheral extends BluetoothGattCallback {
723
720
  // Execute the next command in the queue
724
721
  commandQueueBusy = true;
725
722
  mainHandler.post(new Runnable() {
726
- @Override
727
- public void run() {
728
- try {
729
- nextCommand.run();
730
- } catch (Exception ex) {
731
- Log.d(BleManager.LOG_TAG, "Error, command exception");
732
- completedCommand();
733
- }
723
+ @Override
724
+ public void run() {
725
+ try {
726
+ nextCommand.run();
727
+ } catch (Exception ex) {
728
+ Log.d(BleManager.LOG_TAG, "Error, command exception");
729
+ completedCommand();
734
730
  }
735
- });
731
+ }
732
+ });
736
733
  }
737
734
  }
738
735
 
739
736
  public void readRSSI(final Callback callback) {
740
- if (!isConnected()) {
741
- callback.invoke("Device is not connected", null);
742
- return;
743
- }
744
- if (gatt == null) {
745
- callback.invoke("BluetoothGatt is null", null);
746
- return;
747
- }
748
-
749
- final boolean result = commandQueue.add(new Runnable() {
750
- @Override
751
- public void run() {
752
- if (isConnected()) {
737
+ if (!enqueue(() -> {
738
+ if (!isConnected()) {
739
+ callback.invoke("Device is not connected", null);
740
+ completedCommand();
741
+ return;
742
+ } else if (gatt == null) {
743
+ callback.invoke("BluetoothGatt is null", null);
744
+ completedCommand();
745
+ return;
746
+ } else {
753
747
  readRSSICallback = callback;
754
- if (! gatt.readRemoteRssi()) {
748
+ if (!gatt.readRemoteRssi()) {
749
+ callback.invoke("Read RSSI failed", null);
755
750
  readRSSICallback = null;
756
- sendBackrError(callback, "Read RSSI failed");
757
- completedCommand();
751
+ completedCommand();
758
752
  }
759
- } else {
760
- completedCommand();
761
- }
762
753
  }
763
- });
764
-
765
- if (result) {
766
- nextCommand();
767
- } else {
768
- Log.d(BleManager.LOG_TAG, "Could not queue readRemoteRssi command");
754
+ })) {
755
+ Log.d(BleManager.LOG_TAG, "Could not queue readRemoteRssi command");
769
756
  }
770
757
  }
771
758
 
772
759
  public void refreshCache(Callback callback) {
773
- try {
774
- Method localMethod = gatt.getClass().getMethod("refresh", new Class[0]);
775
- if (localMethod != null) {
776
- boolean res = ((Boolean) localMethod.invoke(gatt, new Object[0])).booleanValue();
777
- callback.invoke(null, res);
778
- } else {
779
- callback.invoke("Could not refresh cache for device.");
760
+ enqueue(() -> {
761
+ try {
762
+ Method localMethod = gatt.getClass().getMethod("refresh", new Class[0]);
763
+ if (localMethod != null) {
764
+ boolean res = ((Boolean) localMethod.invoke(gatt, new Object[0])).booleanValue();
765
+ callback.invoke(null, res);
766
+ } else {
767
+ callback.invoke("Could not refresh cache for device.");
768
+ }
769
+ } catch (Exception localException) {
770
+ Log.e(TAG, "An exception occured while refreshing device");
771
+ callback.invoke(localException.getMessage());
772
+ } finally {
773
+ completedCommand();
780
774
  }
781
- } catch (Exception localException) {
782
- Log.e(TAG, "An exception occured while refreshing device");
783
- callback.invoke(localException.getMessage());
784
- }
775
+ });
785
776
  }
786
777
 
787
778
  public void retrieveServices(Callback callback) {
788
- if (!isConnected()) {
789
- callback.invoke("Device is not connected", null);
790
- return;
791
- }
792
- if (gatt == null) {
793
- callback.invoke("BluetoothGatt is null", null);
794
- return;
795
- }
796
- this.retrieveServicesCallback = callback;
797
- gatt.discoverServices();
779
+ enqueue(() -> {
780
+ if (!isConnected()) {
781
+ callback.invoke("Device is not connected", null);
782
+ completedCommand();
783
+ return;
784
+ } else if (gatt == null) {
785
+ callback.invoke("BluetoothGatt is null", null);
786
+ completedCommand();
787
+ return;
788
+ } else {
789
+ this.retrieveServicesCallback = callback;
790
+ gatt.discoverServices();
791
+ }
792
+ });
798
793
  }
799
794
 
800
795
  // Some peripherals re-use UUIDs for multiple characteristics so we need to
@@ -802,7 +797,7 @@ public class Peripheral extends BluetoothGattCallback {
802
797
  // and UUID of all characteristics instead of using
803
798
  // service.getCharacteristic(characteristicUUID)
804
799
  private BluetoothGattCharacteristic findReadableCharacteristic(BluetoothGattService service,
805
- UUID characteristicUUID) {
800
+ UUID characteristicUUID) {
806
801
 
807
802
  if (service != null) {
808
803
  int read = BluetoothGattCharacteristic.PROPERTY_READ;
@@ -825,157 +820,172 @@ public class Peripheral extends BluetoothGattCallback {
825
820
 
826
821
  public boolean doWrite(final BluetoothGattCharacteristic characteristic, byte[] data, final Callback callback) {
827
822
  final byte[] copyOfData = copyOf(data);
828
- boolean result = commandQueue.add(new Runnable() {
829
- @Override
830
- public void run() {
831
- characteristic.setValue(copyOfData);
832
- if (characteristic.getWriteType() == BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
833
- writeCallback = callback;
834
- else
835
- writeCallback = null;
836
- if (!gatt.writeCharacteristic(characteristic)) {
837
- sendBackrError(writeCallback, "Write failed");
823
+ return enqueue(new Runnable() {
824
+ @Override
825
+ public void run() {
826
+ characteristic.setValue(copyOfData);
827
+ if (characteristic.getWriteType() == BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
828
+ writeCallback = callback;
829
+ else
830
+ writeCallback = null;
831
+ if (!gatt.writeCharacteristic(characteristic)) {
832
+ // write without response, caller will handle the callback
833
+ if (writeCallback != null) {
834
+ writeCallback.invoke("Write failed", writeCallback);
838
835
  writeCallback = null;
839
- completedCommand();
840
836
  }
837
+ completedCommand();
841
838
  }
842
- });
843
-
844
- if (result) {
845
- nextCommand();
846
- } else {
847
- Log.d(BleManager.LOG_TAG, "Could not queue write characteristic command");
848
- }
849
-
850
- return result;
839
+ }
840
+ });
851
841
  }
852
842
 
853
843
  public void write(UUID serviceUUID, UUID characteristicUUID, byte[] data, Integer maxByteSize, Integer queueSleepTime, Callback callback, int writeType) {
854
- if (!isConnected() || gatt == null) {
855
- callback.invoke("Device is not connected", null);
856
- return;
857
- }
844
+ enqueue(() -> {
845
+ if (!isConnected() || gatt == null) {
846
+ callback.invoke("Device is not connected", null);
847
+ completedCommand();
848
+ return;
849
+ }
858
850
 
859
- BluetoothGattService service = gatt.getService(serviceUUID);
860
- BluetoothGattCharacteristic characteristic = findWritableCharacteristic(service, characteristicUUID, writeType);
851
+ BluetoothGattService service = gatt.getService(serviceUUID);
852
+ BluetoothGattCharacteristic characteristic = findWritableCharacteristic(service, characteristicUUID, writeType);
861
853
 
862
- if (characteristic == null) {
863
- callback.invoke("Characteristic " + characteristicUUID + " not found.");
864
- return;
865
- }
854
+ if (characteristic == null) {
855
+ callback.invoke("Characteristic " + characteristicUUID + " not found.");
856
+ completedCommand();
857
+ return;
858
+ }
866
859
 
867
- characteristic.setWriteType(writeType);
860
+ characteristic.setWriteType(writeType);
868
861
 
869
- if (data.length <= maxByteSize) {
870
- if (! doWrite(characteristic, data, callback)) {
871
- callback.invoke("Write failed");
872
- writeCallback = null;
862
+ if (data.length <= maxByteSize) {
863
+ if (! doWrite(characteristic, data, callback)) {
864
+ callback.invoke("Write failed");
865
+ } else {
866
+ if (BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE == writeType) {
867
+ callback.invoke();
868
+ }
869
+ }
873
870
  } else {
874
- if (BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE == writeType) {
875
- callback.invoke();
871
+ int dataLength = data.length;
872
+ int count = 0;
873
+ byte[] firstMessage = null;
874
+ List<byte[]> splittedMessage = new ArrayList<>();
875
+
876
+ while (count < dataLength && (dataLength - count > maxByteSize)) {
877
+ if (count == 0) {
878
+ firstMessage = Arrays.copyOfRange(data, count, count + maxByteSize);
879
+ } else {
880
+ byte[] splitMessage = Arrays.copyOfRange(data, count, count + maxByteSize);
881
+ splittedMessage.add(splitMessage);
882
+ }
883
+ count += maxByteSize;
876
884
  }
877
- }
878
- } else {
879
- int dataLength = data.length;
880
- int count = 0;
881
- byte[] firstMessage = null;
882
- List<byte[]> splittedMessage = new ArrayList<>();
883
-
884
- while (count < dataLength && (dataLength - count > maxByteSize)) {
885
- if (count == 0) {
886
- firstMessage = Arrays.copyOfRange(data, count, count + maxByteSize);
887
- } else {
888
- byte[] splitMessage = Arrays.copyOfRange(data, count, count + maxByteSize);
885
+ if (count < dataLength) {
886
+ // Other bytes in queue
887
+ byte[] splitMessage = Arrays.copyOfRange(data, count, data.length);
889
888
  splittedMessage.add(splitMessage);
890
889
  }
891
- count += maxByteSize;
892
- }
893
- if (count < dataLength) {
894
- // Other bytes in queue
895
- byte[] splitMessage = Arrays.copyOfRange(data, count, data.length);
896
- splittedMessage.add(splitMessage);
897
- }
898
890
 
899
- if (BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT == writeType) {
900
- writeQueue.addAll(splittedMessage);
901
- if (! doWrite(characteristic, firstMessage, callback)) {
902
- writeQueue.clear();
903
- writeCallback = null;
904
- callback.invoke("Write failed");
905
- }
906
- } else {
907
- try {
908
- boolean writeError = false;
891
+ if (BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT == writeType) {
892
+ writeQueue.addAll(splittedMessage);
909
893
  if (! doWrite(characteristic, firstMessage, callback)) {
910
- writeError = true;
894
+ writeQueue.clear();
911
895
  callback.invoke("Write failed");
912
896
  }
913
- if (! writeError) {
914
- Thread.sleep(queueSleepTime);
915
- for (byte[] message : splittedMessage) {
916
- if (! doWrite(characteristic, message, callback)) {
917
- writeError = true;
918
- callback.invoke("Write failed");
919
- break;
920
- }
921
- Thread.sleep(queueSleepTime);
897
+ } else {
898
+ try {
899
+ boolean writeError = false;
900
+ if (! doWrite(characteristic, firstMessage, callback)) {
901
+ writeError = true;
902
+ callback.invoke("Write failed");
922
903
  }
923
904
  if (! writeError) {
924
- callback.invoke();
905
+ Thread.sleep(queueSleepTime);
906
+ for (byte[] message : splittedMessage) {
907
+ if (! doWrite(characteristic, message, callback)) {
908
+ writeError = true;
909
+ callback.invoke("Write failed");
910
+ break;
911
+ }
912
+ Thread.sleep(queueSleepTime);
913
+ }
914
+ if (! writeError) {
915
+ callback.invoke();
916
+ }
925
917
  }
918
+ } catch (InterruptedException e) {
919
+ callback.invoke("Error during writing");
926
920
  }
927
- } catch (InterruptedException e) {
928
- callback.invoke("Error during writing");
929
921
  }
930
922
  }
931
- }
923
+
924
+ completedCommand();
925
+ });
932
926
  }
933
927
 
934
928
  public void requestConnectionPriority(int connectionPriority, Callback callback) {
935
- if (gatt == null) {
936
- callback.invoke("BluetoothGatt is null", null);
937
- return;
938
- }
929
+ enqueue(() -> {
930
+ if (gatt != null) {
931
+ if (Build.VERSION.SDK_INT >= LOLLIPOP) {
932
+ boolean status = gatt.requestConnectionPriority(connectionPriority);
933
+ callback.invoke(null, status);
934
+ } else {
935
+ callback.invoke("Requesting connection priority requires at least API level 21", null);
936
+ }
937
+ } else {
938
+ callback.invoke("BluetoothGatt is null", null);
939
+ }
939
940
 
940
- if (Build.VERSION.SDK_INT >= LOLLIPOP) {
941
- boolean status = gatt.requestConnectionPriority(connectionPriority);
942
- callback.invoke(null, status);
943
- } else {
944
- callback.invoke("Requesting connection priority requires at least API level 21", null);
945
- }
941
+ completedCommand();
942
+ });
946
943
  }
947
944
 
948
945
  public void requestMTU(int mtu, Callback callback) {
949
- if (!isConnected()) {
950
- callback.invoke("Device is not connected", null);
951
- return;
952
- }
946
+ enqueue(() -> {
947
+ if (!isConnected()) {
948
+ callback.invoke("Device is not connected", null);
949
+ completedCommand();
950
+ return;
951
+ }
953
952
 
954
- if (gatt == null) {
955
- callback.invoke("BluetoothGatt is null", null);
956
- return;
957
- }
953
+ if (gatt == null) {
954
+ callback.invoke("BluetoothGatt is null", null);
955
+ completedCommand();
956
+ return;
957
+ }
958
958
 
959
- if (Build.VERSION.SDK_INT >= LOLLIPOP) {
960
- requestMTUCallback = callback;
961
- gatt.requestMtu(mtu);
962
- } else {
963
- callback.invoke("Requesting MTU requires at least API level 21", null);
964
- }
959
+ if (Build.VERSION.SDK_INT >= LOLLIPOP) {
960
+ requestMTUCallback = callback;
961
+ if (!gatt.requestMtu(mtu)) {
962
+ requestMTUCallback.invoke("Request MTU failed", null);
963
+ requestMTUCallback = null;
964
+ completedCommand();
965
+ }
966
+ } else {
967
+ callback.invoke("Requesting MTU requires at least API level 21", null);
968
+ completedCommand();
969
+ }
970
+ });
965
971
  }
966
972
 
967
973
  @Override
968
974
  public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
969
975
  super.onMtuChanged(gatt, mtu, status);
970
- if (requestMTUCallback != null) {
971
- if (status == BluetoothGatt.GATT_SUCCESS) {
972
- requestMTUCallback.invoke(null, mtu);
973
- } else {
974
- requestMTUCallback.invoke("Error requesting MTU status = " + status, null);
976
+ mainHandler.post(() -> {
977
+ if (requestMTUCallback != null) {
978
+ if (status == BluetoothGatt.GATT_SUCCESS) {
979
+ requestMTUCallback.invoke(null, mtu);
980
+ } else {
981
+ requestMTUCallback.invoke("Error requesting MTU status = " + status, null);
982
+ }
983
+
984
+ requestMTUCallback = null;
975
985
  }
976
986
 
977
- requestMTUCallback = null;
978
- }
987
+ completedCommand();
988
+ });
979
989
  }
980
990
 
981
991
  // Some peripherals re-use UUIDs for multiple characteristics so we need to
@@ -983,7 +993,7 @@ public class Peripheral extends BluetoothGattCallback {
983
993
  // and UUID of all characteristics instead of using
984
994
  // service.getCharacteristic(characteristicUUID)
985
995
  private BluetoothGattCharacteristic findWritableCharacteristic(BluetoothGattService service,
986
- UUID characteristicUUID, int writeType) {
996
+ UUID characteristicUUID, int writeType) {
987
997
  try {
988
998
  // get write property
989
999
  int writeProperty = BluetoothGattCharacteristic.PROPERTY_WRITE;
package/ios/BleManager.m CHANGED
@@ -378,7 +378,7 @@ RCT_EXPORT_METHOD(stopScan:(nonnull RCTResponseSenderBlock)callback)
378
378
  }
379
379
  [manager stopScan];
380
380
  if (hasListeners) {
381
- [self sendEventWithName:@"BleManagerStopScan" body:@{}];
381
+ [self sendEventWithName:@"BleManagerStopScan" body:@{@"status": @0}];
382
382
  }
383
383
  callback(@[[NSNull null]]);
384
384
  }
@@ -390,7 +390,7 @@ RCT_EXPORT_METHOD(stopScan:(nonnull RCTResponseSenderBlock)callback)
390
390
  [manager stopScan];
391
391
  if (hasListeners) {
392
392
  if (self.bridge) {
393
- [self sendEventWithName:@"BleManagerStopScan" body:@{}];
393
+ [self sendEventWithName:@"BleManagerStopScan" body:@{@"status": @10}];
394
394
  }
395
395
  }
396
396
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-ble-manager",
3
- "version": "8.4.4",
3
+ "version": "8.6.0",
4
4
  "description": "A BLE module for react native.",
5
5
  "main": "BleManager",
6
6
  "types": "./index.d.ts",