@mentra/engine 0.1.0-dev.0 → 0.1.0-dev.1

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 (441) hide show
  1. package/README.md +42 -1
  2. package/build/engine.d.ts +11 -3
  3. package/build/engine.d.ts.map +1 -1
  4. package/build/engine.js +7 -2
  5. package/build/engine.js.map +1 -1
  6. package/build/facades/dev.d.ts +3 -2
  7. package/build/facades/dev.d.ts.map +1 -1
  8. package/build/facades/dev.js +18 -12
  9. package/build/facades/dev.js.map +1 -1
  10. package/build/facades/gallery.js +1 -1
  11. package/build/facades/gallery.js.map +1 -1
  12. package/build/facades/glasses.d.ts +1 -0
  13. package/build/facades/glasses.d.ts.map +1 -1
  14. package/build/facades/glasses.js +19 -4
  15. package/build/facades/glasses.js.map +1 -1
  16. package/build/facades/glassesSettings.d.ts.map +1 -1
  17. package/build/facades/glassesSettings.js +1 -0
  18. package/build/facades/glassesSettings.js.map +1 -1
  19. package/build/facades/miniapps.d.ts +4 -0
  20. package/build/facades/miniapps.d.ts.map +1 -1
  21. package/build/facades/miniapps.js +5 -0
  22. package/build/facades/miniapps.js.map +1 -1
  23. package/build/facades/ota.d.ts +11 -2
  24. package/build/facades/ota.d.ts.map +1 -1
  25. package/build/facades/ota.js +19 -4
  26. package/build/facades/ota.js.map +1 -1
  27. package/build/facades/pairing.d.ts +4 -0
  28. package/build/facades/pairing.d.ts.map +1 -1
  29. package/build/facades/pairing.js +10 -8
  30. package/build/facades/pairing.js.map +1 -1
  31. package/build/facades/permissions.d.ts +10 -0
  32. package/build/facades/permissions.d.ts.map +1 -1
  33. package/build/facades/permissions.js +10 -0
  34. package/build/facades/permissions.js.map +1 -1
  35. package/build/facades/phoneNotifications.d.ts +0 -4
  36. package/build/facades/phoneNotifications.d.ts.map +1 -1
  37. package/build/facades/phoneNotifications.js +4 -14
  38. package/build/facades/phoneNotifications.js.map +1 -1
  39. package/build/index.d.ts +6 -3
  40. package/build/index.d.ts.map +1 -1
  41. package/build/index.js +4 -2
  42. package/build/index.js.map +1 -1
  43. package/build/internal.d.ts +3 -2
  44. package/build/internal.d.ts.map +1 -1
  45. package/build/internal.js +2 -1
  46. package/build/internal.js.map +1 -1
  47. package/build/react/MentraLiveOtaFlow.d.ts +38 -0
  48. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
  49. package/build/react/MentraLiveOtaFlow.js +528 -0
  50. package/build/react/MentraLiveOtaFlow.js.map +1 -0
  51. package/build/react/index.d.ts +2 -0
  52. package/build/react/index.d.ts.map +1 -0
  53. package/build/react/index.js +2 -0
  54. package/build/react/index.js.map +1 -0
  55. package/build/react/useEngineSnapshot.d.ts +2 -0
  56. package/build/react/useEngineSnapshot.d.ts.map +1 -0
  57. package/build/react/useEngineSnapshot.js +14 -0
  58. package/build/react/useEngineSnapshot.js.map +1 -0
  59. package/build/runtime/bootstrap.d.ts +24 -1
  60. package/build/runtime/bootstrap.d.ts.map +1 -1
  61. package/build/runtime/bootstrap.js +17 -0
  62. package/build/runtime/bootstrap.js.map +1 -1
  63. package/build/runtime/scanQrSeam.d.ts +7 -0
  64. package/build/runtime/scanQrSeam.d.ts.map +1 -0
  65. package/build/runtime/scanQrSeam.js +16 -0
  66. package/build/runtime/scanQrSeam.js.map +1 -0
  67. package/build/services/AppRegistry.d.ts +33 -57
  68. package/build/services/AppRegistry.d.ts.map +1 -1
  69. package/build/services/AppRegistry.js +193 -144
  70. package/build/services/AppRegistry.js.map +1 -1
  71. package/build/services/AudioCloudUplink.d.ts +12 -0
  72. package/build/services/AudioCloudUplink.d.ts.map +1 -1
  73. package/build/services/AudioCloudUplink.js +22 -1
  74. package/build/services/AudioCloudUplink.js.map +1 -1
  75. package/build/services/AudioPlaybackService.d.ts +41 -2
  76. package/build/services/AudioPlaybackService.d.ts.map +1 -1
  77. package/build/services/AudioPlaybackService.js +250 -33
  78. package/build/services/AudioPlaybackService.js.map +1 -1
  79. package/build/services/BlobStore.d.ts +2 -1
  80. package/build/services/BlobStore.d.ts.map +1 -1
  81. package/build/services/BlobStore.js +17 -9
  82. package/build/services/BlobStore.js.map +1 -1
  83. package/build/services/CloudAudioSubscriptionSync.d.ts.map +1 -1
  84. package/build/services/CloudAudioSubscriptionSync.js +13 -1
  85. package/build/services/CloudAudioSubscriptionSync.js.map +1 -1
  86. package/build/services/CloudClientService.d.ts +15 -0
  87. package/build/services/CloudClientService.d.ts.map +1 -1
  88. package/build/services/CloudClientService.js +93 -1
  89. package/build/services/CloudClientService.js.map +1 -1
  90. package/build/services/DeviceEventRouter.js +5 -5
  91. package/build/services/DeviceEventRouter.js.map +1 -1
  92. package/build/services/ForegroundLocationPermission.d.ts +13 -0
  93. package/build/services/ForegroundLocationPermission.d.ts.map +1 -0
  94. package/build/services/ForegroundLocationPermission.js +12 -0
  95. package/build/services/ForegroundLocationPermission.js.map +1 -0
  96. package/build/services/GlassesSettingsSync.d.ts.map +1 -1
  97. package/build/services/GlassesSettingsSync.js +9 -3
  98. package/build/services/GlassesSettingsSync.js.map +1 -1
  99. package/build/services/GlassesStatusProjection.d.ts +2 -1
  100. package/build/services/GlassesStatusProjection.d.ts.map +1 -1
  101. package/build/services/GlassesStatusProjection.js +15 -8
  102. package/build/services/GlassesStatusProjection.js.map +1 -1
  103. package/build/services/HotspotOtaTransport.d.ts +29 -0
  104. package/build/services/HotspotOtaTransport.d.ts.map +1 -0
  105. package/build/services/HotspotOtaTransport.js +146 -0
  106. package/build/services/HotspotOtaTransport.js.map +1 -0
  107. package/build/services/HotspotShutdown.d.ts +17 -0
  108. package/build/services/HotspotShutdown.d.ts.map +1 -0
  109. package/build/services/HotspotShutdown.js +29 -0
  110. package/build/services/HotspotShutdown.js.map +1 -0
  111. package/build/services/LocalDisplayManager.d.ts +15 -0
  112. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  113. package/build/services/LocalDisplayManager.js +106 -20
  114. package/build/services/LocalDisplayManager.js.map +1 -1
  115. package/build/services/LocalMiniappRuntime.d.ts +74 -2
  116. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  117. package/build/services/LocalMiniappRuntime.js +785 -291
  118. package/build/services/LocalMiniappRuntime.js.map +1 -1
  119. package/build/services/LocalMiniappStorage.d.ts +32 -0
  120. package/build/services/LocalMiniappStorage.d.ts.map +1 -0
  121. package/build/services/LocalMiniappStorage.js +66 -0
  122. package/build/services/LocalMiniappStorage.js.map +1 -0
  123. package/build/services/LocalMiniappUserIdentity.d.ts +20 -0
  124. package/build/services/LocalMiniappUserIdentity.d.ts.map +1 -0
  125. package/build/services/LocalMiniappUserIdentity.js +43 -0
  126. package/build/services/LocalMiniappUserIdentity.js.map +1 -0
  127. package/build/services/LocalSttFallbackCoordinator.d.ts +9 -6
  128. package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
  129. package/build/services/LocalSttFallbackCoordinator.js +18 -12
  130. package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
  131. package/build/services/MicStateCoordinator.d.ts +42 -1
  132. package/build/services/MicStateCoordinator.d.ts.map +1 -1
  133. package/build/services/MicStateCoordinator.js +141 -3
  134. package/build/services/MicStateCoordinator.js.map +1 -1
  135. package/build/services/MiniappLauncher.d.ts.map +1 -1
  136. package/build/services/MiniappLauncher.js +23 -3
  137. package/build/services/MiniappLauncher.js.map +1 -1
  138. package/build/services/MiniappLiveness.d.ts +12 -0
  139. package/build/services/MiniappLiveness.d.ts.map +1 -0
  140. package/build/services/MiniappLiveness.js +16 -0
  141. package/build/services/MiniappLiveness.js.map +1 -0
  142. package/build/services/NativeHttpResponse.d.ts +3 -0
  143. package/build/services/NativeHttpResponse.d.ts.map +1 -0
  144. package/build/services/NativeHttpResponse.js +6 -0
  145. package/build/services/NativeHttpResponse.js.map +1 -0
  146. package/build/services/OtaArtifactDownloader.d.ts +65 -0
  147. package/build/services/OtaArtifactDownloader.d.ts.map +1 -0
  148. package/build/services/OtaArtifactDownloader.js +226 -0
  149. package/build/services/OtaArtifactDownloader.js.map +1 -0
  150. package/build/services/OtaAutoChain.d.ts +34 -0
  151. package/build/services/OtaAutoChain.d.ts.map +1 -0
  152. package/build/services/OtaAutoChain.js +83 -0
  153. package/build/services/OtaAutoChain.js.map +1 -0
  154. package/build/services/OtaErrorMapping.d.ts +18 -0
  155. package/build/services/OtaErrorMapping.d.ts.map +1 -0
  156. package/build/services/OtaErrorMapping.js +63 -0
  157. package/build/services/OtaErrorMapping.js.map +1 -0
  158. package/build/services/OtaInstallCoordinator.d.ts +94 -14
  159. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  160. package/build/services/OtaInstallCoordinator.js +574 -130
  161. package/build/services/OtaInstallCoordinator.js.map +1 -1
  162. package/build/services/OtaService.d.ts.map +1 -1
  163. package/build/services/OtaService.js +8 -1
  164. package/build/services/OtaService.js.map +1 -1
  165. package/build/services/OtaUpdateCheckService.d.ts +38 -3
  166. package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
  167. package/build/services/OtaUpdateCheckService.js +142 -22
  168. package/build/services/OtaUpdateCheckService.js.map +1 -1
  169. package/build/services/PhoneCalendarHelpers.d.ts +32 -0
  170. package/build/services/PhoneCalendarHelpers.d.ts.map +1 -0
  171. package/build/services/PhoneCalendarHelpers.js +157 -0
  172. package/build/services/PhoneCalendarHelpers.js.map +1 -0
  173. package/build/services/PhoneCalendarService.d.ts +5 -0
  174. package/build/services/PhoneCalendarService.d.ts.map +1 -0
  175. package/build/services/PhoneCalendarService.js +45 -0
  176. package/build/services/PhoneCalendarService.js.map +1 -0
  177. package/build/services/PhoneCameraFovCoordinator.d.ts +30 -0
  178. package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -0
  179. package/build/services/PhoneCameraFovCoordinator.js +194 -0
  180. package/build/services/PhoneCameraFovCoordinator.js.map +1 -0
  181. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  182. package/build/services/PhoneNotificationsSync.js +12 -10
  183. package/build/services/PhoneNotificationsSync.js.map +1 -1
  184. package/build/services/PhonePhotoCoordinator.d.ts +26 -2
  185. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
  186. package/build/services/PhonePhotoCoordinator.js +79 -9
  187. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  188. package/build/services/PhoneStreamCoordinator.d.ts +8 -1
  189. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  190. package/build/services/PhoneStreamCoordinator.js +125 -13
  191. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  192. package/build/services/PhoneVideoCoordinator.d.ts +2 -0
  193. package/build/services/PhoneVideoCoordinator.d.ts.map +1 -1
  194. package/build/services/PhoneVideoCoordinator.js +10 -0
  195. package/build/services/PhoneVideoCoordinator.js.map +1 -1
  196. package/build/services/SceneRenderer.d.ts.map +1 -1
  197. package/build/services/SceneRenderer.js +15 -0
  198. package/build/services/SceneRenderer.js.map +1 -1
  199. package/build/services/SentenceTtsPipeline.d.ts +31 -0
  200. package/build/services/SentenceTtsPipeline.d.ts.map +1 -0
  201. package/build/services/SentenceTtsPipeline.js +67 -0
  202. package/build/services/SentenceTtsPipeline.js.map +1 -0
  203. package/build/services/SupportProfileSync.d.ts +22 -0
  204. package/build/services/SupportProfileSync.d.ts.map +1 -0
  205. package/build/services/SupportProfileSync.js +213 -0
  206. package/build/services/SupportProfileSync.js.map +1 -0
  207. package/build/services/TranscriptionRouting.d.ts +12 -0
  208. package/build/services/TranscriptionRouting.d.ts.map +1 -0
  209. package/build/services/TranscriptionRouting.js +24 -0
  210. package/build/services/TranscriptionRouting.js.map +1 -0
  211. package/build/services/TtsTextSanitizer.d.ts +5 -0
  212. package/build/services/TtsTextSanitizer.d.ts.map +1 -0
  213. package/build/services/TtsTextSanitizer.js +61 -0
  214. package/build/services/TtsTextSanitizer.js.map +1 -0
  215. package/build/services/WifiAdbRequest.d.ts +17 -0
  216. package/build/services/WifiAdbRequest.d.ts.map +1 -0
  217. package/build/services/WifiAdbRequest.js +35 -0
  218. package/build/services/WifiAdbRequest.js.map +1 -0
  219. package/build/services/asg/asgCameraApi.d.ts +43 -0
  220. package/build/services/asg/asgCameraApi.d.ts.map +1 -1
  221. package/build/services/asg/asgCameraApi.js +509 -26
  222. package/build/services/asg/asgCameraApi.js.map +1 -1
  223. package/build/services/asg/cameraRollExportCoordinator.d.ts +60 -0
  224. package/build/services/asg/cameraRollExportCoordinator.d.ts.map +1 -0
  225. package/build/services/asg/cameraRollExportCoordinator.js +618 -0
  226. package/build/services/asg/cameraRollExportCoordinator.js.map +1 -0
  227. package/build/services/asg/cameraRollExportLedger.d.ts +44 -0
  228. package/build/services/asg/cameraRollExportLedger.d.ts.map +1 -0
  229. package/build/services/asg/cameraRollExportLedger.js +78 -0
  230. package/build/services/asg/cameraRollExportLedger.js.map +1 -0
  231. package/build/services/asg/galleryNotices.d.ts +1 -1
  232. package/build/services/asg/galleryNotices.d.ts.map +1 -1
  233. package/build/services/asg/galleryNotices.js.map +1 -1
  234. package/build/services/asg/galleryPathMigration.d.ts +3 -0
  235. package/build/services/asg/galleryPathMigration.d.ts.map +1 -0
  236. package/build/services/asg/galleryPathMigration.js +26 -0
  237. package/build/services/asg/galleryPathMigration.js.map +1 -0
  238. package/build/services/asg/gallerySettingsService.d.ts +1 -0
  239. package/build/services/asg/gallerySettingsService.d.ts.map +1 -1
  240. package/build/services/asg/gallerySettingsService.js +2 -0
  241. package/build/services/asg/gallerySettingsService.js.map +1 -1
  242. package/build/services/asg/gallerySyncService.d.ts.map +1 -1
  243. package/build/services/asg/gallerySyncService.js +162 -56
  244. package/build/services/asg/gallerySyncService.js.map +1 -1
  245. package/build/services/asg/galleryTransferLedger.d.ts +58 -0
  246. package/build/services/asg/galleryTransferLedger.d.ts.map +1 -0
  247. package/build/services/asg/galleryTransferLedger.js +225 -0
  248. package/build/services/asg/galleryTransferLedger.js.map +1 -0
  249. package/build/services/asg/localNetworkTransport.d.ts +15 -0
  250. package/build/services/asg/localNetworkTransport.d.ts.map +1 -0
  251. package/build/services/asg/localNetworkTransport.js +144 -0
  252. package/build/services/asg/localNetworkTransport.js.map +1 -0
  253. package/build/services/asg/localStorageService.d.ts +18 -0
  254. package/build/services/asg/localStorageService.d.ts.map +1 -1
  255. package/build/services/asg/localStorageService.js +168 -19
  256. package/build/services/asg/localStorageService.js.map +1 -1
  257. package/build/services/asg/mediaProcessingQueue.d.ts +10 -0
  258. package/build/services/asg/mediaProcessingQueue.d.ts.map +1 -1
  259. package/build/services/asg/mediaProcessingQueue.js +193 -62
  260. package/build/services/asg/mediaProcessingQueue.js.map +1 -1
  261. package/build/services/audioPlaybackAssets.d.ts +8 -0
  262. package/build/services/audioPlaybackAssets.d.ts.map +1 -0
  263. package/build/services/audioPlaybackAssets.js +7 -0
  264. package/build/services/audioPlaybackAssets.js.map +1 -0
  265. package/build/services/gallerySyncClock.js +1 -1
  266. package/build/services/gallerySyncClock.js.map +1 -1
  267. package/build/services/glassesClockSync.js +2 -2
  268. package/build/services/glassesClockSync.js.map +1 -1
  269. package/build/services/manifestActions.d.ts +7 -0
  270. package/build/services/manifestActions.d.ts.map +1 -0
  271. package/build/services/manifestActions.js +25 -0
  272. package/build/services/manifestActions.js.map +1 -0
  273. package/build/services/otaDisplayState.d.ts +22 -11
  274. package/build/services/otaDisplayState.d.ts.map +1 -1
  275. package/build/services/otaDisplayState.js +36 -14
  276. package/build/services/otaDisplayState.js.map +1 -1
  277. package/build/services/otaInstallPolicy.d.ts +15 -3
  278. package/build/services/otaInstallPolicy.d.ts.map +1 -1
  279. package/build/services/otaInstallPolicy.js +24 -3
  280. package/build/services/otaInstallPolicy.js.map +1 -1
  281. package/build/services/otaManifestUrl.d.ts +2 -0
  282. package/build/services/otaManifestUrl.d.ts.map +1 -0
  283. package/build/services/{asgOtaVersionUrl.js → otaManifestUrl.js} +15 -5
  284. package/build/services/otaManifestUrl.js.map +1 -0
  285. package/build/services/slimStreamStatus.d.ts +11 -0
  286. package/build/services/slimStreamStatus.d.ts.map +1 -1
  287. package/build/services/slimStreamStatus.js +14 -4
  288. package/build/services/slimStreamStatus.js.map +1 -1
  289. package/build/stores/apps.d.ts.map +1 -1
  290. package/build/stores/apps.js +11 -0
  291. package/build/stores/apps.js.map +1 -1
  292. package/build/stores/bluetoothSettingKeys.d.ts.map +1 -1
  293. package/build/stores/bluetoothSettingKeys.js +2 -0
  294. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  295. package/build/stores/gallerySync.d.ts +2 -0
  296. package/build/stores/gallerySync.d.ts.map +1 -1
  297. package/build/stores/gallerySync.js +2 -0
  298. package/build/stores/gallerySync.js.map +1 -1
  299. package/build/stores/glasses.d.ts.map +1 -1
  300. package/build/stores/glasses.js +3 -0
  301. package/build/stores/glasses.js.map +1 -1
  302. package/build/stores/settings.d.ts +17 -0
  303. package/build/stores/settings.d.ts.map +1 -1
  304. package/build/stores/settings.js +157 -17
  305. package/build/stores/settings.js.map +1 -1
  306. package/build/types/applet.d.ts +2 -0
  307. package/build/types/applet.d.ts.map +1 -1
  308. package/build/types/applet.js.map +1 -1
  309. package/build/types/asg.d.ts +7 -0
  310. package/build/types/asg.d.ts.map +1 -1
  311. package/build/types/asg.js.map +1 -1
  312. package/build/types/enums.d.ts +1 -0
  313. package/build/types/enums.d.ts.map +1 -1
  314. package/build/types/enums.js +1 -0
  315. package/build/types/enums.js.map +1 -1
  316. package/build/types/hardware.d.ts +1 -0
  317. package/build/types/hardware.d.ts.map +1 -1
  318. package/build/types/hardware.js +14 -0
  319. package/build/types/hardware.js.map +1 -1
  320. package/build/utils/configuredDevHost.d.ts +6 -0
  321. package/build/utils/configuredDevHost.d.ts.map +1 -0
  322. package/build/utils/configuredDevHost.js +19 -0
  323. package/build/utils/configuredDevHost.js.map +1 -0
  324. package/build/utils/devMiniappLaunch.d.ts +19 -8
  325. package/build/utils/devMiniappLaunch.d.ts.map +1 -1
  326. package/build/utils/devMiniappLaunch.js +144 -21
  327. package/build/utils/devMiniappLaunch.js.map +1 -1
  328. package/build/utils/diagnosticContext.d.ts.map +1 -1
  329. package/build/utils/diagnosticContext.js +15 -17
  330. package/build/utils/diagnosticContext.js.map +1 -1
  331. package/build/utils/hardware/hardware.d.ts.map +1 -1
  332. package/build/utils/hardware/hardware.js +7 -3
  333. package/build/utils/hardware/hardware.js.map +1 -1
  334. package/build/utils/miniappDiagnostics.d.ts +64 -0
  335. package/build/utils/miniappDiagnostics.d.ts.map +1 -0
  336. package/build/utils/miniappDiagnostics.js +173 -0
  337. package/build/utils/miniappDiagnostics.js.map +1 -0
  338. package/build/utils/permissions/MediaLibraryPermissions.d.ts +11 -0
  339. package/build/utils/permissions/MediaLibraryPermissions.d.ts.map +1 -1
  340. package/build/utils/permissions/MediaLibraryPermissions.js +27 -4
  341. package/build/utils/permissions/MediaLibraryPermissions.js.map +1 -1
  342. package/build/utils/timers/timers.d.ts.map +1 -1
  343. package/build/utils/timers/timers.js +55 -18
  344. package/build/utils/timers/timers.js.map +1 -1
  345. package/package.json +25 -15
  346. package/src/assets/silence.wav +0 -0
  347. package/src/engine.ts +7 -2
  348. package/src/facades/dev.ts +17 -12
  349. package/src/facades/gallery.ts +1 -1
  350. package/src/facades/glasses.ts +17 -4
  351. package/src/facades/glassesSettings.ts +5 -0
  352. package/src/facades/miniapps.ts +7 -0
  353. package/src/facades/ota.ts +19 -4
  354. package/src/facades/pairing.ts +11 -7
  355. package/src/facades/permissions.ts +14 -0
  356. package/src/facades/phoneNotifications.ts +4 -13
  357. package/src/index.ts +26 -2
  358. package/src/internal.ts +3 -1
  359. package/src/react/MentraLiveOtaFlow.tsx +856 -0
  360. package/src/react/index.ts +7 -0
  361. package/src/react/useEngineSnapshot.ts +16 -0
  362. package/src/runtime/bootstrap.ts +33 -1
  363. package/src/runtime/scanQrSeam.ts +20 -0
  364. package/src/services/AppRegistry.ts +224 -149
  365. package/src/services/AudioCloudUplink.ts +23 -1
  366. package/src/services/AudioPlaybackService.ts +287 -38
  367. package/src/services/BlobStore.ts +22 -9
  368. package/src/services/CloudAudioSubscriptionSync.ts +13 -1
  369. package/src/services/CloudClientService.ts +96 -1
  370. package/src/services/DeviceEventRouter.ts +5 -5
  371. package/src/services/ForegroundLocationPermission.ts +24 -0
  372. package/src/services/GlassesSettingsSync.ts +9 -3
  373. package/src/services/GlassesStatusProjection.ts +16 -8
  374. package/src/services/HotspotOtaTransport.ts +184 -0
  375. package/src/services/HotspotShutdown.ts +41 -0
  376. package/src/services/LocalDisplayManager.ts +112 -21
  377. package/src/services/LocalMiniappRuntime.ts +967 -346
  378. package/src/services/LocalMiniappStorage.ts +82 -0
  379. package/src/services/LocalMiniappUserIdentity.ts +46 -0
  380. package/src/services/LocalSttFallbackCoordinator.ts +19 -12
  381. package/src/services/MicStateCoordinator.ts +169 -4
  382. package/src/services/MiniappLauncher.ts +30 -3
  383. package/src/services/MiniappLiveness.ts +24 -0
  384. package/src/services/NativeHttpResponse.ts +6 -0
  385. package/src/services/OtaArtifactDownloader.ts +312 -0
  386. package/src/services/OtaAutoChain.ts +106 -0
  387. package/src/services/OtaErrorMapping.ts +80 -0
  388. package/src/services/OtaInstallCoordinator.ts +645 -143
  389. package/src/services/OtaService.ts +11 -5
  390. package/src/services/OtaUpdateCheckService.ts +180 -20
  391. package/src/services/PhoneCalendarHelpers.ts +212 -0
  392. package/src/services/PhoneCalendarService.ts +65 -0
  393. package/src/services/PhoneCameraFovCoordinator.ts +210 -0
  394. package/src/services/PhoneNotificationsSync.ts +12 -10
  395. package/src/services/PhonePhotoCoordinator.ts +116 -18
  396. package/src/services/PhoneStreamCoordinator.ts +139 -25
  397. package/src/services/PhoneVideoCoordinator.ts +11 -0
  398. package/src/services/SceneRenderer.ts +16 -0
  399. package/src/services/SentenceTtsPipeline.ts +106 -0
  400. package/src/services/SupportProfileSync.ts +218 -0
  401. package/src/services/TranscriptionRouting.ts +37 -0
  402. package/src/services/TtsTextSanitizer.ts +66 -0
  403. package/src/services/WifiAdbRequest.ts +53 -0
  404. package/src/services/asg/asgCameraApi.ts +615 -33
  405. package/src/services/asg/cameraRollExportCoordinator.ts +627 -0
  406. package/src/services/asg/cameraRollExportLedger.ts +122 -0
  407. package/src/services/asg/galleryNotices.ts +1 -0
  408. package/src/services/asg/galleryPathMigration.ts +22 -0
  409. package/src/services/asg/gallerySettingsService.ts +3 -0
  410. package/src/services/asg/gallerySyncService.ts +184 -73
  411. package/src/services/asg/galleryTransferLedger.ts +312 -0
  412. package/src/services/asg/localNetworkTransport.ts +169 -0
  413. package/src/services/asg/localStorageService.ts +179 -24
  414. package/src/services/asg/mediaProcessingQueue.ts +209 -62
  415. package/src/services/audioPlaybackAssets.ts +8 -0
  416. package/src/services/gallerySyncClock.ts +1 -1
  417. package/src/services/glassesClockSync.ts +2 -2
  418. package/src/services/manifestActions.ts +30 -0
  419. package/src/services/otaDisplayState.ts +57 -16
  420. package/src/services/otaInstallPolicy.ts +29 -3
  421. package/src/services/{asgOtaVersionUrl.ts → otaManifestUrl.ts} +16 -4
  422. package/src/services/slimStreamStatus.ts +16 -5
  423. package/src/stores/apps.ts +12 -0
  424. package/src/stores/bluetoothSettingKeys.ts +2 -0
  425. package/src/stores/gallerySync.ts +4 -0
  426. package/src/stores/glasses.ts +3 -0
  427. package/src/stores/settings.ts +179 -18
  428. package/src/types/applet.ts +2 -0
  429. package/src/types/asg.ts +7 -0
  430. package/src/types/enums.ts +2 -1
  431. package/src/types/hardware.ts +17 -0
  432. package/src/utils/configuredDevHost.ts +17 -0
  433. package/src/utils/devMiniappLaunch.ts +151 -23
  434. package/src/utils/diagnosticContext.ts +17 -17
  435. package/src/utils/hardware/hardware.ts +7 -9
  436. package/src/utils/miniappDiagnostics.ts +226 -0
  437. package/src/utils/permissions/MediaLibraryPermissions.ts +35 -4
  438. package/src/utils/timers/timers.ts +57 -21
  439. package/build/services/asgOtaVersionUrl.d.ts +0 -2
  440. package/build/services/asgOtaVersionUrl.d.ts.map +0 -1
  441. package/build/services/asgOtaVersionUrl.js.map +0 -1
@@ -0,0 +1,856 @@
1
+ import React, {useCallback, useEffect, useMemo, useRef, useState} from "react"
2
+ import {ActivityIndicator, Pressable, StyleSheet, Text, View, type StyleProp, type ViewStyle} from "react-native"
3
+ import {SafeAreaView} from "react-native-safe-area-context"
4
+ import Svg, {Path, Rect} from "react-native-svg"
5
+
6
+ import {ota} from "../facades/ota"
7
+ import {
8
+ beginOtaAutoChain,
9
+ clearOtaAutoChainReconnectWait,
10
+ isOtaAutoChainActive,
11
+ otaAutoChainFingerprint,
12
+ otaAutoChainReconnectWaitRemaining,
13
+ stopOtaAutoChain,
14
+ tryAdvanceOtaAutoChain,
15
+ } from "../services/OtaAutoChain"
16
+ import {
17
+ BES_INSTALL_RESTART_MESSAGE,
18
+ getOtaErrorMessage,
19
+ shouldRequireGlassesRebootForBesFailure,
20
+ shouldShowChangeWifiForOtaDownloadFailure,
21
+ } from "../services/OtaErrorMapping"
22
+ import {useEngineSnapshot} from "./useEngineSnapshot"
23
+
24
+ export type MentraLiveOtaFlowPage = "check" | "progress"
25
+
26
+ export type MentraLiveOtaFlowTheme = {
27
+ background: string
28
+ border: string
29
+ error: string
30
+ foreground: string
31
+ primary: string
32
+ primaryText: string
33
+ textDim: string
34
+ }
35
+
36
+ export type MentraLiveOtaFlowTranslate = (key: string, options?: Record<string, string>) => string
37
+
38
+ export type MentraLiveOtaFlowProps = {
39
+ /** Display name used in update copy. */
40
+ deviceName?: string
41
+ /** Entry page. `progress` exists for recovery/deep-link compatibility. */
42
+ initialPage?: MentraLiveOtaFlowPage
43
+ /** Start the OTA-only projections. Full engine hosts should pass false. */
44
+ initializeRuntime?: boolean
45
+ /** Called after the final check or when the user leaves an optional update. */
46
+ onFinished: () => void
47
+ /** Host-owned Wi-Fi setup for glasses that do not support hotspot OTA. */
48
+ onOpenWifiSetup: () => void
49
+ /** Lets a host coordinate its global connection overlay with OTA progress and firmware restarts. */
50
+ onFirmwareRestartingChange?: (restarting: boolean, progressActive: boolean) => void
51
+ /** Enables the existing developer-only escape hatches. */
52
+ allowDevSkip?: boolean
53
+ /** Enables the existing super-mode interrupted-session escape hatch. */
54
+ superMode?: boolean
55
+ /** Optional host localization. Defaults to the Mentra App English OTA copy. */
56
+ translate?: MentraLiveOtaFlowTranslate
57
+ /** Optional host theme. Both hosts use the same layout and state machine. */
58
+ theme?: Partial<MentraLiveOtaFlowTheme>
59
+ style?: StyleProp<ViewStyle>
60
+ }
61
+
62
+ type CheckState = "checking" | "update_available" | "no_update" | "dev_build" | "error"
63
+
64
+ const AUTO_CHAIN_NETWORK_RETRY_DELAY_MS = 5000
65
+ const AUTO_CHAIN_COMPLETE_DELAY_MS = 750
66
+
67
+ const DEFAULT_THEME: MentraLiveOtaFlowTheme = {
68
+ background: "#FFFFFF",
69
+ border: "#D7DFDA",
70
+ error: "#C43131",
71
+ foreground: "#0E2C1A",
72
+ primary: "#00B869",
73
+ primaryText: "#FFFFFF",
74
+ textDim: "#66736B",
75
+ }
76
+
77
+ const ENGLISH_COPY: Record<string, string> = {
78
+ "common:continue": "Continue",
79
+ "ota:checkingForUpdates": "Checking for updates",
80
+ "ota:checkingForUpdatesMessage":
81
+ "Connected devices will perform automatic updates. Automatic updates can be disabled in Device Settings",
82
+ "ota:updateAvailable": "{{deviceName}} Update Available",
83
+ "ota:updateConnectWifi": "Connect your {{deviceName}} to WiFi to install the update.",
84
+ "ota:updateDescription":
85
+ "A new update is available for your glasses. We recommend updating now for the best experience.",
86
+ "ota:downgradeAvailable": "{{deviceName}} Version Change Required",
87
+ "ota:downgradeDescription":
88
+ "This app requires an earlier glasses software version. Your photos and videos will be preserved, but glasses settings will be reset and restored automatically after the change.",
89
+ "ota:updateNow": "Update Now",
90
+ "ota:setupWifi": "Setup WiFi",
91
+ "ota:updateLater": "Later",
92
+ "ota:upToDate": "Up To Date",
93
+ "ota:devBuild": "Development Build",
94
+ "ota:devBuildNoOta":
95
+ "This mobile app is a development build, so automatic glasses updates are disabled. Use the developer settings manifest override to update them manually.",
96
+ "ota:noUpdatesAvailable": "Your glasses are running the latest version.",
97
+ "ota:checkFailed": "Check Failed",
98
+ "ota:checkFailedMessage": "Couldn't check for updates. Please check your connection and try again.",
99
+ "ota:updateInfoUnavailable": "Update Info Unavailable",
100
+ "ota:updateInfoUnavailableMessage":
101
+ "Update information for this version of the app is unavailable. Please check the app store for a newer version of the Mentra App.",
102
+ "ota:downgradeDuration": "Your glasses will restart twice — this may take up to 2 minutes.",
103
+ "ota:versionChangeRestarting": "Installing a different version…",
104
+ "ota:versionChangeVerifying": "Verifying your glasses…",
105
+ "ota:versionChangeKeepNearby": "Keep your glasses nearby and connected. They will restart on their own.",
106
+ "ota:versionChangeComplete": "Version Change Complete",
107
+ "ota:versionChangeCompleteMessage":
108
+ "Your glasses are now on the required version. Their settings were reset and are being restored automatically.",
109
+ "ota:versionChangeFirmwarePassComplete": "Firmware updated",
110
+ "ota:versionChangeFirmwarePassCompleteMessage":
111
+ "Your glasses restarted with new firmware. One more step: they'll now continue to the required version.",
112
+ }
113
+
114
+ function defaultTranslate(key: string, options?: Record<string, string>): string {
115
+ let value = ENGLISH_COPY[key] ?? key
116
+ for (const [name, replacement] of Object.entries(options ?? {})) {
117
+ value = value.replaceAll(`{{${name}}}`, replacement)
118
+ }
119
+ return value
120
+ }
121
+
122
+ export function MentraLiveOtaFlow({
123
+ allowDevSkip = typeof __DEV__ !== "undefined" && __DEV__,
124
+ deviceName = "Mentra Live",
125
+ initialPage = "check",
126
+ initializeRuntime = true,
127
+ onFinished,
128
+ onFirmwareRestartingChange,
129
+ onOpenWifiSetup,
130
+ style,
131
+ superMode = false,
132
+ theme,
133
+ translate = defaultTranslate,
134
+ }: MentraLiveOtaFlowProps) {
135
+ const colors = useMemo(() => ({...DEFAULT_THEME, ...theme}), [theme])
136
+ const [page, setPage] = useState<MentraLiveOtaFlowPage>(initialPage)
137
+ const [checkGeneration, setCheckGeneration] = useState(0)
138
+ const [runtimeReady, setRuntimeReady] = useState(!initializeRuntime)
139
+
140
+ useEffect(() => {
141
+ if (!initializeRuntime) {
142
+ setRuntimeReady(true)
143
+ return
144
+ }
145
+ let cancelled = false
146
+ setRuntimeReady(false)
147
+ void ota.initialize().finally(() => {
148
+ if (!cancelled) setRuntimeReady(true)
149
+ })
150
+ return () => {
151
+ cancelled = true
152
+ }
153
+ }, [initializeRuntime])
154
+
155
+ const showCheck = useCallback(() => {
156
+ setPage("check")
157
+ setCheckGeneration((generation) => generation + 1)
158
+ }, [])
159
+
160
+ return (
161
+ <SafeAreaView style={[styles.safeArea, {backgroundColor: colors.background}, style]}>
162
+ <View style={styles.header}>
163
+ <View />
164
+ <MentraMark color={colors.primary} />
165
+ </View>
166
+ {!runtimeReady ? (
167
+ <FlowPage colors={colors} icon="download" title={translate("ota:checkingForUpdates")}>
168
+ <ActivityIndicator size="large" color={colors.foreground} />
169
+ </FlowPage>
170
+ ) : page === "check" ? (
171
+ <OtaCheckPage
172
+ allowDevSkip={allowDevSkip}
173
+ colors={colors}
174
+ deviceName={deviceName}
175
+ generation={checkGeneration}
176
+ onFinished={onFinished}
177
+ onOpenWifiSetup={onOpenWifiSetup}
178
+ onStartProgress={() => setPage("progress")}
179
+ translate={translate}
180
+ />
181
+ ) : (
182
+ <OtaProgressPage
183
+ colors={colors}
184
+ onFirmwareRestartingChange={onFirmwareRestartingChange}
185
+ onOpenWifiSetup={onOpenWifiSetup}
186
+ onReturnToCheck={showCheck}
187
+ superMode={superMode}
188
+ translate={translate}
189
+ />
190
+ )}
191
+ </SafeAreaView>
192
+ )
193
+ }
194
+
195
+ type CheckPageProps = {
196
+ allowDevSkip: boolean
197
+ colors: MentraLiveOtaFlowTheme
198
+ deviceName: string
199
+ generation: number
200
+ onFinished: () => void
201
+ onOpenWifiSetup: () => void
202
+ onStartProgress: () => void
203
+ translate: MentraLiveOtaFlowTranslate
204
+ }
205
+
206
+ function OtaCheckPage({
207
+ allowDevSkip,
208
+ colors,
209
+ deviceName,
210
+ generation,
211
+ onFinished,
212
+ onOpenWifiSetup,
213
+ onStartProgress,
214
+ translate,
215
+ }: CheckPageProps) {
216
+ const otaSnapshot = useEngineSnapshot(ota.snapshot, ota.onSnapshot)
217
+ const [checkState, setCheckState] = useState<CheckState>("checking")
218
+ const [isUpdateRequired, setIsUpdateRequired] = useState(true)
219
+ const [isDowngradeUpdate, setIsDowngradeUpdate] = useState(false)
220
+ const [errorKind, setErrorKind] = useState<"network" | "pin_unavailable">("network")
221
+ const [updateFingerprint, setUpdateFingerprint] = useState<string | null>(null)
222
+ const [retryGeneration, setRetryGeneration] = useState(0)
223
+ const performCheckGenerationRef = useRef(0)
224
+ const activeCheckKeyRef = useRef<string | null>(null)
225
+ const checkStartedRef = useRef(false)
226
+ const checkCompletedRef = useRef(false)
227
+ const selectedCheckResultRef = useRef<Awaited<ReturnType<typeof ota.checkForUpdates>> | null>(null)
228
+ const onFinishedRef = useRef(onFinished)
229
+ const onStartProgressRef = useRef(onStartProgress)
230
+ onFinishedRef.current = onFinished
231
+ onStartProgressRef.current = onStartProgress
232
+
233
+ const glassesWifiConnected = otaSnapshot.wifiConnected
234
+ const glassesWifiStatusKnown = otaSnapshot.wifiStatusKnown
235
+ const hotspotOtaSupported = otaSnapshot.hotspotOtaVersion === 1
236
+ const canInstallUpdate = glassesWifiStatusKnown && (glassesWifiConnected || hotspotOtaSupported)
237
+ const checkKey = `${generation}:${retryGeneration}`
238
+
239
+ const navigateToProgress = useCallback(() => {
240
+ ota.clearProgress()
241
+ onStartProgressRef.current()
242
+ }, [])
243
+
244
+ useEffect(() => {
245
+ const MIN_DISPLAY_TIME_MS = 1100
246
+ const MAX_WAIT_FOR_VERSION_INFO_MS = 10_000
247
+ if (activeCheckKeyRef.current !== checkKey) {
248
+ activeCheckKeyRef.current = checkKey
249
+ checkStartedRef.current = false
250
+ checkCompletedRef.current = false
251
+ setCheckState("checking")
252
+ }
253
+
254
+ const myGeneration = ++performCheckGenerationRef.current
255
+ let cancelled = false
256
+ let reconnectTimeout: ReturnType<typeof setTimeout> | null = null
257
+
258
+ const performCheck = async () => {
259
+ if (checkCompletedRef.current) return
260
+ if (!otaSnapshot.connected) {
261
+ if (isOtaAutoChainActive()) {
262
+ const remainingMs = otaAutoChainReconnectWaitRemaining()
263
+ if (remainingMs === null) return
264
+ reconnectTimeout = setTimeout(() => {
265
+ if (cancelled || myGeneration !== performCheckGenerationRef.current || ota.snapshot().connected) return
266
+ stopOtaAutoChain()
267
+ checkCompletedRef.current = true
268
+ setCheckState("error")
269
+ }, remainingMs)
270
+ return
271
+ }
272
+ if (checkStartedRef.current) {
273
+ stopOtaAutoChain()
274
+ checkCompletedRef.current = true
275
+ setCheckState("error")
276
+ return
277
+ }
278
+ checkCompletedRef.current = true
279
+ onFinishedRef.current()
280
+ return
281
+ }
282
+
283
+ clearOtaAutoChainReconnectWait()
284
+ checkStartedRef.current = true
285
+ const startTime = Date.now()
286
+ try {
287
+ let result = await ota.checkForUpdates({
288
+ waitForBuildNumberMs: MAX_WAIT_FOR_VERSION_INFO_MS,
289
+ waitForBesVersionMs: 5000,
290
+ waitForMtkVersionMs: 2000,
291
+ refreshVersionInfo: true,
292
+ fixClockBeforeCheck: false,
293
+ })
294
+ if (cancelled || myGeneration !== performCheckGenerationRef.current) return
295
+ if (!result.hasCheckCompleted && result.checkFailureReason === "network" && isOtaAutoChainActive()) {
296
+ await new Promise((resolve) => setTimeout(resolve, AUTO_CHAIN_NETWORK_RETRY_DELAY_MS))
297
+ if (cancelled || myGeneration !== performCheckGenerationRef.current) return
298
+ result = await ota.checkForUpdates({
299
+ waitForBuildNumberMs: MAX_WAIT_FOR_VERSION_INFO_MS,
300
+ waitForBesVersionMs: 5000,
301
+ waitForMtkVersionMs: 2000,
302
+ refreshVersionInfo: true,
303
+ fixClockBeforeCheck: false,
304
+ })
305
+ }
306
+ if (cancelled || myGeneration !== performCheckGenerationRef.current) return
307
+ selectedCheckResultRef.current = result
308
+ await new Promise((resolve) => setTimeout(resolve, Math.max(0, MIN_DISPLAY_TIME_MS - (Date.now() - startTime))))
309
+ if (cancelled || myGeneration !== performCheckGenerationRef.current) return
310
+
311
+ if (result.skippedReason === "disconnected") {
312
+ stopOtaAutoChain()
313
+ checkCompletedRef.current = true
314
+ setCheckState("error")
315
+ return
316
+ }
317
+ if (result.skippedReason === "missing_build") {
318
+ checkCompletedRef.current = true
319
+ if (isOtaAutoChainActive()) {
320
+ stopOtaAutoChain()
321
+ setCheckState("error")
322
+ } else {
323
+ onFinishedRef.current()
324
+ }
325
+ return
326
+ }
327
+ if (result.skippedReason === "dev_build") {
328
+ stopOtaAutoChain()
329
+ checkCompletedRef.current = true
330
+ ota.clearUpdateAvailable()
331
+ setCheckState("dev_build")
332
+ return
333
+ }
334
+ if (!result.hasCheckCompleted) {
335
+ stopOtaAutoChain()
336
+ checkCompletedRef.current = true
337
+ setErrorKind(result.checkFailureReason === "pin_unavailable" ? "pin_unavailable" : "network")
338
+ setCheckState("error")
339
+ return
340
+ }
341
+ if (result.updateAvailable && result.updateInfo) {
342
+ setIsUpdateRequired(result.isRequired)
343
+ setIsDowngradeUpdate(result.updateInfo.isDowngrade === true)
344
+ const fingerprint = otaAutoChainFingerprint(result)
345
+ setUpdateFingerprint(fingerprint)
346
+ if (isOtaAutoChainActive()) {
347
+ const snapshot = ota.snapshot()
348
+ if (!snapshot.wifiStatusKnown) return
349
+ if (!snapshot.wifiConnected && snapshot.hotspotOtaVersion !== 1) {
350
+ stopOtaAutoChain()
351
+ } else {
352
+ const admission = tryAdvanceOtaAutoChain(fingerprint, result.updateInfo.isDowngrade === true)
353
+ if (admission.advance) {
354
+ checkCompletedRef.current = true
355
+ ota.installSession.prepare(result)
356
+ navigateToProgress()
357
+ return
358
+ }
359
+ }
360
+ }
361
+ checkCompletedRef.current = true
362
+ setCheckState("update_available")
363
+ return
364
+ }
365
+ stopOtaAutoChain()
366
+ checkCompletedRef.current = true
367
+ ota.clearUpdateAvailable()
368
+ setCheckState("no_update")
369
+ } catch (error) {
370
+ console.error("OTA check failed:", error)
371
+ await new Promise((resolve) => setTimeout(resolve, Math.max(0, MIN_DISPLAY_TIME_MS - (Date.now() - startTime))))
372
+ if (cancelled || myGeneration !== performCheckGenerationRef.current) return
373
+ stopOtaAutoChain()
374
+ checkCompletedRef.current = true
375
+ setCheckState("error")
376
+ }
377
+ }
378
+
379
+ void performCheck()
380
+ return () => {
381
+ cancelled = true
382
+ if (reconnectTimeout) clearTimeout(reconnectTimeout)
383
+ }
384
+ }, [
385
+ checkKey,
386
+ otaSnapshot.connected,
387
+ otaSnapshot.wifiStatusKnown,
388
+ navigateToProgress,
389
+ ])
390
+
391
+ const retry = () => {
392
+ setCheckState("checking")
393
+ setRetryGeneration((value) => value + 1)
394
+ }
395
+
396
+ const updateNow = () => {
397
+ const result = selectedCheckResultRef.current
398
+ if (!result) {
399
+ setCheckState("error")
400
+ return
401
+ }
402
+ const snapshot = ota.snapshot()
403
+ if (!snapshot.wifiStatusKnown) {
404
+ retry()
405
+ return
406
+ }
407
+ if (!snapshot.wifiConnected && snapshot.hotspotOtaVersion !== 1) {
408
+ onOpenWifiSetup()
409
+ return
410
+ }
411
+ ota.installSession.prepare(result)
412
+ if (updateFingerprint) beginOtaAutoChain(updateFingerprint, isDowngradeUpdate)
413
+ navigateToProgress()
414
+ }
415
+
416
+ if (checkState === "checking") {
417
+ return (
418
+ <FlowPage colors={colors} icon="download" title={translate("ota:checkingForUpdates")}>
419
+ <BodyText colors={colors}>{translate("ota:checkingForUpdatesMessage")}</BodyText>
420
+ <ActivityIndicator size="large" color={colors.foreground} />
421
+ </FlowPage>
422
+ )
423
+ }
424
+
425
+ if (checkState === "update_available") {
426
+ return (
427
+ <FlowPage
428
+ colors={colors}
429
+ icon="download"
430
+ title={translate(isDowngradeUpdate ? "ota:downgradeAvailable" : "ota:updateAvailable", {deviceName})}
431
+ actions={
432
+ <>
433
+ <FlowButton
434
+ colors={colors}
435
+ disabled={!glassesWifiStatusKnown}
436
+ label={translate(!glassesWifiStatusKnown || canInstallUpdate ? "ota:updateNow" : "ota:setupWifi")}
437
+ onPress={updateNow}
438
+ />
439
+ {!isUpdateRequired ? (
440
+ <FlowButton colors={colors} label={translate("ota:updateLater")} onPress={onFinished} secondary />
441
+ ) : null}
442
+ {allowDevSkip && isUpdateRequired ? (
443
+ <FlowButton colors={colors} label="Skip (dev only)" onPress={onFinished} secondary />
444
+ ) : null}
445
+ </>
446
+ }>
447
+ <BodyText colors={colors}>
448
+ {canInstallUpdate
449
+ ? translate(isDowngradeUpdate ? "ota:downgradeDescription" : "ota:updateDescription")
450
+ : translate("ota:updateConnectWifi", {deviceName})}
451
+ </BodyText>
452
+ </FlowPage>
453
+ )
454
+ }
455
+
456
+ if (checkState === "dev_build") {
457
+ return (
458
+ <FlowPage
459
+ actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={onFinished} />}
460
+ colors={colors}
461
+ icon="settings"
462
+ title={translate("ota:devBuild")}>
463
+ <BodyText colors={colors}>{translate("ota:devBuildNoOta")}</BodyText>
464
+ </FlowPage>
465
+ )
466
+ }
467
+
468
+ if (checkState === "no_update") {
469
+ return (
470
+ <FlowPage
471
+ actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={onFinished} />}
472
+ colors={colors}
473
+ icon="check"
474
+ title={translate("ota:upToDate")}>
475
+ <BodyText colors={colors}>{translate("ota:noUpdatesAvailable")}</BodyText>
476
+ </FlowPage>
477
+ )
478
+ }
479
+
480
+ if (errorKind === "pin_unavailable") {
481
+ return (
482
+ <FlowPage
483
+ actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={onFinished} />}
484
+ colors={colors}
485
+ icon="alert"
486
+ title={translate("ota:updateInfoUnavailable")}>
487
+ <BodyText colors={colors}>{translate("ota:updateInfoUnavailableMessage")}</BodyText>
488
+ </FlowPage>
489
+ )
490
+ }
491
+
492
+ return (
493
+ <FlowPage
494
+ actions={
495
+ <>
496
+ <FlowButton colors={colors} label="Retry" onPress={retry} />
497
+ {allowDevSkip ? <FlowButton colors={colors} label="Skip (dev only)" onPress={onFinished} secondary /> : null}
498
+ </>
499
+ }
500
+ colors={colors}
501
+ icon="alert"
502
+ title={translate("ota:checkFailed")}>
503
+ <BodyText colors={colors}>{translate("ota:checkFailedMessage")}</BodyText>
504
+ </FlowPage>
505
+ )
506
+ }
507
+
508
+ type ProgressPageProps = {
509
+ colors: MentraLiveOtaFlowTheme
510
+ onFirmwareRestartingChange?: (restarting: boolean, progressActive: boolean) => void
511
+ onOpenWifiSetup: () => void
512
+ onReturnToCheck: () => void
513
+ superMode: boolean
514
+ translate: MentraLiveOtaFlowTranslate
515
+ }
516
+
517
+ function OtaProgressPage({
518
+ colors,
519
+ onFirmwareRestartingChange,
520
+ onOpenWifiSetup,
521
+ onReturnToCheck,
522
+ superMode,
523
+ translate,
524
+ }: ProgressPageProps) {
525
+ const install = useEngineSnapshot(ota.installSession.snapshot, ota.installSession.onSnapshot)
526
+ const autoChainAdvancedRef = useRef(false)
527
+ const {
528
+ connected,
529
+ continueButtonDisabled,
530
+ displayState,
531
+ errorMsg,
532
+ hotspotArtifactPercent,
533
+ hotspotPhase,
534
+ isVersionChange,
535
+ mtkInstallStallSimulatedPercent,
536
+ otaProgress,
537
+ otaStatus,
538
+ versionChangeConverged,
539
+ versionChangePhase,
540
+ } = install
541
+ const firmwareRestarting = (!connected && displayState === "restarting") || versionChangePhase === "restarting"
542
+
543
+ useEffect(() => {
544
+ onFirmwareRestartingChange?.(firmwareRestarting, true)
545
+ }, [firmwareRestarting, onFirmwareRestartingChange])
546
+
547
+ useEffect(
548
+ () => () => {
549
+ onFirmwareRestartingChange?.(false, false)
550
+ },
551
+ [onFirmwareRestartingChange],
552
+ )
553
+
554
+ useEffect(() => {
555
+ ota.installSession.attach()
556
+ return () => ota.installSession.detach()
557
+ }, [])
558
+
559
+ useEffect(() => {
560
+ if (displayState !== "complete" || !connected || !isOtaAutoChainActive() || autoChainAdvancedRef.current) return
561
+ const timeout = setTimeout(() => {
562
+ if (!isOtaAutoChainActive()) return
563
+ autoChainAdvancedRef.current = true
564
+ ota.installSession.finish()
565
+ onReturnToCheck()
566
+ }, AUTO_CHAIN_COMPLETE_DELAY_MS)
567
+ return () => clearTimeout(timeout)
568
+ }, [connected, displayState, onReturnToCheck])
569
+
570
+ const finishAndCheck = () => {
571
+ ota.installSession.finish()
572
+ onReturnToCheck()
573
+ }
574
+ const stopAndCheck = () => {
575
+ stopOtaAutoChain()
576
+ finishAndCheck()
577
+ }
578
+ const retryInstall = () => {
579
+ onFirmwareRestartingChange?.(false, true)
580
+ ota.installSession.retry()
581
+ }
582
+
583
+ if (versionChangePhase === "restarting" || versionChangePhase === "verifying") {
584
+ return (
585
+ <FlowPage
586
+ colors={colors}
587
+ icon="download"
588
+ title={translate(
589
+ versionChangePhase === "verifying" ? "ota:versionChangeVerifying" : "ota:versionChangeRestarting",
590
+ )}>
591
+ <ActivityIndicator size="large" color={colors.foreground} />
592
+ <BodyText colors={colors}>{translate("ota:versionChangeKeepNearby")}</BodyText>
593
+ <BodyText colors={colors}>{translate("ota:downgradeDuration")}</BodyText>
594
+ </FlowPage>
595
+ )
596
+ }
597
+
598
+ if (displayState === "starting") {
599
+ const hotspotTitle =
600
+ hotspotPhase === "downloading"
601
+ ? "Downloading update to phone..."
602
+ : hotspotPhase === "starting_hotspot"
603
+ ? "Starting glasses hotspot..."
604
+ : hotspotPhase === "joining_hotspot"
605
+ ? "Connecting phone to glasses..."
606
+ : "Starting update..."
607
+ return (
608
+ <FlowPage colors={colors} icon="download" title={hotspotTitle}>
609
+ {hotspotPhase === "downloading" && hotspotArtifactPercent !== null ? (
610
+ <PercentText colors={colors} percent={hotspotArtifactPercent} />
611
+ ) : null}
612
+ <ActivityIndicator size="large" color={colors.foreground} />
613
+ <BodyText colors={colors}>Do not disconnect your glasses</BodyText>
614
+ </FlowPage>
615
+ )
616
+ }
617
+
618
+ if (displayState === "updating") {
619
+ const isDownload = otaStatus?.phase === "download"
620
+ const totalSteps = otaStatus?.totalSteps ?? 1
621
+ const isApkOnlyInstalling = otaStatus?.stepType === "apk" && otaStatus.phase === "install" && totalSteps === 1
622
+ const rawPercent = isDownload
623
+ ? otaStatus?.stepPercent ?? 0
624
+ : totalSteps >= 2
625
+ ? otaStatus?.overallPercent ?? 0
626
+ : otaStatus?.stepPercent ?? 0
627
+ const percent = Math.min(Math.max(rawPercent, mtkInstallStallSimulatedPercent ?? 0, 0), 100)
628
+ return (
629
+ <FlowPage colors={colors} icon="download" title={isDownload ? "Downloading..." : "Installing..."}>
630
+ {isApkOnlyInstalling ? (
631
+ <ActivityIndicator size="large" color={colors.foreground} />
632
+ ) : (
633
+ <>
634
+ <PercentText colors={colors} percent={percent} />
635
+ <View style={[styles.progressTrack, {backgroundColor: colors.border}]}>
636
+ <View style={[styles.progressFill, {backgroundColor: colors.primary, width: `${percent}%`}]} />
637
+ </View>
638
+ </>
639
+ )}
640
+ <BodyText colors={colors}>Do not disconnect your glasses</BodyText>
641
+ {isVersionChange && otaStatus?.phase === "install" ? (
642
+ <BodyText colors={colors}>{translate("ota:downgradeDuration")}</BodyText>
643
+ ) : null}
644
+ </FlowPage>
645
+ )
646
+ }
647
+
648
+ if (displayState === "restarting") {
649
+ return (
650
+ <FlowPage
651
+ actions={
652
+ <FlowButton colors={colors} disabled={continueButtonDisabled} label="Continue" onPress={stopAndCheck} />
653
+ }
654
+ colors={colors}
655
+ icon="check"
656
+ title="Update Installed"
657
+ />
658
+ )
659
+ }
660
+
661
+ if (displayState === "complete") {
662
+ const title = versionChangeConverged
663
+ ? translate("ota:versionChangeComplete")
664
+ : isVersionChange
665
+ ? translate("ota:versionChangeFirmwarePassComplete")
666
+ : "Update complete!"
667
+ const message = versionChangeConverged
668
+ ? translate("ota:versionChangeCompleteMessage")
669
+ : isVersionChange
670
+ ? translate("ota:versionChangeFirmwarePassCompleteMessage")
671
+ : "Your glasses are up to date."
672
+ return (
673
+ <FlowPage
674
+ actions={
675
+ <FlowButton
676
+ colors={colors}
677
+ label={isVersionChange && !versionChangeConverged ? "Continue" : "Done"}
678
+ onPress={finishAndCheck}
679
+ />
680
+ }
681
+ colors={colors}
682
+ icon="check"
683
+ title={title}>
684
+ <BodyText colors={colors}>{message}</BodyText>
685
+ </FlowPage>
686
+ )
687
+ }
688
+
689
+ if (displayState === "failed") {
690
+ const requiresGlassesReboot = shouldRequireGlassesRebootForBesFailure(otaStatus, otaProgress, errorMsg)
691
+ const displayedError = requiresGlassesReboot
692
+ ? BES_INSTALL_RESTART_MESSAGE
693
+ : errorMsg || getOtaErrorMessage(otaStatus?.error)
694
+ const showChangeWifi = shouldShowChangeWifiForOtaDownloadFailure(otaStatus, otaProgress, errorMsg)
695
+ return (
696
+ <FlowPage
697
+ actions={
698
+ <>
699
+ <FlowButton
700
+ colors={colors}
701
+ label={requiresGlassesReboot ? "Done" : "Retry"}
702
+ onPress={requiresGlassesReboot ? stopAndCheck : retryInstall}
703
+ />
704
+ {showChangeWifi ? (
705
+ <FlowButton
706
+ colors={colors}
707
+ label="Change WiFi"
708
+ onPress={() => {
709
+ stopOtaAutoChain()
710
+ onOpenWifiSetup()
711
+ }}
712
+ secondary
713
+ />
714
+ ) : null}
715
+ </>
716
+ }
717
+ colors={colors}
718
+ icon="alert"
719
+ title="Update Failed">
720
+ <BodyText colors={colors}>{displayedError}</BodyText>
721
+ </FlowPage>
722
+ )
723
+ }
724
+
725
+ return (
726
+ <FlowPage
727
+ actions={
728
+ superMode ? (
729
+ <FlowButton
730
+ colors={colors}
731
+ label="Skip (super)"
732
+ onPress={() => {
733
+ stopOtaAutoChain()
734
+ ota.installSession.discard()
735
+ onReturnToCheck()
736
+ }}
737
+ secondary
738
+ />
739
+ ) : undefined
740
+ }
741
+ colors={colors}
742
+ icon="bluetooth"
743
+ title="Glasses disconnected">
744
+ <BodyText colors={colors}>Reconnecting...</BodyText>
745
+ <ActivityIndicator size="large" color={colors.foreground} />
746
+ </FlowPage>
747
+ )
748
+ }
749
+
750
+ type FlowPageProps = {
751
+ actions?: React.ReactNode
752
+ children?: React.ReactNode
753
+ colors: MentraLiveOtaFlowTheme
754
+ icon: "alert" | "bluetooth" | "check" | "download" | "settings"
755
+ title: string
756
+ }
757
+
758
+ function FlowPage({actions, children, colors, icon, title}: FlowPageProps) {
759
+ return (
760
+ <View style={styles.page} testID="mentra-live-ota-flow">
761
+ <View style={styles.centerContent}>
762
+ <FlowIcon colors={colors} name={icon} />
763
+ <Text style={[styles.title, {color: colors.foreground}]}>{title}</Text>
764
+ {children}
765
+ </View>
766
+ {actions ? <View style={styles.actions}>{actions}</View> : <View style={styles.actionSpacer} />}
767
+ </View>
768
+ )
769
+ }
770
+
771
+ function BodyText({children, colors}: {children: React.ReactNode; colors: MentraLiveOtaFlowTheme}) {
772
+ return <Text style={[styles.body, {color: colors.textDim}]}>{children}</Text>
773
+ }
774
+
775
+ function PercentText({colors, percent}: {colors: MentraLiveOtaFlowTheme; percent: number}) {
776
+ return <Text style={[styles.percent, {color: colors.primary}]}>{Math.round(percent)}%</Text>
777
+ }
778
+
779
+ function FlowButton({
780
+ colors,
781
+ disabled = false,
782
+ label,
783
+ onPress,
784
+ secondary = false,
785
+ }: {
786
+ colors: MentraLiveOtaFlowTheme
787
+ disabled?: boolean
788
+ label: string
789
+ onPress: () => void
790
+ secondary?: boolean
791
+ }) {
792
+ return (
793
+ <Pressable
794
+ accessibilityRole="button"
795
+ disabled={disabled}
796
+ onPress={onPress}
797
+ style={({pressed}) => [
798
+ styles.button,
799
+ {
800
+ backgroundColor: secondary ? colors.background : colors.primary,
801
+ borderColor: secondary ? colors.border : colors.primary,
802
+ opacity: disabled ? 0.45 : pressed ? 0.75 : 1,
803
+ },
804
+ ]}
805
+ testID={`button-${label}`}>
806
+ <Text style={[styles.buttonText, {color: secondary ? colors.foreground : colors.primaryText}]}>{label}</Text>
807
+ </Pressable>
808
+ )
809
+ }
810
+
811
+ function MentraMark({color}: {color: string}) {
812
+ return (
813
+ <Svg width={33} height={18} viewBox="0 0 50 27" fill="none">
814
+ <Rect y={14.8072} width={11.8457} height={11.8457} fill={color} />
815
+ <Path d="M9.36639 0L30.7163 14.8072V26.6529L9.36639 11.8457V0Z" fill={color} />
816
+ <Path d="M28.6501 0L50 14.8072V26.6529L28.6501 11.8457V0Z" fill={color} />
817
+ </Svg>
818
+ )
819
+ }
820
+
821
+ function FlowIcon({colors, name}: {colors: MentraLiveOtaFlowTheme; name: FlowPageProps["icon"]}) {
822
+ const color = name === "alert" || name === "bluetooth" ? colors.error : colors.primary
823
+ const glyph =
824
+ name === "check" ? "✓" : name === "alert" ? "!" : name === "settings" ? "⚙" : name === "bluetooth" ? "⌁" : "↓"
825
+ return <Text style={[styles.icon, {color}]}>{glyph}</Text>
826
+ }
827
+
828
+ const styles = StyleSheet.create({
829
+ safeArea: {flex: 1},
830
+ header: {
831
+ alignItems: "center",
832
+ flexDirection: "row",
833
+ height: 48,
834
+ justifyContent: "space-between",
835
+ paddingHorizontal: 20,
836
+ },
837
+ page: {flex: 1, paddingBottom: 24, paddingHorizontal: 24},
838
+ centerContent: {alignItems: "center", flex: 1, gap: 16, justifyContent: "center"},
839
+ actionSpacer: {height: 48},
840
+ actions: {gap: 12},
841
+ icon: {fontSize: 64, fontWeight: "500", lineHeight: 72, textAlign: "center"},
842
+ title: {fontSize: 20, fontWeight: "600", textAlign: "center"},
843
+ body: {fontSize: 14, lineHeight: 20, maxWidth: 420, textAlign: "center"},
844
+ percent: {fontSize: 30, fontVariant: ["tabular-nums"], fontWeight: "700"},
845
+ progressTrack: {borderRadius: 4, height: 8, maxWidth: 420, overflow: "hidden", width: "100%"},
846
+ progressFill: {borderRadius: 4, height: 8},
847
+ button: {
848
+ alignItems: "center",
849
+ borderRadius: 10,
850
+ borderWidth: 1,
851
+ justifyContent: "center",
852
+ minHeight: 48,
853
+ paddingHorizontal: 20,
854
+ },
855
+ buttonText: {fontSize: 15, fontWeight: "700"},
856
+ })