@iotize/device-com-ble.cordova 3.6.0 → 3.6.3

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.
Files changed (45) hide show
  1. package/bundles/iotize-device-com-ble.cordova.umd.js +19 -0
  2. package/bundles/iotize-device-com-ble.cordova.umd.js.map +1 -1
  3. package/bundles/iotize-device-com-ble.cordova.umd.min.js +1 -1
  4. package/bundles/iotize-device-com-ble.cordova.umd.min.js.map +1 -1
  5. package/esm2015/iotize-device-com-ble.cordova.ngsummary.json +1 -1
  6. package/esm2015/lib/definitions.js.map +1 -1
  7. package/esm2015/lib/utility.js +18 -0
  8. package/esm2015/lib/utility.js.map +1 -1
  9. package/esm2015/lib/utility.metadata.json +1 -1
  10. package/esm2015/lib/utility.ngsummary.json +1 -1
  11. package/esm2015/public_api.js +1 -1
  12. package/esm2015/public_api.js.map +1 -1
  13. package/esm2015/public_api.metadata.json +1 -1
  14. package/esm2015/public_api.ngsummary.json +1 -1
  15. package/fesm2015/iotize-device-com-ble.cordova.js +19 -1
  16. package/fesm2015/iotize-device-com-ble.cordova.js.map +1 -1
  17. package/iotize-device-com-ble.cordova.metadata.json +1 -1
  18. package/lib/definitions.d.ts +2 -0
  19. package/lib/utility.d.ts +4 -0
  20. package/package.json +1 -1
  21. package/public_api.d.ts +1 -1
  22. package/src/android/build.gradle +27 -27
  23. package/src/android/src/ble/BLECom.java +10 -6
  24. package/src/android/src/ble/BLEComError.java +119 -119
  25. package/src/android/src/ble/BLEProtocol.java +874 -0
  26. package/src/android/src/ble/BLEScanner.java +283 -283
  27. package/src/android/src/ble/JSONBuilder.java +83 -83
  28. package/src/android/src/ble/PluginResponse.java +129 -129
  29. package/src/android/src/ble/TapUtility.java +26 -26
  30. package/src/android/src/ble/characteristics/AbstractLwM2MRequestCharacteristic.java +48 -0
  31. package/src/android/src/ble/characteristics/CharacteristicAdapter.java +221 -0
  32. package/src/android/src/ble/characteristics/CharacteristicAdapterCallbacks.java +21 -0
  33. package/src/android/src/ble/characteristics/LwM2M20BytesRequestCharacteristicAdapter.java +161 -0
  34. package/src/android/src/ble/characteristics/LwM2MMTURequestCharacteristicAdapter.java +134 -0
  35. package/src/android/src/ble/commands/BLECommand.java +18 -0
  36. package/src/android/src/ble/commands/CharacteristicOperationCompletedNotifier.java +38 -0
  37. package/src/android/src/ble/commands/CommandCompletedNotifier.java +10 -0
  38. package/src/android/src/ble/commands/DescriptorOperationCompletedNotifier.java +37 -0
  39. package/src/android/src/ble/commands/GattOperationCompletedNotifier.java +29 -0
  40. package/src/ios/BLECom.swift +54 -42
  41. package/src/ios/BLEManager.swift +41 -23
  42. package/src/ios/BLETapPeripheral.swift +5 -10
  43. package/src/ios/CBPeripheralConverter.swift +164 -139
  44. package/src/ios/Queue.swift +114 -108
  45. package/iotize-device-com-ble.cordova-3.6.0.tgz +0 -0
@@ -0,0 +1,874 @@
1
+ //
2
+ // Source code recreated from a .class file by IntelliJ IDEA
3
+ // (powered by FernFlower decompiler)
4
+ //
5
+
6
+ package com.iotize.plugin.cordova.ble;
7
+
8
+ import android.bluetooth.BluetoothAdapter;
9
+ import android.bluetooth.BluetoothDevice;
10
+ import android.bluetooth.BluetoothGatt;
11
+ import android.bluetooth.BluetoothGattCallback;
12
+ import android.bluetooth.BluetoothGattCharacteristic;
13
+ import android.bluetooth.BluetoothGattDescriptor;
14
+ import android.bluetooth.BluetoothGattService;
15
+ import android.bluetooth.BluetoothManager;
16
+ import android.content.Context;
17
+ import android.os.Build.VERSION;
18
+ import android.util.Log;
19
+ import androidx.annotation.NonNull;
20
+ import androidx.annotation.Nullable;
21
+ import androidx.annotation.RequiresApi;
22
+ import com.iotize.android.communication.client.impl.protocol.BluetoothProtocol;
23
+ import com.iotize.android.communication.client.impl.protocol.ConnectionState;
24
+ import com.iotize.android.communication.client.impl.protocol.HostProtocol;
25
+ import com.iotize.android.communication.client.impl.protocol.exception.AdapterNotAvailableException;
26
+ import com.iotize.android.communication.client.impl.protocol.exception.ProtocolNotConnectedException;
27
+ import com.iotize.android.communication.client.impl.protocol.exception.TimeOutException;
28
+ import com.iotize.android.communication.client.impl.protocol.listener.OnConnectionStepProgress;
29
+ import com.iotize.android.communication.protocol.ble.BLECommandRunnable;
30
+ import com.iotize.android.communication.protocol.ble.BLEConfig;
31
+ import com.iotize.android.communication.protocol.ble.Constants;
32
+ import com.iotize.android.communication.protocol.ble.exception.CannotWriteDescriptorException;
33
+ import com.iotize.android.communication.protocol.ble.exception.CharacteristicNotAvailableException;
34
+ import com.iotize.android.communication.protocol.ble.exception.InvalidGattStatusException;
35
+ import com.iotize.android.communication.protocol.ble.exception.LwM2MCharacteristicNotAvailable;
36
+ import com.iotize.android.communication.protocol.ble.exception.ServiceNotAvailableException;
37
+ import com.iotize.android.communication.protocol.ble.exception.UnexpectedDisconnectionException;
38
+ import com.iotize.android.core.buffer.ByteArrayHelper;
39
+ import com.iotize.android.core.util.Helper;
40
+ import com.iotize.android.device.api.client.exceptions.NotATapDeviceException;
41
+ import com.iotize.plugin.cordova.ble.characteristics.CharacteristicAdapterCallbacks;
42
+ import com.iotize.plugin.cordova.ble.characteristics.LwM2M20BytesRequestCharacteristicAdapter;
43
+ import com.iotize.plugin.cordova.ble.characteristics.LwM2MMTURequestCharacteristicAdapter;
44
+ import com.iotize.plugin.cordova.ble.characteristics.AbstractLwM2MRequestCharacteristic;
45
+ import com.iotize.plugin.cordova.ble.characteristics.CharacteristicAdapter;
46
+ import com.iotize.plugin.cordova.ble.commands.BLECommand;
47
+ import com.iotize.plugin.cordova.ble.commands.CommandCompletedNotifier;
48
+
49
+ import java.util.Iterator;
50
+ import java.util.LinkedList;
51
+ import java.util.UUID;
52
+ import java.util.concurrent.Callable;
53
+ import java.util.concurrent.ConcurrentLinkedQueue;
54
+ import java.util.concurrent.TimeUnit;
55
+ import java.util.concurrent.atomic.AtomicBoolean;
56
+ import java.util.concurrent.atomic.AtomicReference;
57
+ import java.util.concurrent.locks.Lock;
58
+ import java.util.concurrent.locks.ReentrantLock;
59
+
60
+ @RequiresApi(
61
+ api = 18
62
+ )
63
+ public class BLEProtocol extends BluetoothProtocol {
64
+ public static final long RX_TX_DELAY_MILLISECONDS = 10L;
65
+ public static final long CONNECT_DELAY_MILLISECONDS = 100L;
66
+ private static final int TIMEOUT_CONNECT_DISCONNECT = 8000;
67
+ private static final int TIMEOUT_COM = 10000;
68
+ private static final int RECEIVED_BUFFER_LENGTH = 255;
69
+ @NonNull
70
+ private static final String TAG = "BLEProtocol";
71
+ private static final int DEFAULT_MTU_SIZE = 20;
72
+ @NonNull
73
+ private final BluetoothManager bluetoothManager;
74
+ private int connectionPriority = 1;
75
+ @NonNull
76
+ private final BluetoothDevice mDevice;
77
+ @Nullable
78
+ private MyBluetoothGattCallback mBluetoothGattCallback;
79
+ @NonNull
80
+ private final Context mContext;
81
+ @Nullable
82
+ private Exception lastInternalBLEError;
83
+ @NonNull
84
+ public BLEConfig bleConfig = new BLEConfig();
85
+ @Nullable
86
+ protected BluetoothGatt gatt;
87
+ private ConcurrentLinkedQueue<BLECommand> commandQueue = new ConcurrentLinkedQueue();
88
+ @Nullable
89
+ private AbstractLwM2MRequestCharacteristic lwM2MCharacteristic;
90
+ LinkedList<CharacteristicAdapter> characteristicsAdapters = new LinkedList();
91
+ private AtomicReference<BLECommand> currentBleCommand = new AtomicReference((Object)null);
92
+ @NonNull
93
+ private AtomicBoolean isServiceDiscovered;
94
+ @Nullable
95
+ private OnConnectionStepProgress connectionEventListener;
96
+ private int currentMTU = 20;
97
+ private int requestedMtuSize;
98
+ private Lock readLock;
99
+ private Lock writeLock;
100
+
101
+ private boolean registerLWM2MCharacteristics = true;
102
+
103
+ private void setLwM2MCharacteristic(@NonNull AbstractLwM2MRequestCharacteristic lwM2MCharacteristic) {
104
+ this.characteristicsAdapters.add(lwM2MCharacteristic);
105
+ this.lwM2MCharacteristic = lwM2MCharacteristic;
106
+ this.lwM2MCharacteristic.initialize(this.getGatt(), (AbstractLwM2MRequestCharacteristic.OnCharacteristicInitialized)null);
107
+ }
108
+
109
+ @NonNull
110
+ public BluetoothGatt getGatt() {
111
+ if (this.gatt == null) {
112
+ throw new ProtocolNotConnectedException();
113
+ } else {
114
+ return this.gatt;
115
+ }
116
+ }
117
+
118
+ public BLEProtocol(@NonNull Context context, @NonNull BluetoothDevice mDevice) {
119
+ this.requestedMtuSize = this.currentMTU;
120
+ this.readLock = new ReentrantLock();
121
+ this.writeLock = new ReentrantLock();
122
+ this.mContext = context;
123
+ this.mDevice = mDevice;
124
+ this.protocolConfiguration.connectionTimeoutMillis = 10000L;
125
+ this.isServiceDiscovered = new AtomicBoolean(false);
126
+ BluetoothManager manager = (BluetoothManager)context.getSystemService("bluetooth");
127
+ if (manager == null) {
128
+ throw new IllegalStateException("Bluetooth manager is not available");
129
+ } else {
130
+ this.bluetoothManager = manager;
131
+ }
132
+ }
133
+
134
+ public BLEProtocol setConnectionEventListener(OnConnectionStepProgress connectionEventListener) {
135
+ this.connectionEventListener = connectionEventListener;
136
+ return this;
137
+ }
138
+
139
+ public void setConnectionPriority(int connectionPriority) {
140
+ this.connectionPriority = connectionPriority;
141
+ }
142
+
143
+ public int getConnectionPriority() {
144
+ return this.connectionPriority;
145
+ }
146
+
147
+ public static BLEProtocol fromAddress(@NonNull Context context, @NonNull String address) throws AdapterNotAvailableException {
148
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
149
+ if (bluetoothAdapter == null) {
150
+ throw new AdapterNotAvailableException("Bluetooth adapter is not available on this device");
151
+ } else {
152
+ BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address);
153
+ return new BLEProtocol(context, bluetoothDevice);
154
+ }
155
+ }
156
+
157
+ public static BLEProtocol fromDevice(@NonNull Context context, BluetoothDevice bluetoothDevice) throws AdapterNotAvailableException {
158
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
159
+ if (bluetoothAdapter == null) {
160
+ throw new AdapterNotAvailableException("Bluetooth adapter is not available on this device");
161
+ } else {
162
+ return new BLEProtocol(context, bluetoothDevice);
163
+ }
164
+ }
165
+
166
+ @RequiresApi(
167
+ api = 18
168
+ )
169
+ public long bleConnect() throws Exception {
170
+ try {
171
+ this.currentMTU = 20;
172
+ this.lastInternalBLEError = null;
173
+ int bleRetryCount = 0;
174
+ long count = 0L;
175
+
176
+ while(bleRetryCount <= this.bleConfig.maxConnectRetry) {
177
+ try {
178
+ this.connectToGatt();
179
+ count = this.waitForAndroidBleConnection(count, this.protocolConfiguration.connectionTimeoutMillis);
180
+ break;
181
+ } catch (InvalidGattStatusException var6) {
182
+ InvalidGattStatusException gattStatusError = (InvalidGattStatusException)this.lastInternalBLEError;
183
+ if (gattStatusError.getStatus() != 133) {
184
+ throw var6;
185
+ }
186
+
187
+ Log.w("BLEProtocol", "Retry after GATT_ERROR", gattStatusError);
188
+ ++bleRetryCount;
189
+ this.lastInternalBLEError = null;
190
+ } catch (Exception var7) {
191
+ throw var7;
192
+ }
193
+ }
194
+
195
+ Log.d("BLEProtocol", "Connection successful (nb retry=" + bleRetryCount + ")");
196
+ return count;
197
+ } catch (Exception var8) {
198
+ this.closeAndDisconnect();
199
+ throw var8;
200
+ }
201
+ }
202
+
203
+ @RequiresApi(
204
+ api = 18
205
+ )
206
+ public void _connect() throws Exception {
207
+ try {
208
+ long duration = this.bleConnect();
209
+ this.discoverServices(this.protocolConfiguration.connectionTimeoutMillis - duration);
210
+ Log.d("BLEProtocol", "Connection to Tap and services discovered");
211
+ } catch (Exception var3) {
212
+ this.closeAndDisconnect();
213
+ throw var3;
214
+ }
215
+ }
216
+
217
+ protected long prepareLwm2mService(long count) throws Exception {
218
+ count = this.waitForCharacteristicInitialized(count, this.protocolConfiguration.connectionTimeoutMillis);
219
+ return count;
220
+ }
221
+
222
+ private void disconnectIfErrorAndThrow() throws Exception {
223
+ if (this.lastInternalBLEError != null) {
224
+ this.closeAndDisconnect();
225
+ throw this.lastInternalBLEError;
226
+ }
227
+ }
228
+
229
+ private long waitForAndroidBleConnection(long count, long timeout) throws Exception {
230
+ Log.d("BLEProtocol", "waitForAndroidBleConnection STARTING");
231
+ this.waitUntilConditionOrInternalError(() -> {
232
+ return this.getBluetoothConnectionState() == 2;
233
+ }, timeout, 100L);
234
+ Log.d("BLEProtocol", "waitForAndroidBleConnection DONE count = " + count);
235
+ return count;
236
+ }
237
+
238
+ private long waitForCharacteristicInitialized(long count, long timeout) throws Exception {
239
+ Log.v("BLEProtocol", "waitForCharacteristicRead STARTING");
240
+ count = this.waitUntilConditionOrInternalError(() -> {
241
+ return this.lwM2MCharacteristic != null && this.lwM2MCharacteristic.isInitialized();
242
+ }, timeout, 10L);
243
+ Log.v("BLEProtocol", "waitForCharacteristicRead DONE count = " + count);
244
+ return count;
245
+ }
246
+
247
+ @RequiresApi(
248
+ api = 18
249
+ )
250
+ public void _disconnect() throws Exception {
251
+ try {
252
+ this.currentMTU = 20;
253
+ this.cancelPendingOperations();
254
+ this.closeAndDisconnect();
255
+ } finally {
256
+ this.lastInternalBLEError = null;
257
+ }
258
+
259
+ }
260
+
261
+ private void cancelPendingOperations() {
262
+ }
263
+
264
+ @RequiresApi(
265
+ api = 18
266
+ )
267
+ public void write(byte[] data) throws Exception {
268
+ if (data == null) {
269
+ Log.w("BLEProtocol", "Writing null data. Skip...");
270
+ } else if (data.length > 245) {
271
+ throw new IllegalArgumentException("Maximum frame size with ble is 245 bytes (found " + data.length + " bytes)");
272
+ } else {
273
+ this.beforeReadWriteLwm2m();
274
+ if (this.writeLock.tryLock(15000L, TimeUnit.MILLISECONDS)) {
275
+ try {
276
+ this.lwM2MCharacteristic.sendLwM2MTapRequest(this.getGatt(), data);
277
+ } finally {
278
+ this.writeLock.unlock();
279
+ }
280
+ }
281
+
282
+ }
283
+ }
284
+
285
+ private void beforeReadWriteLwm2m() throws Exception {
286
+ if (!this.isServiceDiscovered.get()) {
287
+ this.discoverServices(this.protocolConfiguration.sendTimeoutMillis);
288
+ }
289
+
290
+ if (!this.hasTapLwM2MService()) {
291
+ throw new NotATapDeviceException("Tap LwM2M BLE service to communicate using LwM2M Tap requests does not exist on this device.");
292
+ } else {
293
+ this.prepareLwm2mService(0L);
294
+ this.assertLwm2mServicePrepared();
295
+ }
296
+ }
297
+
298
+ @RequiresApi(
299
+ api = 18
300
+ )
301
+ public void connectToGatt() throws AdapterNotAvailableException {
302
+ if (this.mBluetoothGattCallback == null) {
303
+ this.mBluetoothGattCallback = new MyBluetoothGattCallback();
304
+ }
305
+
306
+ if (this.gatt != null) {
307
+ Log.w("BLEProtocol", "connectToGatt() Reusing previous connection " + this.gatt);
308
+ switch (this.getBluetoothConnectionState()) {
309
+ case 0:
310
+ this.gatt.connect();
311
+ break;
312
+ case 1:
313
+ Log.w("BLEProtocol", "connectToGatt() already connecting...");
314
+ break;
315
+ case 2:
316
+ return;
317
+ case 3:
318
+ throw new IllegalStateException("Already disconnecting");
319
+ }
320
+ } else {
321
+ this.notifyStepProgress(1);
322
+ if (VERSION.SDK_INT >= 23) {
323
+ this.gatt = this.mDevice.connectGatt(this.mContext, false, this.mBluetoothGattCallback, 2);
324
+ } else {
325
+ this.gatt = this.mDevice.connectGatt(this.mContext, false, this.mBluetoothGattCallback);
326
+ }
327
+ }
328
+
329
+ if (this.gatt == null) {
330
+ throw new AdapterNotAvailableException("Bluetooth gatt is not available");
331
+ } else {
332
+ Log.i("BLEProtocol", "connectToGatt() with " + this.gatt);
333
+ }
334
+ }
335
+
336
+ private void notifyStepProgress(int code) {
337
+ this.notifyStepProgress(code, (Object)null);
338
+ }
339
+
340
+ private void notifyStepProgress(int code, Object payload) {
341
+ Log.i("BLEProtocol", "notifyStepProgress() code = " + code + "; payload= " + payload);
342
+ if (this.connectionEventListener != null) {
343
+ this.connectionEventListener.onStepProgress(code, payload);
344
+ }
345
+
346
+ }
347
+
348
+ public byte[] read() throws Exception {
349
+ if (this.readLock.tryLock(15000L, TimeUnit.MILLISECONDS)) {
350
+ byte[] data;
351
+ try {
352
+ data = this.waitForData();
353
+ } finally {
354
+ this.readLock.unlock();
355
+ }
356
+
357
+ Log.d("BLEProtocol", "Received: 0x" + Helper.ByteArrayToHexString(data));
358
+ return data;
359
+ } else {
360
+ throw new TimeOutException("While waiting for BLE write");
361
+ }
362
+ }
363
+
364
+ private void assertLwm2mServicePrepared() throws LwM2MCharacteristicNotAvailable {
365
+ if (this.gatt != null && this.isServiceDiscovered.get()) {
366
+ if (this.lwM2MCharacteristic == null) {
367
+ throw new LwM2MCharacteristicNotAvailable();
368
+ }
369
+ } else {
370
+ this.closeAndDisconnect();
371
+ throw new ProtocolNotConnectedException();
372
+ }
373
+ }
374
+
375
+ private byte[] waitForData() throws Exception {
376
+ byte[] var2;
377
+ try {
378
+ this.waitUntilConditionOrInternalError(() -> {
379
+ return this.lwM2MCharacteristic.getTapResponse() != null;
380
+ }, 10000L, 100L);
381
+ byte[] tapResponseBytes = this.lwM2MCharacteristic.getTapResponse();
382
+ Log.d("BLEProtocol", "Read stream has " + tapResponseBytes.length + " bytes of data");
383
+ var2 = ByteArrayHelper.copy(tapResponseBytes);
384
+ } finally {
385
+ this.lwM2MCharacteristic.reset();
386
+ }
387
+
388
+ return var2;
389
+ }
390
+
391
+ private long waitUntilConditionOrInternalError(Callable<Boolean> condition, long timeoutCom, long waitDelayMilliseconds) throws Exception {
392
+ long time = (long)this.waitUntilCondition(() -> {
393
+ return this.lastInternalBLEError != null || (Boolean)condition.call();
394
+ }, timeoutCom, waitDelayMilliseconds);
395
+ if (this.lastInternalBLEError != null) {
396
+ throw this.lastInternalBLEError;
397
+ } else {
398
+ return time;
399
+ }
400
+ }
401
+
402
+ private void waitForMtuSizeChanged(long timeout) throws Exception {
403
+ this.waitUntilConditionOrInternalError(() -> {
404
+ return this.currentMTU >= this.requestedMtuSize;
405
+ }, timeout, 100L);
406
+ }
407
+
408
+ public HostProtocol getType() {
409
+ return HostProtocol.BLE;
410
+ }
411
+
412
+ private synchronized void closeAndDisconnect() {
413
+ try {
414
+ if (this.gatt != null) {
415
+ this.gatt.disconnect();
416
+
417
+ try {
418
+ this.waitForConnectionState(0);
419
+ } catch (UnexpectedDisconnectionException var6) {
420
+ } catch (Exception var7) {
421
+ Log.e("BLEProtocol", "Cannot disconnect properly", var7);
422
+ }
423
+
424
+ this.gatt.close();
425
+ }
426
+ } finally {
427
+ this.gatt = null;
428
+ this.lwM2MCharacteristic = null;
429
+ this.isServiceDiscovered.set(false);
430
+ this.characteristicsAdapters.clear();
431
+ this.currentBleCommand.set(null);
432
+ this.setConnectionStatus(ConnectionState.DISCONNECTED);
433
+ }
434
+
435
+ }
436
+
437
+ private long waitForConnectionState(int connectionState) throws Exception {
438
+ return this.waitUntilConditionOrInternalError(() -> {
439
+ return this.getBluetoothConnectionState() == connectionState;
440
+ }, 8000L, 100L);
441
+ }
442
+
443
+ private int waitUntilCondition(Callable<Boolean> condition, long timeout, long delay) throws Exception {
444
+ int count;
445
+ for(count = 0; (timeout < 0L || (long)count < timeout) && !(Boolean)condition.call(); count = (int)((long)count + delay)) {
446
+ Thread.sleep(delay);
447
+ }
448
+
449
+ if (timeout >= 0L && (long)count >= timeout) {
450
+ throw new TimeOutException("BLE timeout after " + timeout + "ms");
451
+ } else {
452
+ return count;
453
+ }
454
+ }
455
+
456
+ @RequiresApi(
457
+ api = 18
458
+ )
459
+ @NonNull
460
+ private BluetoothGattCharacteristic getCharacteristic(@NonNull UUID svcUuid, @NonNull UUID charUuid) throws ServiceNotAvailableException, CharacteristicNotAvailableException {
461
+ BluetoothGattService services = this.getGatt().getService(svcUuid);
462
+ if (services == null) {
463
+ Log.e("BLEProtocol", "Bluetooth service " + svcUuid + " is null");
464
+ throw new ServiceNotAvailableException(svcUuid);
465
+ } else {
466
+ BluetoothGattCharacteristic characteristic = services.getCharacteristic(charUuid);
467
+ if (characteristic == null) {
468
+ throw new CharacteristicNotAvailableException(svcUuid, charUuid);
469
+ } else {
470
+ return characteristic;
471
+ }
472
+ }
473
+ }
474
+
475
+ @RequiresApi(
476
+ api = 18
477
+ )
478
+ @Nullable
479
+ private BluetoothGattCharacteristic findCharacteristic(@NonNull UUID svcUuid, @NonNull UUID charUuid) {
480
+ BluetoothGattService services = this.getGatt().getService(svcUuid);
481
+ return services == null ? null : services.getCharacteristic(charUuid);
482
+ }
483
+
484
+ public CharacteristicAdapter getCharacteristicAdapter(@NonNull UUID svcUuid, @NonNull UUID charUuid) throws ServiceNotAvailableException, CharacteristicNotAvailableException {
485
+ CharacteristicAdapter adapter = this.findCharacteristicAdapter(svcUuid, charUuid);
486
+ if (adapter == null) {
487
+ throw new CharacteristicNotAvailableException(svcUuid, charUuid);
488
+ } else {
489
+ return adapter;
490
+ }
491
+ }
492
+
493
+ public boolean hasTapLwM2MService() {
494
+ this.assertBleConnnected();
495
+ BluetoothGatt gatt = this.getGatt();
496
+ return gatt.getService(Constants.SERVICE_SPP_OVER_LE) != null || gatt.getService(Constants.SERVICE_SPP_OVER_LE_FAST) != null;
497
+ }
498
+
499
+ public void discoverServices(boolean registerLWM2MCharacteristics) throws Exception {
500
+ this.registerLWM2MCharacteristics = registerLWM2MCharacteristics;
501
+ this.discoverServices();
502
+ }
503
+
504
+ public void discoverServices() throws Exception {
505
+ this.discoverServices(this.protocolConfiguration.connectionTimeoutMillis);
506
+ }
507
+
508
+ public void discoverServices(long timeoutMillis) throws Exception {
509
+ this.discoverServicesAsync();
510
+ this.waitForServiceDiscovery(0L, timeoutMillis);
511
+ }
512
+
513
+ public void discoverServicesAsync() {
514
+ this.assertBleConnnected();
515
+ this.isServiceDiscovered.set(false);
516
+ this.characteristicsAdapters.clear();
517
+ Log.i("BLEProtocol", "Bluetooth is now connected to device. Start service discovery");
518
+ this.getGatt().discoverServices();
519
+ }
520
+
521
+ private void assertBleConnnected() throws ProtocolNotConnectedException {
522
+ if (this.gatt == null) {
523
+ throw new IllegalStateException("Bluetooth gatt is not connected yet");
524
+ } else if (this.getBluetoothConnectionState() != 2) {
525
+ throw new ProtocolNotConnectedException();
526
+ }
527
+ }
528
+
529
+ private long waitForServiceDiscovery(long count, long timeoutMillis) throws Exception {
530
+ count += this.waitUntilConditionOrInternalError(() -> {
531
+ return this.isServiceDiscovered.get();
532
+ }, timeoutMillis, 100L);
533
+ return count;
534
+ }
535
+
536
+ public BluetoothDevice getBluetoothDevice() {
537
+ return this.mDevice;
538
+ }
539
+
540
+ private int getBluetoothConnectionState() {
541
+ return this.bluetoothManager.getConnectionState(this.mDevice, 7);
542
+ }
543
+
544
+ @Nullable
545
+ private CharacteristicAdapter findCharacteristicAdapter(@NonNull BluetoothGattCharacteristic characteristic) {
546
+ return this.findCharacteristicAdapter(characteristic.getService().getUuid(), characteristic.getUuid());
547
+ }
548
+
549
+ @Nullable
550
+ private CharacteristicAdapter findCharacteristicAdapter(UUID serviceId, UUID characId) {
551
+ Iterator var3 = this.characteristicsAdapters.iterator();
552
+
553
+ CharacteristicAdapter adapter;
554
+ do {
555
+ if (!var3.hasNext()) {
556
+ BluetoothGattCharacteristic characteristic = this.findCharacteristic(serviceId, characId);
557
+ if (characteristic != null) {
558
+ adapter = new CharacteristicAdapter(this, characteristic, (CharacteristicAdapterCallbacks)null);
559
+ this.characteristicsAdapters.add(adapter);
560
+ return adapter;
561
+ }
562
+
563
+ return null;
564
+ }
565
+
566
+ adapter = (CharacteristicAdapter)var3.next();
567
+ } while(!adapter.characteristic.getUuid().equals(characId) || !adapter.characteristic.getService().getUuid().equals(serviceId));
568
+
569
+ return adapter;
570
+ }
571
+
572
+ public void queueCommand(BLECommand command) {
573
+ Log.d("BLEProtocol", "Queuing Command (total: " + this.commandQueue.size() + ")");
574
+ this.commandQueue.add(command);
575
+ if (this.currentBleCommand.get() == null) {
576
+ this.processCommands();
577
+ }
578
+
579
+ }
580
+
581
+ private synchronized void processCommands() {
582
+ if (this.currentBleCommand.get() == null) {
583
+ Log.d("BLEProtocol", "Processing next command...");
584
+ BLECommand command = (BLECommand)this.commandQueue.poll();
585
+ this.currentBleCommand.set(command);
586
+ if (command != null) {
587
+ try {
588
+ command.runnable.run();
589
+ } catch (Exception var3) {
590
+ command.notifier.notifyError(var3);
591
+ }
592
+ } else {
593
+ Log.d("BLEProtocol", "Command Queue is empty.");
594
+ }
595
+
596
+ }
597
+ }
598
+
599
+ public int getMTU() {
600
+ return this.currentMTU;
601
+ }
602
+
603
+ public int setMTU(int mtu) {
604
+ return this.currentMTU = mtu;
605
+ }
606
+
607
+ private synchronized void notifyGattOperationResult(int status) {
608
+ BLECommand command = (BLECommand)this.currentBleCommand.get();
609
+ this.currentBleCommand.set(null);
610
+ if (command != null) {
611
+ command.notifier.notifyResult(status);
612
+ }
613
+
614
+ this.processCommands();
615
+ }
616
+
617
+ public void requestMtuSize(@NonNull final BluetoothGatt gatt, final int requestedMtuSize, @Nullable OnGattOperationCallback callback) {
618
+ if (VERSION.SDK_INT >= 21 && this.currentMTU < requestedMtuSize) {
619
+ this.queueCommand(new BLECommand(new BLECommandRunnable() {
620
+ public void run() throws Exception {
621
+ Log.d("BLEProtocol", "request mtu size: " + requestedMtuSize);
622
+ BLEProtocol.this.requestedMtuSize = requestedMtuSize;
623
+ gatt.requestMtu(requestedMtuSize);
624
+ }
625
+ }, new GattOperationCompletedNotifier(callback)));
626
+ } else if (callback != null) {
627
+ callback.onResult(0);
628
+ }
629
+
630
+ }
631
+
632
+ public String toString() {
633
+ return "BLEProtocol{" + this.getConnectionStatus().toString() + ", mDevice=" + this.mDevice + '}';
634
+ }
635
+
636
+ public interface OnGattOperationCallback {
637
+ void onResult(int var1);
638
+
639
+ void onError(@NonNull Exception var1);
640
+ }
641
+
642
+ public interface StepCode {
643
+ int CONNECT_TO_GATT = 1;
644
+ int CONNECTING_TO_GATT = 2;
645
+ int CONNECTED_TO_GATT = 3;
646
+ int SERVICE_DISCOVERED = 4;
647
+ int READ_CHARACTERISTIC_UPGRADE_APP_INFO = 5;
648
+ int READ_CHARACTERISTIC_SPP_OVER_LE = 6;
649
+ int SEND_PACKET_CHUNK = 7;
650
+ }
651
+
652
+ @RequiresApi(
653
+ api = 18
654
+ )
655
+ private class MyBluetoothGattCallback extends BluetoothGattCallback {
656
+ private MyBluetoothGattCallback() {
657
+ }
658
+
659
+ @RequiresApi(
660
+ api = 18
661
+ )
662
+ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
663
+ Log.i("BLEProtocol", "onConnectionStateChange(): status=" + status + ", newState: " + newState);
664
+ BLEProtocol.this.gatt = gatt;
665
+ this.checkGattStatusCode(gatt, status);
666
+ switch (newState) {
667
+ case 0:
668
+ default:
669
+ if (BLEProtocol.this.lastInternalBLEError == null) {
670
+ BLEProtocol.this.lastInternalBLEError = new UnexpectedDisconnectionException();
671
+ }
672
+
673
+ BLEProtocol.this.closeAndDisconnect();
674
+ break;
675
+ case 1:
676
+ BLEProtocol.this.notifyStepProgress(2);
677
+ break;
678
+ case 2:
679
+ BLEProtocol.this.notifyStepProgress(3);
680
+ break;
681
+ case 3:
682
+ BLEProtocol.this.setConnectionStatus(ConnectionState.DISCONNECTING);
683
+ }
684
+
685
+ }
686
+
687
+ @RequiresApi(
688
+ api = 18
689
+ )
690
+ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
691
+ Log.i("BLEProtocol", "onServicesDiscovered received: '" + status + "' for gatt " + gatt);
692
+ if (this.checkGattStatusCode(gatt, status)) {
693
+ try {
694
+ BLEProtocol.this.notifyStepProgress(4);
695
+ BLEProtocol.this.gatt = gatt;
696
+ if (VERSION.SDK_INT >= 21) {
697
+ Log.d("BLEProtocol", "Setting priority to '" + BLEProtocol.this.connectionPriority + "' for gatt: " + gatt.toString());
698
+ gatt.requestConnectionPriority(BLEProtocol.this.connectionPriority);
699
+ }
700
+ if (registerLWM2MCharacteristics) {
701
+ if (gatt.getService(Constants.SERVICE_SPP_OVER_LE_FAST) != null) {
702
+ BLEProtocol.this.setLwM2MCharacteristic(new LwM2MMTURequestCharacteristicAdapter(BLEProtocol.this, BLEProtocol.this.getCharacteristic(Constants.SERVICE_SPP_OVER_LE_FAST, Constants.CHARACTERISTIC_SPP_Over_LE_BUFFER_FAST)));
703
+ } else if (gatt.getService(Constants.SERVICE_SPP_OVER_LE) != null) {
704
+ BLEProtocol.this.setLwM2MCharacteristic(new LwM2M20BytesRequestCharacteristicAdapter(BLEProtocol.this, BLEProtocol.this.getCharacteristic(Constants.SERVICE_SPP_OVER_LE, Constants.CHARACTERISTIC_SPP_Over_LE_BUFFER)));
705
+ }
706
+ }
707
+
708
+
709
+ BLEProtocol.this.isServiceDiscovered.set(true);
710
+ } catch (Exception var4) {
711
+ BLEProtocol.this.lastInternalBLEError = var4;
712
+ }
713
+
714
+ }
715
+ }
716
+
717
+ @RequiresApi(
718
+ api = 18
719
+ )
720
+ public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
721
+ Log.d("BLEProtocol", "onCharacteristicRead: status:" + status + ". characteristic: " + characteristic.getUuid() + ". Gatt: " + gatt);
722
+ this.checkGattStatusCode(gatt, status);
723
+
724
+ try {
725
+ CharacteristicAdapter characteristicAdapter = BLEProtocol.this.findCharacteristicAdapter(characteristic);
726
+ if (characteristicAdapter != null) {
727
+ characteristicAdapter.onCharacteristicRead(gatt, status);
728
+ } else {
729
+ Log.w("BLEProtocol", "onCharacteristicRead(" + characteristic.getUuid() + ") no action defined");
730
+ }
731
+ } catch (Exception var5) {
732
+ BLEProtocol.this.lastInternalBLEError = var5;
733
+ }
734
+
735
+ BLEProtocol.this.notifyGattOperationResult(status);
736
+ }
737
+
738
+ private boolean checkGattStatusCode(BluetoothGatt gatt, int status) {
739
+ if (status != 0) {
740
+ Log.e("BLEProtocol", "onCharacteristicRead ERROR");
741
+ BLEProtocol.this.lastInternalBLEError = new InvalidGattStatusException(gatt, status);
742
+ return false;
743
+ } else {
744
+ return true;
745
+ }
746
+ }
747
+
748
+ public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
749
+ try {
750
+ CharacteristicAdapterCallbacks characteristicAdapter = BLEProtocol.this.findCharacteristicAdapter(characteristic);
751
+ if (characteristicAdapter != null) {
752
+ characteristicAdapter.onCharacteristicValueChanged(gatt);
753
+ } else {
754
+ Log.w("BLEProtocol", "onCharacteristicChanged(" + characteristic.getUuid() + ") no action defined");
755
+ }
756
+ } catch (Exception var4) {
757
+ Log.e("BLEProtocol", "Unexpected error:", var4);
758
+ BLEProtocol.this.lastInternalBLEError = var4;
759
+ }
760
+
761
+ }
762
+
763
+ public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
764
+ try {
765
+ Log.d("BLEProtocol", "onCharacteristicWrite() status: " + status + ". characteristic: " + characteristic + ". Gatt: " + gatt);
766
+ if (!this.checkGattStatusCode(gatt, status)) {
767
+ Log.e("BLEProtocol", "onCharacteristicWrite error with code " + status);
768
+ }
769
+
770
+ CharacteristicAdapter characteristicAdapter = BLEProtocol.this.findCharacteristicAdapter(characteristic);
771
+ if (characteristicAdapter != null) {
772
+ characteristicAdapter.onCharacteristicWrite(gatt, status);
773
+ } else {
774
+ Log.w("BLEProtocol", "onCharacteristicWrite(" + characteristic.getUuid() + ") no action defined");
775
+ }
776
+ } catch (Exception var5) {
777
+ BLEProtocol.this.lastInternalBLEError = var5;
778
+ }
779
+
780
+ BLEProtocol.this.notifyGattOperationResult(status);
781
+ }
782
+
783
+ public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
784
+ Log.d("BLEProtocol", "onDescriptorWrite() status: " + status + ". Characteristic: " + descriptor.getCharacteristic().getUuid() + ", descriptor value: " + Helper.ByteArrayToHexString(descriptor.getValue()) + ". Gatt: " + gatt);
785
+ if (!this.checkGattStatusCode(gatt, status)) {
786
+ Log.e("BLEProtocol", "onDescriptorWrite FAILED: " + status);
787
+ BLEProtocol.this.lastInternalBLEError = new CannotWriteDescriptorException(descriptor);
788
+ }
789
+
790
+ try {
791
+ CharacteristicAdapter characteristicAdapter = BLEProtocol.this.findCharacteristicAdapter(descriptor.getCharacteristic());
792
+ if (characteristicAdapter != null) {
793
+ characteristicAdapter.onDescriptorWrite(gatt, descriptor, status);
794
+ } else {
795
+ Log.w("BLEProtocol", "onDescriptorWrite(" + descriptor.getUuid() + ") no action defined");
796
+ }
797
+ } catch (Exception var5) {
798
+ BLEProtocol.this.lastInternalBLEError = var5;
799
+ }
800
+
801
+ BLEProtocol.this.notifyGattOperationResult(status);
802
+ }
803
+
804
+ public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
805
+ Log.d("BLEProtocol", "onMtuChanged() status: " + status + ". mtu: " + mtu + ". Gatt: " + gatt);
806
+ if (!this.checkGattStatusCode(gatt, status)) {
807
+ Log.e("BLEProtocol", "onMtuChanged FAILED: " + status);
808
+ } else {
809
+ BLEProtocol.this.currentMTU = mtu;
810
+ BLEProtocol.this.notifyGattOperationResult(status);
811
+ }
812
+ }
813
+
814
+ public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
815
+ Log.d("BLEProtocol", "onPhyUpdate");
816
+ if (!this.checkGattStatusCode(gatt, status)) {
817
+ Log.e("BLEProtocol", "onPhyUpdate FAILED: " + status);
818
+ }
819
+ }
820
+
821
+ public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
822
+ Log.d("BLEProtocol", "onPhyRead");
823
+ if (!this.checkGattStatusCode(gatt, status)) {
824
+ Log.e("BLEProtocol", "onPhyRead FAILED: " + status);
825
+ }
826
+ }
827
+
828
+ public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
829
+ Log.d("BLEProtocol", "onDescriptorRead");
830
+ if (!this.checkGattStatusCode(gatt, status)) {
831
+ Log.e("BLEProtocol", "onDescriptorRead FAILED: " + status);
832
+ }
833
+
834
+ BLEProtocol.this.notifyGattOperationResult(status);
835
+ }
836
+
837
+ public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
838
+ Log.d("BLEProtocol", "onReliableWriteCompleted");
839
+ if (!this.checkGattStatusCode(gatt, status)) {
840
+ Log.e("BLEProtocol", "onReliableWriteCompleted FAILED: " + status);
841
+ }
842
+ }
843
+
844
+ public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
845
+ Log.d("BLEProtocol", "onReadRemoteRssi");
846
+ if (!this.checkGattStatusCode(gatt, status)) {
847
+ Log.e("BLEProtocol", "onReadRemoteRssi FAILED: " + status);
848
+ }
849
+ }
850
+ }
851
+
852
+ public class GattOperationCompletedNotifier implements CommandCompletedNotifier {
853
+ @Nullable
854
+ public final OnGattOperationCallback callback;
855
+
856
+ public GattOperationCompletedNotifier(@Nullable OnGattOperationCallback callback) {
857
+ this.callback = callback;
858
+ }
859
+
860
+ public void notifyResult(int status) {
861
+ if (this.callback != null) {
862
+ this.callback.onResult(status);
863
+ }
864
+
865
+ }
866
+
867
+ public void notifyError(@NonNull Exception err) {
868
+ if (this.callback != null) {
869
+ this.callback.onError(err);
870
+ }
871
+
872
+ }
873
+ }
874
+ }