@onekeyfe/hd-core 1.2.0-alpha.67 → 1.2.0-alpha.68

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 (254) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +313 -0
  2. package/__tests__/DeviceCommands.test.ts +59 -13
  3. package/__tests__/DeviceEventRegistration.test.ts +6 -0
  4. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +198 -3
  5. package/__tests__/core-initialization.test.ts +23 -0
  6. package/__tests__/device-connector-protocol.test.ts +81 -0
  7. package/__tests__/device-lifecycle-events.test.ts +105 -3
  8. package/__tests__/device-pool-state.test.ts +22 -0
  9. package/__tests__/device-settings.test.ts +39 -18
  10. package/__tests__/device-state-contract.test.ts +1 -0
  11. package/__tests__/device-state-mapper.test.ts +13 -1
  12. package/__tests__/device-utils.test.ts +48 -1
  13. package/__tests__/deviceSettings.test.ts +11 -1
  14. package/__tests__/deviceUploadNft.test.ts +316 -0
  15. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +5 -0
  16. package/__tests__/get-device-state.test.ts +132 -12
  17. package/__tests__/homescreen.test.ts +41 -1
  18. package/__tests__/kaspa-use-tweak-pro2.test.ts +2 -2
  19. package/__tests__/kaspaSignTransaction.test.ts +3 -26
  20. package/__tests__/logBlockEvent.test.ts +1 -1
  21. package/__tests__/method-protocol-support.test.ts +19 -0
  22. package/__tests__/open-wallet-session.test.ts +568 -37
  23. package/__tests__/pro2Nft.test.ts +108 -0
  24. package/__tests__/protocol-binding.test.ts +89 -0
  25. package/__tests__/protocol-v2-resources.test.ts +340 -0
  26. package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
  27. package/__tests__/protocol-v2-unlock-policy.test.ts +300 -37
  28. package/__tests__/protocol-v2.test.ts +1449 -867
  29. package/__tests__/protocolV2FileWrite.test.ts +152 -0
  30. package/__tests__/protocolV2UiInteraction.test.ts +63 -0
  31. package/__tests__/public-pro2-api-boundary.test.ts +1 -0
  32. package/__tests__/search-devices.test.ts +12 -3
  33. package/__tests__/tron-sign-message-init.test.ts +2 -2
  34. package/__tests__/uiProgressThrottle.test.ts +74 -0
  35. package/__tests__/uiPromiseRegistry.test.ts +115 -0
  36. package/dist/api/BaseMethod.d.ts +3 -1
  37. package/dist/api/BaseMethod.d.ts.map +1 -1
  38. package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
  39. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  40. package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
  41. package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
  42. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  43. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  44. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  45. package/dist/api/FirmwareUpdateV4.d.ts +11 -4
  46. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  47. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  48. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  49. package/dist/api/SearchDevices.d.ts.map +1 -1
  50. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  51. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  52. package/dist/api/device/DeviceUnlock.d.ts +2 -2
  53. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  54. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +4 -3
  55. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  56. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  57. package/dist/api/helpers/protocolV2FileWrite.d.ts +9 -0
  58. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  59. package/dist/api/index.d.ts +2 -0
  60. package/dist/api/index.d.ts.map +1 -1
  61. package/dist/api/kaspa/KaspaGetAddress.d.ts +1 -1
  62. package/dist/api/kaspa/KaspaSignTransaction.d.ts +1 -1
  63. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  64. package/dist/api/polkadot/PolkadotGetAddress.d.ts +1 -1
  65. package/dist/api/polkadot/networks.d.ts +1 -1
  66. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
  67. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
  68. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  69. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  70. package/dist/api/solana/SolSignMessage.d.ts +1 -1
  71. package/dist/api/solana/SolSignOffchainMessage.d.ts +1 -1
  72. package/dist/api/solana/SolSignTransaction.d.ts +2 -2
  73. package/dist/api/sui/SuiGetAddress.d.ts +1 -1
  74. package/dist/api/sui/SuiGetPublicKey.d.ts +1 -1
  75. package/dist/api/sui/SuiSignMessage.d.ts +1 -1
  76. package/dist/api/sui/SuiSignTransaction.d.ts +1 -1
  77. package/dist/api/ton/TonGetAddress.d.ts +1 -1
  78. package/dist/api/ton/TonSignMessage.d.ts +1 -1
  79. package/dist/api/ton/TonSignProof.d.ts +1 -1
  80. package/dist/api/tron/TronSignMessage.d.ts +2 -2
  81. package/dist/api/tron/TronSignTransaction.d.ts +1 -1
  82. package/dist/core/deviceEventRegistration.d.ts +2 -0
  83. package/dist/core/deviceEventRegistration.d.ts.map +1 -1
  84. package/dist/core/index.d.ts.map +1 -1
  85. package/dist/core/uiPromiseRegistry.d.ts +6 -0
  86. package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
  87. package/dist/data-manager/DataManager.d.ts +9 -3
  88. package/dist/data-manager/DataManager.d.ts.map +1 -1
  89. package/dist/data-manager/TransportManager.d.ts.map +1 -1
  90. package/dist/device/Device.d.ts +29 -5
  91. package/dist/device/Device.d.ts.map +1 -1
  92. package/dist/device/DeviceCommands.d.ts +4 -4
  93. package/dist/device/DeviceCommands.d.ts.map +1 -1
  94. package/dist/device/DeviceConnector.d.ts +2 -1
  95. package/dist/device/DeviceConnector.d.ts.map +1 -1
  96. package/dist/device/DevicePool.d.ts.map +1 -1
  97. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -1
  98. package/dist/events/device.d.ts +4 -0
  99. package/dist/events/device.d.ts.map +1 -1
  100. package/dist/events/logBlockEvent.d.ts.map +1 -1
  101. package/dist/events/ui-promise.d.ts +4 -2
  102. package/dist/events/ui-promise.d.ts.map +1 -1
  103. package/dist/events/ui-request.d.ts +31 -2
  104. package/dist/events/ui-request.d.ts.map +1 -1
  105. package/dist/events/ui-response.d.ts +10 -2
  106. package/dist/events/ui-response.d.ts.map +1 -1
  107. package/dist/index.d.ts +243 -69
  108. package/dist/index.js +2563 -1217
  109. package/dist/inject.d.ts +6 -1
  110. package/dist/inject.d.ts.map +1 -1
  111. package/dist/lowLevelInject.d.ts.map +1 -1
  112. package/dist/protocols/protocol-v2/features.d.ts +0 -4
  113. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  114. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
  115. package/dist/protocols/protocol-v2/resources.d.ts +30 -0
  116. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
  117. package/dist/protocols/protocol-v2/uiInteraction.d.ts +7 -4
  118. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  119. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
  120. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  121. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
  122. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
  123. package/dist/protocols/protocol-v2/walletSession.d.ts +6 -1
  124. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  125. package/dist/topLevelInject.d.ts.map +1 -1
  126. package/dist/types/api/checkAllFirmwareRelease.d.ts +3 -1
  127. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  128. package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
  129. package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
  130. package/dist/types/api/deviceUnlock.d.ts +5 -1
  131. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  132. package/dist/types/api/export.d.ts +1 -0
  133. package/dist/types/api/export.d.ts.map +1 -1
  134. package/dist/types/api/firmwareUpdate.d.ts +4 -2
  135. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  136. package/dist/types/api/index.d.ts +6 -1
  137. package/dist/types/api/index.d.ts.map +1 -1
  138. package/dist/types/api/protocolV2.d.ts +3 -0
  139. package/dist/types/api/protocolV2.d.ts.map +1 -1
  140. package/dist/types/device.d.ts +2 -2
  141. package/dist/types/device.d.ts.map +1 -1
  142. package/dist/types/params.d.ts +1 -0
  143. package/dist/types/params.d.ts.map +1 -1
  144. package/dist/types/settings.d.ts +38 -8
  145. package/dist/types/settings.d.ts.map +1 -1
  146. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  147. package/dist/utils/deviceFeaturesUtils.d.ts +4 -0
  148. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  149. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  150. package/dist/utils/deviceSettings.d.ts.map +1 -1
  151. package/dist/utils/homescreen.d.ts +4 -0
  152. package/dist/utils/homescreen.d.ts.map +1 -1
  153. package/dist/utils/index.d.ts +1 -1
  154. package/dist/utils/index.d.ts.map +1 -1
  155. package/dist/utils/patch.d.ts +1 -1
  156. package/dist/utils/patch.d.ts.map +1 -1
  157. package/dist/utils/pro2Nft.d.ts +31 -0
  158. package/dist/utils/pro2Nft.d.ts.map +1 -0
  159. package/dist/utils/pro2Wallpaper.d.ts +10 -0
  160. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  161. package/dist/utils/uiProgressThrottle.d.ts +3 -0
  162. package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
  163. package/package.json +4 -4
  164. package/src/api/BaseMethod.ts +8 -10
  165. package/src/api/CheckAllFirmwareRelease.ts +61 -11
  166. package/src/api/DetectDeviceConnectProtocol.ts +18 -0
  167. package/src/api/FirmwareUpdate.ts +6 -2
  168. package/src/api/FirmwareUpdateV2.ts +5 -2
  169. package/src/api/FirmwareUpdateV3.ts +6 -2
  170. package/src/api/FirmwareUpdateV4.ts +463 -258
  171. package/src/api/GetPassphraseState.ts +7 -1
  172. package/src/api/OpenWalletSession.ts +71 -17
  173. package/src/api/SearchDevices.ts +3 -1
  174. package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
  175. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +36 -11
  176. package/src/api/device/DeviceSettings.ts +5 -4
  177. package/src/api/device/DeviceUnlock.ts +8 -3
  178. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +27 -12
  179. package/src/api/firmware/uploadFirmware.ts +17 -4
  180. package/src/api/helpers/protocolV2FileWrite.ts +202 -63
  181. package/src/api/index.ts +2 -0
  182. package/src/api/kaspa/KaspaGetAddress.ts +1 -1
  183. package/src/api/kaspa/KaspaSignTransaction.ts +2 -13
  184. package/src/api/polkadot/networks.ts +3 -3
  185. package/src/api/protocol-v2/DeviceUploadNft.ts +197 -0
  186. package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
  187. package/src/api/protocol-v2/helpers.ts +1 -1
  188. package/src/api/solana/SolSignMessage.ts +1 -1
  189. package/src/api/solana/SolSignOffchainMessage.ts +1 -1
  190. package/src/api/solana/SolSignTransaction.ts +2 -2
  191. package/src/api/sui/SuiGetAddress.ts +1 -1
  192. package/src/api/sui/SuiGetPublicKey.ts +1 -1
  193. package/src/api/sui/SuiSignMessage.ts +1 -1
  194. package/src/api/sui/SuiSignTransaction.ts +1 -1
  195. package/src/api/ton/TonGetAddress.ts +1 -1
  196. package/src/api/ton/TonSignMessage.ts +1 -1
  197. package/src/api/ton/TonSignProof.ts +1 -1
  198. package/src/api/tron/TronSignMessage.ts +2 -2
  199. package/src/api/tron/TronSignTransaction.ts +1 -1
  200. package/src/core/deviceEventRegistration.ts +4 -0
  201. package/src/core/index.ts +213 -111
  202. package/src/core/uiPromiseRegistry.ts +63 -0
  203. package/src/data/messages/messages-protocol-v2.json +25 -0
  204. package/src/data-manager/DataManager.ts +88 -11
  205. package/src/data-manager/TransportManager.ts +6 -0
  206. package/src/device/Device.ts +273 -43
  207. package/src/device/DeviceCommands.ts +31 -4
  208. package/src/device/DeviceConnector.ts +33 -13
  209. package/src/device/DevicePool.ts +21 -7
  210. package/src/deviceProfile/buildDeviceFeatures.ts +2 -2
  211. package/src/deviceProfile/protocolV2DeviceIdentity.ts +3 -0
  212. package/src/events/device.ts +4 -0
  213. package/src/events/logBlockEvent.ts +1 -0
  214. package/src/events/ui-promise.ts +4 -2
  215. package/src/events/ui-request.ts +36 -2
  216. package/src/events/ui-response.ts +12 -2
  217. package/src/inject.ts +58 -2
  218. package/src/lowLevelInject.ts +6 -3
  219. package/src/protocols/protocol-v2/features.ts +10 -7
  220. package/src/protocols/protocol-v2/firmware.ts +2 -0
  221. package/src/protocols/protocol-v2/resources.ts +390 -0
  222. package/src/protocols/protocol-v2/uiInteraction.ts +46 -6
  223. package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
  224. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +131 -0
  225. package/src/protocols/protocol-v2/walletSession.ts +214 -36
  226. package/src/topLevelInject.ts +6 -3
  227. package/src/types/api/checkAllFirmwareRelease.ts +3 -1
  228. package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
  229. package/src/types/api/deviceUnlock.ts +12 -1
  230. package/src/types/api/export.ts +1 -0
  231. package/src/types/api/firmwareUpdate.ts +6 -3
  232. package/src/types/api/index.ts +13 -0
  233. package/src/types/api/protocolV2.ts +13 -0
  234. package/src/types/device.ts +15 -3
  235. package/src/types/params.ts +7 -1
  236. package/src/types/settings.ts +60 -9
  237. package/src/utils/deviceFeaturesCompat.ts +5 -0
  238. package/src/utils/deviceFeaturesUtils.ts +14 -3
  239. package/src/utils/deviceInfoUtils.ts +2 -0
  240. package/src/utils/deviceSettings.ts +3 -0
  241. package/src/utils/homescreen.ts +32 -6
  242. package/src/utils/index.ts +6 -1
  243. package/src/utils/pro2Nft.ts +142 -0
  244. package/src/utils/pro2Wallpaper.ts +35 -8
  245. package/src/utils/uiProgressThrottle.ts +63 -0
  246. package/dist/api/firmware/progressThrottle.d.ts +0 -3
  247. package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
  248. package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
  249. package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
  250. package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
  251. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
  252. package/src/api/firmware/progressThrottle.ts +0 -44
  253. package/src/protocols/protocol-v2/lockedError.ts +0 -10
  254. package/src/protocols/protocol-v2/unlockRetry.ts +0 -109
@@ -1,6 +1,7 @@
1
1
  import type {
2
2
  deviceGetOnboardingStatus,
3
3
  deviceReboot,
4
+ deviceUploadNft,
4
5
  deviceUploadWallpaper,
5
6
  testProtocolV2Ping,
6
7
  uploadPortfolio,
@@ -18,6 +19,7 @@ import type { checkBootloaderRelease } from './checkBootloaderRelease';
18
19
  import type { checkAllFirmwareRelease } from './checkAllFirmwareRelease';
19
20
  import type { checkFirmwareTypeAvailable } from './checkFirmwareTypeAvailable';
20
21
  import type { searchDevices } from './searchDevices';
22
+ import type { detectDeviceConnectProtocol } from './detectDeviceConnectProtocol';
21
23
  import type { getFeatures } from './getFeatures';
22
24
  import type { getDeviceState } from './getDeviceState';
23
25
  import type { getOnekeyFeatures } from './getOnekeyFeatures';
@@ -152,6 +154,7 @@ import type { benfenSignMessage } from './benfenSignMessage';
152
154
  import type { neoGetAddress } from './neoGetAddress';
153
155
  import type { neoSignTransaction } from './neoSignTransaction';
154
156
  import type { ConnectSettings } from '../settings';
157
+ import type { HardwareConnectProtocol } from '@onekeyfe/hd-shared';
155
158
 
156
159
  export * from './export';
157
160
  export type { DeviceStateScope, GetDeviceStateParams } from './getDeviceState';
@@ -176,6 +179,14 @@ export type CoreApi = {
176
179
  removeAllListeners: typeof removeAllListeners;
177
180
  dispose: () => void | Promise<void>;
178
181
  call: (params: any) => Promise<any>;
182
+ /**
183
+ * Bind a protocol that has already been verified for one transport endpoint.
184
+ * Every later SDK call for the same connectId uses it as a strict expectation.
185
+ */
186
+ setDeviceConnectProtocol: (
187
+ connectId: string,
188
+ connectProtocol: HardwareConnectProtocol | undefined
189
+ ) => void;
179
190
  uiResponse: typeof uiResponse;
180
191
  cancel: (connectId?: string) => void;
181
192
  updateSettings: typeof updateSettings;
@@ -203,6 +214,7 @@ export type CoreApi = {
203
214
  * Device function
204
215
  */
205
216
  searchDevices: typeof searchDevices;
217
+ detectDeviceConnectProtocol: typeof detectDeviceConnectProtocol;
206
218
  promptWebDeviceAccess: typeof promptWebDeviceAccess;
207
219
  getFeatures: typeof getFeatures;
208
220
  getDeviceState: typeof getDeviceState;
@@ -248,6 +260,7 @@ export type CoreApi = {
248
260
  */
249
261
  deviceReboot: typeof deviceReboot;
250
262
  deviceGetOnboardingStatus: typeof deviceGetOnboardingStatus;
263
+ deviceUploadNft: typeof deviceUploadNft;
251
264
  deviceUploadWallpaper: typeof deviceUploadWallpaper;
252
265
  uploadPortfolio: typeof uploadPortfolio;
253
266
 
@@ -5,6 +5,10 @@ import type {
5
5
  DeviceUploadWallpaperParams,
6
6
  DeviceUploadWallpaperResponse,
7
7
  } from '../../api/protocol-v2/DeviceUploadWallpaper';
8
+ import type {
9
+ DeviceUploadNftParams,
10
+ DeviceUploadNftResponse,
11
+ } from '../../api/protocol-v2/DeviceUploadNft';
8
12
 
9
13
  // Re-export implementation parameter types as the single source of truth.
10
14
  export type { DeviceRebootParams, RebootTypeInput } from '../../api/protocol-v2/helpers';
@@ -12,6 +16,10 @@ export type {
12
16
  DeviceUploadWallpaperParams,
13
17
  DeviceUploadWallpaperResponse,
14
18
  } from '../../api/protocol-v2/DeviceUploadWallpaper';
19
+ export type {
20
+ DeviceUploadNftParams,
21
+ DeviceUploadNftResponse,
22
+ } from '../../api/protocol-v2/DeviceUploadNft';
15
23
 
16
24
  // ── Shared response shapes (Protocol V2 file system) ────────────────────
17
25
 
@@ -52,6 +60,11 @@ export declare function deviceUploadWallpaper(
52
60
  params: CommonParams & DeviceUploadWallpaperParams
53
61
  ): Response<DeviceUploadWallpaperResponse>;
54
62
 
63
+ export declare function deviceUploadNft(
64
+ connectId: string,
65
+ params: CommonParams & DeviceUploadNftParams
66
+ ): Response<DeviceUploadNftResponse>;
67
+
55
68
  export declare function uploadPortfolio(
56
69
  connectId: string,
57
70
  params: {
@@ -210,7 +210,9 @@ export type DeviceStateStatus = {
210
210
  recoveryMode: boolean | null;
211
211
  passphraseProtection: boolean | null;
212
212
  pinProtection: boolean | null;
213
+ /** `attach_to_pin_enabled`:是否至少存在一个 Attach PIN 绑定。 */
213
214
  attachToPinEnabled: boolean | null;
215
+ /** `unlocked_by_attach_to_pin`:本次解锁是否由 Attach PIN 完成。 */
214
216
  unlockedAttachPin: boolean | null;
215
217
  };
216
218
 
@@ -321,6 +323,7 @@ export type NormalizedFeatures = {
321
323
  sdProtection: boolean | null;
322
324
  wipeCodeProtection: boolean | null;
323
325
  passphraseAlwaysOnDevice: boolean | null;
326
+ /** `attach_to_pin_enabled`:是否至少存在一个 Attach PIN 绑定。 */
324
327
  attachToPinEnabled?: boolean | null;
325
328
  safetyChecks: Enum_SafetyCheckLevel | null;
326
329
  autoLockDelayMs: number | null;
@@ -371,14 +374,21 @@ export type IDeviceType =
371
374
  | EDeviceType.Mini
372
375
  | EDeviceType.Touch
373
376
  | EDeviceType.Pro
374
- | EDeviceType.Pro2;
377
+ | EDeviceType.Pro2
378
+ | EDeviceType.Neo;
375
379
 
376
380
  /**
377
381
  * model_classic: 'classic' | 'classic1s' | 'classicpure'
378
382
  * model_mini: 'classic' | 'classic1s' | 'classicpure' | 'mini'
379
383
  * model_touch: 'touch' | 'pro'
384
+ * model_pro2: 'pro2' | 'neo'
380
385
  */
381
- export type IDeviceModel = 'model_classic' | 'model_mini' | 'model_touch' | 'model_classic1s';
386
+ export type IDeviceModel =
387
+ | 'model_classic'
388
+ | 'model_mini'
389
+ | 'model_touch'
390
+ | 'model_classic1s'
391
+ | 'model_pro2';
382
392
 
383
393
  export const DeviceModelToTypes: { [deviceModel in IDeviceModel]: IDeviceType[] } = {
384
394
  model_mini: [
@@ -388,6 +398,7 @@ export const DeviceModelToTypes: { [deviceModel in IDeviceModel]: IDeviceType[]
388
398
  EDeviceType.Mini,
389
399
  ],
390
400
  model_touch: [EDeviceType.Touch, EDeviceType.Pro],
401
+ model_pro2: [EDeviceType.Pro2, EDeviceType.Neo],
391
402
  model_classic: [EDeviceType.Classic, EDeviceType.Classic1s, EDeviceType.ClassicPure],
392
403
  model_classic1s: [EDeviceType.Classic1s, EDeviceType.ClassicPure],
393
404
  };
@@ -399,7 +410,8 @@ export const DeviceTypeToModels: { [deviceType in IDeviceType]: IDeviceModel[] }
399
410
  [EDeviceType.Mini]: ['model_mini'],
400
411
  [EDeviceType.Touch]: ['model_touch'],
401
412
  [EDeviceType.Pro]: ['model_touch'],
402
- [EDeviceType.Pro2]: [],
413
+ [EDeviceType.Pro2]: ['model_pro2'],
414
+ [EDeviceType.Neo]: ['model_pro2'],
403
415
  [EDeviceType.Unknown]: [],
404
416
  };
405
417
 
@@ -61,9 +61,15 @@ export interface CommonParams {
61
61
 
62
62
  /**
63
63
  * Strictly expected transport protocol. The SDK actively verifies this value and
64
- * rejects a mismatch. If omitted, a cached protocol only influences probe order.
64
+ * rejects a mismatch. After a successful probe, the cached protocol is also strict.
65
65
  */
66
66
  connectProtocol?: HardwareConnectProtocol;
67
+
68
+ /**
69
+ * Ignore a previously bound protocol for this call and actively detect the
70
+ * protocol again. Intended for the first verified connection or explicit recovery.
71
+ */
72
+ forceProtocolDetection?: boolean;
67
73
  }
68
74
 
69
75
  export type Params<T> = CommonParams & T & { bundle?: undefined };
@@ -64,6 +64,49 @@ export type IProtocolV2FirmwareComponent = {
64
64
  version?: IVersionArray;
65
65
  };
66
66
 
67
+ export type IProtocolV2ResourceType =
68
+ | 'images'
69
+ | 'animation'
70
+ | 'wallpaper'
71
+ | 'translations'
72
+ | 'roobert'
73
+ | 'noto';
74
+
75
+ /** Pro2 RES package descriptor. Hashes identify content without a human-managed version. */
76
+ export type IProtocolV2Resource = {
77
+ type: IProtocolV2ResourceType;
78
+ url: string;
79
+ /** Complete okpkg file size in bytes. */
80
+ size: number;
81
+ /** SHA-256 of the complete okpkg file. */
82
+ fileHash: string;
83
+ /** SHA3-512 header_hash from the signed okpkg header. */
84
+ headerHash: string;
85
+ };
86
+
87
+ /** A file from the Protocol V2 resource manifest, written directly with FileWrite. */
88
+ export type IProtocolV2ResourceFile = {
89
+ name?: string;
90
+ url: string;
91
+ devicePath: string;
92
+ size: number;
93
+ /** SHA-256 of the complete file. */
94
+ fileHash: string;
95
+ };
96
+
97
+ /** Optional Protocol V2 boot resources restored as individual files. */
98
+ export type IProtocolV2BootResources = {
99
+ required: false;
100
+ target: 'RES';
101
+ manifestUrl?: string;
102
+ files: IProtocolV2ResourceFile[];
103
+ };
104
+
105
+ export type IProtocolV2Resources = {
106
+ stable: IProtocolV2Resource[];
107
+ boot?: IProtocolV2BootResources;
108
+ };
109
+
67
110
  /** Pro2 RESC bundle okpkg descriptor for incremental FileWrite synchronization. */
68
111
  export type IProtocolV2ResourceBundle = {
69
112
  /** Bundle name, such as images, animation, translations, or fonts_roobert. */
@@ -139,17 +182,25 @@ export type IBLEFirmwareReleaseInfo = {
139
182
  };
140
183
 
141
184
  type IKnownDevice = Exclude<IDeviceType, 'unknown'>;
185
+ type ILegacyKnownDevice = Exclude<IKnownDevice, 'neo'>;
186
+
187
+ type IDeviceReleaseInfo = {
188
+ firmware: IFirmwareReleaseInfo[];
189
+ /** Protocol V2 payload package set */
190
+ 'firmware-v1'?: IFirmwareReleaseInfo[];
191
+ 'firmware-v2'?: IFirmwareReleaseInfo[];
192
+ 'firmware-v8'?: IFirmwareReleaseInfo[];
193
+ 'firmware-btc-v8'?: IFirmwareReleaseInfo[];
194
+ ble: IBLEFirmwareReleaseInfo[];
195
+ /** Independent Protocol V2 resource release configuration. */
196
+ resources?: IProtocolV2Resources;
197
+ };
142
198
 
143
199
  export type DeviceTypeMap = {
144
- [k in IKnownDevice]: {
145
- firmware: IFirmwareReleaseInfo[];
146
- /** Pro2 Protocol V2 payload package set */
147
- 'firmware-v1'?: IFirmwareReleaseInfo[];
148
- 'firmware-v2'?: IFirmwareReleaseInfo[];
149
- 'firmware-v8'?: IFirmwareReleaseInfo[];
150
- 'firmware-btc-v8'?: IFirmwareReleaseInfo[];
151
- ble: IBLEFirmwareReleaseInfo[];
152
- };
200
+ [k in ILegacyKnownDevice]: IDeviceReleaseInfo;
201
+ } & {
202
+ /** Optional until every remote-config producer publishes a Neo entry. */
203
+ neo?: IDeviceReleaseInfo;
153
204
  };
154
205
 
155
206
  export type AssetsMap = {
@@ -66,6 +66,8 @@ export const resolveDeviceType = (features?: DeviceFeaturesInput): IDeviceType =
66
66
  return EDeviceType.Pro;
67
67
  case 'PRO2':
68
68
  return EDeviceType.Pro2;
69
+ case 'NEO':
70
+ return EDeviceType.Neo;
69
71
  case 'PURE':
70
72
  return EDeviceType.ClassicPure;
71
73
  default:
@@ -75,6 +77,9 @@ export const resolveDeviceType = (features?: DeviceFeaturesInput): IDeviceType =
75
77
  if (compatible.model?.toString().toLowerCase() === EDeviceType.Pro2) {
76
78
  return EDeviceType.Pro2;
77
79
  }
80
+ if (compatible.model?.toString().toLowerCase() === EDeviceType.Neo) {
81
+ return EDeviceType.Neo;
82
+ }
78
83
 
79
84
  const serialNo = resolveDeviceSerialNo(features);
80
85
  const prefix = serialNo.slice(0, 2).toLowerCase();
@@ -74,7 +74,8 @@ export const supportInputPinOnSoftware = (features?: Features): SupportFeatureTy
74
74
  if (
75
75
  deviceType === EDeviceType.Touch ||
76
76
  deviceType === EDeviceType.Pro ||
77
- deviceType === EDeviceType.Pro2
77
+ deviceType === EDeviceType.Pro2 ||
78
+ deviceType === EDeviceType.Neo
78
79
  ) {
79
80
  return { support: false };
80
81
  }
@@ -90,7 +91,8 @@ export const supportNewPassphrase = (features?: Features): SupportFeatureType =>
90
91
  if (
91
92
  deviceType === EDeviceType.Touch ||
92
93
  deviceType === EDeviceType.Pro ||
93
- deviceType === EDeviceType.Pro2
94
+ deviceType === EDeviceType.Pro2 ||
95
+ deviceType === EDeviceType.Neo
94
96
  ) {
95
97
  return { support: true };
96
98
  }
@@ -106,6 +108,8 @@ export const getPassphraseStateWithRefreshDeviceInfo = async (
106
108
  expectPassphraseState?: string;
107
109
  onlyMainPin?: boolean;
108
110
  initSession?: boolean;
111
+ deriveCardano?: boolean;
112
+ rejectAttachPinForMainWallet?: boolean;
109
113
  }
110
114
  ) => {
111
115
  if (device.isProtocolV2()) {
@@ -121,6 +125,8 @@ export const getPassphraseStateWithRefreshDeviceInfo = async (
121
125
  initSession: options?.initSession,
122
126
  expectedPassphraseState: options?.expectPassphraseState,
123
127
  onlyMainPin: options?.onlyMainPin,
128
+ deriveCardano: options?.deriveCardano,
129
+ rejectAttachPinForMainWallet: options?.rejectAttachPinForMainWallet,
124
130
  });
125
131
  }
126
132
 
@@ -139,7 +145,8 @@ export const getPassphraseStateWithRefreshDeviceInfo = async (
139
145
  const isModeT =
140
146
  deviceType === EDeviceType.Touch ||
141
147
  deviceType === EDeviceType.Pro ||
142
- deviceType === EDeviceType.Pro2;
148
+ deviceType === EDeviceType.Pro2 ||
149
+ deviceType === EDeviceType.Neo;
143
150
 
144
151
  // 如果可以获取到 passphraseState,但是设备 features 显示设备未开启 passphrase,需要刷新设备状态
145
152
  // if passphraseState can be obtained, but the device features show that the device has not enabled passphrase, the device status needs to be refreshed
@@ -185,6 +192,8 @@ export const getPassphraseState = async (
185
192
  expectPassphraseState?: string;
186
193
  onlyMainPin?: boolean;
187
194
  initSession?: boolean;
195
+ deriveCardano?: boolean;
196
+ rejectAttachPinForMainWallet?: boolean;
188
197
  }
189
198
  ): Promise<{
190
199
  passphraseState: string | undefined;
@@ -205,6 +214,8 @@ export const getPassphraseState = async (
205
214
  initSession: options?.initSession,
206
215
  expectedPassphraseState: options?.expectPassphraseState,
207
216
  onlyMainPin: options?.onlyMainPin,
217
+ deriveCardano: options?.deriveCardano,
218
+ rejectAttachPinForMainWallet: options?.rejectAttachPinForMainWallet,
208
219
  });
209
220
  }
210
221
 
@@ -31,6 +31,7 @@ export const getDeviceTypeByBleName = (name?: string): IDeviceType => {
31
31
  if (/^Touch/i.test(name)) return EDeviceType.Touch;
32
32
 
33
33
  if (/\bPro\s*2\b/i.test(name) || /^Pro2/i.test(name)) return EDeviceType.Pro2;
34
+ if (/\bNeo\b/i.test(name) || /^Neo/i.test(name)) return EDeviceType.Neo;
34
35
  if (/\bPro\b/i.test(name) || /^Pro/i.test(name)) return EDeviceType.Pro;
35
36
 
36
37
  return EDeviceType.Unknown;
@@ -93,6 +94,7 @@ export const getMethodVersionRange = (
93
94
  }
94
95
 
95
96
  const modelFallbacks: IDeviceModel[] = [
97
+ 'model_pro2',
96
98
  'model_classic1s',
97
99
  'model_classic',
98
100
  'model_mini',
@@ -127,6 +127,7 @@ export const getLanguageConfig = (deviceType: IDeviceType): Record<string, strin
127
127
  keys = Object.keys(LANGUAGE_LABELS) as LanguageKey[];
128
128
  break;
129
129
  case EDeviceType.Pro2:
130
+ case EDeviceType.Neo:
130
131
  return PRO2_LANGUAGE_OPTIONS.map(option => ({ ...option }));
131
132
  default:
132
133
  keys = [];
@@ -176,6 +177,7 @@ export const getAutoLockOptions = (
176
177
  case EDeviceType.Touch:
177
178
  case EDeviceType.Pro:
178
179
  case EDeviceType.Pro2:
180
+ case EDeviceType.Neo:
179
181
  return withNever([30_000, 60_000, 120_000, 300_000, 600_000, 1_800_000], protocol);
180
182
  default:
181
183
  return [];
@@ -197,6 +199,7 @@ export const getAutoShutDownOptions = (
197
199
  case EDeviceType.Pro:
198
200
  return withNever([60_000, 120_000, 300_000, 600_000], protocol);
199
201
  case EDeviceType.Pro2:
202
+ case EDeviceType.Neo:
200
203
  return withNever([60_000, 120_000, 300_000, 600_000, 1_800_000], protocol);
201
204
  default:
202
205
  return [];
@@ -4,6 +4,12 @@ import { EDeviceType } from '@onekeyfe/hd-shared';
4
4
  import { getDeviceType } from './deviceInfoUtils';
5
5
  import { getDeviceFirmwareVersion } from './deviceVersionUtils';
6
6
  import { PRO2_WALLPAPER_HEIGHT, PRO2_WALLPAPER_WIDTH } from './pro2Wallpaper';
7
+ import {
8
+ PRO2_NFT_IMAGE_HEIGHT,
9
+ PRO2_NFT_IMAGE_WIDTH,
10
+ PRO2_NFT_THUMBNAIL_HEIGHT,
11
+ PRO2_NFT_THUMBNAIL_WIDTH,
12
+ } from './pro2Nft';
7
13
 
8
14
  import type { Features, IDeviceType } from '../types';
9
15
 
@@ -302,6 +308,31 @@ type SizeConfig = {
302
308
  radius?: number;
303
309
  };
304
310
 
311
+ export const getNftSize = ({
312
+ deviceType,
313
+ thumbnail,
314
+ }: {
315
+ deviceType: IDeviceType;
316
+ thumbnail?: boolean;
317
+ }): SizeConfig | undefined => {
318
+ const sizes: Partial<Record<IDeviceType, { full: SizeConfig; thumbnail: SizeConfig }>> = {
319
+ touch: {
320
+ full: { width: 480, height: 800 },
321
+ thumbnail: { width: 238, height: 238 },
322
+ },
323
+ pro: {
324
+ full: { width: 480, height: 800 },
325
+ thumbnail: { width: 226, height: 226, radius: 40 },
326
+ },
327
+ pro2: {
328
+ full: { width: PRO2_NFT_IMAGE_WIDTH, height: PRO2_NFT_IMAGE_HEIGHT },
329
+ thumbnail: { width: PRO2_NFT_THUMBNAIL_WIDTH, height: PRO2_NFT_THUMBNAIL_HEIGHT },
330
+ },
331
+ };
332
+
333
+ return sizes[deviceType]?.[thumbnail ? 'thumbnail' : 'full'];
334
+ };
335
+
305
336
  export const getHomeScreenSize = ({
306
337
  deviceType,
307
338
  homeScreenType,
@@ -312,12 +343,7 @@ export const getHomeScreenSize = ({
312
343
  thumbnail?: boolean;
313
344
  }) => {
314
345
  if (deviceType === EDeviceType.Pro2) {
315
- return thumbnail
316
- ? undefined
317
- : {
318
- width: PRO2_WALLPAPER_WIDTH,
319
- height: PRO2_WALLPAPER_HEIGHT,
320
- };
346
+ return thumbnail ? undefined : { width: PRO2_WALLPAPER_WIDTH, height: PRO2_WALLPAPER_HEIGHT };
321
347
  }
322
348
 
323
349
  const sizes: Partial<
@@ -54,7 +54,12 @@ export { getHDPath, getScriptType, getOutputScriptType } from '../api/helpers/pa
54
54
 
55
55
  export const isBleConnect = (env: string) => env === 'react-native' || env === 'lowlevel';
56
56
 
57
- export { getHomeScreenHex, getHomeScreenDefaultList, getHomeScreenSize } from './homescreen';
57
+ export {
58
+ getHomeScreenHex,
59
+ getHomeScreenDefaultList,
60
+ getHomeScreenSize,
61
+ getNftSize,
62
+ } from './homescreen';
58
63
  export { encodePro2Wallpaper, PRO2_WALLPAPER_HEIGHT, PRO2_WALLPAPER_WIDTH } from './pro2Wallpaper';
59
64
  export type { Pro2WallpaperColorFormat } from './pro2Wallpaper';
60
65
 
@@ -0,0 +1,142 @@
1
+ import { blake2s } from '@noble/hashes/blake2s';
2
+ import { bytesToHex } from '@noble/hashes/utils';
3
+
4
+ import { invalidParameter } from '../api/helpers/filesystemValidation';
5
+ import { encodePro2Image } from './pro2Wallpaper';
6
+
7
+ export const PRO2_NFT_IMAGE_WIDTH = 540;
8
+ export const PRO2_NFT_IMAGE_HEIGHT = 540;
9
+ export const PRO2_NFT_THUMBNAIL_WIDTH = 263;
10
+ export const PRO2_NFT_THUMBNAIL_HEIGHT = 263;
11
+ export const PRO2_NFT_DIRECTORY = 'vol1:/nft';
12
+ export const PRO2_NFT_DEFAULT_CHUNK_SIZE = 2048;
13
+ export const PRO2_NFT_DEFAULT_PACE_MS = 0;
14
+ export const PRO2_NFT_DEFAULT_TIMEOUT_MS = 15_000;
15
+ export const PRO2_NFT_MIN_CHUNK_SIZE = 64;
16
+ export const PRO2_NFT_MAX_CHUNK_SIZE = 2048;
17
+ export const PRO2_NFT_MAX_ITEMS = 10;
18
+
19
+ export type Pro2NftImage = {
20
+ width: number;
21
+ height: number;
22
+ rgba: Uint8Array | ArrayBuffer;
23
+ };
24
+
25
+ export type Pro2NftBundle = {
26
+ basename: string;
27
+ image: Uint8Array;
28
+ thumbnail: Uint8Array;
29
+ metadata: Uint8Array;
30
+ };
31
+
32
+ const PRO2_NFT_BASENAME_PATTERN = /^nft-[0-9a-f]{8}-[1-9][0-9]*$/;
33
+
34
+ type Pro2NftFileType = 'image' | 'thumbnail' | 'metadata';
35
+
36
+ function parsePro2NftFile(listedPath: string):
37
+ | {
38
+ basename: string;
39
+ fileType: Pro2NftFileType;
40
+ }
41
+ | undefined {
42
+ const filename = listedPath.trim().split('/').at(-1);
43
+ if (!filename) return undefined;
44
+
45
+ let basename: string | undefined;
46
+ let fileType: Pro2NftFileType | undefined;
47
+ if (filename.endsWith('_m.bin')) {
48
+ basename = filename.slice(0, -'_m.bin'.length);
49
+ fileType = 'thumbnail';
50
+ } else if (filename.endsWith('.json')) {
51
+ basename = filename.slice(0, -'.json'.length);
52
+ fileType = 'metadata';
53
+ } else if (filename.endsWith('.bin')) {
54
+ basename = filename.slice(0, -'.bin'.length);
55
+ fileType = 'image';
56
+ }
57
+
58
+ return basename && fileType && PRO2_NFT_BASENAME_PATTERN.test(basename)
59
+ ? { basename, fileType }
60
+ : undefined;
61
+ }
62
+
63
+ export function getCompletePro2NftBasenames(childFiles?: string): Set<string> {
64
+ const filesByBasename = new Map<string, Set<Pro2NftFileType>>();
65
+
66
+ for (const listedPath of childFiles?.split('\n') ?? []) {
67
+ const file = parsePro2NftFile(listedPath);
68
+ if (file) {
69
+ const fileTypes = filesByBasename.get(file.basename) ?? new Set<Pro2NftFileType>();
70
+ fileTypes.add(file.fileType);
71
+ filesByBasename.set(file.basename, fileTypes);
72
+ }
73
+ }
74
+
75
+ return new Set(
76
+ [...filesByBasename.entries()]
77
+ .filter(([, fileTypes]) => fileTypes.size === 3)
78
+ .map(([basename]) => basename)
79
+ );
80
+ }
81
+
82
+ function utf8Length(value: string): number {
83
+ return new TextEncoder().encode(value).byteLength;
84
+ }
85
+
86
+ function assertImage(
87
+ name: string,
88
+ image: Pro2NftImage,
89
+ expectedWidth: number,
90
+ expectedHeight: number
91
+ ) {
92
+ if (image.width !== expectedWidth || image.height !== expectedHeight) {
93
+ throw invalidParameter(
94
+ `Pro2 NFT ${name} dimensions must be ${expectedWidth}x${expectedHeight}.`
95
+ );
96
+ }
97
+ if (!(image.rgba instanceof ArrayBuffer) && !ArrayBuffer.isView(image.rgba)) {
98
+ throw invalidParameter(`Parameter [${name}.rgba] must be an ArrayBuffer or Uint8Array.`);
99
+ }
100
+ }
101
+
102
+ export function buildPro2NftBundle(options: {
103
+ image: Pro2NftImage;
104
+ thumbnail: Pro2NftImage;
105
+ title: string;
106
+ subtitle: string;
107
+ timestampMs: number;
108
+ }): Pro2NftBundle {
109
+ const { image, thumbnail, title, subtitle, timestampMs } = options;
110
+ assertImage('image', image, PRO2_NFT_IMAGE_WIDTH, PRO2_NFT_IMAGE_HEIGHT);
111
+ assertImage('thumbnail', thumbnail, PRO2_NFT_THUMBNAIL_WIDTH, PRO2_NFT_THUMBNAIL_HEIGHT);
112
+ const titleLength = typeof title === 'string' ? utf8Length(title) : 0;
113
+ const subtitleLength =
114
+ typeof subtitle === 'string' ? utf8Length(subtitle) : Number.POSITIVE_INFINITY;
115
+ if (titleLength < 1 || titleLength > 63) {
116
+ throw invalidParameter('Pro2 NFT title must contain 1 to 63 UTF-8 bytes.');
117
+ }
118
+ if (subtitleLength > 95) {
119
+ throw invalidParameter('Pro2 NFT subtitle must contain at most 95 UTF-8 bytes.');
120
+ }
121
+ if (!Number.isSafeInteger(timestampMs) || timestampMs <= 0) {
122
+ throw invalidParameter('Parameter [timestampMs] must be a positive safe integer.');
123
+ }
124
+
125
+ const encodedImage = encodePro2Image({ ...image, alphaMode: 'black-background' }).data;
126
+ const encodedThumbnail = encodePro2Image({
127
+ ...thumbnail,
128
+ alphaMode: 'black-background',
129
+ }).data;
130
+ const metadata = new TextEncoder().encode(JSON.stringify({ title, subtitle }));
131
+ if (metadata.byteLength === 0 || metadata.byteLength > 512) {
132
+ throw invalidParameter('Pro2 NFT metadata must contain 1 to 512 UTF-8 bytes.');
133
+ }
134
+
135
+ const hash8 = bytesToHex(blake2s(encodedImage)).slice(0, 8);
136
+ return {
137
+ basename: `nft-${hash8}-${timestampMs}`,
138
+ image: encodedImage,
139
+ thumbnail: encodedThumbnail,
140
+ metadata,
141
+ };
142
+ }
@@ -8,6 +8,8 @@ export const PRO2_WALLPAPER_HEIGHT = 1024;
8
8
 
9
9
  export type Pro2WallpaperColorFormat = 'RGB565' | 'RGB565A8';
10
10
 
11
+ export type Pro2ImageAlphaMode = 'preserve' | 'black-background';
12
+
11
13
  const COLOR_FORMAT_RGB565 = 0x12;
12
14
  const COLOR_FORMAT_RGB565A8 = 0x14;
13
15
 
@@ -36,10 +38,11 @@ function align(value: number, boundary: number): number {
36
38
  return Math.ceil(value / boundary) * boundary;
37
39
  }
38
40
 
39
- export function encodePro2Wallpaper(options: {
41
+ export function encodePro2Image(options: {
40
42
  width: number;
41
43
  height: number;
42
44
  rgba: Uint8Array | ArrayBuffer;
45
+ alphaMode?: Pro2ImageAlphaMode;
43
46
  }): { data: Uint8Array; colorFormat: Pro2WallpaperColorFormat } {
44
47
  const { width, height } = options;
45
48
  if (!Number.isInteger(width) || width <= 0 || width > 0xffff) {
@@ -57,11 +60,14 @@ export function encodePro2Wallpaper(options: {
57
60
  );
58
61
  }
59
62
 
63
+ const alphaMode = options.alphaMode ?? 'preserve';
60
64
  let hasTransparency = false;
61
- for (let index = 3; index < rgba.length; index += 4) {
62
- if (rgba[index] !== 0xff) {
63
- hasTransparency = true;
64
- break;
65
+ if (alphaMode === 'preserve') {
66
+ for (let index = 3; index < rgba.length; index += 4) {
67
+ if (rgba[index] !== 0xff) {
68
+ hasTransparency = true;
69
+ break;
70
+ }
65
71
  }
66
72
  }
67
73
 
@@ -85,9 +91,22 @@ export function encodePro2Wallpaper(options: {
85
91
  for (let x = 0; x < width; x += 1) {
86
92
  const sourceOffset = (y * width + x) * 4;
87
93
  const thresholdIndex = ((y & 7) << 3) + (x & 7);
88
- const red = Math.min(rgba[sourceOffset] + RED_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
89
- const green = Math.min(rgba[sourceOffset + 1] + GREEN_THRESHOLD[thresholdIndex], 0xff) & 0xfc;
90
- const blue = Math.min(rgba[sourceOffset + 2] + BLUE_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
94
+ const alpha = rgba[sourceOffset + 3];
95
+ const redChannel =
96
+ alphaMode === 'black-background'
97
+ ? Math.round((rgba[sourceOffset] * alpha) / 0xff)
98
+ : rgba[sourceOffset];
99
+ const greenChannel =
100
+ alphaMode === 'black-background'
101
+ ? Math.round((rgba[sourceOffset + 1] * alpha) / 0xff)
102
+ : rgba[sourceOffset + 1];
103
+ const blueChannel =
104
+ alphaMode === 'black-background'
105
+ ? Math.round((rgba[sourceOffset + 2] * alpha) / 0xff)
106
+ : rgba[sourceOffset + 2];
107
+ const red = Math.min(redChannel + RED_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
108
+ const green = Math.min(greenChannel + GREEN_THRESHOLD[thresholdIndex], 0xff) & 0xfc;
109
+ const blue = Math.min(blueChannel + BLUE_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
91
110
  const rgb565 = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
92
111
  const rgbOffset = 12 + y * stride + x * 2;
93
112
  data[rgbOffset] = rgb565 & 0xff;
@@ -101,3 +120,11 @@ export function encodePro2Wallpaper(options: {
101
120
 
102
121
  return { data, colorFormat };
103
122
  }
123
+
124
+ export function encodePro2Wallpaper(options: {
125
+ width: number;
126
+ height: number;
127
+ rgba: Uint8Array | ArrayBuffer;
128
+ }): { data: Uint8Array; colorFormat: Pro2WallpaperColorFormat } {
129
+ return encodePro2Image(options);
130
+ }