@onekeyfe/hd-core 1.2.0-alpha.166 → 1.2.0-alpha.168

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/dist/index.js CHANGED
@@ -42471,6 +42471,18 @@ const PRO2_WALLPAPER_WIDTH = 604;
42471
42471
  const PRO2_WALLPAPER_HEIGHT = 1024;
42472
42472
  const COLOR_FORMAT_RGB565 = 0x12;
42473
42473
  const COLOR_FORMAT_RGB565A8 = 0x14;
42474
+ const COLOR_FORMAT_I8 = 0x0a;
42475
+ const IMAGE_FLAG_COMPRESSED = 0x0008;
42476
+ const IMAGE_COMPRESSION_LZ4 = 0x00000002;
42477
+ const I8_PALETTE_SIZE = 256 * 4;
42478
+ const I8_RED_LEVELS = 6;
42479
+ const I8_GREEN_LEVELS = 7;
42480
+ const I8_BLUE_LEVELS = 6;
42481
+ const LZ4_MIN_MATCH = 4;
42482
+ const LZ4_LAST_LITERALS = 5;
42483
+ const LZ4_MATCH_FIND_LIMIT = 12;
42484
+ const LZ4_HASH_BITS = 16;
42485
+ const LZ4_HASH_MULTIPLIER = -1640531535;
42474
42486
  const RED_THRESHOLD = [
42475
42487
  1, 7, 3, 5, 0, 8, 2, 6, 7, 1, 5, 3, 8, 0, 6, 2, 3, 5, 0, 8, 2, 6, 1, 7, 5, 3, 8, 0, 6, 2, 7, 1, 0,
42476
42488
  8, 2, 6, 1, 7, 3, 5, 8, 0, 6, 2, 7, 1, 5, 3, 2, 6, 1, 7, 3, 5, 0, 8, 6, 2, 7, 1, 5, 3, 8, 0,
@@ -42492,6 +42504,149 @@ function asBytes(rgba) {
42492
42504
  function align(value, boundary) {
42493
42505
  return Math.ceil(value / boundary) * boundary;
42494
42506
  }
42507
+ function writeLz4Length(output, offset, length) {
42508
+ let cursor = offset;
42509
+ let remaining = length;
42510
+ while (remaining >= 0xff) {
42511
+ output[cursor] = 0xff;
42512
+ cursor += 1;
42513
+ remaining -= 0xff;
42514
+ }
42515
+ output[cursor] = remaining;
42516
+ return cursor + 1;
42517
+ }
42518
+ function readUint32LittleEndian(data, offset) {
42519
+ return (data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24));
42520
+ }
42521
+ function getLz4Hash(sequence) {
42522
+ return (Math.imul(sequence, LZ4_HASH_MULTIPLIER) >>> (32 - LZ4_HASH_BITS)) & 0xffff;
42523
+ }
42524
+ function compressLz4Block(input) {
42525
+ const output = new Uint8Array(input.byteLength + Math.floor(input.byteLength / 0xff) + 16);
42526
+ const hashTable = new Int32Array(1 << LZ4_HASH_BITS);
42527
+ hashTable.fill(-1);
42528
+ let anchor = 0;
42529
+ let inputOffset = 0;
42530
+ let outputOffset = 0;
42531
+ const matchFindEnd = input.byteLength - LZ4_MATCH_FIND_LIMIT;
42532
+ const matchCopyEnd = input.byteLength - LZ4_LAST_LITERALS;
42533
+ while (inputOffset <= matchFindEnd) {
42534
+ const sequence = readUint32LittleEndian(input, inputOffset);
42535
+ const hash = getLz4Hash(sequence);
42536
+ const reference = hashTable[hash];
42537
+ hashTable[hash] = inputOffset;
42538
+ const matchOffset = inputOffset - reference;
42539
+ const hasMatch = reference >= 0 &&
42540
+ matchOffset <= 0xffff &&
42541
+ readUint32LittleEndian(input, reference) === sequence;
42542
+ if (hasMatch) {
42543
+ let matchLength = LZ4_MIN_MATCH;
42544
+ while (inputOffset + matchLength < matchCopyEnd &&
42545
+ input[reference + matchLength] === input[inputOffset + matchLength]) {
42546
+ matchLength += 1;
42547
+ }
42548
+ const literalLength = inputOffset - anchor;
42549
+ const encodedMatchLength = matchLength - LZ4_MIN_MATCH;
42550
+ const tokenOffset = outputOffset;
42551
+ outputOffset += 1;
42552
+ output[tokenOffset] =
42553
+ (Math.min(literalLength, 0x0f) << 4) | Math.min(encodedMatchLength, 0x0f);
42554
+ if (literalLength >= 0x0f) {
42555
+ outputOffset = writeLz4Length(output, outputOffset, literalLength - 0x0f);
42556
+ }
42557
+ output.set(input.subarray(anchor, inputOffset), outputOffset);
42558
+ outputOffset += literalLength;
42559
+ output[outputOffset] = matchOffset & 0xff;
42560
+ output[outputOffset + 1] = matchOffset >> 8;
42561
+ outputOffset += 2;
42562
+ if (encodedMatchLength >= 0x0f) {
42563
+ outputOffset = writeLz4Length(output, outputOffset, encodedMatchLength - 0x0f);
42564
+ }
42565
+ const matchStart = inputOffset;
42566
+ inputOffset += matchLength;
42567
+ anchor = inputOffset;
42568
+ for (let cursor = Math.max(matchStart + 1, inputOffset - 2); cursor < inputOffset; cursor += 1) {
42569
+ if (cursor <= matchFindEnd) {
42570
+ hashTable[getLz4Hash(readUint32LittleEndian(input, cursor))] = cursor;
42571
+ }
42572
+ }
42573
+ }
42574
+ else {
42575
+ inputOffset += 1;
42576
+ }
42577
+ }
42578
+ const literalLength = input.byteLength - anchor;
42579
+ const tokenOffset = outputOffset;
42580
+ outputOffset += 1;
42581
+ output[tokenOffset] = Math.min(literalLength, 0x0f) << 4;
42582
+ if (literalLength >= 0x0f) {
42583
+ outputOffset = writeLz4Length(output, outputOffset, literalLength - 0x0f);
42584
+ }
42585
+ output.set(input.subarray(anchor), outputOffset);
42586
+ outputOffset += literalLength;
42587
+ return output.slice(0, outputOffset);
42588
+ }
42589
+ function quantizeChannel(value, levels) {
42590
+ return Math.floor((value * (levels - 1) + 0x7f) / 0xff);
42591
+ }
42592
+ function expandChannel(value, levels) {
42593
+ return Math.floor((value * 0xff + Math.floor((levels - 1) / 2)) / (levels - 1));
42594
+ }
42595
+ function encodePro2I8Lz4(options) {
42596
+ const { width, height } = options;
42597
+ if (!Number.isInteger(width) || width <= 0 || width > 0xffff) {
42598
+ throw invalidParameter$2('Wallpaper width must be an integer between 1 and 65535.');
42599
+ }
42600
+ if (!Number.isInteger(height) || height <= 0 || height > 0xffff) {
42601
+ throw invalidParameter$2('Wallpaper height must be an integer between 1 and 65535.');
42602
+ }
42603
+ const rgba = asBytes(options.rgba);
42604
+ const expectedLength = width * height * 4;
42605
+ if (rgba.byteLength !== expectedLength) {
42606
+ throw invalidParameter$2(`Wallpaper RGBA data length must be ${expectedLength} bytes, received ${rgba.byteLength}.`);
42607
+ }
42608
+ const stride = width;
42609
+ const rawData = new Uint8Array(I8_PALETTE_SIZE + stride * height);
42610
+ for (let red = 0; red < I8_RED_LEVELS; red += 1) {
42611
+ for (let green = 0; green < I8_GREEN_LEVELS; green += 1) {
42612
+ for (let blue = 0; blue < I8_BLUE_LEVELS; blue += 1) {
42613
+ const paletteIndex = (red * I8_GREEN_LEVELS + green) * I8_BLUE_LEVELS + blue;
42614
+ const paletteOffset = paletteIndex * 4;
42615
+ rawData[paletteOffset] = expandChannel(blue, I8_BLUE_LEVELS);
42616
+ rawData[paletteOffset + 1] = expandChannel(green, I8_GREEN_LEVELS);
42617
+ rawData[paletteOffset + 2] = expandChannel(red, I8_RED_LEVELS);
42618
+ rawData[paletteOffset + 3] = 0xff;
42619
+ }
42620
+ }
42621
+ }
42622
+ for (let pixel = 0; pixel < width * height; pixel += 1) {
42623
+ const sourceOffset = pixel * 4;
42624
+ const alpha = rgba[sourceOffset + 3];
42625
+ const red = Math.round((rgba[sourceOffset] * alpha) / 0xff);
42626
+ const green = Math.round((rgba[sourceOffset + 1] * alpha) / 0xff);
42627
+ const blue = Math.round((rgba[sourceOffset + 2] * alpha) / 0xff);
42628
+ const paletteIndex = (quantizeChannel(red, I8_RED_LEVELS) * I8_GREEN_LEVELS +
42629
+ quantizeChannel(green, I8_GREEN_LEVELS)) *
42630
+ I8_BLUE_LEVELS +
42631
+ quantizeChannel(blue, I8_BLUE_LEVELS);
42632
+ rawData[I8_PALETTE_SIZE + pixel] = paletteIndex;
42633
+ }
42634
+ const compressed = compressLz4Block(rawData);
42635
+ const data = new Uint8Array(24 + compressed.byteLength);
42636
+ const view = new DataView(data.buffer);
42637
+ data[0] = 0x19;
42638
+ data[1] = COLOR_FORMAT_I8;
42639
+ view.setUint16(2, IMAGE_FLAG_COMPRESSED, true);
42640
+ view.setUint16(4, width, true);
42641
+ view.setUint16(6, height, true);
42642
+ view.setUint16(8, stride, true);
42643
+ view.setUint16(10, 0, true);
42644
+ view.setUint32(12, IMAGE_COMPRESSION_LZ4, true);
42645
+ view.setUint32(16, compressed.byteLength, true);
42646
+ view.setUint32(20, rawData.byteLength, true);
42647
+ data.set(compressed, 24);
42648
+ return { data, colorFormat: 'I8' };
42649
+ }
42495
42650
  function encodePro2Image(options) {
42496
42651
  var _a;
42497
42652
  const { width, height } = options;
@@ -42559,6 +42714,9 @@ function encodePro2Image(options) {
42559
42714
  return { data, colorFormat };
42560
42715
  }
42561
42716
  function encodePro2Wallpaper(options) {
42717
+ if (options.encoding === 'i8-lz4') {
42718
+ return encodePro2I8Lz4(options);
42719
+ }
42562
42720
  return encodePro2Image(options);
42563
42721
  }
42564
42722
 
@@ -51875,6 +52033,15 @@ const isProtocolV2TerminalInstallStatusError = (error) => {
51875
52033
  const isProtocolV2TargetStatusFinished = (status) => normalizeProtocolV2TargetStatus(status) === PROTOCOL_V2_TARGET_STATUS_FINISHED;
51876
52034
  const isProtocolV2TargetStatusInProgress = (status) => normalizeProtocolV2TargetStatus(status) === PROTOCOL_V2_TARGET_STATUS_PENDING ||
51877
52035
  normalizeProtocolV2TargetStatus(status) === PROTOCOL_V2_TARGET_STATUS_IN_PROGRESS;
52036
+ const getProtocolV2FirmwareStatusFingerprint = (statusTargets) => JSON.stringify(statusTargets.map(target => {
52037
+ var _a, _b, _c, _d, _e;
52038
+ return ({
52039
+ targetId: (_a = normalizeProtocolV2TargetId(target.target_id)) !== null && _a !== void 0 ? _a : target.target_id,
52040
+ status: (_c = (_b = normalizeProtocolV2TargetStatus(target.status)) !== null && _b !== void 0 ? _b : target.status) !== null && _c !== void 0 ? _c : null,
52041
+ payloadVersion: (_d = target.payload_version) !== null && _d !== void 0 ? _d : null,
52042
+ path: (_e = target.path) !== null && _e !== void 0 ? _e : null,
52043
+ });
52044
+ }));
51878
52045
  const isProtocolV2TargetStatusFailed = (status) => {
51879
52046
  const normalizedStatus = normalizeProtocolV2TargetStatus(status);
51880
52047
  return (typeof normalizedStatus === 'number' && normalizedStatus >= PROTOCOL_V2_TARGET_STATUS_FAILED_MIN);
@@ -53371,13 +53538,18 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53371
53538
  return __awaiter(this, void 0, void 0, function* () {
53372
53539
  const expectedTargetIds = new Set(targets.map(target => target.target_id));
53373
53540
  const expectedPaths = new Map(targets.map(target => [target.target_id, target.path]));
53374
- const startTime = Date.now();
53541
+ const confirmationStartedAt = Date.now();
53542
+ let installStartedAt = requireCurrentInstallStatus ? undefined : confirmationStartedAt;
53543
+ const effectiveBaselineStatusTargets = this.protocolV2InstallStatusBaseline;
53544
+ const baselineStatusFingerprint = effectiveBaselineStatusTargets
53545
+ ? getProtocolV2FirmwareStatusFingerprint(effectiveBaselineStatusTargets)
53546
+ : undefined;
53375
53547
  let lastError;
53376
53548
  let shouldReconnect = false;
53377
53549
  let deviceInfo;
53378
53550
  let installEvidenceObserved = false;
53379
53551
  let currentInstallStatusObserved = false;
53380
- while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
53552
+ while (Date.now() - (installStartedAt !== null && installStartedAt !== void 0 ? installStartedAt : confirmationStartedAt) < PROTOCOL_V2_INSTALL_TIMEOUT) {
53381
53553
  this.throwIfAborted();
53382
53554
  try {
53383
53555
  if (shouldReconnect) {
@@ -53401,14 +53573,27 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53401
53573
  const statusTargets = statusResponse.type === 'DeviceFirmwareUpdateStatus'
53402
53574
  ? ((_a = statusResponse.message.records) !== null && _a !== void 0 ? _a : [])
53403
53575
  : [];
53404
- const hasInProgressTarget = statusTargets.some(target => {
53576
+ const hasPendingOrInProgressTarget = statusTargets.some(target => {
53405
53577
  const targetId = normalizeProtocolV2TargetId(target.target_id);
53406
53578
  return (targetId !== undefined &&
53407
53579
  expectedTargetIds.has(targetId) &&
53408
53580
  isProtocolV2TargetStatusInProgress(target.status));
53409
53581
  });
53410
- if (hasInProgressTarget) {
53582
+ const isExpectedStatusSnapshot = statusTargets.length === targets.length &&
53583
+ targets.every((expectedTarget, index) => {
53584
+ const statusTarget = statusTargets[index];
53585
+ return (statusTarget !== undefined &&
53586
+ normalizeProtocolV2TargetId(statusTarget.target_id) === expectedTarget.target_id &&
53587
+ statusTarget.path === expectedTarget.path);
53588
+ });
53589
+ const statusFingerprint = getProtocolV2FirmwareStatusFingerprint(statusTargets);
53590
+ const hasCurrentInstallTransition = baselineStatusFingerprint !== undefined
53591
+ ? isExpectedStatusSnapshot && statusFingerprint !== baselineStatusFingerprint
53592
+ : hasPendingOrInProgressTarget;
53593
+ if (!currentInstallStatusObserved && hasCurrentInstallTransition) {
53411
53594
  currentInstallStatusObserved = true;
53595
+ installStartedAt = Date.now();
53596
+ Log$7.log('[FirmwareUpdateV4] current firmware install records observed');
53412
53597
  }
53413
53598
  const hasMatchingTargetStatus = statusTargets.some(target => {
53414
53599
  const targetId = normalizeProtocolV2TargetId(target.target_id);
@@ -53718,14 +53903,41 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53718
53903
  });
53719
53904
  }
53720
53905
  protocolV2StartFirmwareUpdate({ targets, }) {
53906
+ var _a;
53721
53907
  return __awaiter(this, void 0, void 0, function* () {
53722
53908
  this.protocolV2LastRuntimeProbeFeatures = undefined;
53909
+ this.protocolV2InstallStatusBaseline = undefined;
53723
53910
  const commands = this.device.getCommands();
53724
53911
  yield commands.typedCall('DeviceFirmwareUpdateStage', 'Success', { targets });
53912
+ try {
53913
+ const baselineStatusResponse = yield commands.typedCall('DeviceFirmwareUpdateStatusGet', ['DeviceFirmwareUpdateStatus', 'Success'], {
53914
+ fields: {
53915
+ status: true,
53916
+ payload_version: true,
53917
+ path: true,
53918
+ },
53919
+ }, { timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT });
53920
+ this.protocolV2InstallStatusBaseline =
53921
+ baselineStatusResponse.type === 'DeviceFirmwareUpdateStatus'
53922
+ ? ((_a = baselineStatusResponse.message.records) !== null && _a !== void 0 ? _a : [])
53923
+ : [];
53924
+ }
53925
+ catch (error) {
53926
+ Log$7.log('[FirmwareUpdateV4] unable to capture pre-install firmware status: ', error);
53927
+ }
53725
53928
  this.device.setCancelableAction(() => commands.cancelDevice());
53726
53929
  const interaction = this.device.createProtocolV2UiPhaseMetadata('button', 'start');
53727
53930
  this.postMessage(createUiMessage(UI_REQUEST.REQUEST_BUTTON, Object.assign({ device: this.device.toMessageObject(), source: 'method-lifecycle', reason: 'firmware-update', completion: 'operation-completed', deviceOnly: true, operation: this.name }, (interaction ? { interaction } : {}))));
53728
- yield commands.call('DeviceFirmwareUpdateRequest', {}, { returnAfterWrite: true });
53931
+ try {
53932
+ yield commands.call('DeviceFirmwareUpdateRequest', {});
53933
+ }
53934
+ catch (error) {
53935
+ this.throwIfAborted();
53936
+ if (!isProtocolV2DeviceDisconnectedError(error)) {
53937
+ throw error;
53938
+ }
53939
+ Log$7.log('[FirmwareUpdateV4] BLE transport released after install request; continue status polling');
53940
+ }
53729
53941
  });
53730
53942
  }
53731
53943
  protocolV2Reboot(rebootType) {
@@ -54213,10 +54425,15 @@ class DeviceUploadWallpaper extends BaseMethod {
54213
54425
  return ['V2'];
54214
54426
  }
54215
54427
  init() {
54216
- const { jpegBase64, fileName, chunkSize } = this.payload;
54428
+ const { jpegBase64, fileName, chunkSize, encoding } = this.payload;
54217
54429
  if (chunkSize !== undefined && (!Number.isInteger(chunkSize) || chunkSize <= 0)) {
54218
54430
  throw invalidParameter$1('Parameter [chunkSize] must be a positive integer.');
54219
54431
  }
54432
+ if (encoding !== undefined && encoding !== 'rgb565' && encoding !== 'i8-lz4') {
54433
+ throw invalidParameter$1('Parameter [encoding] must be either rgb565 or i8-lz4.');
54434
+ }
54435
+ const env = DataManager.getSettings('env');
54436
+ const resolvedEncoding = encoding !== null && encoding !== void 0 ? encoding : (env && DataManager.isBleConnect(env) ? 'i8-lz4' : 'rgb565');
54220
54437
  const decoded = decodeJpegBase64ToRgba({
54221
54438
  jpegBase64,
54222
54439
  parameterName: 'jpegBase64',
@@ -54227,9 +54444,10 @@ class DeviceUploadWallpaper extends BaseMethod {
54227
54444
  width: PRO2_WALLPAPER_WIDTH,
54228
54445
  height: PRO2_WALLPAPER_HEIGHT,
54229
54446
  rgba: decoded.data,
54447
+ encoding: resolvedEncoding,
54230
54448
  });
54231
54449
  this.path = `${WALLPAPER_DIRECTORY}/${normalizeFileName(fileName, this.encoded.data)}`;
54232
- this.params = { jpegBase64, fileName, chunkSize };
54450
+ this.params = { jpegBase64, fileName, chunkSize, encoding: resolvedEncoding };
54233
54451
  this.unlockPolicy = 'unlock-before-run';
54234
54452
  this.protocolV2PreUnlockPinType = hdTransport.DeviceSessionPinType.Any;
54235
54453
  this.skipForceUpdateCheck = true;
@@ -65068,8 +65286,6 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
65068
65286
  if ((_g = method.payload) === null || _g === void 0 ? void 0 : _g.onlyConnectBleDevice) {
65069
65287
  preWarmCallbackTask === null || preWarmCallbackTask === void 0 ? void 0 : preWarmCallbackTask.resolve();
65070
65288
  Log.debug('Call API - only connect ble device: ', device === null || device === void 0 ? void 0 : device.mainId);
65071
- completeMethodRequestContext(method);
65072
- requestQueue.releaseTask(method.responseID);
65073
65289
  return createResponseMessage(method.responseID, true, null);
65074
65290
  }
65075
65291
  Log.debug('Call API - setDevice: ', device.mainId);
@@ -65445,31 +65661,7 @@ function isMissingDetectedProtocolV2Error(method, error) {
65445
65661
  typeof typedError.message === 'string' &&
65446
65662
  typedError.message.includes('Device protocol has not been detected'));
65447
65663
  }
65448
- const BLE_ACQUIRE_DEADLINE_MS = 60 * 1000;
65449
- function raceBleAcquire(acquirePromise, abortSignal) {
65450
- return new Promise((resolve, reject) => {
65451
- let settled = false;
65452
- const settle = (fn) => {
65453
- if (settled)
65454
- return;
65455
- settled = true;
65456
- clearTimeout(deadline);
65457
- abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.removeEventListener('abort', onAbort);
65458
- fn();
65459
- };
65460
- const onAbort = () => settle(() => reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled)));
65461
- const deadline = setTimeout(() => settle(() => reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE acquire exceeded ${BLE_ACQUIRE_DEADLINE_MS}ms deadline`))), BLE_ACQUIRE_DEADLINE_MS);
65462
- acquirePromise.then(value => settle(() => resolve(value)), error => settle(() => reject(error)));
65463
- if (abortSignal) {
65464
- if (abortSignal.aborted) {
65465
- onAbort();
65466
- return;
65467
- }
65468
- abortSignal.addEventListener('abort', onAbort);
65469
- }
65470
- });
65471
- }
65472
- function connectDeviceForBle(method, device, abortSignal, retryCount = 0) {
65664
+ function connectDeviceForBle(method, device, retryCount = 0) {
65473
65665
  var _a;
65474
65666
  return __awaiter(this, void 0, void 0, function* () {
65475
65667
  try {
@@ -65484,32 +65676,9 @@ function connectDeviceForBle(method, device, abortSignal, retryCount = 0) {
65484
65676
  !device.commands ||
65485
65677
  device.commands.disposed;
65486
65678
  if (shouldAcquire) {
65487
- const useAcquireGuards = DataManager.getSettings('env') === 'desktop-web-ble';
65488
- if (useAcquireGuards && (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted)) {
65489
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled);
65490
- }
65491
- if (!useAcquireGuards) {
65492
- yield device.acquire(method.payload.connectProtocol, {
65493
- forceProtocolDetection: method.payload.forceProtocolDetection,
65494
- });
65495
- }
65496
- else {
65497
- try {
65498
- yield raceBleAcquire(device.acquire(method.payload.connectProtocol, {
65499
- forceProtocolDetection: method.payload.forceProtocolDetection,
65500
- }), abortSignal);
65501
- }
65502
- catch (err) {
65503
- device.beginConnectionAttempt();
65504
- if (err.errorCode === hdShared.HardwareErrorCode.BleTimeoutError &&
65505
- device.mainId &&
65506
- device.deviceConnector) {
65507
- yield device.deviceConnector.disconnect(device.mainId).catch(() => undefined);
65508
- device.markTransportDisconnected();
65509
- }
65510
- throw err;
65511
- }
65512
- }
65679
+ yield device.acquire(method.payload.connectProtocol, {
65680
+ forceProtocolDetection: method.payload.forceProtocolDetection,
65681
+ });
65513
65682
  }
65514
65683
  if ((_a = method.payload) === null || _a === void 0 ? void 0 : _a.onlyConnectBleDevice) {
65515
65684
  if (shouldAcquire) {
@@ -65540,7 +65709,7 @@ function connectDeviceForBle(method, device, abortSignal, retryCount = 0) {
65540
65709
  const nextRetry = retryCount + 1;
65541
65710
  Log.debug(`Bluetooth connection will retry, retry count: ${nextRetry}`);
65542
65711
  yield wait(3000);
65543
- yield connectDeviceForBle(method, device, abortSignal, nextRetry);
65712
+ yield connectDeviceForBle(method, device, nextRetry);
65544
65713
  }
65545
65714
  else {
65546
65715
  throw err;
@@ -65625,7 +65794,7 @@ const ensureConnected = (_context, method, connectId, pollingId, abortSignal) =>
65625
65794
  if (tryCount === 1) {
65626
65795
  device.beginConnectionAttempt();
65627
65796
  }
65628
- yield connectDeviceForBle(method, device, abortSignal);
65797
+ yield connectDeviceForBle(method, device);
65629
65798
  }
65630
65799
  resolve(device);
65631
65800
  return;
@@ -1,6 +1,7 @@
1
1
  export declare const PRO2_WALLPAPER_WIDTH = 604;
2
2
  export declare const PRO2_WALLPAPER_HEIGHT = 1024;
3
- export type Pro2WallpaperColorFormat = 'RGB565' | 'RGB565A8';
3
+ export type Pro2WallpaperColorFormat = 'RGB565' | 'RGB565A8' | 'I8';
4
+ export type Pro2WallpaperEncoding = 'rgb565' | 'i8-lz4';
4
5
  export type Pro2ImageAlphaMode = 'preserve' | 'black-background';
5
6
  export declare function encodePro2Image(options: {
6
7
  width: number;
@@ -15,6 +16,7 @@ export declare function encodePro2Wallpaper(options: {
15
16
  width: number;
16
17
  height: number;
17
18
  rgba: Uint8Array | ArrayBuffer;
19
+ encoding?: Pro2WallpaperEncoding;
18
20
  }): {
19
21
  data: Uint8Array;
20
22
  colorFormat: Pro2WallpaperColorFormat;
@@ -1 +1 @@
1
- {"version":3,"file":"pro2Wallpaper.d.ts","sourceRoot":"","sources":["../../src/utils/pro2Wallpaper.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE7D,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,kBAAkB,CAAC;AA8BjE,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;IAC/B,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAChC,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,wBAAwB,CAAA;CAAE,CA4E9D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;CAChC,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,wBAAwB,CAAA;CAAE,CAE9D"}
1
+ {"version":3,"file":"pro2Wallpaper.d.ts","sourceRoot":"","sources":["../../src/utils/pro2Wallpaper.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,UAAU,GAAG,IAAI,CAAC;AAEpE,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExD,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,kBAAkB,CAAC;AA4NjE,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;IAC/B,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAChC,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,wBAAwB,CAAA;CAAE,CA4E9D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;IAC/B,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,wBAAwB,CAAA;CAAE,CAK9D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-core",
3
- "version": "1.2.0-alpha.166",
3
+ "version": "1.2.0-alpha.168",
4
4
  "description": "Core processes and APIs for communicating with OneKey hardware devices.",
5
5
  "author": "OneKey",
6
6
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
@@ -25,8 +25,8 @@
25
25
  "url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
26
26
  },
27
27
  "dependencies": {
28
- "@onekeyfe/hd-shared": "1.2.0-alpha.166",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.166",
28
+ "@onekeyfe/hd-shared": "1.2.0-alpha.168",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.168",
30
30
  "axios": "1.15.2",
31
31
  "bignumber.js": "^9.0.2",
32
32
  "buffer": "^6.0.3",
@@ -46,5 +46,5 @@
46
46
  "@types/w3c-web-usb": "^1.0.10",
47
47
  "@types/web-bluetooth": "^0.0.21"
48
48
  },
49
- "gitHead": "3dd1b964d8503ee800f44466b8c08e3d59be67e8"
49
+ "gitHead": "70f16e98ede0365f106ae8add83e82afff761c4c"
50
50
  }
@@ -375,6 +375,18 @@ const isProtocolV2TargetStatusInProgress = (
375
375
  normalizeProtocolV2TargetStatus(status) === PROTOCOL_V2_TARGET_STATUS_PENDING ||
376
376
  normalizeProtocolV2TargetStatus(status) === PROTOCOL_V2_TARGET_STATUS_IN_PROGRESS;
377
377
 
378
+ const getProtocolV2FirmwareStatusFingerprint = (
379
+ statusTargets: ProtocolV2FirmwareUpdateStatusTarget[]
380
+ ) =>
381
+ JSON.stringify(
382
+ statusTargets.map(target => ({
383
+ targetId: normalizeProtocolV2TargetId(target.target_id) ?? target.target_id,
384
+ status: normalizeProtocolV2TargetStatus(target.status) ?? target.status ?? null,
385
+ payloadVersion: target.payload_version ?? null,
386
+ path: target.path ?? null,
387
+ }))
388
+ );
389
+
378
390
  const isProtocolV2TargetStatusFailed = (status: ProtocolV2FirmwareUpdateStatusTarget['status']) => {
379
391
  const normalizedStatus = normalizeProtocolV2TargetStatus(status);
380
392
  return (
@@ -530,6 +542,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
530
542
 
531
543
  private protocolV2InstallBaselineVersions = new Map<number, string>();
532
544
 
545
+ private protocolV2InstallStatusBaseline?: ProtocolV2FirmwareUpdateStatusTarget[];
546
+
533
547
  private protocolV2LastRuntimeProbeFeatures?: Features;
534
548
 
535
549
  private protocolV2LastTransferProgress?: number;
@@ -2383,7 +2397,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2383
2397
  ) {
2384
2398
  const expectedTargetIds = new Set(targets.map(target => target.target_id));
2385
2399
  const expectedPaths = new Map(targets.map(target => [target.target_id, target.path]));
2386
- const startTime = Date.now();
2400
+ const confirmationStartedAt = Date.now();
2401
+ let installStartedAt = requireCurrentInstallStatus ? undefined : confirmationStartedAt;
2402
+ const effectiveBaselineStatusTargets = this.protocolV2InstallStatusBaseline;
2403
+ const baselineStatusFingerprint = effectiveBaselineStatusTargets
2404
+ ? getProtocolV2FirmwareStatusFingerprint(effectiveBaselineStatusTargets)
2405
+ : undefined;
2387
2406
  let lastError: unknown;
2388
2407
  // DeviceFirmwareUpdateRequest leaves the current loader link usable for status polling.
2389
2408
  // Reconnecting here probes DeviceInfo, which loaders reject while installation is active.
@@ -2392,7 +2411,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2392
2411
  let installEvidenceObserved = false;
2393
2412
  let currentInstallStatusObserved = false;
2394
2413
 
2395
- while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
2414
+ while (Date.now() - (installStartedAt ?? confirmationStartedAt) < PROTOCOL_V2_INSTALL_TIMEOUT) {
2396
2415
  // A transport release caused by an explicit workflow cancellation must not
2397
2416
  // be mistaken for the expected device reboot during installation.
2398
2417
  this.throwIfAborted();
@@ -2426,7 +2445,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2426
2445
  statusResponse.type === 'DeviceFirmwareUpdateStatus'
2427
2446
  ? ((statusResponse.message.records ?? []) as ProtocolV2FirmwareUpdateStatusTarget[])
2428
2447
  : [];
2429
- const hasInProgressTarget = statusTargets.some(target => {
2448
+ const hasPendingOrInProgressTarget = statusTargets.some(target => {
2430
2449
  const targetId = normalizeProtocolV2TargetId(target.target_id);
2431
2450
  return (
2432
2451
  targetId !== undefined &&
@@ -2434,8 +2453,25 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2434
2453
  isProtocolV2TargetStatusInProgress(target.status)
2435
2454
  );
2436
2455
  });
2437
- if (hasInProgressTarget) {
2456
+ const isExpectedStatusSnapshot =
2457
+ statusTargets.length === targets.length &&
2458
+ targets.every((expectedTarget, index) => {
2459
+ const statusTarget = statusTargets[index];
2460
+ return (
2461
+ statusTarget !== undefined &&
2462
+ normalizeProtocolV2TargetId(statusTarget.target_id) === expectedTarget.target_id &&
2463
+ statusTarget.path === expectedTarget.path
2464
+ );
2465
+ });
2466
+ const statusFingerprint = getProtocolV2FirmwareStatusFingerprint(statusTargets);
2467
+ const hasCurrentInstallTransition =
2468
+ baselineStatusFingerprint !== undefined
2469
+ ? isExpectedStatusSnapshot && statusFingerprint !== baselineStatusFingerprint
2470
+ : hasPendingOrInProgressTarget;
2471
+ if (!currentInstallStatusObserved && hasCurrentInstallTransition) {
2438
2472
  currentInstallStatusObserved = true;
2473
+ installStartedAt = Date.now();
2474
+ Log.log('[FirmwareUpdateV4] current firmware install records observed');
2439
2475
  }
2440
2476
  const hasMatchingTargetStatus = statusTargets.some(target => {
2441
2477
  const targetId = normalizeProtocolV2TargetId(target.target_id);
@@ -2849,8 +2885,30 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2849
2885
  targets: Array<{ target_id: number; path: string }>;
2850
2886
  }) {
2851
2887
  this.protocolV2LastRuntimeProbeFeatures = undefined;
2888
+ this.protocolV2InstallStatusBaseline = undefined;
2852
2889
  const commands = this.device.getCommands();
2853
2890
  await commands.typedCall('DeviceFirmwareUpdateStage', 'Success', { targets });
2891
+ try {
2892
+ const baselineStatusResponse = await commands.typedCall(
2893
+ 'DeviceFirmwareUpdateStatusGet',
2894
+ ['DeviceFirmwareUpdateStatus', 'Success'],
2895
+ {
2896
+ fields: {
2897
+ status: true,
2898
+ payload_version: true,
2899
+ path: true,
2900
+ },
2901
+ },
2902
+ { timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT }
2903
+ );
2904
+ this.protocolV2InstallStatusBaseline =
2905
+ baselineStatusResponse.type === 'DeviceFirmwareUpdateStatus'
2906
+ ? ((baselineStatusResponse.message.records ??
2907
+ []) as ProtocolV2FirmwareUpdateStatusTarget[])
2908
+ : [];
2909
+ } catch (error) {
2910
+ Log.log('[FirmwareUpdateV4] unable to capture pre-install firmware status: ', error);
2911
+ }
2854
2912
  this.device.setCancelableAction(() => commands.cancelDevice());
2855
2913
  const interaction = this.device.createProtocolV2UiPhaseMetadata('button', 'start');
2856
2914
  this.postMessage(
@@ -2864,7 +2922,17 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2864
2922
  ...(interaction ? { interaction } : {}),
2865
2923
  })
2866
2924
  );
2867
- await commands.call('DeviceFirmwareUpdateRequest', {}, { returnAfterWrite: true });
2925
+ try {
2926
+ await commands.call('DeviceFirmwareUpdateRequest', {});
2927
+ } catch (error) {
2928
+ this.throwIfAborted();
2929
+ if (!isProtocolV2DeviceDisconnectedError(error)) {
2930
+ throw error;
2931
+ }
2932
+ Log.log(
2933
+ '[FirmwareUpdateV4] BLE transport released after install request; continue status polling'
2934
+ );
2935
+ }
2868
2936
  }
2869
2937
 
2870
2938
  private async protocolV2Reboot(rebootType: DeviceRebootType) {
@@ -7,6 +7,7 @@ import { BaseMethod } from '../BaseMethod';
7
7
  import { decodeJpegBase64ToRgba } from '../helpers/base64Data';
8
8
  import { invalidParameter } from '../helpers/filesystemValidation';
9
9
  import { writeProtocolV2File } from '../helpers/protocolV2FileWrite';
10
+ import { DataManager } from '../../data-manager';
10
11
  import { UI_REQUEST, createUiMessage } from '../../events/ui-request';
11
12
  import { supportsProtocolV2Message } from '../../protocols/protocol-v2/features';
12
13
  import { LoggerNames, getLogger } from '../../utils';
@@ -14,6 +15,7 @@ import {
14
15
  PRO2_WALLPAPER_HEIGHT,
15
16
  PRO2_WALLPAPER_WIDTH,
16
17
  type Pro2WallpaperColorFormat,
18
+ type Pro2WallpaperEncoding,
17
19
  encodePro2Wallpaper,
18
20
  } from '../../utils/pro2Wallpaper';
19
21
 
@@ -21,6 +23,7 @@ export type DeviceUploadWallpaperParams = {
21
23
  jpegBase64: string;
22
24
  fileName?: string;
23
25
  chunkSize?: number;
26
+ encoding?: Pro2WallpaperEncoding;
24
27
  };
25
28
 
26
29
  export type DeviceUploadWallpaperResponse = {
@@ -61,10 +64,16 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
61
64
  private path = '';
62
65
 
63
66
  init() {
64
- const { jpegBase64, fileName, chunkSize } = this.payload;
67
+ const { jpegBase64, fileName, chunkSize, encoding } = this.payload;
65
68
  if (chunkSize !== undefined && (!Number.isInteger(chunkSize) || chunkSize <= 0)) {
66
69
  throw invalidParameter('Parameter [chunkSize] must be a positive integer.');
67
70
  }
71
+ if (encoding !== undefined && encoding !== 'rgb565' && encoding !== 'i8-lz4') {
72
+ throw invalidParameter('Parameter [encoding] must be either rgb565 or i8-lz4.');
73
+ }
74
+ const env = DataManager.getSettings('env');
75
+ const resolvedEncoding: Pro2WallpaperEncoding =
76
+ encoding ?? (env && DataManager.isBleConnect(env) ? 'i8-lz4' : 'rgb565');
68
77
 
69
78
  const decoded = decodeJpegBase64ToRgba({
70
79
  jpegBase64,
@@ -76,9 +85,10 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
76
85
  width: PRO2_WALLPAPER_WIDTH,
77
86
  height: PRO2_WALLPAPER_HEIGHT,
78
87
  rgba: decoded.data,
88
+ encoding: resolvedEncoding,
79
89
  });
80
90
  this.path = `${WALLPAPER_DIRECTORY}/${normalizeFileName(fileName, this.encoded.data)}`;
81
- this.params = { jpegBase64, fileName, chunkSize };
91
+ this.params = { jpegBase64, fileName, chunkSize, encoding: resolvedEncoding };
82
92
  this.unlockPolicy = 'unlock-before-run';
83
93
  // File writes and wallpaper apply require an unlocked device. Either PIN
84
94
  // may authorize this device-management action.