@onekeyfe/hd-core 1.2.0-alpha.11 → 1.2.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/__tests__/protocol-v2-bootloader-mode.test.ts +37 -0
  2. package/__tests__/protocol-v2.test.ts +240 -82
  3. package/__tests__/protocolV2FileWrite.test.ts +67 -0
  4. package/dist/api/FileWrite.d.ts.map +1 -1
  5. package/dist/api/FirmwareUpdateV4.d.ts +2 -0
  6. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  7. package/dist/api/helpers/protocolV2FileWrite.d.ts +32 -0
  8. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -0
  9. package/dist/api/index.d.ts +1 -1
  10. package/dist/api/index.d.ts.map +1 -1
  11. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +6 -0
  12. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts.map +1 -0
  13. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
  14. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  15. package/dist/device/Device.d.ts.map +1 -1
  16. package/dist/deviceProfile/buildDeviceFeatures.d.ts +2 -2
  17. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  18. package/dist/deviceProfile/buildDeviceProfile.d.ts.map +1 -1
  19. package/dist/index.d.ts +9 -11
  20. package/dist/index.js +736 -391
  21. package/dist/protocols/protocol-v2/features.d.ts +1 -0
  22. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  23. package/dist/protocols/protocol-v2/index.d.ts +1 -1
  24. package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
  25. package/dist/types/api/getDeviceInfo.d.ts +1 -1
  26. package/dist/types/api/getDeviceInfo.d.ts.map +1 -1
  27. package/dist/types/api/index.d.ts +2 -2
  28. package/dist/types/api/index.d.ts.map +1 -1
  29. package/dist/types/api/protocolV2.d.ts +2 -5
  30. package/dist/types/api/protocolV2.d.ts.map +1 -1
  31. package/dist/types/device.d.ts +3 -2
  32. package/dist/types/device.d.ts.map +1 -1
  33. package/dist/utils/patch.d.ts +1 -1
  34. package/dist/utils/patch.d.ts.map +1 -1
  35. package/package.json +4 -4
  36. package/src/api/FileWrite.ts +18 -186
  37. package/src/api/FirmwareUpdateV4.ts +46 -6
  38. package/src/api/cardano/CardanoSignMessage.ts +1 -1
  39. package/src/api/cardano/CardanoSignTransaction.ts +1 -1
  40. package/src/api/helpers/protocolV2FileWrite.ts +168 -0
  41. package/src/api/index.ts +1 -1
  42. package/src/api/protocol-v2/DeviceGetOnboardingStatus.ts +18 -0
  43. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +22 -52
  44. package/src/api/protocol-v2/helpers.ts +0 -3
  45. package/src/data/messages/messages-protocol-v2.json +422 -16
  46. package/src/data/messages/messages.json +0 -8
  47. package/src/device/Device.ts +7 -17
  48. package/src/deviceProfile/buildDeviceFeatures.ts +28 -12
  49. package/src/deviceProfile/buildDeviceProfile.ts +8 -6
  50. package/src/inject.ts +2 -2
  51. package/src/protocols/protocol-v2/features.ts +19 -1
  52. package/src/protocols/protocol-v2/index.ts +2 -0
  53. package/src/types/api/getDeviceInfo.ts +1 -1
  54. package/src/types/api/index.ts +2 -2
  55. package/src/types/api/protocolV2.ts +6 -6
  56. package/src/types/device.ts +6 -1
  57. package/dist/api/protocol-v2/FilesystemDiskControl.d.ts +0 -13
  58. package/dist/api/protocol-v2/FilesystemDiskControl.d.ts.map +0 -1
  59. package/src/api/protocol-v2/FilesystemDiskControl.ts +0 -50
@@ -379,6 +379,25 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
379
379
  };
380
380
  };
381
381
 
382
+ export const assertProtocolV2ReconnectIdentity = (
383
+ expectedDeviceId?: string,
384
+ actualDeviceId?: string
385
+ ) => {
386
+ if (!expectedDeviceId) return;
387
+ if (!actualDeviceId) {
388
+ throw ERRORS.TypedError(
389
+ HardwareErrorCode.DeviceNotFound,
390
+ 'Protocol V2 reconnect identity unavailable'
391
+ );
392
+ }
393
+ if (actualDeviceId !== expectedDeviceId) {
394
+ throw ERRORS.TypedError(
395
+ HardwareErrorCode.DeviceNotFound,
396
+ `Protocol V2 reconnect identity mismatch: expected ${expectedDeviceId}, received ${actualDeviceId}`
397
+ );
398
+ }
399
+ };
400
+
382
401
  /**
383
402
  * FirmwareUpdateV4 is the complete Protocol V2 firmware update flow.
384
403
  *
@@ -388,6 +407,8 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
388
407
  * - completion waits for target status to finish, reboots to normal, then polls DeviceInfo
389
408
  */
390
409
  export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareUpdateV4Params> {
410
+ private protocolV2ExpectedDeviceId?: string;
411
+
391
412
  init() {
392
413
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
393
414
  this.requireDeviceMode = [];
@@ -476,6 +497,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
476
497
 
477
498
  private async runProtocolV2() {
478
499
  const deviceFeatures = await this.getProtocolV2DeviceFeatures();
500
+ this.protocolV2ExpectedDeviceId = deviceFeatures.deviceId ?? undefined;
479
501
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
480
502
  const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
481
503
 
@@ -917,6 +939,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
917
939
  timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
918
940
  });
919
941
  const features = this.device.updateProtocolV2Features(deviceInfo);
942
+ assertProtocolV2ReconnectIdentity(
943
+ this.protocolV2ExpectedDeviceId,
944
+ features.deviceId ?? undefined
945
+ );
920
946
  if (features?.bootloaderMode) {
921
947
  return features;
922
948
  }
@@ -1134,6 +1160,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1134
1160
  request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
1135
1161
  });
1136
1162
  const features = this.device.updateProtocolV2Features(deviceInfo);
1163
+ assertProtocolV2ReconnectIdentity(
1164
+ this.protocolV2ExpectedDeviceId,
1165
+ features.deviceId ?? undefined
1166
+ );
1137
1167
  if (this.isProtocolV2NormalModeFeatures(features)) {
1138
1168
  Log.log('Protocol V2 firmware install finished; device is back in normal mode');
1139
1169
  return true;
@@ -1288,6 +1318,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1288
1318
  request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
1289
1319
  });
1290
1320
  const features = this.device.updateProtocolV2Features(deviceInfo);
1321
+ assertProtocolV2ReconnectIdentity(
1322
+ this.protocolV2ExpectedDeviceId,
1323
+ features.deviceId ?? undefined
1324
+ );
1291
1325
  if (features.bootloaderMode || features.mode === 'bootloader') {
1292
1326
  throw ERRORS.TypedError(
1293
1327
  HardwareErrorCode.DeviceNotFound,
@@ -1334,6 +1368,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1334
1368
  this.device.commands.disposed = false;
1335
1369
  this.device.getCommands().mainId = this.device.mainId ?? '';
1336
1370
  await this.device.initialize();
1371
+ assertProtocolV2ReconnectIdentity(
1372
+ this.protocolV2ExpectedDeviceId,
1373
+ this.device.getCurrentDeviceId()
1374
+ );
1337
1375
  return;
1338
1376
  }
1339
1377
 
@@ -1355,6 +1393,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1355
1393
  this.device.commands.disposed = false;
1356
1394
  this.device.getCommands().mainId = this.device.mainId ?? '';
1357
1395
  await this.device.initialize();
1396
+ assertProtocolV2ReconnectIdentity(
1397
+ this.protocolV2ExpectedDeviceId,
1398
+ this.device.getCurrentDeviceId()
1399
+ );
1358
1400
  }
1359
1401
 
1360
1402
  private async protocolV2CommonUpdateProcess(params: ProtocolV2FileTransferParams) {
@@ -1416,12 +1458,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1416
1458
  overwrite,
1417
1459
  progress
1418
1460
  );
1419
- const processedByte = Number(writeRes.message.processed_byte);
1420
- const nextOffset =
1421
- Number.isFinite(processedByte) && processedByte > offset
1422
- ? processedByte
1423
- : offset + chunkLength;
1424
- if (nextOffset <= offset || nextOffset > payload.byteLength) {
1461
+ const rawProcessedByte = writeRes.message.processed_byte;
1462
+ const processedByte = Number(rawProcessedByte);
1463
+ const nextOffset = rawProcessedByte === undefined ? offset + chunkLength : processedByte;
1464
+ if (!Number.isFinite(nextOffset) || nextOffset <= offset || nextOffset > chunkEnd) {
1425
1465
  throw ERRORS.TypedError(
1426
1466
  HardwareErrorCode.EmmcFileWriteFirmwareError,
1427
1467
  `invalid processed_byte ${writeRes.message.processed_byte} for offset ${offset}`
@@ -14,7 +14,7 @@ export default class CardanoSignMessage extends BaseMethod<CardanoSignMessagePar
14
14
  init() {
15
15
  this.checkDeviceId = true;
16
16
  this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
17
- this.allowUsePreInitialize = true;
17
+ this.allowUsePreInitialize = false;
18
18
 
19
19
  const { payload } = this;
20
20
  validateParams(payload, [
@@ -48,7 +48,7 @@ export default class CardanoSignTransaction extends BaseMethod<any> {
48
48
  init() {
49
49
  this.checkDeviceId = true;
50
50
  this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
51
- this.allowUsePreInitialize = true;
51
+ this.allowUsePreInitialize = false;
52
52
 
53
53
  this.hasBundle = !!this.payload?.bundle;
54
54
 
@@ -0,0 +1,168 @@
1
+ import {
2
+ PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
3
+ PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE,
4
+ } from '@onekeyfe/hd-transport';
5
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
6
+
7
+ import { DataManager } from '../../data-manager';
8
+
9
+ import type { DeviceCommands } from '../../device/DeviceCommands';
10
+
11
+ export type ProtocolV2FileWriteData = ArrayBuffer | Uint8Array | Blob | string;
12
+
13
+ export type ProtocolV2FileWriteProgress = {
14
+ progress: number;
15
+ transferredBytes: number;
16
+ totalBytes: number;
17
+ rateBytesPerSecond?: number;
18
+ elapsedMs: number;
19
+ };
20
+
21
+ export type ProtocolV2FileWriteOptions = {
22
+ commands: Pick<DeviceCommands, 'typedCall'>;
23
+ path: string;
24
+ data: ProtocolV2FileWriteData;
25
+ offset?: number;
26
+ totalSize?: number;
27
+ chunkSize?: number;
28
+ chunkLen?: number;
29
+ overwrite?: boolean;
30
+ append?: boolean;
31
+ uiPercentage?: number;
32
+ timeoutMs?: number;
33
+ throwIfAborted?: () => void;
34
+ onProgress?: (progress: ProtocolV2FileWriteProgress) => void;
35
+ };
36
+
37
+ const MIN_FILE_CHUNK_SIZE = 64;
38
+
39
+ function getProtocolV2FileChunkLimit() {
40
+ const env = DataManager.getSettings('env');
41
+ return env && DataManager.isBleConnect(env)
42
+ ? PROTOCOL_V2_BLE_FILE_CHUNK_SIZE
43
+ : PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
44
+ }
45
+
46
+ async function dataToUint8Array(data: ProtocolV2FileWriteData): Promise<Uint8Array> {
47
+ if (typeof data === 'string') return new TextEncoder().encode(data);
48
+ if (data instanceof ArrayBuffer) return new Uint8Array(data);
49
+ if (ArrayBuffer.isView(data)) {
50
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
51
+ }
52
+ if (typeof Blob !== 'undefined' && data instanceof Blob) {
53
+ return new Uint8Array(await data.arrayBuffer());
54
+ }
55
+ throw ERRORS.TypedError(
56
+ HardwareErrorCode.CallMethodInvalidParameter,
57
+ 'Unsupported FilesystemFileWrite data'
58
+ );
59
+ }
60
+
61
+ function normalizeChunkSize(value: unknown, maxChunkSize: number): number {
62
+ const numeric = Number(value);
63
+ if (!Number.isFinite(numeric) || numeric <= 0) return maxChunkSize;
64
+ return Math.min(Math.max(Math.floor(numeric), MIN_FILE_CHUNK_SIZE), maxChunkSize);
65
+ }
66
+
67
+ function getDeviceTransferProgress(before: number, after: number, total: number) {
68
+ if (!Number.isFinite(total) || total <= 0) return 100;
69
+ if (before <= 0 && after < total) return 0;
70
+ if (after >= total) return 100;
71
+ return Math.min(Math.max(Math.ceil((after / total) * 100), 1), 99);
72
+ }
73
+
74
+ function getConfirmedProgress(processed: number, total: number, written: number, length: number) {
75
+ if (Number.isFinite(processed) && Number.isFinite(total) && total > 0) {
76
+ if (processed >= total) return 100;
77
+ return Math.min(Math.max(Math.floor((processed / total) * 100), 0), 99);
78
+ }
79
+ if (length > 0) return written >= length ? 100 : Math.floor((written / length) * 100);
80
+ return 100;
81
+ }
82
+
83
+ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
84
+ options.throwIfAborted?.();
85
+ const data = await dataToUint8Array(options.data);
86
+ const dataLength = data.byteLength;
87
+ const startOffset =
88
+ Number.isFinite(options.offset) && Number(options.offset) > 0 ? Number(options.offset) : 0;
89
+ const totalSize =
90
+ Number.isFinite(options.totalSize) && Number(options.totalSize) > 0
91
+ ? Number(options.totalSize)
92
+ : startOffset + dataLength;
93
+
94
+ if (totalSize < startOffset + dataLength) {
95
+ throw ERRORS.TypedError(
96
+ HardwareErrorCode.RuntimeError,
97
+ `FilesystemFileWrite totalSize ${totalSize} is smaller than offset + data length ${
98
+ startOffset + dataLength
99
+ }`
100
+ );
101
+ }
102
+
103
+ const chunkSize = normalizeChunkSize(
104
+ options.chunkSize ?? options.chunkLen,
105
+ getProtocolV2FileChunkLimit()
106
+ );
107
+ let written = 0;
108
+ let chunks = 0;
109
+ let lastMessage: Record<string, unknown> | undefined;
110
+ const startTime = Date.now();
111
+
112
+ while (written < dataLength) {
113
+ options.throwIfAborted?.();
114
+ const chunk = data.slice(written, Math.min(written + chunkSize, dataLength));
115
+ const offset = startOffset + written;
116
+ const progress =
117
+ options.uiPercentage ??
118
+ getDeviceTransferProgress(offset, offset + chunk.byteLength, totalSize);
119
+ const response = await options.commands.typedCall(
120
+ 'FilesystemFileWrite',
121
+ 'FilesystemFile',
122
+ {
123
+ file: { path: options.path, offset, total_size: totalSize, data: chunk },
124
+ overwrite: chunks === 0 ? options.overwrite ?? false : false,
125
+ append: options.append ?? false,
126
+ ui_percentage: progress,
127
+ },
128
+ { timeoutMs: options.timeoutMs }
129
+ );
130
+ options.throwIfAborted?.();
131
+ lastMessage = response.message;
132
+ const rawProcessedByte = response.message?.processed_byte;
133
+ const processedByte = Number(rawProcessedByte);
134
+ if (
135
+ rawProcessedByte !== undefined &&
136
+ (!Number.isFinite(processedByte) ||
137
+ processedByte <= offset ||
138
+ processedByte > offset + chunk.byteLength)
139
+ ) {
140
+ throw ERRORS.TypedError(
141
+ HardwareErrorCode.RuntimeError,
142
+ `FilesystemFileWrite invalid processed_byte ${processedByte}`
143
+ );
144
+ }
145
+ written =
146
+ rawProcessedByte === undefined ? written + chunk.byteLength : processedByte - startOffset;
147
+ chunks += 1;
148
+ const elapsedMs = Date.now() - startTime;
149
+ const transferredBytes = Math.min(written, dataLength);
150
+ options.onProgress?.({
151
+ progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength),
152
+ transferredBytes,
153
+ totalBytes: dataLength,
154
+ rateBytesPerSecond:
155
+ elapsedMs > 0 ? Math.round((transferredBytes / elapsedMs) * 1000) : undefined,
156
+ elapsedMs,
157
+ });
158
+ }
159
+
160
+ return {
161
+ ...lastMessage,
162
+ path: options.path,
163
+ offset: startOffset,
164
+ total_size: totalSize,
165
+ processed_byte: startOffset + written,
166
+ chunks,
167
+ };
168
+ }
package/src/api/index.ts CHANGED
@@ -49,6 +49,7 @@ export { default as ping } from './protocol-v2/Ping';
49
49
  export { default as deviceReboot } from './protocol-v2/DeviceReboot';
50
50
  export { default as deviceInfoGet } from './protocol-v2/DeviceInfoGet';
51
51
  export { default as deviceStatusGet } from './protocol-v2/DeviceStatusGet';
52
+ export { default as deviceGetOnboardingStatus } from './protocol-v2/DeviceGetOnboardingStatus';
52
53
  export { default as deviceSessionGet } from './protocol-v2/DeviceSessionGet';
53
54
  export { default as deviceFirmwareUpdate } from './protocol-v2/DeviceFirmwareUpdate';
54
55
  export { default as deviceGetFirmwareUpdateStatus } from './protocol-v2/DeviceGetFirmwareUpdateStatus';
@@ -60,7 +61,6 @@ export { default as deviceSettingsPageShow } from './protocol-v2/DeviceSettingsP
60
61
  export { default as deviceUploadWallpaper } from './protocol-v2/DeviceUploadWallpaper';
61
62
  export { default as filesystemPermissionFix } from './protocol-v2/FilesystemPermissionFix';
62
63
  export { default as filesystemFormat } from './protocol-v2/FilesystemFormat';
63
- export { default as filesystemDiskControl } from './protocol-v2/FilesystemDiskControl';
64
64
  export { default as fileRead } from './FileRead';
65
65
  export { default as fileWrite } from './FileWrite';
66
66
  export { default as fileDelete } from './FileDelete';
@@ -0,0 +1,18 @@
1
+ import { BaseMethod } from '../BaseMethod';
2
+
3
+ export default class DeviceGetOnboardingStatus extends BaseMethod {
4
+ init() {
5
+ this.requireProtocolV2 = true;
6
+ this.skipForceUpdateCheck = true;
7
+ this.useDevicePassphraseState = false;
8
+ }
9
+
10
+ async run() {
11
+ const { message } = await this.device.commands.typedCall(
12
+ 'DevGetOnboardingStatus',
13
+ 'DevOnboardingStatus',
14
+ {}
15
+ );
16
+ return message;
17
+ }
18
+ }
@@ -1,19 +1,15 @@
1
1
  import { blake2s } from '@noble/hashes/blake2s';
2
2
  import { bytesToHex } from '@noble/hashes/utils';
3
- import {
4
- PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
5
- PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE,
6
- WallpaperTarget,
7
- } from '@onekeyfe/hd-transport';
8
3
 
9
4
  import { BaseMethod } from '../BaseMethod';
10
5
  import { invalidParameter } from '../helpers/filesystemValidation';
11
- import { DataManager } from '../../data-manager';
6
+ import { writeProtocolV2File } from '../helpers/protocolV2FileWrite';
7
+ import { UI_REQUEST, createUiMessage } from '../../events/ui-request';
12
8
  import {
13
- encodePro2Wallpaper,
14
9
  PRO2_WALLPAPER_HEIGHT,
15
10
  PRO2_WALLPAPER_WIDTH,
16
11
  type Pro2WallpaperColorFormat,
12
+ encodePro2Wallpaper,
17
13
  } from '../../utils/pro2Wallpaper';
18
14
 
19
15
  export type DeviceUploadWallpaperParams = {
@@ -34,13 +30,6 @@ export type DeviceUploadWallpaperResponse = {
34
30
  const WALLPAPER_DIRECTORY = 'vol0:/wallpapers/user';
35
31
  const SAFE_FILE_NAME = /^[A-Za-z0-9_-]+(?:\.bin)?$/;
36
32
 
37
- function getDefaultChunkSize(): number {
38
- const env = DataManager.getSettings('env');
39
- return env && DataManager.isBleConnect(env)
40
- ? PROTOCOL_V2_BLE_FILE_CHUNK_SIZE
41
- : PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
42
- }
43
-
44
33
  function normalizeFileName(fileName: string | undefined, data: Uint8Array): string {
45
34
  if (fileName !== undefined && (!fileName || !SAFE_FILE_NAME.test(fileName))) {
46
35
  throw invalidParameter(
@@ -102,53 +91,34 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
102
91
 
103
92
  private async upload() {
104
93
  if (this.uploaded) return;
105
- const encoded = this.encoded;
94
+ const { encoded } = this;
106
95
  if (!encoded) throw invalidParameter('Wallpaper data has not been initialized.');
107
96
 
108
- const maxChunkSize = getDefaultChunkSize();
109
- const requestedChunkSize = this.params.chunkSize ?? maxChunkSize;
110
- const chunkSize = Math.min(Math.max(64, Math.floor(requestedChunkSize)), maxChunkSize);
111
- let offset = 0;
112
- while (offset < encoded.data.byteLength) {
113
- const chunk = encoded.data.slice(offset, Math.min(offset + chunkSize, encoded.data.byteLength));
114
- const response = await this.device.commands.typedCall(
115
- 'FilesystemFileWrite',
116
- 'FilesystemFile',
117
- {
118
- file: {
119
- path: this.path,
120
- offset,
121
- total_size: encoded.data.byteLength,
122
- data: chunk,
123
- },
124
- overwrite: offset === 0,
125
- append: false,
126
- ui_percentage: Math.min(
127
- Math.ceil(((offset + chunk.byteLength) / encoded.data.byteLength) * 100),
128
- 100
129
- ),
130
- },
131
- { timeoutMs: undefined }
132
- );
133
- const processedByte = Number(response.message?.processed_byte);
134
- offset = Number.isFinite(processedByte) && processedByte > offset
135
- ? processedByte
136
- : offset + chunk.byteLength;
137
- if (offset > encoded.data.byteLength) {
138
- throw invalidParameter(`Invalid processed_byte returned by device: ${processedByte}.`);
139
- }
140
- }
97
+ await writeProtocolV2File({
98
+ commands: this.device.commands,
99
+ path: this.path,
100
+ data: encoded.data,
101
+ totalSize: encoded.data.byteLength,
102
+ chunkSize: this.params.chunkSize,
103
+ overwrite: true,
104
+ append: false,
105
+ throwIfAborted: () => this.throwIfAborted(),
106
+ onProgress: payload => {
107
+ if (typeof this.postMessage === 'function') {
108
+ this.postMessage(createUiMessage(UI_REQUEST.DEVICE_PROGRESS, payload));
109
+ }
110
+ },
111
+ });
141
112
  this.uploaded = true;
142
113
  }
143
114
 
144
115
  async run(): Promise<DeviceUploadWallpaperResponse> {
145
- const encoded = this.encoded;
116
+ const { encoded } = this;
146
117
  if (!encoded) throw invalidParameter('Wallpaper data has not been initialized.');
147
118
  await this.ensureDirectory();
148
119
  await this.upload();
149
- const response = await this.device.commands.typedCall('SetWallpaper', 'Success', {
150
- target: WallpaperTarget.Lock,
151
- path: this.path,
120
+ const response = await this.device.commands.typedCall('DeviceSettingsSet', 'Success', {
121
+ settings: { wallpaper_path: this.path },
152
122
  });
153
123
  return {
154
124
  path: this.path,
@@ -118,9 +118,6 @@ export const isProtocolV2DeviceDisconnectedError = (error: unknown) => {
118
118
  message.includes('connection has timed out unexpectedly') ||
119
119
  message.includes('connection error has occured') ||
120
120
  message.includes('connection error has occurred') ||
121
- message.includes('transferIn') ||
122
- message.includes('transferin') ||
123
- message.includes('usbdevice') ||
124
121
  message.includes('multiplatformbleadapter') ||
125
122
  message.includes('multipalformebleadapter') ||
126
123
  compactMessage.includes('rxerrorerror6') ||