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 +2 -2
- package/android/src/main/java/it/innove/BleManager.java +3 -3
- package/android/src/main/java/it/innove/LegacyScanManager.java +1 -0
- package/android/src/main/java/it/innove/LollipopScanManager.java +3 -1
- package/android/src/main/java/it/innove/Peripheral.java +448 -438
- package/ios/BleManager.m +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -691,12 +691,12 @@ The scanning for peripherals is ended.
|
|
|
691
691
|
|
|
692
692
|
**Arguments**
|
|
693
693
|
|
|
694
|
-
- `
|
|
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
|
}
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
e
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
|
|
292
|
+
mainHandler.post(() -> {
|
|
293
|
+
gatt = gatta;
|
|
290
294
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
newState = BluetoothProfile.STATE_DISCONNECTED;
|
|
295
|
-
}
|
|
295
|
+
if (status != BluetoothGatt.GATT_SUCCESS) {
|
|
296
|
+
gatt.close();
|
|
297
|
+
}
|
|
296
298
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
299
|
+
connecting = false;
|
|
300
|
+
if (newState == BluetoothProfile.STATE_CONNECTED && status == BluetoothGatt.GATT_SUCCESS) {
|
|
301
|
+
connected = true;
|
|
300
302
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
-
|
|
310
|
-
}
|
|
311
|
-
};
|
|
313
|
+
};
|
|
312
314
|
|
|
313
|
-
|
|
315
|
+
mainHandler.post(discoverServicesRunnable);
|
|
314
316
|
|
|
315
|
-
|
|
317
|
+
sendConnectionEvent(device, "BleManagerConnectPeripheral", status);
|
|
316
318
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
-
|
|
325
|
+
} else if (newState == BluetoothProfile.STATE_DISCONNECTED || status != BluetoothGatt.GATT_SUCCESS) {
|
|
324
326
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
if (discoverServicesRunnable != null) {
|
|
328
|
+
mainHandler.removeCallbacks(discoverServicesRunnable);
|
|
329
|
+
discoverServicesRunnable = null;
|
|
330
|
+
}
|
|
329
331
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
416
|
-
if (status
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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
|
-
|
|
422
|
-
|
|
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
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (status
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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
|
-
|
|
453
|
-
|
|
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
|
-
|
|
471
|
-
if (
|
|
472
|
-
|
|
473
|
-
|
|
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
|
-
|
|
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
|
-
|
|
480
|
-
}
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
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
|
-
|
|
584
|
-
|
|
585
|
-
|
|
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
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
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
|
-
|
|
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
|
-
|
|
647
|
-
|
|
648
|
-
|
|
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
|
-
|
|
655
|
-
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
656
|
+
BluetoothGattService service = gatt.getService(serviceUUID);
|
|
657
|
+
final BluetoothGattCharacteristic characteristic = findReadableCharacteristic(service, characteristicUUID);
|
|
658
658
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
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
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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
|
-
|
|
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
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
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 (!
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
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 (!
|
|
748
|
+
if (!gatt.readRemoteRssi()) {
|
|
749
|
+
callback.invoke("Read RSSI failed", null);
|
|
755
750
|
readRSSICallback = null;
|
|
756
|
-
|
|
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
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
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
|
-
|
|
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
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
844
|
+
enqueue(() -> {
|
|
845
|
+
if (!isConnected() || gatt == null) {
|
|
846
|
+
callback.invoke("Device is not connected", null);
|
|
847
|
+
completedCommand();
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
858
850
|
|
|
859
|
-
|
|
860
|
-
|
|
851
|
+
BluetoothGattService service = gatt.getService(serviceUUID);
|
|
852
|
+
BluetoothGattCharacteristic characteristic = findWritableCharacteristic(service, characteristicUUID, writeType);
|
|
861
853
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
854
|
+
if (characteristic == null) {
|
|
855
|
+
callback.invoke("Characteristic " + characteristicUUID + " not found.");
|
|
856
|
+
completedCommand();
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
866
859
|
|
|
867
|
-
|
|
860
|
+
characteristic.setWriteType(writeType);
|
|
868
861
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
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
|
-
|
|
875
|
-
|
|
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
|
-
|
|
879
|
-
|
|
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
|
-
|
|
900
|
-
|
|
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
|
-
|
|
894
|
+
writeQueue.clear();
|
|
911
895
|
callback.invoke("Write failed");
|
|
912
896
|
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
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
|
-
|
|
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
|
-
|
|
936
|
-
|
|
937
|
-
|
|
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
|
-
|
|
941
|
-
|
|
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
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
946
|
+
enqueue(() -> {
|
|
947
|
+
if (!isConnected()) {
|
|
948
|
+
callback.invoke("Device is not connected", null);
|
|
949
|
+
completedCommand();
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
953
952
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
953
|
+
if (gatt == null) {
|
|
954
|
+
callback.invoke("BluetoothGatt is null", null);
|
|
955
|
+
completedCommand();
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
958
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
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
|
-
|
|
971
|
-
if (
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|