@onekeyfe/hd-transport-react-native 1.2.0-alpha.70 → 1.2.0-alpha.71

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.
@@ -3,7 +3,7 @@ export default class BleTransport {
3
3
  id: string;
4
4
  name: string;
5
5
  device: Device;
6
- mtuSize: number;
6
+ mtuSize: number | undefined;
7
7
  writeCharacteristic: Characteristic;
8
8
  notifyCharacteristic: Characteristic;
9
9
  notifySubscription?: Subscription;
@@ -1 +1 @@
1
- {"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEjF,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,SAA6B;IAEjC,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,SAAM;IAEb,mBAAmB,EAAE,cAAc,CAAC;IAEpC,oBAAoB,EAAE,cAAc,CAAC;IAErC,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAElC,sBAAsB,CAAC,EAAE,YAAY,CAAC;IAEtC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,YAAY,CAAC,EAAE,MAAM,CAAC;gBAGpB,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,cAAc,EACnC,oBAAoB,EAAE,cAAc;IAQhC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAOlD"}
1
+ {"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEjF,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,SAA6B;IAEjC,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAE5B,mBAAmB,EAAE,cAAc,CAAC;IAEpC,oBAAoB,EAAE,cAAc,CAAC;IAErC,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAElC,sBAAsB,CAAC,EAAE,YAAY,CAAC;IAEtC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,YAAY,CAAC,EAAE,MAAM,CAAC;gBAGpB,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,cAAc,EACnC,oBAAoB,EAAE,cAAc;IAQhC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAOlD"}
@@ -10,4 +10,10 @@ export declare function resolveProtocolV2PacketCapacity({ platform, iosPacketLen
10
10
  androidPacketLength?: number;
11
11
  mtu?: number | null;
12
12
  }): number;
13
+ export declare function shouldWriteProtocolV2WithResponse({ platform, highVolume, requestedWithResponse, characteristic, }: {
14
+ platform: BlePlatform;
15
+ highVolume: boolean;
16
+ requestedWithResponse?: boolean;
17
+ characteristic: BleWriteCapability;
18
+ }): boolean;
13
19
  //# sourceMappingURL=bleStrategy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bleStrategy.d.ts","sourceRoot":"","sources":["../src/bleStrategy.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sBAAsB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5C,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,kBAAkB,WAEvE;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,QAAQ,EACR,eAAmC,EACnC,mBAA2C,EAC3C,GAAG,GACJ,EAAE;IACD,QAAQ,EAAE,WAAW,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,UAWA"}
1
+ {"version":3,"file":"bleStrategy.d.ts","sourceRoot":"","sources":["../src/bleStrategy.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sBAAsB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5C,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,kBAAkB,WAEvE;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,QAAQ,EACR,eAA+C,EAC/C,mBAAuD,EACvD,GAAG,GACJ,EAAE;IACD,QAAQ,EAAE,WAAW,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,UAQA;AAED,wBAAgB,iCAAiC,CAAC,EAChD,QAAQ,EACR,UAAU,EACV,qBAAqB,EACrB,cAAc,GACf,EAAE;IACD,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,cAAc,EAAE,kBAAkB,CAAC;CACpC,WAIA"}
@@ -1,6 +1,7 @@
1
1
  export declare const IOS_PACKET_LENGTH = 128;
2
2
  export declare const ANDROID_PACKET_LENGTH = 192;
3
- export declare const ANDROID_DEFAULT_MTU = 23;
3
+ export declare const IOS_PROTOCOL_V2_PACKET_LENGTH = 244;
4
+ export declare const ANDROID_PROTOCOL_V2_PACKET_LENGTH = 514;
4
5
  export declare const getBluetoothServiceUuids: () => string[];
5
6
  export declare const getInfosForServiceUuid: (serviceUuid: string, deviceType: 'classic') => {
6
7
  serviceUuid: string;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA8BtC,eAAO,MAAM,wBAAwB,gBAA0B,CAAC;AAChE,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,cAAc,SAAS;iBA1BhE,MAAM;;;QA2CtB,CAAC;AAEF,eAAO,MAAM,gBAAgB,UAAW,MAAM,GAAG,IAAI,WACP,CAAC;AAE/C,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,UAAU,MAAM,GAAG,IAAI,YAGxE,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,eAAO,MAAM,iCAAiC,MAAM,CAAC;AA8BrD,eAAO,MAAM,wBAAwB,gBAA0B,CAAC;AAChE,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,cAAc,SAAS;iBA1BhE,MAAM;;;QA2CtB,CAAC;AAEF,eAAO,MAAM,gBAAgB,UAAW,MAAM,GAAG,IAAI,WACP,CAAC;AAE/C,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,UAAU,MAAM,GAAG,IAAI,YAGxE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ declare class BleTransport {
8
8
  id: string;
9
9
  name: string;
10
10
  device: Device;
11
- mtuSize: number;
11
+ mtuSize: number | undefined;
12
12
  writeCharacteristic: Characteristic;
13
13
  notifyCharacteristic: Characteristic;
14
14
  notifySubscription?: Subscription;
@@ -119,6 +119,9 @@ declare class ReactNativeBleTransport {
119
119
  private protocolV2Links;
120
120
  private monitorTokens;
121
121
  private disconnectEventTokens;
122
+ private protocolV2HighVolumeLogSignatures;
123
+ private androidHighPriorityDevices;
124
+ private androidPriorityResetTimers;
122
125
  private nextMonitorToken;
123
126
  constructor(options: TransportOptions);
124
127
  init(logger: any, emitter: EventEmitter): void;
@@ -194,6 +197,10 @@ declare class ReactNativeBleTransport {
194
197
  private writeProtocolV2Packet;
195
198
  private writeProtocolV2Frame;
196
199
  private callProtocolV2;
200
+ private clearAndroidPriorityResetTimer;
201
+ private enableAndroidHighConnectionPriority;
202
+ private scheduleAndroidBalancedConnectionPriority;
203
+ private restoreAndroidConnectionPriority;
197
204
  private createProtocolV2Adapter;
198
205
  getProtocolType(path: string): ProtocolType | undefined;
199
206
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -93,7 +93,8 @@ const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
93
93
 
94
94
  const IOS_PACKET_LENGTH = 128;
95
95
  const ANDROID_PACKET_LENGTH = 192;
96
- const ANDROID_DEFAULT_MTU = 23;
96
+ const IOS_PROTOCOL_V2_PACKET_LENGTH = 244;
97
+ const ANDROID_PROTOCOL_V2_PACKET_LENGTH = 514;
97
98
  const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
98
99
  const OneKeyServices = {
99
100
  classic: {
@@ -134,15 +135,20 @@ const isSameBleUuid = (left, right) => {
134
135
  function hasWritableCapability(characteristic) {
135
136
  return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
136
137
  }
137
- function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PACKET_LENGTH, androidPacketLength = ANDROID_PACKET_LENGTH, mtu, }) {
138
- if (platform === 'ios') {
139
- return iosPacketLength;
138
+ function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PROTOCOL_V2_PACKET_LENGTH, androidPacketLength = ANDROID_PROTOCOL_V2_PACKET_LENGTH, mtu, }) {
139
+ if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= 3) {
140
+ throw new Error(`Protocol V2 BLE requires a negotiated MTU, received: ${String(mtu)}`);
140
141
  }
141
- if (platform === 'android') {
142
- const payloadLength = Math.max((mtu !== null && mtu !== void 0 ? mtu : ANDROID_DEFAULT_MTU) - 3, 1);
143
- return Math.min(androidPacketLength, payloadLength);
144
- }
145
- return androidPacketLength;
142
+ const payloadLength = Math.floor(mtu) - 3;
143
+ const configuredPacketLength = platform === 'ios' ? iosPacketLength : androidPacketLength;
144
+ return Math.min(configuredPacketLength, payloadLength);
145
+ }
146
+ function shouldWriteProtocolV2WithResponse({ platform, highVolume, requestedWithResponse, characteristic, }) {
147
+ if (!characteristic.isWritableWithResponse)
148
+ return false;
149
+ if (!characteristic.isWritableWithoutResponse)
150
+ return true;
151
+ return requestedWithResponse === true || (platform === 'ios' && !highVolume);
146
152
  }
147
153
 
148
154
  const timer = process.env.NODE_ENV === 'development'
@@ -202,7 +208,6 @@ const isHeaderChunk = (chunk) => {
202
208
  class BleTransport {
203
209
  constructor(device, writeCharacteristic, notifyCharacteristic) {
204
210
  this.name = 'ReactNativeBleTransport';
205
- this.mtuSize = 23;
206
211
  this.id = device.id;
207
212
  this.device = device;
208
213
  this.writeCharacteristic = writeCharacteristic;
@@ -226,7 +231,6 @@ const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 :
226
231
  const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
227
232
  const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
228
233
  const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
229
- const IOS_PROTOCOL_V2_CONTROL_WRITE_DELAY_MS = 5;
230
234
  const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
231
235
  const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
232
236
  const ANDROID_GATT_CONGESTED_STATUS = 143;
@@ -285,8 +289,8 @@ const DEVICE_SCAN_TIMEOUT_MS = 3000;
285
289
  const IOS_NOTIFY_READY_DELAY_MS = 150;
286
290
  const ANDROID_NOTIFY_READY_DELAY_MS = 300;
287
291
  const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
288
- iosPacketLength: IOS_PACKET_LENGTH,
289
- androidPacketLength: ANDROID_PACKET_LENGTH,
292
+ iosPacketLength: IOS_PROTOCOL_V2_PACKET_LENGTH,
293
+ androidPacketLength: ANDROID_PROTOCOL_V2_PACKET_LENGTH,
290
294
  };
291
295
  let protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
292
296
  const normalizePositiveInteger = (value, fallback) => {
@@ -315,10 +319,15 @@ function inferProtocolHintFromDeviceName(name) {
315
319
  function getDeviceDisplayName(device) {
316
320
  return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
317
321
  }
318
- const ANDROID_REQUEST_MTU = 256;
322
+ const IOS_REQUEST_MTU = 247;
323
+ const ANDROID_REQUEST_MTU = 517;
324
+ const BLE_MTU_REFRESH_THRESHOLD = 247;
325
+ const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
326
+ const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
327
+ const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
319
328
  const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
320
329
  const connectOptions = {
321
- requestMTU: ANDROID_REQUEST_MTU,
330
+ requestMTU: getRequestedBleMtu(),
322
331
  timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
323
332
  refreshGatt: 'OnConnected',
324
333
  };
@@ -345,23 +354,25 @@ const tryToGetConfiguration = (device) => {
345
354
  return null;
346
355
  return infos;
347
356
  };
348
- const requestAndroidMtu = (device) => __awaiter(void 0, void 0, void 0, function* () {
349
- if (reactNative.Platform.OS !== 'android')
357
+ const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void 0, void 0, function* () {
358
+ if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
350
359
  return device;
351
360
  try {
352
- const mtuDevice = yield device.requestMTU(ANDROID_REQUEST_MTU);
353
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU configured', {
354
- deviceId: device.id,
355
- requested: ANDROID_REQUEST_MTU,
356
- actual: mtuDevice.mtu,
357
- });
361
+ const mtuDevice = yield device.requestMTU(getRequestedBleMtu());
358
362
  return mtuDevice;
359
363
  }
360
364
  catch (error) {
361
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android MTU request failed:', error);
365
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
366
+ platform: reactNative.Platform.OS,
367
+ stage,
368
+ attempt,
369
+ actual: device.mtu,
370
+ error: error instanceof Error ? error.message : String(error),
371
+ });
362
372
  return device;
363
373
  }
364
374
  });
375
+ const resolveNegotiatedMtu = (device) => requestNegotiatedMtu(device, 'connected', 0);
365
376
  function remapError(error) {
366
377
  var _a;
367
378
  if (error instanceof reactNativeBlePlx.BleError) {
@@ -423,6 +434,9 @@ class ReactNativeBleTransport {
423
434
  });
424
435
  this.monitorTokens = new Map();
425
436
  this.disconnectEventTokens = new Map();
437
+ this.protocolV2HighVolumeLogSignatures = new Map();
438
+ this.androidHighPriorityDevices = new Set();
439
+ this.androidPriorityResetTimers = new Map();
426
440
  this.nextMonitorToken = 1;
427
441
  this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
428
442
  }
@@ -739,9 +753,7 @@ class ReactNativeBleTransport {
739
753
  return __awaiter(this, void 0, void 0, function* () {
740
754
  const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, device));
741
755
  const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
742
- if (reactNative.Platform.OS === 'android') {
743
- transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport$1.mtuSize;
744
- }
756
+ transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
745
757
  const monitorToken = this.nextMonitorToken;
746
758
  this.nextMonitorToken += 1;
747
759
  const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
@@ -750,6 +762,7 @@ class ReactNativeBleTransport {
750
762
  this.monitorTokens.set(uuid, monitorToken);
751
763
  transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
752
764
  transportCache[uuid] = transport$1;
765
+ this.protocolV2HighVolumeLogSignatures.set(uuid, new Set());
753
766
  this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
754
767
  if (reactNative.Platform.OS === 'ios') {
755
768
  yield new Promise(resolve => {
@@ -759,6 +772,31 @@ class ReactNativeBleTransport {
759
772
  else if (reactNative.Platform.OS === 'android') {
760
773
  yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
761
774
  }
775
+ const initialMtu = transport$1.mtuSize;
776
+ let refreshAttempts = 0;
777
+ if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
778
+ (typeof transport$1.mtuSize !== 'number' || transport$1.mtuSize < BLE_MTU_REFRESH_THRESHOLD)) {
779
+ refreshAttempts += 1;
780
+ let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
781
+ transport$1.device = refreshedDevice;
782
+ transport$1.mtuSize =
783
+ typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
784
+ if (typeof transport$1.mtuSize !== 'number' || transport$1.mtuSize < BLE_MTU_REFRESH_THRESHOLD) {
785
+ yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
786
+ refreshAttempts += 1;
787
+ refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
788
+ transport$1.device = refreshedDevice;
789
+ transport$1.mtuSize =
790
+ typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
791
+ }
792
+ }
793
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
794
+ platform: reactNative.Platform.OS,
795
+ requested: getRequestedBleMtu(),
796
+ initial: initialMtu,
797
+ actual: transport$1.mtuSize,
798
+ refreshAttempts,
799
+ });
762
800
  return transport$1;
763
801
  });
764
802
  }
@@ -875,7 +913,7 @@ class ReactNativeBleTransport {
875
913
  }
876
914
  }
877
915
  }
878
- device = yield requestAndroidMtu(device);
916
+ device = yield resolveNegotiatedMtu(device);
879
917
  const acquiredDevice = device;
880
918
  const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
881
919
  const protocolHint = expectedProtocol
@@ -897,7 +935,7 @@ class ReactNativeBleTransport {
897
935
  if (!currentTransport) {
898
936
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
899
937
  }
900
- this.attachDisconnectSubscription(currentTransport, acquiredDevice, uuid);
938
+ this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
901
939
  return { uuid, protocolType };
902
940
  }
903
941
  catch (error) {
@@ -1036,6 +1074,7 @@ class ReactNativeBleTransport {
1036
1074
  this.resetProtocolV2Frames(uuid);
1037
1075
  return Promise.resolve(true);
1038
1076
  }
1077
+ yield this.restoreAndroidConnectionPriority(uuid, transport);
1039
1078
  if (transport) {
1040
1079
  if (this.monitorTokens.get(uuid) === transport.monitorToken) {
1041
1080
  this.monitorTokens.delete(uuid);
@@ -1056,6 +1095,7 @@ class ReactNativeBleTransport {
1056
1095
  }
1057
1096
  delete transportCache[uuid];
1058
1097
  }
1098
+ this.protocolV2HighVolumeLogSignatures.delete(uuid);
1059
1099
  this.deviceProtocol.delete(uuid);
1060
1100
  this.probingProtocols.delete(uuid);
1061
1101
  (_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
@@ -1800,8 +1840,12 @@ class ReactNativeBleTransport {
1800
1840
  }
1801
1841
  writeProtocolV2Packet(uuid, transport, base64, context, assertCurrentGeneration) {
1802
1842
  return __awaiter(this, void 0, void 0, function* () {
1803
- const shouldUseWriteWithResponse = transport.writeCharacteristic.isWritableWithResponse &&
1804
- (context.writeWithResponse === true || (reactNative.Platform.OS === 'ios' && !context.highVolume));
1843
+ const shouldUseWriteWithResponse = shouldWriteProtocolV2WithResponse({
1844
+ platform: reactNative.Platform.OS,
1845
+ highVolume: context.highVolume,
1846
+ requestedWithResponse: context.writeWithResponse,
1847
+ characteristic: transport.writeCharacteristic,
1848
+ });
1805
1849
  let attempt = 0;
1806
1850
  for (;;) {
1807
1851
  assertCurrentGeneration();
@@ -1847,27 +1891,21 @@ class ReactNativeBleTransport {
1847
1891
  platform: reactNative.Platform.OS,
1848
1892
  iosPacketLength: tuning.iosPacketLength,
1849
1893
  androidPacketLength: tuning.androidPacketLength,
1850
- mtu: reactNative.Platform.OS === 'android' ? transport$1.mtuSize : undefined,
1894
+ mtu: transport$1.mtuSize,
1851
1895
  });
1852
- const initialDelayMs = reactNative.Platform.OS === 'ios' && !context.highVolume && frame.length <= packetCapacity
1853
- ? IOS_PROTOCOL_V2_CONTROL_WRITE_DELAY_MS
1854
- : 0;
1855
1896
  yield transport.writeProtocolV2BleFrame({
1856
1897
  frame,
1857
1898
  packetCapacity,
1858
1899
  assertActive: assertCurrentGeneration,
1859
1900
  signal: context.signal,
1860
1901
  abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
1861
- initialDelayMs,
1862
- burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
1863
- burstPauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
1864
- flushDelayMs: FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS,
1865
1902
  wait: delay,
1866
1903
  writePacket: packet => this.writeProtocolV2Packet(uuid, transport$1, buffer.Buffer.from(packet).toString('base64'), context, assertCurrentGeneration),
1867
1904
  });
1868
1905
  });
1869
1906
  }
1870
1907
  callProtocolV2(uuid, name, data, options) {
1908
+ var _a;
1871
1909
  return __awaiter(this, void 0, void 0, function* () {
1872
1910
  if (!this._messages || !this._messagesV2) {
1873
1911
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
@@ -1876,11 +1914,35 @@ class ReactNativeBleTransport {
1876
1914
  const highVolumeWrite = transport.LogBlockCommand.has(name);
1877
1915
  if (highVolumeWrite) {
1878
1916
  const tuning = getProtocolV2BleTuning();
1879
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
1880
- name,
1881
- writeMode: (options === null || options === void 0 ? void 0 : options.writeWithResponse) ? 'withResponse' : 'withoutResponse',
1882
- packetCapacity: reactNative.Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength,
1917
+ const currentTransport = this.getCachedTransport(uuid);
1918
+ const writeWithResponse = shouldWriteProtocolV2WithResponse({
1919
+ platform: reactNative.Platform.OS,
1920
+ highVolume: true,
1921
+ requestedWithResponse: options === null || options === void 0 ? void 0 : options.writeWithResponse,
1922
+ characteristic: currentTransport.writeCharacteristic,
1883
1923
  });
1924
+ const packetCapacity = resolveProtocolV2PacketCapacity({
1925
+ platform: reactNative.Platform.OS,
1926
+ iosPacketLength: tuning.iosPacketLength,
1927
+ androidPacketLength: tuning.androidPacketLength,
1928
+ mtu: currentTransport.mtuSize,
1929
+ });
1930
+ const writeMode = writeWithResponse ? 'withResponse' : 'withoutResponse';
1931
+ const logSignature = `${name}:${writeMode}:${String(currentTransport.mtuSize)}:${packetCapacity}`;
1932
+ const loggedSignatures = (_a = this.protocolV2HighVolumeLogSignatures.get(uuid)) !== null && _a !== void 0 ? _a : new Set();
1933
+ if (!loggedSignatures.has(logSignature)) {
1934
+ loggedSignatures.add(logSignature);
1935
+ this.protocolV2HighVolumeLogSignatures.set(uuid, loggedSignatures);
1936
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
1937
+ name,
1938
+ writeMode,
1939
+ reportedMtu: currentTransport.mtuSize,
1940
+ packetCapacity,
1941
+ });
1942
+ }
1943
+ }
1944
+ if (highVolumeWrite) {
1945
+ yield this.enableAndroidHighConnectionPriority(uuid);
1884
1946
  }
1885
1947
  try {
1886
1948
  return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
@@ -1889,6 +1951,71 @@ class ReactNativeBleTransport {
1889
1951
  Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
1890
1952
  throw e;
1891
1953
  }
1954
+ finally {
1955
+ if (highVolumeWrite) {
1956
+ this.scheduleAndroidBalancedConnectionPriority(uuid);
1957
+ }
1958
+ }
1959
+ });
1960
+ }
1961
+ clearAndroidPriorityResetTimer(uuid) {
1962
+ const timerId = this.androidPriorityResetTimers.get(uuid);
1963
+ if (timerId !== undefined) {
1964
+ clearTimeout(timerId);
1965
+ this.androidPriorityResetTimers.delete(uuid);
1966
+ }
1967
+ }
1968
+ enableAndroidHighConnectionPriority(uuid) {
1969
+ return __awaiter(this, void 0, void 0, function* () {
1970
+ if (reactNative.Platform.OS !== 'android')
1971
+ return;
1972
+ this.clearAndroidPriorityResetTimer(uuid);
1973
+ if (this.androidHighPriorityDevices.has(uuid))
1974
+ return;
1975
+ const transport = transportCache[uuid];
1976
+ if (!transport)
1977
+ return;
1978
+ try {
1979
+ transport.device = yield transport.device.requestConnectionPriority(reactNativeBlePlx.ConnectionPriority.High);
1980
+ this.androidHighPriorityDevices.add(uuid);
1981
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
1982
+ priority: 'high',
1983
+ });
1984
+ }
1985
+ catch (error) {
1986
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE high priority request failed', {
1987
+ error: error instanceof Error ? error.message : String(error),
1988
+ });
1989
+ }
1990
+ });
1991
+ }
1992
+ scheduleAndroidBalancedConnectionPriority(uuid) {
1993
+ if (reactNative.Platform.OS !== 'android' || !this.androidHighPriorityDevices.has(uuid))
1994
+ return;
1995
+ this.clearAndroidPriorityResetTimer(uuid);
1996
+ const timerId = setTimeout(() => {
1997
+ this.androidPriorityResetTimers.delete(uuid);
1998
+ this.restoreAndroidConnectionPriority(uuid, transportCache[uuid]).catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE priority restore failed', error));
1999
+ }, ANDROID_HIGH_PRIORITY_IDLE_MS);
2000
+ this.androidPriorityResetTimers.set(uuid, timerId);
2001
+ }
2002
+ restoreAndroidConnectionPriority(uuid, transport) {
2003
+ return __awaiter(this, void 0, void 0, function* () {
2004
+ this.clearAndroidPriorityResetTimer(uuid);
2005
+ if (reactNative.Platform.OS !== 'android' || !this.androidHighPriorityDevices.delete(uuid) || !transport) {
2006
+ return;
2007
+ }
2008
+ try {
2009
+ transport.device = yield transport.device.requestConnectionPriority(reactNativeBlePlx.ConnectionPriority.Balanced);
2010
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
2011
+ priority: 'balanced',
2012
+ });
2013
+ }
2014
+ catch (error) {
2015
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE balanced priority request failed', {
2016
+ error: error instanceof Error ? error.message : String(error),
2017
+ });
2018
+ }
1892
2019
  });
1893
2020
  }
1894
2021
  createProtocolV2Adapter(uuid) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-react-native",
3
- "version": "1.2.0-alpha.70",
3
+ "version": "1.2.0-alpha.71",
4
4
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -20,11 +20,11 @@
20
20
  "lint:fix": "eslint . --fix"
21
21
  },
22
22
  "dependencies": {
23
- "@onekeyfe/hd-core": "1.2.0-alpha.70",
24
- "@onekeyfe/hd-shared": "1.2.0-alpha.70",
25
- "@onekeyfe/hd-transport": "1.2.0-alpha.70",
23
+ "@onekeyfe/hd-core": "1.2.0-alpha.71",
24
+ "@onekeyfe/hd-shared": "1.2.0-alpha.71",
25
+ "@onekeyfe/hd-transport": "1.2.0-alpha.71",
26
26
  "@onekeyfe/react-native-ble-utils": "^0.1.6",
27
27
  "react-native-ble-plx": "3.5.1"
28
28
  },
29
- "gitHead": "d86b033cf970f97e060c49fe4cf618f38b9ce666"
29
+ "gitHead": "c58f39f2e5c54a98faa8844cd8b6b0453a17d80c"
30
30
  }
@@ -9,7 +9,7 @@ export default class BleTransport {
9
9
 
10
10
  device: Device;
11
11
 
12
- mtuSize = 23;
12
+ mtuSize: number | undefined;
13
13
 
14
14
  writeCharacteristic: Characteristic;
15
15
 
@@ -1,4 +1,8 @@
1
- import { hasWritableCapability, resolveProtocolV2PacketCapacity } from '../bleStrategy';
1
+ import {
2
+ hasWritableCapability,
3
+ resolveProtocolV2PacketCapacity,
4
+ shouldWriteProtocolV2WithResponse,
5
+ } from '../bleStrategy';
2
6
 
3
7
  describe('React Native BLE strategy', () => {
4
8
  test('accepts writeWithoutResponse-only characteristics', () => {
@@ -10,27 +14,35 @@ describe('React Native BLE strategy', () => {
10
14
  expect(hasWritableCapability(characteristic)).toBe(true);
11
15
  });
12
16
 
13
- test('falls back to Android default ATT payload when MTU is unavailable', () => {
14
- expect(
17
+ test('rejects Protocol V2 packet sizing when MTU is unavailable', () => {
18
+ expect(() =>
15
19
  resolveProtocolV2PacketCapacity({
16
20
  platform: 'android',
17
- androidPacketLength: 192,
18
21
  mtu: null,
19
22
  })
20
- ).toBe(20);
23
+ ).toThrow('Protocol V2 BLE requires a negotiated MTU');
21
24
  });
22
25
 
23
26
  test('caps Android packet length by negotiated MTU payload', () => {
24
27
  expect(
25
28
  resolveProtocolV2PacketCapacity({
26
29
  platform: 'android',
27
- androidPacketLength: 192,
30
+ androidPacketLength: 244,
28
31
  mtu: 100,
29
32
  })
30
33
  ).toBe(97);
31
34
  });
32
35
 
33
- test('keeps iOS packet length controlled by tuning profile', () => {
36
+ test('uses the Android 517 MTU payload when fully negotiated', () => {
37
+ expect(
38
+ resolveProtocolV2PacketCapacity({
39
+ platform: 'android',
40
+ mtu: 517,
41
+ })
42
+ ).toBe(514);
43
+ });
44
+
45
+ test('caps iOS packet length by the system-negotiated write payload', () => {
34
46
  expect(
35
47
  resolveProtocolV2PacketCapacity({
36
48
  platform: 'ios',
@@ -39,4 +51,62 @@ describe('React Native BLE strategy', () => {
39
51
  })
40
52
  ).toBe(244);
41
53
  });
54
+
55
+ test('uses the reported iOS MTU without a compatibility fallback', () => {
56
+ expect(
57
+ resolveProtocolV2PacketCapacity({
58
+ platform: 'ios',
59
+ iosPacketLength: 128,
60
+ mtu: 23,
61
+ })
62
+ ).toBe(20);
63
+ });
64
+
65
+ test('uses a smaller system-negotiated iOS write payload', () => {
66
+ expect(
67
+ resolveProtocolV2PacketCapacity({
68
+ platform: 'ios',
69
+ iosPacketLength: 244,
70
+ mtu: 185,
71
+ })
72
+ ).toBe(182);
73
+ });
74
+
75
+ test('uses withoutResponse for a high-volume write unless explicitly overridden', () => {
76
+ const characteristic = {
77
+ isWritableWithResponse: true,
78
+ isWritableWithoutResponse: true,
79
+ };
80
+
81
+ expect(
82
+ shouldWriteProtocolV2WithResponse({
83
+ platform: 'ios',
84
+ highVolume: true,
85
+ requestedWithResponse: false,
86
+ characteristic,
87
+ })
88
+ ).toBe(false);
89
+ expect(
90
+ shouldWriteProtocolV2WithResponse({
91
+ platform: 'ios',
92
+ highVolume: true,
93
+ requestedWithResponse: true,
94
+ characteristic,
95
+ })
96
+ ).toBe(true);
97
+ });
98
+
99
+ test('falls back to withResponse when withoutResponse is unavailable', () => {
100
+ expect(
101
+ shouldWriteProtocolV2WithResponse({
102
+ platform: 'ios',
103
+ highVolume: true,
104
+ requestedWithResponse: false,
105
+ characteristic: {
106
+ isWritableWithResponse: true,
107
+ isWritableWithoutResponse: false,
108
+ },
109
+ })
110
+ ).toBe(true);
111
+ });
42
112
  });
@@ -7,6 +7,7 @@ import transportPackage, {
7
7
  import { HardwareErrorCode, createDeferred } from '@onekeyfe/hd-shared';
8
8
 
9
9
  import ReactNativeBleTransport, {
10
+ BLE_WRITE_PACKET_TIMEOUT_MS,
10
11
  configureProtocolV2BleTuning,
11
12
  getFirmwareUploadWriteRetryType,
12
13
  resetProtocolV2BleTuning,
@@ -32,6 +33,7 @@ jest.mock('react-native-ble-plx', () => ({
32
33
  CharacteristicNotFound: 404,
33
34
  },
34
35
  BleManager: jest.fn(),
36
+ ConnectionPriority: { Balanced: 0, High: 1, LowPower: 2 },
35
37
  ScanMode: { LowLatency: 2 },
36
38
  }));
37
39
 
@@ -157,6 +159,7 @@ const createHarness = ({
157
159
  id: uuid,
158
160
  name: deviceName,
159
161
  localName: deviceName,
162
+ mtu: 247,
160
163
  serviceUUIDs: ['00000001-0000-1000-8000-00805f9b34fb'],
161
164
  isConnected: jest.fn(() => Promise.resolve(true)),
162
165
  cancelConnection: jest.fn(() => Promise.resolve()),
@@ -164,7 +167,9 @@ const createHarness = ({
164
167
  disconnectCallback = callback;
165
168
  return { remove: jest.fn() };
166
169
  }),
167
- };
170
+ } as any;
171
+ device.requestMTU = jest.fn(() => Promise.resolve(device));
172
+ device.requestConnectionPriority = jest.fn(() => Promise.resolve(device));
168
173
  const bleManager = {
169
174
  devices: jest.fn(() => Promise.resolve([device])),
170
175
  connectedDevices: jest.fn(() => Promise.resolve([])),
@@ -172,18 +177,21 @@ const createHarness = ({
172
177
  };
173
178
  const transport = new ReactNativeBleTransport({ scanTimeout: 1 });
174
179
  const emitter = new EventEmitter();
180
+ const logger = { debug: jest.fn(), error: jest.fn() };
175
181
  transport.blePlxManager = bleManager;
176
182
  transport.resolveCharacteristics = jest.fn(() =>
177
183
  Promise.resolve({ writeCharacteristic, notifyCharacteristic })
178
184
  );
179
- transport.init({ debug: jest.fn(), error: jest.fn() }, emitter);
185
+ transport.init(logger, emitter);
180
186
  transport.configure(protocolV1Schema);
181
187
  transport.configureProtocolV2(protocolV2Schema);
182
188
 
183
189
  return {
184
190
  transport,
185
191
  emitter,
192
+ logger,
186
193
  uuid,
194
+ device,
187
195
  sentSeqs,
188
196
  writeCharacteristic,
189
197
  setShouldRespond(value: boolean) {
@@ -247,6 +255,7 @@ const createV1Harness = ({
247
255
  id: uuid,
248
256
  name: 'OneKey Classic',
249
257
  localName: 'OneKey Classic',
258
+ mtu: 247,
250
259
  serviceUUIDs: ['00000001-0000-1000-8000-00805f9b34fb'],
251
260
  isConnected: jest.fn(() => Promise.resolve(true)),
252
261
  cancelConnection: jest.fn(() => Promise.resolve()),
@@ -255,7 +264,8 @@ const createV1Harness = ({
255
264
  disconnectSubscriptionRemovers.push(remove);
256
265
  return { remove };
257
266
  }),
258
- };
267
+ } as any;
268
+ device.requestMTU = jest.fn(() => Promise.resolve(device));
259
269
  const transport = new ReactNativeBleTransport({ scanTimeout: 1 });
260
270
  const bleManager = {
261
271
  devices: jest.fn(() => Promise.resolve([device])),
@@ -392,7 +402,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
392
402
  });
393
403
 
394
404
  test('actively probes Protocol V2 on iOS when only a name-derived hint is available', async () => {
395
- const { transport, uuid, sentSeqs, writeCharacteristic } = createHarness({
405
+ const { transport, uuid, device, sentSeqs, writeCharacteristic } = createHarness({
396
406
  deviceName: 'Pro2 6E9E',
397
407
  });
398
408
 
@@ -400,6 +410,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
400
410
  uuid,
401
411
  protocolType: 'V2',
402
412
  });
413
+ expect(device.requestMTU).toHaveBeenCalledWith(247);
403
414
  expect(writeCharacteristic.writeWithResponse).toHaveBeenCalledTimes(1);
404
415
 
405
416
  await expect(
@@ -429,6 +440,57 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
429
440
  await transport.release(uuid, true);
430
441
  });
431
442
 
443
+ test('continues with the current MTU when the connected snapshot refresh fails', async () => {
444
+ const { transport, uuid, device } = createHarness();
445
+ const mtuError = new Error('MTU refresh failed');
446
+ device.requestMTU.mockRejectedValueOnce(mtuError);
447
+
448
+ await expect(transport.acquire({ uuid })).resolves.toEqual({
449
+ uuid,
450
+ protocolType: 'V2',
451
+ });
452
+ expect(device.requestMTU).toHaveBeenCalledTimes(1);
453
+ expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(247);
454
+ await transport.release(uuid, true);
455
+ });
456
+
457
+ test('refreshes a transient bootloader MTU after notifications are ready', async () => {
458
+ const { transport, uuid, device } = createHarness();
459
+ device.mtu = 23;
460
+ device.requestMTU
461
+ .mockResolvedValueOnce(device)
462
+ .mockResolvedValueOnce(device)
463
+ .mockImplementationOnce(() => {
464
+ device.mtu = 247;
465
+ return Promise.resolve(device);
466
+ });
467
+
468
+ await expect(transport.acquire({ uuid })).resolves.toEqual({
469
+ uuid,
470
+ protocolType: 'V2',
471
+ });
472
+ expect(device.requestMTU).toHaveBeenCalledTimes(3);
473
+ expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(247);
474
+ await transport.release(uuid, true);
475
+ });
476
+
477
+ test('continues with a low bootloader MTU when the bounded retry fails', async () => {
478
+ const { transport, uuid, device } = createHarness();
479
+ device.mtu = 23;
480
+ device.requestMTU
481
+ .mockResolvedValueOnce(device)
482
+ .mockResolvedValueOnce(device)
483
+ .mockRejectedValueOnce(new Error('bootloader MTU retry failed'));
484
+
485
+ await expect(transport.acquire({ uuid })).resolves.toEqual({
486
+ uuid,
487
+ protocolType: 'V2',
488
+ });
489
+ expect(device.requestMTU).toHaveBeenCalledTimes(3);
490
+ expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(23);
491
+ await transport.release(uuid, true);
492
+ });
493
+
432
494
  test('reconnects before falling back to Protocol V1 after a fatal V2 probe failure', async () => {
433
495
  setPlatformOS('android');
434
496
  const { transport, uuid, device, notifySubscriptionRemovers, disconnectSubscriptionRemovers } =
@@ -564,16 +626,40 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
564
626
  });
565
627
 
566
628
  test('keeps iOS Protocol V2 high-volume calls on withoutResponse', async () => {
567
- const { transport, uuid, writeCharacteristic } = createHarness();
629
+ const { transport, uuid, logger, writeCharacteristic } = createHarness();
568
630
 
569
631
  await transport.acquire({ uuid, expectedProtocol: 'V2' });
570
632
 
571
633
  await transport.call(uuid, 'FileWrite', {});
572
- expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(1);
634
+ await transport.call(uuid, 'FileWrite', {});
635
+ expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(2);
573
636
  expect(writeCharacteristic.writeWithResponse).not.toHaveBeenCalled();
637
+ expect(
638
+ logger.debug.mock.calls.filter(
639
+ ([message]) =>
640
+ message === '[ReactNativeBleTransport] Protocol V2 high-volume write configured'
641
+ )
642
+ ).toHaveLength(1);
574
643
  await transport.release(uuid, true);
575
644
  });
576
645
 
646
+ test('uses Android 517 MTU and high connection priority during Protocol V2 high-volume calls', async () => {
647
+ setPlatformOS('android');
648
+ const { transport, uuid, device } = createHarness();
649
+
650
+ await transport.acquire({ uuid, expectedProtocol: 'V2' });
651
+ expect(device.requestMTU).toHaveBeenCalledWith(517);
652
+
653
+ await transport.call(uuid, 'FileWrite', {});
654
+ await transport.call(uuid, 'FileWrite', {});
655
+
656
+ expect(device.requestConnectionPriority).toHaveBeenCalledTimes(1);
657
+ expect(device.requestConnectionPriority).toHaveBeenCalledWith(1);
658
+
659
+ await transport.release(uuid, true);
660
+ expect(device.requestConnectionPriority).toHaveBeenLastCalledWith(0);
661
+ });
662
+
577
663
  test('uses withResponse for an iOS Protocol V2 firmware file write when requested', async () => {
578
664
  const { transport, uuid, writeCharacteristic } = createHarness();
579
665
 
@@ -630,7 +716,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
630
716
  expect(writeWithoutResponse).not.toHaveBeenCalled();
631
717
  });
632
718
 
633
- test('paces a one-packet Protocol V2 control write on iOS', async () => {
719
+ test('does not pace a one-packet Protocol V2 control write on iOS', async () => {
634
720
  const transport = new ReactNativeBleTransport({ scanTimeout: 1 }) as any;
635
721
  const writeWithoutResponse = jest.fn().mockResolvedValue(undefined);
636
722
  const bleTransport = {
@@ -656,11 +742,10 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
656
742
  jest.fn()
657
743
  );
658
744
 
659
- await Promise.resolve();
660
- expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), 5);
661
- expect(writeWithoutResponse).not.toHaveBeenCalled();
662
-
663
745
  await call;
746
+ expect(setTimeoutSpy.mock.calls.map(([, timeout]) => timeout)).toEqual([
747
+ BLE_WRITE_PACKET_TIMEOUT_MS,
748
+ ]);
664
749
  expect(writeWithoutResponse).toHaveBeenCalledTimes(1);
665
750
  } finally {
666
751
  setTimeoutSpy.mockRestore();
@@ -766,4 +851,40 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
766
851
  ).rejects.toMatchObject({ errorCode: 205 });
767
852
  expect(writeWithoutResponse).toHaveBeenCalledTimes(1);
768
853
  });
854
+
855
+ test('does not apply fixed burst or flush pauses to high-volume Protocol V2 writes', async () => {
856
+ const transport = new ReactNativeBleTransport({ scanTimeout: 1 }) as any;
857
+ const writeWithoutResponse = jest.fn().mockResolvedValue(undefined);
858
+ const bleTransport = {
859
+ mtuSize: 247,
860
+ writeCharacteristic: { writeWithoutResponse },
861
+ };
862
+ const context = {
863
+ messageName: 'FileWrite',
864
+ timeoutMs: 1000,
865
+ highVolume: true,
866
+ generation: 1,
867
+ signal: new AbortController().signal,
868
+ };
869
+ const setTimeoutSpy = jest.spyOn(global, 'setTimeout');
870
+
871
+ try {
872
+ await transport.writeProtocolV2Frame(
873
+ 'test-device',
874
+ bleTransport,
875
+ new Uint8Array(600),
876
+ context,
877
+ jest.fn()
878
+ );
879
+
880
+ expect(writeWithoutResponse).toHaveBeenCalledTimes(3);
881
+ expect(setTimeoutSpy.mock.calls.map(([, timeout]) => timeout)).toEqual([
882
+ BLE_WRITE_PACKET_TIMEOUT_MS,
883
+ BLE_WRITE_PACKET_TIMEOUT_MS,
884
+ BLE_WRITE_PACKET_TIMEOUT_MS,
885
+ ]);
886
+ } finally {
887
+ setTimeoutSpy.mockRestore();
888
+ }
889
+ });
769
890
  });
@@ -1,4 +1,4 @@
1
- import { ANDROID_DEFAULT_MTU, ANDROID_PACKET_LENGTH, IOS_PACKET_LENGTH } from './constants';
1
+ import { ANDROID_PROTOCOL_V2_PACKET_LENGTH, IOS_PROTOCOL_V2_PACKET_LENGTH } from './constants';
2
2
 
3
3
  export type BlePlatform = 'ios' | 'android' | string;
4
4
 
@@ -13,8 +13,8 @@ export function hasWritableCapability(characteristic: BleWriteCapability) {
13
13
 
14
14
  export function resolveProtocolV2PacketCapacity({
15
15
  platform,
16
- iosPacketLength = IOS_PACKET_LENGTH,
17
- androidPacketLength = ANDROID_PACKET_LENGTH,
16
+ iosPacketLength = IOS_PROTOCOL_V2_PACKET_LENGTH,
17
+ androidPacketLength = ANDROID_PROTOCOL_V2_PACKET_LENGTH,
18
18
  mtu,
19
19
  }: {
20
20
  platform: BlePlatform;
@@ -22,14 +22,27 @@ export function resolveProtocolV2PacketCapacity({
22
22
  androidPacketLength?: number;
23
23
  mtu?: number | null;
24
24
  }) {
25
- if (platform === 'ios') {
26
- return iosPacketLength;
25
+ if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= 3) {
26
+ throw new Error(`Protocol V2 BLE requires a negotiated MTU, received: ${String(mtu)}`);
27
27
  }
28
28
 
29
- if (platform === 'android') {
30
- const payloadLength = Math.max((mtu ?? ANDROID_DEFAULT_MTU) - 3, 1);
31
- return Math.min(androidPacketLength, payloadLength);
32
- }
29
+ const payloadLength = Math.floor(mtu) - 3;
30
+ const configuredPacketLength = platform === 'ios' ? iosPacketLength : androidPacketLength;
31
+ return Math.min(configuredPacketLength, payloadLength);
32
+ }
33
33
 
34
- return androidPacketLength;
34
+ export function shouldWriteProtocolV2WithResponse({
35
+ platform,
36
+ highVolume,
37
+ requestedWithResponse,
38
+ characteristic,
39
+ }: {
40
+ platform: BlePlatform;
41
+ highVolume: boolean;
42
+ requestedWithResponse?: boolean;
43
+ characteristic: BleWriteCapability;
44
+ }) {
45
+ if (!characteristic.isWritableWithResponse) return false;
46
+ if (!characteristic.isWritableWithoutResponse) return true;
47
+ return requestedWithResponse === true || (platform === 'ios' && !highVolume);
35
48
  }
package/src/constants.ts CHANGED
@@ -2,7 +2,8 @@ import { createKnownBleUuidAliases, matchesKnownBleUuid } from '@onekeyfe/hd-sha
2
2
 
3
3
  export const IOS_PACKET_LENGTH = 128;
4
4
  export const ANDROID_PACKET_LENGTH = 192;
5
- export const ANDROID_DEFAULT_MTU = 23;
5
+ export const IOS_PROTOCOL_V2_PACKET_LENGTH = 244;
6
+ export const ANDROID_PROTOCOL_V2_PACKET_LENGTH = 514;
6
7
 
7
8
  type BluetoothServices = Record<
8
9
  string,
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  BleError,
6
6
  BleErrorCode,
7
7
  BleManager as BlePlxManager,
8
+ ConnectionPriority,
8
9
  ScanMode,
9
10
  } from 'react-native-ble-plx';
10
11
  import ByteBuffer from 'bytebuffer';
@@ -32,11 +33,17 @@ import {
32
33
  } from '@onekeyfe/hd-shared';
33
34
 
34
35
  import { getConnectedDeviceIds, onDeviceBondState, pairDevice } from './BleManager';
35
- import { hasWritableCapability, resolveProtocolV2PacketCapacity } from './bleStrategy';
36
+ import {
37
+ hasWritableCapability,
38
+ resolveProtocolV2PacketCapacity,
39
+ shouldWriteProtocolV2WithResponse,
40
+ } from './bleStrategy';
36
41
  import { subscribeBleOn } from './subscribeBleOn';
37
42
  import {
38
43
  ANDROID_PACKET_LENGTH,
44
+ ANDROID_PROTOCOL_V2_PACKET_LENGTH,
39
45
  IOS_PACKET_LENGTH,
46
+ IOS_PROTOCOL_V2_PACKET_LENGTH,
40
47
  getBluetoothServiceUuids,
41
48
  getInfosForServiceUuid,
42
49
  isSameBleUuid,
@@ -61,7 +68,6 @@ const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = Platform.OS === 'ios' ? 4 : 5;
61
68
  const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = Platform.OS === 'ios' ? 8 : 10;
62
69
  const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = Platform.OS === 'ios' ? 24 : 30;
63
70
  const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
64
- const IOS_PROTOCOL_V2_CONTROL_WRITE_DELAY_MS = 5;
65
71
  const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
66
72
  const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY =
67
73
  Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
@@ -162,8 +168,8 @@ export type ProtocolV2BleTuning = {
162
168
  type ResolvedProtocolV2BleTuning = Required<ProtocolV2BleTuning>;
163
169
 
164
170
  const DEFAULT_PROTOCOL_V2_BLE_TUNING: ResolvedProtocolV2BleTuning = {
165
- iosPacketLength: IOS_PACKET_LENGTH,
166
- androidPacketLength: ANDROID_PACKET_LENGTH,
171
+ iosPacketLength: IOS_PROTOCOL_V2_PACKET_LENGTH,
172
+ androidPacketLength: ANDROID_PROTOCOL_V2_PACKET_LENGTH,
167
173
  };
168
174
 
169
175
  let protocolV2BleTuning: ResolvedProtocolV2BleTuning = { ...DEFAULT_PROTOCOL_V2_BLE_TUNING };
@@ -205,12 +211,19 @@ function getDeviceDisplayName(device?: Device | null) {
205
211
  return device?.name || device?.localName || null;
206
212
  }
207
213
 
208
- const ANDROID_REQUEST_MTU = 256;
214
+ const IOS_REQUEST_MTU = 247;
215
+ const ANDROID_REQUEST_MTU = 517;
216
+ const BLE_MTU_REFRESH_THRESHOLD = 247;
217
+ const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
218
+ const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
219
+
220
+ const getRequestedBleMtu = () =>
221
+ Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
209
222
 
210
223
  const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
211
224
 
212
225
  const connectOptions: Record<string, unknown> = {
213
- requestMTU: ANDROID_REQUEST_MTU,
226
+ requestMTU: getRequestedBleMtu(),
214
227
  timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
215
228
  refreshGatt: 'OnConnected',
216
229
  };
@@ -264,23 +277,32 @@ const tryToGetConfiguration = (device: Device) => {
264
277
  return infos;
265
278
  };
266
279
 
267
- const requestAndroidMtu = async (device: Device) => {
268
- if (Platform.OS !== 'android') return device;
280
+ const requestNegotiatedMtu = async (
281
+ device: Device,
282
+ stage: 'connected' | 'servicesAndNotifyReady',
283
+ attempt: number
284
+ ) => {
285
+ if (Platform.OS !== 'ios' && Platform.OS !== 'android') return device;
269
286
 
270
287
  try {
271
- const mtuDevice = await device.requestMTU(ANDROID_REQUEST_MTU);
272
- Log?.debug('[ReactNativeBleTransport] MTU configured', {
273
- deviceId: device.id,
274
- requested: ANDROID_REQUEST_MTU,
275
- actual: mtuDevice.mtu,
276
- });
288
+ // iOS ignores the requested value but react-native-ble-plx returns a fresh
289
+ // Device snapshot whose MTU is derived from CoreBluetooth's maximum write length.
290
+ const mtuDevice = await device.requestMTU(getRequestedBleMtu());
277
291
  return mtuDevice;
278
292
  } catch (error) {
279
- Log?.debug('[ReactNativeBleTransport] Android MTU request failed:', error);
293
+ Log?.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
294
+ platform: Platform.OS,
295
+ stage,
296
+ attempt,
297
+ actual: device.mtu,
298
+ error: error instanceof Error ? error.message : String(error),
299
+ });
280
300
  return device;
281
301
  }
282
302
  };
283
303
 
304
+ const resolveNegotiatedMtu = (device: Device) => requestNegotiatedMtu(device, 'connected', 0);
305
+
284
306
  type IOBleErrorRemap = Error | BleError | null | undefined;
285
307
 
286
308
  function remapError(error: IOBleErrorRemap) {
@@ -394,6 +416,12 @@ export default class ReactNativeBleTransport {
394
416
 
395
417
  private disconnectEventTokens: Map<string, number> = new Map();
396
418
 
419
+ private protocolV2HighVolumeLogSignatures: Map<string, Set<string>> = new Map();
420
+
421
+ private androidHighPriorityDevices: Set<string> = new Set();
422
+
423
+ private androidPriorityResetTimers: Map<string, ReturnType<typeof setTimeout>> = new Map();
424
+
397
425
  private nextMonitorToken = 1;
398
426
 
399
427
  constructor(options: TransportOptions) {
@@ -775,9 +803,7 @@ export default class ReactNativeBleTransport {
775
803
  const { writeCharacteristic, notifyCharacteristic } =
776
804
  characteristics ?? (await this.resolveCharacteristicsWithTimeout(uuid, device));
777
805
  const transport = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
778
- if (Platform.OS === 'android') {
779
- transport.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport.mtuSize;
780
- }
806
+ transport.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
781
807
  const monitorToken = this.nextMonitorToken;
782
808
  this.nextMonitorToken += 1;
783
809
  const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
@@ -791,6 +817,7 @@ export default class ReactNativeBleTransport {
791
817
  notifyTransactionId
792
818
  );
793
819
  transportCache[uuid] = transport;
820
+ this.protocolV2HighVolumeLogSignatures.set(uuid, new Set());
794
821
  this.protocolV2Assemblers.set(
795
822
  uuid,
796
823
  new ProtocolV2FrameAssembler(PROTOCOL_V2_BLE_FRAME_MAX_BYTES)
@@ -804,6 +831,40 @@ export default class ReactNativeBleTransport {
804
831
  await delay(ANDROID_NOTIFY_READY_DELAY_MS);
805
832
  }
806
833
 
834
+ const initialMtu = transport.mtuSize;
835
+ let refreshAttempts = 0;
836
+ if (
837
+ (Platform.OS === 'ios' || Platform.OS === 'android') &&
838
+ (typeof transport.mtuSize !== 'number' || transport.mtuSize < BLE_MTU_REFRESH_THRESHOLD)
839
+ ) {
840
+ refreshAttempts += 1;
841
+ let refreshedDevice = await requestNegotiatedMtu(
842
+ transport.device,
843
+ 'servicesAndNotifyReady',
844
+ 1
845
+ );
846
+ transport.device = refreshedDevice;
847
+ transport.mtuSize =
848
+ typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
849
+
850
+ if (typeof transport.mtuSize !== 'number' || transport.mtuSize < BLE_MTU_REFRESH_THRESHOLD) {
851
+ await delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
852
+ refreshAttempts += 1;
853
+ refreshedDevice = await requestNegotiatedMtu(transport.device, 'servicesAndNotifyReady', 2);
854
+ transport.device = refreshedDevice;
855
+ transport.mtuSize =
856
+ typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
857
+ }
858
+ }
859
+
860
+ Log?.debug('[ReactNativeBleTransport] BLE MTU ready', {
861
+ platform: Platform.OS,
862
+ requested: getRequestedBleMtu(),
863
+ initial: initialMtu,
864
+ actual: transport.mtuSize,
865
+ refreshAttempts,
866
+ });
867
+
807
868
  return transport;
808
869
  }
809
870
 
@@ -946,7 +1007,7 @@ export default class ReactNativeBleTransport {
946
1007
  }
947
1008
  }
948
1009
 
949
- device = await requestAndroidMtu(device);
1010
+ device = await resolveNegotiatedMtu(device);
950
1011
  const acquiredDevice = device;
951
1012
  const { writeCharacteristic, notifyCharacteristic } =
952
1013
  await this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
@@ -981,7 +1042,7 @@ export default class ReactNativeBleTransport {
981
1042
  if (!currentTransport) {
982
1043
  throw ERRORS.TypedError(HardwareErrorCode.TransportNotFound);
983
1044
  }
984
- this.attachDisconnectSubscription(currentTransport, acquiredDevice, uuid);
1045
+ this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
985
1046
  return { uuid, protocolType };
986
1047
  } catch (error) {
987
1048
  await this.release(uuid, true);
@@ -1151,6 +1212,8 @@ export default class ReactNativeBleTransport {
1151
1212
  return Promise.resolve(true);
1152
1213
  }
1153
1214
 
1215
+ await this.restoreAndroidConnectionPriority(uuid, transport);
1216
+
1154
1217
  if (transport) {
1155
1218
  if (this.monitorTokens.get(uuid) === transport.monitorToken) {
1156
1219
  this.monitorTokens.delete(uuid);
@@ -1180,6 +1243,8 @@ export default class ReactNativeBleTransport {
1180
1243
  delete transportCache[uuid];
1181
1244
  }
1182
1245
 
1246
+ this.protocolV2HighVolumeLogSignatures.delete(uuid);
1247
+
1183
1248
  this.deviceProtocol.delete(uuid);
1184
1249
  this.probingProtocols.delete(uuid);
1185
1250
  // Preserve a name-derived hint across disconnects so reconnect can probe V2 first.
@@ -2106,9 +2171,12 @@ export default class ReactNativeBleTransport {
2106
2171
  context: ProtocolV2CallContext,
2107
2172
  assertCurrentGeneration: () => void
2108
2173
  ) {
2109
- const shouldUseWriteWithResponse =
2110
- transport.writeCharacteristic.isWritableWithResponse &&
2111
- (context.writeWithResponse === true || (Platform.OS === 'ios' && !context.highVolume));
2174
+ const shouldUseWriteWithResponse = shouldWriteProtocolV2WithResponse({
2175
+ platform: Platform.OS,
2176
+ highVolume: context.highVolume,
2177
+ requestedWithResponse: context.writeWithResponse,
2178
+ characteristic: transport.writeCharacteristic,
2179
+ });
2112
2180
  let attempt = 0;
2113
2181
  for (;;) {
2114
2182
  assertCurrentGeneration();
@@ -2167,24 +2235,14 @@ export default class ReactNativeBleTransport {
2167
2235
  platform: Platform.OS,
2168
2236
  iosPacketLength: tuning.iosPacketLength,
2169
2237
  androidPacketLength: tuning.androidPacketLength,
2170
- mtu: Platform.OS === 'android' ? transport.mtuSize : undefined,
2238
+ mtu: transport.mtuSize,
2171
2239
  });
2172
- // Match Desktop BLE pacing so Pro2 firmware can finish the previous response
2173
- // before the next single-packet control command is written.
2174
- const initialDelayMs =
2175
- Platform.OS === 'ios' && !context.highVolume && frame.length <= packetCapacity
2176
- ? IOS_PROTOCOL_V2_CONTROL_WRITE_DELAY_MS
2177
- : 0;
2178
2240
  await writeProtocolV2BleFrame({
2179
2241
  frame,
2180
2242
  packetCapacity,
2181
2243
  assertActive: assertCurrentGeneration,
2182
2244
  signal: context.signal,
2183
2245
  abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
2184
- initialDelayMs,
2185
- burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
2186
- burstPauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
2187
- flushDelayMs: FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS,
2188
2246
  wait: delay,
2189
2247
  writePacket: packet =>
2190
2248
  this.writeProtocolV2Packet(
@@ -2212,11 +2270,39 @@ export default class ReactNativeBleTransport {
2212
2270
 
2213
2271
  if (highVolumeWrite) {
2214
2272
  const tuning = getProtocolV2BleTuning();
2215
- Log?.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
2216
- name,
2217
- writeMode: options?.writeWithResponse ? 'withResponse' : 'withoutResponse',
2218
- packetCapacity: Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength,
2273
+ const currentTransport = this.getCachedTransport(uuid);
2274
+ const writeWithResponse = shouldWriteProtocolV2WithResponse({
2275
+ platform: Platform.OS,
2276
+ highVolume: true,
2277
+ requestedWithResponse: options?.writeWithResponse,
2278
+ characteristic: currentTransport.writeCharacteristic,
2219
2279
  });
2280
+ const packetCapacity = resolveProtocolV2PacketCapacity({
2281
+ platform: Platform.OS,
2282
+ iosPacketLength: tuning.iosPacketLength,
2283
+ androidPacketLength: tuning.androidPacketLength,
2284
+ mtu: currentTransport.mtuSize,
2285
+ });
2286
+ const writeMode = writeWithResponse ? 'withResponse' : 'withoutResponse';
2287
+ const logSignature = `${name}:${writeMode}:${String(
2288
+ currentTransport.mtuSize
2289
+ )}:${packetCapacity}`;
2290
+ const loggedSignatures =
2291
+ this.protocolV2HighVolumeLogSignatures.get(uuid) ?? new Set<string>();
2292
+ if (!loggedSignatures.has(logSignature)) {
2293
+ loggedSignatures.add(logSignature);
2294
+ this.protocolV2HighVolumeLogSignatures.set(uuid, loggedSignatures);
2295
+ Log?.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
2296
+ name,
2297
+ writeMode,
2298
+ reportedMtu: currentTransport.mtuSize,
2299
+ packetCapacity,
2300
+ });
2301
+ }
2302
+ }
2303
+
2304
+ if (highVolumeWrite) {
2305
+ await this.enableAndroidHighConnectionPriority(uuid);
2220
2306
  }
2221
2307
 
2222
2308
  try {
@@ -2230,6 +2316,73 @@ export default class ReactNativeBleTransport {
2230
2316
  } catch (e) {
2231
2317
  Log?.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
2232
2318
  throw e;
2319
+ } finally {
2320
+ if (highVolumeWrite) {
2321
+ this.scheduleAndroidBalancedConnectionPriority(uuid);
2322
+ }
2323
+ }
2324
+ }
2325
+
2326
+ private clearAndroidPriorityResetTimer(uuid: string) {
2327
+ const timerId = this.androidPriorityResetTimers.get(uuid);
2328
+ if (timerId !== undefined) {
2329
+ clearTimeout(timerId);
2330
+ this.androidPriorityResetTimers.delete(uuid);
2331
+ }
2332
+ }
2333
+
2334
+ private async enableAndroidHighConnectionPriority(uuid: string) {
2335
+ if (Platform.OS !== 'android') return;
2336
+
2337
+ this.clearAndroidPriorityResetTimer(uuid);
2338
+ if (this.androidHighPriorityDevices.has(uuid)) return;
2339
+
2340
+ const transport = transportCache[uuid];
2341
+ if (!transport) return;
2342
+
2343
+ try {
2344
+ transport.device = await transport.device.requestConnectionPriority(ConnectionPriority.High);
2345
+ this.androidHighPriorityDevices.add(uuid);
2346
+ Log?.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
2347
+ priority: 'high',
2348
+ });
2349
+ } catch (error) {
2350
+ Log?.debug('[ReactNativeBleTransport] Android BLE high priority request failed', {
2351
+ error: error instanceof Error ? error.message : String(error),
2352
+ });
2353
+ }
2354
+ }
2355
+
2356
+ private scheduleAndroidBalancedConnectionPriority(uuid: string) {
2357
+ if (Platform.OS !== 'android' || !this.androidHighPriorityDevices.has(uuid)) return;
2358
+
2359
+ this.clearAndroidPriorityResetTimer(uuid);
2360
+ const timerId = setTimeout(() => {
2361
+ this.androidPriorityResetTimers.delete(uuid);
2362
+ this.restoreAndroidConnectionPriority(uuid, transportCache[uuid]).catch(error =>
2363
+ Log?.debug('[ReactNativeBleTransport] Android BLE priority restore failed', error)
2364
+ );
2365
+ }, ANDROID_HIGH_PRIORITY_IDLE_MS);
2366
+ this.androidPriorityResetTimers.set(uuid, timerId);
2367
+ }
2368
+
2369
+ private async restoreAndroidConnectionPriority(uuid: string, transport?: BleTransport) {
2370
+ this.clearAndroidPriorityResetTimer(uuid);
2371
+ if (Platform.OS !== 'android' || !this.androidHighPriorityDevices.delete(uuid) || !transport) {
2372
+ return;
2373
+ }
2374
+
2375
+ try {
2376
+ transport.device = await transport.device.requestConnectionPriority(
2377
+ ConnectionPriority.Balanced
2378
+ );
2379
+ Log?.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
2380
+ priority: 'balanced',
2381
+ });
2382
+ } catch (error) {
2383
+ Log?.debug('[ReactNativeBleTransport] Android BLE balanced priority request failed', {
2384
+ error: error instanceof Error ? error.message : String(error),
2385
+ });
2233
2386
  }
2234
2387
  }
2235
2388