@onekeyfe/hd-transport-react-native 1.2.2-alpha.11 → 1.2.2-alpha.110
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 +1 -1
- package/dist/BleManager.d.ts +1 -1
- package/dist/BleManager.d.ts.map +1 -1
- package/dist/bleNativeDisconnect.d.ts +3 -0
- package/dist/bleNativeDisconnect.d.ts.map +1 -0
- package/dist/bleStaleBond.d.ts.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +320 -68
- package/package.json +6 -6
- package/src/BleManager.ts +73 -5
- package/src/__tests__/bleNativeDisconnect.test.ts +33 -0
- package/src/__tests__/bleStaleBond.test.ts +8 -0
- package/src/__tests__/connectTimeout.test.ts +343 -3
- package/src/__tests__/protocolV2Link.test.ts +292 -2
- package/src/__tests__/staleCallTimeout.test.ts +34 -5
- package/src/bleNativeDisconnect.ts +40 -0
- package/src/bleStaleBond.ts +3 -0
- package/src/index.ts +256 -66
package/dist/index.js
CHANGED
|
@@ -57,36 +57,73 @@ const bleLogger = {
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
const Logger = bleLogger;
|
|
60
|
+
const bondFailureReasons = {
|
|
61
|
+
1: 'authentication_failed',
|
|
62
|
+
2: 'rejected',
|
|
63
|
+
3: 'canceled',
|
|
64
|
+
4: 'device_unreachable',
|
|
65
|
+
5: 'discovery_in_progress',
|
|
66
|
+
6: 'timeout',
|
|
67
|
+
7: 'repeated_attempts',
|
|
68
|
+
8: 'remote_canceled',
|
|
69
|
+
9: 'removed',
|
|
70
|
+
};
|
|
60
71
|
const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].getConnectedPeripherals(serviceUuids);
|
|
61
72
|
const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
|
|
62
|
-
const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
|
|
73
|
+
const onDeviceBondState = (bleMacAddress, signal) => new Promise((resolve, reject) => {
|
|
74
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
75
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
63
78
|
const cleanup = () => {
|
|
64
79
|
if (timeout) {
|
|
65
80
|
clearTimeout(timeout);
|
|
66
81
|
}
|
|
67
82
|
if (cleanupListener)
|
|
68
83
|
cleanupListener();
|
|
84
|
+
signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
|
|
85
|
+
};
|
|
86
|
+
const onAbort = () => {
|
|
87
|
+
cleanup();
|
|
88
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
|
|
69
89
|
};
|
|
90
|
+
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort, { once: true });
|
|
70
91
|
const timeout = setTimeout(() => {
|
|
71
92
|
cleanup();
|
|
72
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, '
|
|
93
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', {
|
|
94
|
+
phase: 'bond',
|
|
95
|
+
reason: 'timeout',
|
|
96
|
+
}));
|
|
73
97
|
}, 60 * 1000);
|
|
74
98
|
const cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
|
|
75
|
-
var _a;
|
|
99
|
+
var _a, _b;
|
|
76
100
|
if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
|
|
77
101
|
return;
|
|
78
102
|
}
|
|
79
103
|
const { bondState } = peripheral;
|
|
80
104
|
const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
|
|
81
|
-
const
|
|
105
|
+
const hasFailed = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
|
|
82
106
|
Logger.debug('onDeviceBondState bondState:', bondState);
|
|
83
107
|
if (hasBonded) {
|
|
84
108
|
cleanup();
|
|
85
109
|
resolve(peripheral);
|
|
86
110
|
}
|
|
87
|
-
else if (
|
|
111
|
+
else if (hasFailed) {
|
|
88
112
|
cleanup();
|
|
89
|
-
|
|
113
|
+
const nativeReason = 'reason' in bondState && typeof bondState.reason === 'number'
|
|
114
|
+
? bondState.reason
|
|
115
|
+
: undefined;
|
|
116
|
+
const reason = nativeReason === undefined ? 'unknown' : (_b = bondFailureReasons[nativeReason]) !== null && _b !== void 0 ? _b : 'unknown';
|
|
117
|
+
const params = Object.assign({ phase: 'bond', reason }, (nativeReason === undefined ? {} : { nativeReason }));
|
|
118
|
+
if (reason === 'timeout') {
|
|
119
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', params));
|
|
120
|
+
}
|
|
121
|
+
else if (reason === 'canceled') {
|
|
122
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'Bluetooth pairing canceled', params));
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing failed', params));
|
|
126
|
+
}
|
|
90
127
|
}
|
|
91
128
|
});
|
|
92
129
|
});
|
|
@@ -194,6 +231,27 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
|
|
|
194
231
|
}, ms);
|
|
195
232
|
});
|
|
196
233
|
|
|
234
|
+
const BLE_PLX_DEVICE_DISCONNECTED = 201;
|
|
235
|
+
const IOS_PERIPHERAL_DISCONNECTED = 7;
|
|
236
|
+
const nativeErrorText$1 = (error) => [error.reason, error.message]
|
|
237
|
+
.filter((value) => typeof value === 'string')
|
|
238
|
+
.join(' ');
|
|
239
|
+
const isNativeBleDisconnectError = (error) => {
|
|
240
|
+
if (!error || typeof error !== 'object') {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
const nativeError = error;
|
|
244
|
+
return (nativeError.errorCode === BLE_PLX_DEVICE_DISCONNECTED ||
|
|
245
|
+
nativeError.iosErrorCode === IOS_PERIPHERAL_DISCONNECTED);
|
|
246
|
+
};
|
|
247
|
+
const toBleDisconnectHardwareError = (error) => {
|
|
248
|
+
if ((error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleDeviceDisconnected) {
|
|
249
|
+
return error;
|
|
250
|
+
}
|
|
251
|
+
const nativeError = (error !== null && error !== void 0 ? error : {});
|
|
252
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, nativeErrorText$1(nativeError) || undefined);
|
|
253
|
+
};
|
|
254
|
+
|
|
197
255
|
const ATT_INSUFFICIENT_AUTHENTICATION = 5;
|
|
198
256
|
const ATT_INSUFFICIENT_ENCRYPTION = 15;
|
|
199
257
|
const IOS_PEER_REMOVED_PAIRING_INFORMATION = 14;
|
|
@@ -207,6 +265,8 @@ const isNativeBleStaleBondError = (error) => {
|
|
|
207
265
|
const nativeError = error;
|
|
208
266
|
if (nativeError.attErrorCode === ATT_INSUFFICIENT_AUTHENTICATION ||
|
|
209
267
|
nativeError.attErrorCode === ATT_INSUFFICIENT_ENCRYPTION ||
|
|
268
|
+
nativeError.androidErrorCode === ATT_INSUFFICIENT_AUTHENTICATION ||
|
|
269
|
+
nativeError.androidErrorCode === ATT_INSUFFICIENT_ENCRYPTION ||
|
|
210
270
|
nativeError.iosErrorCode === IOS_PEER_REMOVED_PAIRING_INFORMATION) {
|
|
211
271
|
return true;
|
|
212
272
|
}
|
|
@@ -256,6 +316,7 @@ class BleTransport {
|
|
|
256
316
|
const { check, ProtocolV1, parseConfigure } = transport__default["default"];
|
|
257
317
|
const Log = bleLogger;
|
|
258
318
|
const transportCache = {};
|
|
319
|
+
let bleManagerResetPromise;
|
|
259
320
|
const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 5;
|
|
260
321
|
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
|
|
261
322
|
const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
|
|
@@ -314,6 +375,17 @@ const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
|
|
|
314
375
|
const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
|
|
315
376
|
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
316
377
|
error.message.startsWith(WEDGED_WRITE_MESSAGE);
|
|
378
|
+
const shouldRethrowProtocolProbeError = (error) => {
|
|
379
|
+
const code = error === null || error === void 0 ? void 0 : error.errorCode;
|
|
380
|
+
return (hdShared.isBleStaleBondHardwareError(error) ||
|
|
381
|
+
isNativeBleDisconnectError(error) ||
|
|
382
|
+
code === hdShared.HardwareErrorCode.BleDeviceNotBonded ||
|
|
383
|
+
code === hdShared.HardwareErrorCode.BleDeviceBondedCanceled ||
|
|
384
|
+
code === hdShared.HardwareErrorCode.BleDeviceDisconnected ||
|
|
385
|
+
code === hdShared.HardwareErrorCode.BleCharacteristicNotifyError ||
|
|
386
|
+
code === hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure ||
|
|
387
|
+
code === hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
388
|
+
};
|
|
317
389
|
const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
318
390
|
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
319
391
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
@@ -404,10 +476,10 @@ const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void
|
|
|
404
476
|
}
|
|
405
477
|
});
|
|
406
478
|
const resolveNegotiatedMtu = (device) => requestNegotiatedMtu(device, 'connected', 0);
|
|
407
|
-
function remapError(error
|
|
479
|
+
function remapError(error) {
|
|
408
480
|
var _a;
|
|
409
481
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
410
|
-
if (
|
|
482
|
+
if (isNativeBleStaleBondError(error)) {
|
|
411
483
|
throw toBleStaleBondHardwareError(error);
|
|
412
484
|
}
|
|
413
485
|
if ((error === null || error === void 0 ? void 0 : error.attErrorCode) === 22) {
|
|
@@ -427,6 +499,7 @@ class ReactNativeBleTransport {
|
|
|
427
499
|
this.name = 'ReactNativeBleTransport';
|
|
428
500
|
this.configured = false;
|
|
429
501
|
this.stopped = false;
|
|
502
|
+
this.bondAbortController = new AbortController();
|
|
430
503
|
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
431
504
|
this.runPromise = null;
|
|
432
505
|
this.runPromiseDeviceId = null;
|
|
@@ -472,6 +545,7 @@ class ReactNativeBleTransport {
|
|
|
472
545
|
this.androidPriorityResetTimers = new Map();
|
|
473
546
|
this.nextMonitorToken = 1;
|
|
474
547
|
this.lifecycleOperations = new Map();
|
|
548
|
+
this.scanCleanups = new Set();
|
|
475
549
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
476
550
|
}
|
|
477
551
|
init(logger, emitter) {
|
|
@@ -500,10 +574,38 @@ class ReactNativeBleTransport {
|
|
|
500
574
|
listen() {
|
|
501
575
|
}
|
|
502
576
|
getPlxManager() {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
577
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
578
|
+
while (bleManagerResetPromise) {
|
|
579
|
+
yield this.waitForManagerReset();
|
|
580
|
+
}
|
|
581
|
+
if (this.stopped)
|
|
582
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
583
|
+
if (!this.blePlxManager)
|
|
584
|
+
this.blePlxManager = new reactNativeBlePlx.BleManager();
|
|
585
|
+
return this.blePlxManager;
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
waitForManagerReset() {
|
|
589
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
590
|
+
if (!bleManagerResetPromise)
|
|
591
|
+
return;
|
|
592
|
+
let timeout;
|
|
593
|
+
try {
|
|
594
|
+
yield Promise.race([
|
|
595
|
+
bleManagerResetPromise,
|
|
596
|
+
new Promise((_, reject) => {
|
|
597
|
+
timeout = setTimeout(() => reject(this.createWedgedBleSetupError()), BLE_CONNECT_TIMEOUT_MS);
|
|
598
|
+
}),
|
|
599
|
+
]);
|
|
600
|
+
}
|
|
601
|
+
catch (_a) {
|
|
602
|
+
throw this.createWedgedBleSetupError();
|
|
603
|
+
}
|
|
604
|
+
finally {
|
|
605
|
+
if (timeout)
|
|
606
|
+
clearTimeout(timeout);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
507
609
|
}
|
|
508
610
|
resolveCharacteristics(device) {
|
|
509
611
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -668,30 +770,55 @@ class ReactNativeBleTransport {
|
|
|
668
770
|
}
|
|
669
771
|
enumerate() {
|
|
670
772
|
return __awaiter(this, void 0, void 0, function* () {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
if (reactNative.
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
|
|
686
|
-
reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
|
|
687
|
-
]);
|
|
688
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
|
|
689
|
-
if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
|
|
690
|
-
resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
|
|
691
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
773
|
+
const scanStartedAt = Date.now();
|
|
774
|
+
let firstDeviceMs;
|
|
775
|
+
const blePlxManager = yield this.getPlxManager();
|
|
776
|
+
yield subscribeBleOn(blePlxManager);
|
|
777
|
+
if (reactNative.Platform.OS === 'android' && reactNative.Platform.Version >= 31) {
|
|
778
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, please wait...');
|
|
779
|
+
const resultConnect = yield reactNative.PermissionsAndroid.requestMultiple([
|
|
780
|
+
reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
|
|
781
|
+
reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
|
|
782
|
+
]);
|
|
783
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
|
|
784
|
+
if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
|
|
785
|
+
resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
|
|
786
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
|
|
694
787
|
}
|
|
788
|
+
}
|
|
789
|
+
if (this.stopped)
|
|
790
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
791
|
+
return new Promise((resolve, reject) => {
|
|
792
|
+
const deviceList = [];
|
|
793
|
+
let finished = false;
|
|
794
|
+
let scanCleanup;
|
|
795
|
+
const finishScan = (error) => {
|
|
796
|
+
if (scanCleanup)
|
|
797
|
+
return scanCleanup;
|
|
798
|
+
finished = true;
|
|
799
|
+
clearScanTimer();
|
|
800
|
+
scanCleanup = this.runNativeTeardown('scan', blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
|
|
801
|
+
yield blePlxManager.stopDeviceScan();
|
|
802
|
+
})).then(() => {
|
|
803
|
+
this.scanCleanups.delete(cancelScan);
|
|
804
|
+
if (error)
|
|
805
|
+
reject(error);
|
|
806
|
+
else
|
|
807
|
+
resolve(deviceList);
|
|
808
|
+
});
|
|
809
|
+
return scanCleanup;
|
|
810
|
+
};
|
|
811
|
+
const cancelScan = () => finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
|
|
812
|
+
this.scanCleanups.add(cancelScan);
|
|
813
|
+
const clearScanTimer = timer.timeout(() => {
|
|
814
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] scan completed', {
|
|
815
|
+
elapsedMs: Date.now() - scanStartedAt,
|
|
816
|
+
firstDeviceMs,
|
|
817
|
+
deviceCount: deviceList.length,
|
|
818
|
+
scanWindowMs: this.scanTimeout,
|
|
819
|
+
});
|
|
820
|
+
finishScan();
|
|
821
|
+
}, this.scanTimeout);
|
|
695
822
|
blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
|
|
696
823
|
allowDuplicates: true,
|
|
697
824
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
@@ -700,19 +827,17 @@ class ReactNativeBleTransport {
|
|
|
700
827
|
if (error) {
|
|
701
828
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
702
829
|
if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
|
|
703
|
-
|
|
830
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
704
831
|
}
|
|
705
832
|
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.BluetoothUnauthorized) {
|
|
706
|
-
|
|
833
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationError));
|
|
707
834
|
}
|
|
708
835
|
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.LocationServicesDisabled) {
|
|
709
|
-
|
|
710
|
-
}
|
|
711
|
-
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) {
|
|
712
|
-
timer.timeout(() => { }, this.scanTimeout);
|
|
836
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationServicesDisabled));
|
|
713
837
|
}
|
|
838
|
+
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) ;
|
|
714
839
|
else {
|
|
715
|
-
|
|
840
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, (_a = error.reason) !== null && _a !== void 0 ? _a : ''));
|
|
716
841
|
}
|
|
717
842
|
return;
|
|
718
843
|
}
|
|
@@ -737,6 +862,8 @@ class ReactNativeBleTransport {
|
|
|
737
862
|
});
|
|
738
863
|
}
|
|
739
864
|
});
|
|
865
|
+
if (finished)
|
|
866
|
+
return;
|
|
740
867
|
getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
|
|
741
868
|
for (const device of devices) {
|
|
742
869
|
const localName = 'localName' in device && typeof device.localName === 'string'
|
|
@@ -752,10 +879,11 @@ class ReactNativeBleTransport {
|
|
|
752
879
|
addDevice(device);
|
|
753
880
|
}
|
|
754
881
|
}
|
|
755
|
-
});
|
|
882
|
+
}, error => Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral failed:', error));
|
|
756
883
|
const addDevice = (device) => {
|
|
757
884
|
var _a;
|
|
758
|
-
if (deviceList.every(d => d.id !== device.id)) {
|
|
885
|
+
if (!finished && deviceList.every(d => d.id !== device.id)) {
|
|
886
|
+
firstDeviceMs !== null && firstDeviceMs !== void 0 ? firstDeviceMs : (firstDeviceMs = Date.now() - scanStartedAt);
|
|
759
887
|
const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
|
|
760
888
|
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
761
889
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
|
|
@@ -765,16 +893,14 @@ class ReactNativeBleTransport {
|
|
|
765
893
|
});
|
|
766
894
|
}
|
|
767
895
|
};
|
|
768
|
-
|
|
769
|
-
blePlxManager.stopDeviceScan();
|
|
770
|
-
resolve(deviceList);
|
|
771
|
-
}, this.scanTimeout);
|
|
772
|
-
}));
|
|
896
|
+
});
|
|
773
897
|
});
|
|
774
898
|
}
|
|
775
899
|
installTransportForAcquire(uuid, device, characteristics) {
|
|
776
900
|
return __awaiter(this, void 0, void 0, function* () {
|
|
777
901
|
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, device));
|
|
902
|
+
if (this.stopped)
|
|
903
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
778
904
|
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
779
905
|
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
|
|
780
906
|
const monitorToken = this.nextMonitorToken;
|
|
@@ -795,17 +921,23 @@ class ReactNativeBleTransport {
|
|
|
795
921
|
else if (reactNative.Platform.OS === 'android') {
|
|
796
922
|
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
797
923
|
}
|
|
924
|
+
if (this.stopped)
|
|
925
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
798
926
|
const initialMtu = transport$1.mtuSize;
|
|
799
927
|
let refreshAttempts = 0;
|
|
800
928
|
if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
|
|
801
929
|
shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
802
930
|
refreshAttempts += 1;
|
|
803
931
|
let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
|
|
932
|
+
if (this.stopped)
|
|
933
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
804
934
|
transport$1.device = refreshedDevice;
|
|
805
935
|
transport$1.mtuSize =
|
|
806
936
|
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
807
937
|
if (shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
808
938
|
yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
|
|
939
|
+
if (this.stopped)
|
|
940
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
809
941
|
refreshAttempts += 1;
|
|
810
942
|
refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
|
|
811
943
|
transport$1.device = refreshedDevice;
|
|
@@ -813,6 +945,8 @@ class ReactNativeBleTransport {
|
|
|
813
945
|
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
814
946
|
}
|
|
815
947
|
}
|
|
948
|
+
if (this.stopped)
|
|
949
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
816
950
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
|
|
817
951
|
platform: reactNative.Platform.OS,
|
|
818
952
|
requested: getRequestedBleMtu(),
|
|
@@ -835,6 +969,8 @@ class ReactNativeBleTransport {
|
|
|
835
969
|
acquireUnlocked(input) {
|
|
836
970
|
var _a;
|
|
837
971
|
return __awaiter(this, void 0, void 0, function* () {
|
|
972
|
+
if (this.stopped)
|
|
973
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
838
974
|
const { uuid, forceCleanRunPromise, expectedProtocol, skipProtocolProbe } = input;
|
|
839
975
|
const shouldMapProtocolV2StaleBond = expectedProtocol
|
|
840
976
|
? expectedProtocol === 'V2'
|
|
@@ -869,6 +1005,8 @@ class ReactNativeBleTransport {
|
|
|
869
1005
|
if (isCachedDeviceConnected &&
|
|
870
1006
|
cachedProtocol &&
|
|
871
1007
|
(!expectedProtocol || cachedProtocol === expectedProtocol)) {
|
|
1008
|
+
if (this.stopped)
|
|
1009
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
872
1010
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
|
|
873
1011
|
return { uuid, protocolType: cachedProtocol };
|
|
874
1012
|
}
|
|
@@ -892,15 +1030,27 @@ class ReactNativeBleTransport {
|
|
|
892
1030
|
Log === null || Log === void 0 ? void 0 : Log.debug('subscribeBleOn error: ', error);
|
|
893
1031
|
throw error;
|
|
894
1032
|
}
|
|
1033
|
+
if (this.stopped)
|
|
1034
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
895
1035
|
if (reactNative.Platform.OS === 'android') {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1036
|
+
try {
|
|
1037
|
+
const bondState = yield pairDevice(uuid);
|
|
1038
|
+
if (bondState.bonding) {
|
|
1039
|
+
yield onDeviceBondState(uuid, this.bondAbortController.signal);
|
|
1040
|
+
}
|
|
1041
|
+
else if (!bondState.bonded) {
|
|
1042
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
|
|
1043
|
+
}
|
|
899
1044
|
}
|
|
900
|
-
|
|
901
|
-
|
|
1045
|
+
catch (error) {
|
|
1046
|
+
yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1047
|
+
yield this.runBestEffortNativeOperation('bond failure: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid));
|
|
1048
|
+
}));
|
|
1049
|
+
throw error;
|
|
902
1050
|
}
|
|
903
1051
|
}
|
|
1052
|
+
if (this.stopped)
|
|
1053
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
904
1054
|
if (!device) {
|
|
905
1055
|
const devices = yield blePlxManager.devices([uuid]);
|
|
906
1056
|
[device] = devices;
|
|
@@ -931,7 +1081,7 @@ class ReactNativeBleTransport {
|
|
|
931
1081
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleAlreadyConnected);
|
|
932
1082
|
}
|
|
933
1083
|
else {
|
|
934
|
-
remapError(e
|
|
1084
|
+
remapError(e);
|
|
935
1085
|
}
|
|
936
1086
|
}
|
|
937
1087
|
}
|
|
@@ -955,23 +1105,44 @@ class ReactNativeBleTransport {
|
|
|
955
1105
|
try {
|
|
956
1106
|
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
957
1107
|
}
|
|
958
|
-
catch (
|
|
959
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ',
|
|
960
|
-
if (
|
|
1108
|
+
catch (fallbackError) {
|
|
1109
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', fallbackError);
|
|
1110
|
+
if (fallbackError.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
961
1111
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
|
|
962
1112
|
yield disconnectedDevice.cancelConnection();
|
|
963
1113
|
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
964
1114
|
}
|
|
1115
|
+
else {
|
|
1116
|
+
remapError(fallbackError);
|
|
1117
|
+
}
|
|
965
1118
|
}
|
|
966
1119
|
}
|
|
967
1120
|
else {
|
|
968
|
-
remapError(e
|
|
1121
|
+
remapError(e);
|
|
969
1122
|
}
|
|
970
1123
|
}
|
|
971
1124
|
}
|
|
1125
|
+
if (this.stopped)
|
|
1126
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1127
|
+
if (reactNative.Platform.OS === 'android' && !(yield device.isConnected().catch(() => false))) {
|
|
1128
|
+
const disconnectedDevice = device;
|
|
1129
|
+
yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1130
|
+
yield Promise.all([
|
|
1131
|
+
this.runBestEffortNativeOperation('connect failure: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid)),
|
|
1132
|
+
this.runBestEffortNativeOperation('connect failure: cancel device connection', () => disconnectedDevice.cancelConnection()),
|
|
1133
|
+
]);
|
|
1134
|
+
}));
|
|
1135
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'device is not connected');
|
|
1136
|
+
}
|
|
1137
|
+
if (this.stopped)
|
|
1138
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
972
1139
|
device = yield resolveNegotiatedMtu(device);
|
|
1140
|
+
if (this.stopped)
|
|
1141
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
973
1142
|
const acquiredDevice = device;
|
|
974
1143
|
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
|
|
1144
|
+
if (this.stopped)
|
|
1145
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
975
1146
|
const protocolHint = expectedProtocol
|
|
976
1147
|
? undefined
|
|
977
1148
|
: (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid);
|
|
@@ -1014,6 +1185,8 @@ class ReactNativeBleTransport {
|
|
|
1014
1185
|
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
|
|
1015
1186
|
yield this.installTransportForAcquire(uuid, acquiredDevice);
|
|
1016
1187
|
}));
|
|
1188
|
+
if (this.stopped)
|
|
1189
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1017
1190
|
const currentTransport = transportCache[uuid];
|
|
1018
1191
|
if (!currentTransport) {
|
|
1019
1192
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
@@ -1022,7 +1195,7 @@ class ReactNativeBleTransport {
|
|
|
1022
1195
|
return { uuid, protocolType };
|
|
1023
1196
|
}
|
|
1024
1197
|
catch (error) {
|
|
1025
|
-
if (hdShared.isBleStaleBondHardwareError(error)) {
|
|
1198
|
+
if (hdShared.isBleStaleBondHardwareError(error) || shouldRethrowProtocolProbeError(error)) {
|
|
1026
1199
|
yield this.disconnectUnlocked(uuid);
|
|
1027
1200
|
}
|
|
1028
1201
|
else {
|
|
@@ -1435,7 +1608,43 @@ class ReactNativeBleTransport {
|
|
|
1435
1608
|
});
|
|
1436
1609
|
}
|
|
1437
1610
|
stop() {
|
|
1611
|
+
var _a;
|
|
1612
|
+
if (this.stopPromise)
|
|
1613
|
+
return this.stopPromise;
|
|
1438
1614
|
this.stopped = true;
|
|
1615
|
+
this.bondAbortController.abort();
|
|
1616
|
+
const deviceIds = new Set([
|
|
1617
|
+
...this.monitorTokens.keys(),
|
|
1618
|
+
...this.sessionProtocols.keys(),
|
|
1619
|
+
...this.lifecycleOperations.keys(),
|
|
1620
|
+
...(this.runPromiseDeviceId ? [this.runPromiseDeviceId] : []),
|
|
1621
|
+
]);
|
|
1622
|
+
const scans = Array.from(this.scanCleanups, cleanup => cleanup());
|
|
1623
|
+
this.androidPriorityResetTimers.forEach(timeout => clearTimeout(timeout));
|
|
1624
|
+
this.androidPriorityResetTimers.clear();
|
|
1625
|
+
this.androidHighPriorityDevices.clear();
|
|
1626
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1627
|
+
(_a = this.runPromise) === null || _a === void 0 ? void 0 : _a.reject(error);
|
|
1628
|
+
this.runPromise = null;
|
|
1629
|
+
this.runPromiseDeviceId = null;
|
|
1630
|
+
deviceIds.forEach(uuid => this.rejectProtocolV2Frames(uuid, error));
|
|
1631
|
+
const manager = this.blePlxManager;
|
|
1632
|
+
const pendingConnections = manager
|
|
1633
|
+
? Array.from(this.lifecycleOperations.keys(), uuid => this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1634
|
+
yield this.runBestEffortNativeOperation('stop: cancel pending device connection', () => manager.cancelDeviceConnection(uuid));
|
|
1635
|
+
})))
|
|
1636
|
+
: [];
|
|
1637
|
+
this.stopPromise = Promise.all([
|
|
1638
|
+
...scans,
|
|
1639
|
+
...pendingConnections,
|
|
1640
|
+
...Array.from(deviceIds, uuid => this.disconnect(uuid)),
|
|
1641
|
+
]).then(() => __awaiter(this, void 0, void 0, function* () {
|
|
1642
|
+
yield this.protocolV2Links.invalidateAllLinks('React Native BLE transport stopped');
|
|
1643
|
+
yield this.waitForManagerReset();
|
|
1644
|
+
this.blePlxManager = undefined;
|
|
1645
|
+
this.emitter = undefined;
|
|
1646
|
+
}));
|
|
1647
|
+
return this.stopPromise;
|
|
1439
1648
|
}
|
|
1440
1649
|
disconnect(session) {
|
|
1441
1650
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1565,13 +1774,27 @@ class ReactNativeBleTransport {
|
|
|
1565
1774
|
});
|
|
1566
1775
|
}
|
|
1567
1776
|
cancel() {
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1777
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1778
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
|
|
1779
|
+
const pending = this.runPromise;
|
|
1780
|
+
const deviceId = this.runPromiseDeviceId;
|
|
1781
|
+
if (pending) {
|
|
1782
|
+
pending.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled));
|
|
1783
|
+
if (this.runPromise === pending) {
|
|
1784
|
+
this.runPromise = null;
|
|
1785
|
+
this.runPromiseDeviceId = null;
|
|
1786
|
+
}
|
|
1787
|
+
if (deviceId)
|
|
1788
|
+
yield this.disconnect(deviceId);
|
|
1789
|
+
}
|
|
1790
|
+
});
|
|
1572
1791
|
}
|
|
1573
1792
|
connectWithTimeout(uuid, connect) {
|
|
1574
1793
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1794
|
+
if (this.stopped)
|
|
1795
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1796
|
+
const startedAt = Date.now();
|
|
1797
|
+
let succeeded = false;
|
|
1575
1798
|
let timer;
|
|
1576
1799
|
let timedOut = false;
|
|
1577
1800
|
const pending = connect();
|
|
@@ -1586,6 +1809,7 @@ class ReactNativeBleTransport {
|
|
|
1586
1809
|
}, BLE_CONNECT_TIMEOUT_MS);
|
|
1587
1810
|
}),
|
|
1588
1811
|
]);
|
|
1812
|
+
succeeded = true;
|
|
1589
1813
|
return result;
|
|
1590
1814
|
}
|
|
1591
1815
|
catch (error) {
|
|
@@ -1600,11 +1824,19 @@ class ReactNativeBleTransport {
|
|
|
1600
1824
|
finally {
|
|
1601
1825
|
if (timer)
|
|
1602
1826
|
clearTimeout(timer);
|
|
1827
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] connect completed', {
|
|
1828
|
+
connectIdSuffix: uuid.slice(-8),
|
|
1829
|
+
elapsedMs: Date.now() - startedAt,
|
|
1830
|
+
succeeded,
|
|
1831
|
+
backstopExpired: timedOut,
|
|
1832
|
+
});
|
|
1603
1833
|
}
|
|
1604
1834
|
});
|
|
1605
1835
|
}
|
|
1606
1836
|
resolveCharacteristicsWithTimeout(uuid, device) {
|
|
1607
1837
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1838
|
+
const startedAt = Date.now();
|
|
1839
|
+
let succeeded = false;
|
|
1608
1840
|
let timer;
|
|
1609
1841
|
let timedOut = false;
|
|
1610
1842
|
const pending = this.resolveCharacteristics(device);
|
|
@@ -1620,6 +1852,7 @@ class ReactNativeBleTransport {
|
|
|
1620
1852
|
}),
|
|
1621
1853
|
]);
|
|
1622
1854
|
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1855
|
+
succeeded = true;
|
|
1623
1856
|
return result;
|
|
1624
1857
|
}
|
|
1625
1858
|
catch (error) {
|
|
@@ -1634,6 +1867,12 @@ class ReactNativeBleTransport {
|
|
|
1634
1867
|
finally {
|
|
1635
1868
|
if (timer)
|
|
1636
1869
|
clearTimeout(timer);
|
|
1870
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] GATT setup completed', {
|
|
1871
|
+
connectIdSuffix: uuid.slice(-8),
|
|
1872
|
+
elapsedMs: Date.now() - startedAt,
|
|
1873
|
+
succeeded,
|
|
1874
|
+
backstopExpired: timedOut,
|
|
1875
|
+
});
|
|
1637
1876
|
}
|
|
1638
1877
|
});
|
|
1639
1878
|
}
|
|
@@ -1735,6 +1974,8 @@ class ReactNativeBleTransport {
|
|
|
1735
1974
|
}
|
|
1736
1975
|
}
|
|
1737
1976
|
resetPlxManager() {
|
|
1977
|
+
if (bleManagerResetPromise)
|
|
1978
|
+
return;
|
|
1738
1979
|
const manager = this.blePlxManager;
|
|
1739
1980
|
this.blePlxManager = undefined;
|
|
1740
1981
|
const reason = 'React Native BLE manager reset';
|
|
@@ -1776,12 +2017,20 @@ class ReactNativeBleTransport {
|
|
|
1776
2017
|
this.connectionSetupTimeoutCounts.clear();
|
|
1777
2018
|
this.monitorTokens.clear();
|
|
1778
2019
|
this.protocolV2Assemblers.clear();
|
|
2020
|
+
let reset;
|
|
1779
2021
|
try {
|
|
1780
|
-
manager === null || manager === void 0 ? void 0 : manager.destroy();
|
|
2022
|
+
reset = Promise.resolve(manager === null || manager === void 0 ? void 0 : manager.destroy());
|
|
1781
2023
|
}
|
|
1782
2024
|
catch (error) {
|
|
1783
|
-
|
|
2025
|
+
reset = Promise.reject(error);
|
|
1784
2026
|
}
|
|
2027
|
+
bleManagerResetPromise = reset;
|
|
2028
|
+
reset.then(() => {
|
|
2029
|
+
if (bleManagerResetPromise === reset)
|
|
2030
|
+
bleManagerResetPromise = undefined;
|
|
2031
|
+
}, error => {
|
|
2032
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE manager destroy failed:', error);
|
|
2033
|
+
});
|
|
1785
2034
|
}
|
|
1786
2035
|
createProtocolMismatchError(expected) {
|
|
1787
2036
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
@@ -1931,7 +2180,7 @@ class ReactNativeBleTransport {
|
|
|
1931
2180
|
catch (error) {
|
|
1932
2181
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1933
2182
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
1934
|
-
if (
|
|
2183
|
+
if (shouldRethrowProtocolProbeError(error)) {
|
|
1935
2184
|
throw error;
|
|
1936
2185
|
}
|
|
1937
2186
|
return false;
|
|
@@ -1957,7 +2206,7 @@ class ReactNativeBleTransport {
|
|
|
1957
2206
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1958
2207
|
this.resetProtocolV2Frames(uuid);
|
|
1959
2208
|
},
|
|
1960
|
-
shouldRethrow:
|
|
2209
|
+
shouldRethrow: shouldRethrowProtocolProbeError,
|
|
1961
2210
|
});
|
|
1962
2211
|
if (!detected) {
|
|
1963
2212
|
this.clearProbeProtocol(uuid, 'V2');
|
|
@@ -2084,6 +2333,9 @@ class ReactNativeBleTransport {
|
|
|
2084
2333
|
this.rememberStaleBondError(uuid, bondError);
|
|
2085
2334
|
throw bondError;
|
|
2086
2335
|
}
|
|
2336
|
+
if (isNativeBleDisconnectError(error)) {
|
|
2337
|
+
throw toBleDisconnectHardwareError(error);
|
|
2338
|
+
}
|
|
2087
2339
|
if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
|
|
2088
2340
|
attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
2089
2341
|
throw error;
|