@glassly/engine 0.1.0-dev.99 → 0.2.9-beta.448

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 (501) hide show
  1. package/README.md +28 -0
  2. package/build/engine.d.ts +32 -10
  3. package/build/engine.d.ts.map +1 -1
  4. package/build/engine.js +24 -16
  5. package/build/engine.js.map +1 -1
  6. package/build/facades/dev.d.ts +9 -0
  7. package/build/facades/dev.d.ts.map +1 -1
  8. package/build/facades/dev.js +9 -0
  9. package/build/facades/dev.js.map +1 -1
  10. package/build/facades/display.d.ts +10 -3
  11. package/build/facades/display.d.ts.map +1 -1
  12. package/build/facades/display.js +22 -8
  13. package/build/facades/display.js.map +1 -1
  14. package/build/facades/displayMirror.d.ts +11 -0
  15. package/build/facades/displayMirror.d.ts.map +1 -1
  16. package/build/facades/displayMirror.js +22 -0
  17. package/build/facades/displayMirror.js.map +1 -1
  18. package/build/facades/glasses.d.ts +31 -1
  19. package/build/facades/glasses.d.ts.map +1 -1
  20. package/build/facades/glasses.js +51 -0
  21. package/build/facades/glasses.js.map +1 -1
  22. package/build/facades/memory.d.ts +0 -6
  23. package/build/facades/memory.d.ts.map +1 -1
  24. package/build/facades/memory.js +1 -9
  25. package/build/facades/memory.js.map +1 -1
  26. package/build/facades/miniapps.d.ts +3 -1
  27. package/build/facades/miniapps.d.ts.map +1 -1
  28. package/build/facades/miniapps.js +3 -1
  29. package/build/facades/miniapps.js.map +1 -1
  30. package/build/facades/pairing.d.ts.map +1 -1
  31. package/build/facades/pairing.js +5 -4
  32. package/build/facades/pairing.js.map +1 -1
  33. package/build/facades/permissions.d.ts +2 -0
  34. package/build/facades/permissions.d.ts.map +1 -1
  35. package/build/facades/permissions.js +48 -0
  36. package/build/facades/permissions.js.map +1 -1
  37. package/build/facades/phoneNotifications.d.ts +20 -9
  38. package/build/facades/phoneNotifications.d.ts.map +1 -1
  39. package/build/facades/phoneNotifications.js +33 -26
  40. package/build/facades/phoneNotifications.js.map +1 -1
  41. package/build/facades/settings.d.ts.map +1 -1
  42. package/build/facades/settings.js +1 -2
  43. package/build/facades/settings.js.map +1 -1
  44. package/build/generated/releaseMetadata.js +4 -4
  45. package/build/generated/releaseMetadata.js.map +1 -1
  46. package/build/index.d.ts +6 -4
  47. package/build/index.d.ts.map +1 -1
  48. package/build/index.js +5 -4
  49. package/build/index.js.map +1 -1
  50. package/build/react/MentraLiveOtaFlow.js +2 -2
  51. package/build/react/MentraLiveOtaFlow.js.map +1 -1
  52. package/build/react/useMentraLiveOta.d.ts.map +1 -1
  53. package/build/react/useMentraLiveOta.js +8 -7
  54. package/build/react/useMentraLiveOta.js.map +1 -1
  55. package/build/runtime/config.d.ts +1 -1
  56. package/build/runtime/config.d.ts.map +1 -1
  57. package/build/runtime/config.js.map +1 -1
  58. package/build/services/AppRegistry.d.ts +4 -1
  59. package/build/services/AppRegistry.d.ts.map +1 -1
  60. package/build/services/AppRegistry.js +21 -1
  61. package/build/services/AppRegistry.js.map +1 -1
  62. package/build/services/BlobStore.d.ts +2 -2
  63. package/build/services/BlobStore.js +3 -3
  64. package/build/services/BlobStore.js.map +1 -1
  65. package/build/services/CloudClientService.d.ts +7 -3
  66. package/build/services/CloudClientService.d.ts.map +1 -1
  67. package/build/services/CloudClientService.js +34 -9
  68. package/build/services/CloudClientService.js.map +1 -1
  69. package/build/services/DevServerBridge.d.ts +1 -18
  70. package/build/services/DevServerBridge.d.ts.map +1 -1
  71. package/build/services/DevServerBridge.js +9 -8
  72. package/build/services/DevServerBridge.js.map +1 -1
  73. package/build/services/DeviceEventRouter.d.ts.map +1 -1
  74. package/build/services/DeviceEventRouter.js +58 -71
  75. package/build/services/DeviceEventRouter.js.map +1 -1
  76. package/build/services/DisplayDiagnostics.d.ts +5 -0
  77. package/build/services/DisplayDiagnostics.d.ts.map +1 -0
  78. package/build/services/DisplayDiagnostics.js +105 -0
  79. package/build/services/DisplayDiagnostics.js.map +1 -0
  80. package/build/services/DisplayProcessor.d.ts +6 -7
  81. package/build/services/DisplayProcessor.d.ts.map +1 -1
  82. package/build/services/DisplayProcessor.js +17 -45
  83. package/build/services/DisplayProcessor.js.map +1 -1
  84. package/build/services/GestureDotsService.d.ts +10 -4
  85. package/build/services/GestureDotsService.d.ts.map +1 -1
  86. package/build/services/GestureDotsService.js +70 -16
  87. package/build/services/GestureDotsService.js.map +1 -1
  88. package/build/services/GlassesKeyboardInput.d.ts +77 -0
  89. package/build/services/GlassesKeyboardInput.d.ts.map +1 -0
  90. package/build/services/GlassesKeyboardInput.js +261 -0
  91. package/build/services/GlassesKeyboardInput.js.map +1 -0
  92. package/build/services/GlassesSensorService.d.ts +47 -0
  93. package/build/services/GlassesSensorService.d.ts.map +1 -0
  94. package/build/services/GlassesSensorService.js +242 -0
  95. package/build/services/GlassesSensorService.js.map +1 -0
  96. package/build/services/GlassesTouchInput.d.ts +14 -0
  97. package/build/services/GlassesTouchInput.d.ts.map +1 -0
  98. package/build/services/GlassesTouchInput.js +107 -0
  99. package/build/services/GlassesTouchInput.js.map +1 -0
  100. package/build/services/HeadingService.d.ts +0 -6
  101. package/build/services/HeadingService.d.ts.map +1 -1
  102. package/build/services/HeadingService.js +0 -27
  103. package/build/services/HeadingService.js.map +1 -1
  104. package/build/services/HotspotShutdown.d.ts.map +1 -1
  105. package/build/services/HotspotShutdown.js +2 -1
  106. package/build/services/HotspotShutdown.js.map +1 -1
  107. package/build/services/JSCrashloopReportService.js +2 -2
  108. package/build/services/JSCrashloopReportService.js.map +1 -1
  109. package/build/services/JSRouter.d.ts +6 -4
  110. package/build/services/JSRouter.d.ts.map +1 -1
  111. package/build/services/JSRouter.js +15 -13
  112. package/build/services/JSRouter.js.map +1 -1
  113. package/build/services/LocalDisplayManager.d.ts +35 -7
  114. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  115. package/build/services/LocalDisplayManager.js +105 -27
  116. package/build/services/LocalDisplayManager.js.map +1 -1
  117. package/build/services/LocalMiniappDataMigration.d.ts +1 -1
  118. package/build/services/LocalMiniappDataMigration.js +1 -1
  119. package/build/services/LocalMiniappDataMigration.js.map +1 -1
  120. package/build/services/LocalMiniappRuntime.d.ts +64 -11
  121. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  122. package/build/services/LocalMiniappRuntime.js +441 -35
  123. package/build/services/LocalMiniappRuntime.js.map +1 -1
  124. package/build/services/LocalSttFallbackCoordinator.d.ts +3 -0
  125. package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
  126. package/build/services/LocalSttFallbackCoordinator.js +27 -8
  127. package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
  128. package/build/services/MemoryStore.d.ts +8 -33
  129. package/build/services/MemoryStore.d.ts.map +1 -1
  130. package/build/services/MemoryStore.js +30 -56
  131. package/build/services/MemoryStore.js.map +1 -1
  132. package/build/services/MiniappEngine.d.ts +3 -3
  133. package/build/services/MiniappEngine.js +7 -7
  134. package/build/services/MiniappEngine.js.map +1 -1
  135. package/build/services/MiniappLauncher.d.ts +8 -0
  136. package/build/services/MiniappLauncher.d.ts.map +1 -1
  137. package/build/services/MiniappLauncher.js +19 -1
  138. package/build/services/MiniappLauncher.js.map +1 -1
  139. package/build/services/MirrorService.d.ts +24 -0
  140. package/build/services/MirrorService.d.ts.map +1 -0
  141. package/build/services/MirrorService.js +132 -0
  142. package/build/services/MirrorService.js.map +1 -0
  143. package/build/services/NativeNavigationService.d.ts +2 -3
  144. package/build/services/NativeNavigationService.d.ts.map +1 -1
  145. package/build/services/NativeNavigationService.js +24 -21
  146. package/build/services/NativeNavigationService.js.map +1 -1
  147. package/build/services/NavigationHandlers.d.ts.map +1 -1
  148. package/build/services/NavigationHandlers.js +10 -5
  149. package/build/services/NavigationHandlers.js.map +1 -1
  150. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  151. package/build/services/OtaInstallCoordinator.js +24 -23
  152. package/build/services/OtaInstallCoordinator.js.map +1 -1
  153. package/build/services/PairedGlassesLatch.d.ts +7 -0
  154. package/build/services/PairedGlassesLatch.d.ts.map +1 -0
  155. package/build/services/PairedGlassesLatch.js +38 -0
  156. package/build/services/PairedGlassesLatch.js.map +1 -0
  157. package/build/services/PhoneActivity.d.ts +23 -0
  158. package/build/services/PhoneActivity.d.ts.map +1 -0
  159. package/build/services/PhoneActivity.js +111 -0
  160. package/build/services/PhoneActivity.js.map +1 -0
  161. package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -1
  162. package/build/services/PhoneCameraFovCoordinator.js +4 -3
  163. package/build/services/PhoneCameraFovCoordinator.js.map +1 -1
  164. package/build/services/PhoneNotificationsSync.d.ts +40 -6
  165. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  166. package/build/services/PhoneNotificationsSync.js +160 -84
  167. package/build/services/PhoneNotificationsSync.js.map +1 -1
  168. package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
  169. package/build/services/PhonePhotoCoordinator.js +6 -5
  170. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  171. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  172. package/build/services/PhoneStreamCoordinator.js +8 -7
  173. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  174. package/build/services/STTModelManager.d.ts +3 -0
  175. package/build/services/STTModelManager.d.ts.map +1 -1
  176. package/build/services/STTModelManager.js +15 -1
  177. package/build/services/STTModelManager.js.map +1 -1
  178. package/build/services/SceneRenderer.d.ts +43 -2
  179. package/build/services/SceneRenderer.d.ts.map +1 -1
  180. package/build/services/SceneRenderer.js +123 -8
  181. package/build/services/SceneRenderer.js.map +1 -1
  182. package/build/services/StreamLifecycleController.d.ts.map +1 -1
  183. package/build/services/StreamLifecycleController.js +6 -14
  184. package/build/services/StreamLifecycleController.js.map +1 -1
  185. package/build/services/TTSModelManager.js +1 -1
  186. package/build/services/TTSModelManager.js.map +1 -1
  187. package/build/services/UIRouter.d.ts +2 -2
  188. package/build/services/UIRouter.js +5 -5
  189. package/build/services/UIRouter.js.map +1 -1
  190. package/build/services/asg/galleryPathMigration.js +1 -1
  191. package/build/services/asg/galleryPathMigration.js.map +1 -1
  192. package/build/services/asg/gallerySyncService.js +2 -2
  193. package/build/services/asg/gallerySyncService.js.map +1 -1
  194. package/build/services/asg/localStorageService.d.ts.map +1 -1
  195. package/build/services/asg/localStorageService.js +3 -3
  196. package/build/services/asg/localStorageService.js.map +1 -1
  197. package/build/services/debug/DashboardOpenTrace.d.ts +32 -0
  198. package/build/services/debug/DashboardOpenTrace.d.ts.map +1 -0
  199. package/build/services/debug/DashboardOpenTrace.js +128 -0
  200. package/build/services/debug/DashboardOpenTrace.js.map +1 -0
  201. package/build/services/debug/dashboardOpenTimeline.d.ts +77 -0
  202. package/build/services/debug/dashboardOpenTimeline.d.ts.map +1 -0
  203. package/build/services/debug/dashboardOpenTimeline.js +195 -0
  204. package/build/services/debug/dashboardOpenTimeline.js.map +1 -0
  205. package/build/services/effectiveCapabilities.d.ts.map +1 -1
  206. package/build/services/effectiveCapabilities.js +25 -13
  207. package/build/services/effectiveCapabilities.js.map +1 -1
  208. package/build/services/gestureClaims.d.ts +34 -15
  209. package/build/services/gestureClaims.d.ts.map +1 -1
  210. package/build/services/gestureClaims.js +42 -21
  211. package/build/services/gestureClaims.js.map +1 -1
  212. package/build/services/manifestFields.d.ts +9 -0
  213. package/build/services/manifestFields.d.ts.map +1 -0
  214. package/build/services/manifestFields.js +26 -0
  215. package/build/services/manifestFields.js.map +1 -0
  216. package/build/services/memoryStoreInstance.d.ts +0 -10
  217. package/build/services/memoryStoreInstance.d.ts.map +1 -1
  218. package/build/services/memoryStoreInstance.js +2 -31
  219. package/build/services/memoryStoreInstance.js.map +1 -1
  220. package/build/services/mirrorSnapshot.d.ts +16 -0
  221. package/build/services/mirrorSnapshot.d.ts.map +1 -0
  222. package/build/services/mirrorSnapshot.js +102 -0
  223. package/build/services/mirrorSnapshot.js.map +1 -0
  224. package/build/services/nativeNavigationGate.d.ts +8 -0
  225. package/build/services/nativeNavigationGate.d.ts.map +1 -0
  226. package/build/services/nativeNavigationGate.js +12 -0
  227. package/build/services/nativeNavigationGate.js.map +1 -0
  228. package/build/services/notificationAppCatalog.d.ts +7 -0
  229. package/build/services/notificationAppCatalog.d.ts.map +1 -0
  230. package/build/services/notificationAppCatalog.js +16 -0
  231. package/build/services/notificationAppCatalog.js.map +1 -0
  232. package/build/services/notifications/notificationPolicy.d.ts +55 -0
  233. package/build/services/notifications/notificationPolicy.d.ts.map +1 -0
  234. package/build/services/notifications/notificationPolicy.js +41 -0
  235. package/build/services/notifications/notificationPolicy.js.map +1 -0
  236. package/build/services/pages/OverlayPages.d.ts +26 -0
  237. package/build/services/pages/OverlayPages.d.ts.map +1 -0
  238. package/build/services/pages/OverlayPages.js +80 -0
  239. package/build/services/pages/OverlayPages.js.map +1 -0
  240. package/build/services/pages/PageHost.d.ts +32 -0
  241. package/build/services/pages/PageHost.d.ts.map +1 -0
  242. package/build/services/pages/PageHost.js +99 -0
  243. package/build/services/pages/PageHost.js.map +1 -0
  244. package/build/services/pages/overlayApps.d.ts +25 -0
  245. package/build/services/pages/overlayApps.d.ts.map +1 -0
  246. package/build/services/pages/overlayApps.js +66 -0
  247. package/build/services/pages/overlayApps.js.map +1 -0
  248. package/build/services/pages/pageEligibility.d.ts +9 -0
  249. package/build/services/pages/pageEligibility.d.ts.map +1 -0
  250. package/build/services/pages/pageEligibility.js +27 -0
  251. package/build/services/pages/pageEligibility.js.map +1 -0
  252. package/build/services/settingsBridge.d.ts +58 -0
  253. package/build/services/settingsBridge.d.ts.map +1 -0
  254. package/build/services/settingsBridge.js +90 -0
  255. package/build/services/settingsBridge.js.map +1 -0
  256. package/build/services/speakerProfileStoreInstance.js +1 -1
  257. package/build/services/speakerProfileStoreInstance.js.map +1 -1
  258. package/build/services/uiShim.d.ts +1 -1
  259. package/build/services/uiShim.js +4 -4
  260. package/build/services/uiShim.js.map +1 -1
  261. package/build/stores/appVisibility.d.ts +28 -0
  262. package/build/stores/appVisibility.d.ts.map +1 -1
  263. package/build/stores/appVisibility.js +34 -0
  264. package/build/stores/appVisibility.js.map +1 -1
  265. package/build/stores/apps.d.ts +13 -0
  266. package/build/stores/apps.d.ts.map +1 -1
  267. package/build/stores/apps.js +66 -12
  268. package/build/stores/apps.js.map +1 -1
  269. package/build/stores/bluetoothSettingKeys.js +1 -1
  270. package/build/stores/bluetoothSettingKeys.js.map +1 -1
  271. package/build/stores/display.d.ts +3 -3
  272. package/build/stores/display.d.ts.map +1 -1
  273. package/build/stores/display.js +16 -4
  274. package/build/stores/display.js.map +1 -1
  275. package/build/stores/glasses.d.ts.map +1 -1
  276. package/build/stores/glasses.js +14 -1
  277. package/build/stores/glasses.js.map +1 -1
  278. package/build/stores/settings.d.ts +1 -0
  279. package/build/stores/settings.d.ts.map +1 -1
  280. package/build/stores/settings.js +170 -44
  281. package/build/stores/settings.js.map +1 -1
  282. package/build/types/applet.d.ts +14 -1
  283. package/build/types/applet.d.ts.map +1 -1
  284. package/build/types/applet.js.map +1 -1
  285. package/build/types/capabilities/even-realities-g2.d.ts.map +1 -1
  286. package/build/types/capabilities/even-realities-g2.js +5 -0
  287. package/build/types/capabilities/even-realities-g2.js.map +1 -1
  288. package/build/types/capabilities/simulated-glasses.d.ts +1 -1
  289. package/build/types/capabilities/simulated-glasses.d.ts.map +1 -1
  290. package/build/types/capabilities/simulated-glasses.js +7 -4
  291. package/build/types/capabilities/simulated-glasses.js.map +1 -1
  292. package/build/types/hardware.d.ts +20 -1
  293. package/build/types/hardware.d.ts.map +1 -1
  294. package/build/types/hardware.js +2 -0
  295. package/build/types/hardware.js.map +1 -1
  296. package/build/types/index.d.ts +1 -0
  297. package/build/types/index.d.ts.map +1 -1
  298. package/build/types/index.js +1 -0
  299. package/build/types/index.js.map +1 -1
  300. package/build/utils/debouncedPatch.d.ts +3 -1
  301. package/build/utils/debouncedPatch.d.ts.map +1 -1
  302. package/build/utils/debouncedPatch.js +6 -3
  303. package/build/utils/debouncedPatch.js.map +1 -1
  304. package/build/utils/devMiniappLaunch.d.ts.map +1 -1
  305. package/build/utils/devMiniappLaunch.js +4 -3
  306. package/build/utils/devMiniappLaunch.js.map +1 -1
  307. package/build/utils/display/measurer/TextMeasurer.d.ts +2 -159
  308. package/build/utils/display/measurer/TextMeasurer.d.ts.map +1 -1
  309. package/build/utils/display/measurer/TextMeasurer.js +2 -272
  310. package/build/utils/display/measurer/TextMeasurer.js.map +1 -1
  311. package/build/utils/display/measurer/script-detection.d.ts +1 -52
  312. package/build/utils/display/measurer/script-detection.d.ts.map +1 -1
  313. package/build/utils/display/measurer/script-detection.js +2 -183
  314. package/build/utils/display/measurer/script-detection.js.map +1 -1
  315. package/build/utils/display/pixelArt.d.ts +3 -0
  316. package/build/utils/display/pixelArt.d.ts.map +1 -0
  317. package/build/utils/display/pixelArt.js +3 -0
  318. package/build/utils/display/pixelArt.js.map +1 -0
  319. package/build/utils/display/profiles/g1.d.ts +1 -32
  320. package/build/utils/display/profiles/g1.d.ts.map +1 -1
  321. package/build/utils/display/profiles/g1.js +2 -212
  322. package/build/utils/display/profiles/g1.js.map +1 -1
  323. package/build/utils/display/profiles/g2.d.ts +1 -12
  324. package/build/utils/display/profiles/g2.d.ts.map +1 -1
  325. package/build/utils/display/profiles/g2.js +2 -33
  326. package/build/utils/display/profiles/g2.js.map +1 -1
  327. package/build/utils/display/profiles/nex.d.ts +1 -9
  328. package/build/utils/display/profiles/nex.d.ts.map +1 -1
  329. package/build/utils/display/profiles/nex.js +2 -149
  330. package/build/utils/display/profiles/nex.js.map +1 -1
  331. package/build/utils/display/profiles/types.d.ts +1 -102
  332. package/build/utils/display/profiles/types.d.ts.map +1 -1
  333. package/build/utils/display/profiles/types.js.map +1 -1
  334. package/build/utils/display/profiles/z100.d.ts +1 -32
  335. package/build/utils/display/profiles/z100.d.ts.map +1 -1
  336. package/build/utils/display/profiles/z100.js +2 -181
  337. package/build/utils/display/profiles/z100.js.map +1 -1
  338. package/build/utils/display/scene/degrade.d.ts.map +1 -1
  339. package/build/utils/display/scene/degrade.js +4 -1
  340. package/build/utils/display/scene/degrade.js.map +1 -1
  341. package/build/utils/display/scene/differ.d.ts +13 -1
  342. package/build/utils/display/scene/differ.d.ts.map +1 -1
  343. package/build/utils/display/scene/differ.js +22 -0
  344. package/build/utils/display/scene/differ.js.map +1 -1
  345. package/build/utils/display/scene/index.d.ts +1 -1
  346. package/build/utils/display/scene/index.d.ts.map +1 -1
  347. package/build/utils/display/scene/index.js.map +1 -1
  348. package/build/utils/display/scene/process.d.ts.map +1 -1
  349. package/build/utils/display/scene/process.js +183 -11
  350. package/build/utils/display/scene/process.js.map +1 -1
  351. package/build/utils/display/scene/store.d.ts +1 -1
  352. package/build/utils/display/scene/store.d.ts.map +1 -1
  353. package/build/utils/display/scene/store.js +0 -0
  354. package/build/utils/display/scene/store.js.map +1 -1
  355. package/build/utils/display/scene/svgPath.d.ts +9 -0
  356. package/build/utils/display/scene/svgPath.d.ts.map +1 -0
  357. package/build/utils/display/scene/svgPath.js +167 -0
  358. package/build/utils/display/scene/svgPath.js.map +1 -0
  359. package/build/utils/display/scene/types.d.ts +2 -142
  360. package/build/utils/display/scene/types.d.ts.map +1 -1
  361. package/build/utils/display/scene/types.js +0 -0
  362. package/build/utils/display/scene/types.js.map +1 -1
  363. package/build/utils/display/wrapper/TextWrapper.d.ts +1 -101
  364. package/build/utils/display/wrapper/TextWrapper.d.ts.map +1 -1
  365. package/build/utils/display/wrapper/TextWrapper.js +2 -470
  366. package/build/utils/display/wrapper/TextWrapper.js.map +1 -1
  367. package/build/utils/display/wrapper/types.d.ts +2 -74
  368. package/build/utils/display/wrapper/types.d.ts.map +1 -1
  369. package/build/utils/display/wrapper/types.js +2 -10
  370. package/build/utils/display/wrapper/types.js.map +1 -1
  371. package/build/utils/hardware/hardware.js +1 -1
  372. package/build/utils/hardware/hardware.js.map +1 -1
  373. package/build/utils/timers/timers.d.ts.map +1 -1
  374. package/build/utils/timers/timers.js +26 -4
  375. package/build/utils/timers/timers.js.map +1 -1
  376. package/package.json +8 -8
  377. package/src/engine.ts +24 -15
  378. package/src/facades/dev.ts +10 -0
  379. package/src/facades/display.ts +21 -8
  380. package/src/facades/displayMirror.ts +29 -0
  381. package/src/facades/glasses.ts +61 -1
  382. package/src/facades/memory.ts +1 -12
  383. package/src/facades/miniapps.ts +4 -1
  384. package/src/facades/pairing.ts +8 -6
  385. package/src/facades/permissions.ts +46 -0
  386. package/src/facades/phoneNotifications.ts +45 -26
  387. package/src/facades/settings.ts +1 -2
  388. package/src/generated/releaseMetadata.ts +4 -4
  389. package/src/index.ts +6 -9
  390. package/src/react/MentraLiveOtaFlow.tsx +2 -2
  391. package/src/react/useMentraLiveOta.ts +14 -8
  392. package/src/runtime/config.ts +1 -1
  393. package/src/services/AppRegistry.ts +43 -7
  394. package/src/services/BlobStore.ts +3 -3
  395. package/src/services/CloudClientService.ts +37 -10
  396. package/src/services/DevServerBridge.ts +12 -10
  397. package/src/services/DeviceEventRouter.ts +73 -74
  398. package/src/services/DisplayDiagnostics.ts +107 -0
  399. package/src/services/DisplayProcessor.ts +20 -55
  400. package/src/services/GestureDotsService.ts +77 -16
  401. package/src/services/GlassesKeyboardInput.ts +306 -0
  402. package/src/services/GlassesSensorService.ts +233 -0
  403. package/src/services/GlassesTouchInput.ts +128 -0
  404. package/src/services/HeadingService.ts +0 -24
  405. package/src/services/HotspotShutdown.ts +3 -1
  406. package/src/services/JSCrashloopReportService.ts +2 -2
  407. package/src/services/JSRouter.ts +29 -14
  408. package/src/services/LocalDisplayManager.ts +112 -26
  409. package/src/services/LocalMiniappDataMigration.ts +1 -1
  410. package/src/services/LocalMiniappRuntime.ts +500 -43
  411. package/src/services/LocalSttFallbackCoordinator.ts +28 -7
  412. package/src/services/MemoryStore.ts +32 -80
  413. package/src/services/MiniappEngine.ts +7 -7
  414. package/src/services/MiniappLauncher.ts +25 -1
  415. package/src/services/MirrorService.ts +139 -0
  416. package/src/services/NativeNavigationService.ts +29 -25
  417. package/src/services/NavigationHandlers.ts +10 -5
  418. package/src/services/OtaInstallCoordinator.ts +36 -34
  419. package/src/services/PairedGlassesLatch.ts +39 -0
  420. package/src/services/PhoneActivity.ts +116 -0
  421. package/src/services/PhoneCameraFovCoordinator.ts +6 -4
  422. package/src/services/PhoneNotificationsSync.ts +185 -103
  423. package/src/services/PhonePhotoCoordinator.ts +9 -10
  424. package/src/services/PhoneStreamCoordinator.ts +13 -11
  425. package/src/services/STTModelManager.ts +15 -1
  426. package/src/services/SceneRenderer.ts +148 -10
  427. package/src/services/StreamLifecycleController.ts +9 -7
  428. package/src/services/TTSModelManager.ts +1 -1
  429. package/src/services/UIRouter.ts +5 -5
  430. package/src/services/asg/galleryPathMigration.ts +1 -1
  431. package/src/services/asg/gallerySyncService.ts +2 -2
  432. package/src/services/asg/localStorageService.ts +3 -3
  433. package/src/services/debug/DashboardOpenTrace.ts +153 -0
  434. package/src/services/debug/dashboardOpenTimeline.ts +237 -0
  435. package/src/services/effectiveCapabilities.ts +32 -13
  436. package/src/services/gestureClaims.ts +72 -23
  437. package/src/services/manifestFields.ts +23 -0
  438. package/src/services/memoryStoreInstance.ts +2 -34
  439. package/src/services/mirrorSnapshot.ts +116 -0
  440. package/src/services/nativeNavigationGate.ts +14 -0
  441. package/src/services/notificationAppCatalog.ts +21 -0
  442. package/src/services/notifications/notificationPolicy.ts +87 -0
  443. package/src/services/pages/OverlayPages.ts +86 -0
  444. package/src/services/pages/PageHost.ts +116 -0
  445. package/src/services/pages/overlayApps.ts +72 -0
  446. package/src/services/pages/pageEligibility.ts +30 -0
  447. package/src/services/settingsBridge.ts +111 -0
  448. package/src/services/speakerProfileStoreInstance.ts +1 -1
  449. package/src/services/uiShim.ts +4 -4
  450. package/src/stores/appVisibility.ts +45 -0
  451. package/src/stores/apps.ts +110 -32
  452. package/src/stores/bluetoothSettingKeys.ts +1 -1
  453. package/src/stores/display.ts +18 -7
  454. package/src/stores/glasses.ts +15 -1
  455. package/src/stores/settings.ts +175 -51
  456. package/src/types/applet.ts +14 -1
  457. package/src/types/capabilities/even-realities-g2.ts +6 -0
  458. package/src/types/capabilities/simulated-glasses.ts +8 -4
  459. package/src/types/hardware.ts +34 -1
  460. package/src/types/index.ts +1 -0
  461. package/src/utils/debouncedPatch.ts +8 -4
  462. package/src/utils/devMiniappLaunch.ts +5 -3
  463. package/src/utils/display/measurer/TextMeasurer.ts +3 -346
  464. package/src/utils/display/measurer/script-detection.ts +10 -218
  465. package/src/utils/display/pixelArt.ts +3 -0
  466. package/src/utils/display/profiles/g1.ts +2 -236
  467. package/src/utils/display/profiles/g2.ts +2 -39
  468. package/src/utils/display/profiles/nex.ts +2 -166
  469. package/src/utils/display/profiles/types.ts +9 -132
  470. package/src/utils/display/profiles/z100.ts +2 -198
  471. package/src/utils/display/scene/degrade.ts +4 -1
  472. package/src/utils/display/scene/differ.ts +25 -1
  473. package/src/utils/display/scene/index.ts +5 -0
  474. package/src/utils/display/scene/process.ts +196 -13
  475. package/src/utils/display/scene/store.ts +0 -0
  476. package/src/utils/display/scene/svgPath.ts +163 -0
  477. package/src/utils/display/scene/types.ts +0 -0
  478. package/src/utils/display/wrapper/TextWrapper.ts +2 -546
  479. package/src/utils/display/wrapper/types.ts +3 -102
  480. package/src/utils/hardware/hardware.ts +1 -1
  481. package/src/utils/timers/timers.ts +32 -4
  482. package/build/services/CustomDashboardModel.d.ts +0 -48
  483. package/build/services/CustomDashboardModel.d.ts.map +0 -1
  484. package/build/services/CustomDashboardModel.js +0 -73
  485. package/build/services/CustomDashboardModel.js.map +0 -1
  486. package/build/services/CustomDashboardService.d.ts +0 -63
  487. package/build/services/CustomDashboardService.d.ts.map +0 -1
  488. package/build/services/CustomDashboardService.js +0 -576
  489. package/build/services/CustomDashboardService.js.map +0 -1
  490. package/build/services/DashboardCoordinator.d.ts +0 -26
  491. package/build/services/DashboardCoordinator.d.ts.map +0 -1
  492. package/build/services/DashboardCoordinator.js +0 -125
  493. package/build/services/DashboardCoordinator.js.map +0 -1
  494. package/build/services/iosNotificationAppCatalog.d.ts +0 -13
  495. package/build/services/iosNotificationAppCatalog.d.ts.map +0 -1
  496. package/build/services/iosNotificationAppCatalog.js +0 -28
  497. package/build/services/iosNotificationAppCatalog.js.map +0 -1
  498. package/src/services/CustomDashboardModel.ts +0 -83
  499. package/src/services/CustomDashboardService.ts +0 -598
  500. package/src/services/DashboardCoordinator.ts +0 -121
  501. package/src/services/iosNotificationAppCatalog.ts +0 -39
@@ -1,39 +1,49 @@
1
1
  /**
2
- * Phone-notifications sync — engine-owned. Started by `engine.start()`.
2
+ * Phone-notifications sync — engine-owned, started by `engine.start()`. Keeps
3
+ * three things in step with settings and the connected glasses, for any host:
3
4
  *
4
- * Android: pushes the notification-forwarding operational kill switch + config
5
- * (`android_notification_listener_enabled` and `notifications_blocklist`) to
6
- * the native NotificationListener via `CrustModule.setNotificationConfig`, so
7
- * the blocklist reaches the listener for ANY host — not just the Glassly App,
8
- * where this used to live in MantleManager. The Android service is desired by
9
- * default now that its cold start is isolated from React Native. Native code
10
- * keeps the component discoverable in Android's notification-access Settings,
11
- * but only binds the service after access is granted. The debug setting remains
12
- * a hidden emergency kill switch; Notify's running state gates presentation,
13
- * not capture.
5
+ * - Android: the notification listener's kill switch + per-app blocklist
6
+ * (`CrustModule.setNotificationConfig`). The listener runs in its own
7
+ * guarded process and is desired by default; the debug setting stays a
8
+ * hidden emergency switch. Notify's running state gates presentation, not
9
+ * capture.
10
+ * - Glasses whose firmware presents notifications (`hasNativeNotifications`):
11
+ * one `GlassesNotificationConfig` pushed through the Bluetooth SDK whenever
12
+ * a setting, the phone's activity, the seen-apps list or the connected
13
+ * glasses change. Drivers re-apply their last config on reconnect; the push
14
+ * repeats on connection so a fresh driver gets it too.
15
+ * - The seen-apps list (`notification_seen_apps`) from `notification_app_seen`:
16
+ * glasses that read the phone's stream report each source app, which is
17
+ * the only app enumeration iOS offers.
14
18
  *
15
- * iOS: the G2 consumes notifications on-firmware via ANCS, so the phone's job
16
- * is config, not capture. This sync (a) records the apps the glasses report
17
- * posting notifications (`notification_app_seen` → `ios_notification_seen_apps`)
18
- * and (b) maps the shared `notifications_blocklist` + the G2 display settings
19
- * onto the native `notification_filter` / `notification_ctrl` DeviceStore keys,
20
- * which the bluetooth-sdk pushes to the glasses (and replays on reconnect).
21
- * The firmware filter is allow-based and fail-open: an empty blocklist disables
22
- * whitelisting entirely; any block enables it with allowlist = (catalog ∪ seen)
23
- * minus blocked.
19
+ * Presentation is one question with one answer (`presentationOwner`); hosts
20
+ * ask it per event instead of reasoning about models or platforms.
24
21
  */
25
22
  import {Platform} from "react-native"
26
23
  import {shallow} from "zustand/shallow"
27
24
  import CrustModule from "@glassly/crust"
25
+ import type {PhoneNotificationEvent} from "@glassly/crust"
26
+ import type {GlassesNotificationConfig} from "@glassly/bluetooth-sdk"
28
27
  import BluetoothSdk from "@glassly/bluetooth-sdk/internal"
29
- import type {
30
- G2NotificationCtrlSetting,
31
- G2NotificationFilterSetting,
32
- NotificationAppSeenEvent,
33
- } from "@glassly/bluetooth-sdk/internal"
28
+ import type {NotificationAppSeenEvent} from "@glassly/bluetooth-sdk/internal"
34
29
 
30
+ import {useGlassesStore} from "../stores/glasses"
35
31
  import {useSettingsStore, SETTINGS} from "../stores/settings"
36
- import {IOS_NOTIFICATION_APP_CATALOG} from "./iosNotificationAppCatalog"
32
+ import {DeviceTypes} from "../types/enums"
33
+ import {getModelCapabilities} from "../types/hardware"
34
+ import {isGlassesConnected} from "./GlassesReadiness"
35
+ import {notificationAppCatalog} from "./notificationAppCatalog"
36
+ import {
37
+ glassesNotificationConfig,
38
+ presentationOwner,
39
+ type NotificationApp,
40
+ type PresentationOwner,
41
+ } from "./notifications/notificationPolicy"
42
+ import {overlayViewerRunning} from "./pages/overlayApps"
43
+ import {pagesEligible} from "./pages/pageEligibility"
44
+ import {isPhoneActive, onPhoneActivityChange} from "./PhoneActivity"
45
+
46
+ export type {PresentationOwner}
37
47
 
38
48
  export interface SeenNotificationApp {
39
49
  appId: string
@@ -41,29 +51,17 @@ export interface SeenNotificationApp {
41
51
  lastSeen: number
42
52
  }
43
53
 
44
- let unsubscribe: (() => void) | null = null
45
- let seenAppsSubscription: {remove(): void} | null = null
46
-
47
- function pushAndroidConfig(): void {
48
- const s = useSettingsStore.getState()
49
- const listenerEnabled = Boolean(s.getSetting(SETTINGS.android_notification_listener_enabled.key))
50
- const blocklist = s.getSetting(SETTINGS.notifications_blocklist.key)
51
- CrustModule.setNotificationConfig(listenerEnabled, Array.isArray(blocklist) ? blocklist : []).catch((err: unknown) =>
52
- console.warn(`PhoneNotificationsSync: setNotificationConfig failed: ${(err as Error)?.message ?? err}`),
53
- )
54
- }
54
+ let unsubscribers: Array<() => void> = []
55
55
 
56
56
  export function getSeenNotificationApps(): SeenNotificationApp[] {
57
- const seen = useSettingsStore.getState().getSetting(SETTINGS.ios_notification_seen_apps.key)
57
+ const seen = useSettingsStore.getState().getSetting(SETTINGS.notification_seen_apps.key)
58
58
  return Array.isArray(seen) ? (seen as SeenNotificationApp[]) : []
59
59
  }
60
60
 
61
61
  /** Catalog ∪ seen apps, seen display names winning. Sorted by name. */
62
- export function getKnownNotificationApps(): Array<{appId: string; displayName: string}> {
62
+ export function getKnownNotificationApps(): NotificationApp[] {
63
63
  const merged = new Map<string, string>()
64
- for (const app of IOS_NOTIFICATION_APP_CATALOG) {
65
- merged.set(app.appId, app.displayName)
66
- }
64
+ for (const app of notificationAppCatalog()) merged.set(app.appId, app.displayName)
67
65
  for (const app of getSeenNotificationApps()) {
68
66
  if (app.appId) merged.set(app.appId, app.displayName || app.appId)
69
67
  }
@@ -72,41 +70,127 @@ export function getKnownNotificationApps(): Array<{appId: string; displayName: s
72
70
  .sort((a, b) => a.displayName.localeCompare(b.displayName))
73
71
  }
74
72
 
75
- export function computeG2NotificationFilter(): G2NotificationFilterSetting {
76
- const blocklistValue = useSettingsStore.getState().getSetting(SETTINGS.notifications_blocklist.key)
77
- const blocklist = Array.isArray(blocklistValue) ? (blocklistValue as string[]) : []
78
- const blocked = new Set(blocklist)
79
- // The list is included even while filtering is off, so the on-glass file
80
- // already holds the user's current list when a first block enables it.
81
- const apps = getKnownNotificationApps()
82
- .filter((app) => !blocked.has(app.appId))
83
- .map((app) => ({id: app.appId, name: app.displayName}))
84
- return {enabled: blocked.size > 0, apps}
73
+ /**
74
+ * Apps to show in a notification filter UI (package/bundle id, name, icon).
75
+ * Android: installed apps. iOS: seeded catalog ∪ glasses-reported apps
76
+ * (icons unavailable — iOS offers no cross-app icon lookup).
77
+ */
78
+ export function installedNotificationApps(): Promise<
79
+ Array<{packageName: string; appName: string; icon: string | null}>
80
+ > {
81
+ if (Platform.OS === "android") return CrustModule.getInstalledApps()
82
+ if (Platform.OS !== "ios") return Promise.resolve([])
83
+ return Promise.resolve(
84
+ getKnownNotificationApps().map((app) => ({packageName: app.appId, appName: app.displayName, icon: null})),
85
+ )
85
86
  }
86
87
 
87
- function computeG2NotificationCtrl(): G2NotificationCtrlSetting {
88
+ /** The connected (or remembered) model presents notifications in firmware. */
89
+ export function nativeNotificationsSupported(): boolean {
90
+ const model = useGlassesStore.getState().deviceModel as DeviceTypes
91
+ return getModelCapabilities(model).hasNativeNotifications === true
92
+ }
93
+
94
+ /** Popup durations the firmware accepts, or an empty list when it takes any. */
95
+ export function nativeNotificationPopupSeconds(): number[] {
96
+ const model = useGlassesStore.getState().deviceModel as DeviceTypes
97
+ return getModelCapabilities(model).nativeNotificationPopupSeconds ?? []
98
+ }
99
+
100
+ export function notificationsEnabled(): boolean {
101
+ return useSettingsStore.getState().getSetting(SETTINGS.notifications_enabled.key) !== false
102
+ }
103
+
104
+ export function desiredGlassesNotificationConfig(): GlassesNotificationConfig {
88
105
  const s = useSettingsStore.getState()
89
- return {
90
- enabled: Boolean(s.getSetting(SETTINGS.g2_notifications_enabled.key)),
91
- auto_display: Boolean(s.getSetting(SETTINGS.g2_notification_auto_display.key)),
92
- disp_time: Number(s.getSetting(SETTINGS.g2_notification_disp_time.key)) || 0,
93
- avoid_disturb: Boolean(s.getSetting(SETTINGS.g2_notification_avoid_disturb.key)),
94
- }
106
+ const blocklist = s.getSetting(SETTINGS.notifications_blocklist.key)
107
+ return glassesNotificationConfig({
108
+ enabled: notificationsEnabled(),
109
+ popups: s.getSetting(SETTINGS.notifications_popups.key) !== false,
110
+ popupSeconds: Number(s.getSetting(SETTINGS.notifications_popup_seconds.key)),
111
+ holdDuringApps: s.getSetting(SETTINGS.notifications_hold_during_apps.key) !== false,
112
+ ignoreWhileActive: s.getSetting(SETTINGS.notifications_ignore_while_active.key) === true,
113
+ phoneActive: isPhoneActive(),
114
+ blockedApps: Array.isArray(blocklist) ? (blocklist as string[]) : [],
115
+ knownApps: getKnownNotificationApps(),
116
+ })
117
+ }
118
+
119
+ /**
120
+ * Who presents the next phone notification. `hostActive` is the host's own
121
+ * presentation surface (Notify in the Glassly App); the engine has no view of
122
+ * it.
123
+ */
124
+ export function currentPresentationOwner(hostActive: boolean): PresentationOwner {
125
+ return presentationOwner({
126
+ enabled: notificationsEnabled(),
127
+ pagesEligible: pagesEligible(),
128
+ // The viewer is an overlay miniapp listening to phone notifications
129
+ // (ADR-0006): with none running, nothing draws one on eligible glasses.
130
+ viewerRunning: overlayViewerRunning(),
131
+ nativeNotifications: nativeNotificationsSupported() && isGlassesConnected(useGlassesStore.getState().connection),
132
+ hostActive,
133
+ })
95
134
  }
96
135
 
97
- function pushIosConfig(): void {
98
- // The native DeviceStore dedupes unchanged values and replays these to the
99
- // glasses on every reconnect, so pushing eagerly is cheap.
100
- void Promise.resolve(
101
- BluetoothSdk.updateBluetoothSettings({
102
- notification_ctrl: computeG2NotificationCtrl(),
103
- notification_filter: computeG2NotificationFilter(),
136
+ /**
137
+ * Whether the glasses may read the phone's notifications. iOS glasses read
138
+ * the stream themselves under the Bluetooth notification-sharing consent the
139
+ * driver reports as `ancsAuthorized`; Android glasses get content from the
140
+ * phone's listener, whose grant the permission flow owns.
141
+ */
142
+ export function captureAuthorization(): "granted" | "denied" | "unknown" | "not_needed" {
143
+ if (Platform.OS !== "ios") return "not_needed"
144
+ if (!nativeNotificationsSupported()) return "not_needed"
145
+ const glasses = useGlassesStore.getState()
146
+ if (!isGlassesConnected(glasses.connection)) return "unknown"
147
+ return glasses.ancsAuthorized ? "granted" : "denied"
148
+ }
149
+
150
+ /**
151
+ * Hand one captured notification to glasses whose firmware presents it from
152
+ * uploaded content (Android). Glasses that read the phone's stream reject it;
153
+ * callers only reach here when the owner is `firmware`.
154
+ */
155
+ export function uploadPhoneNotification(event: PhoneNotificationEvent): Promise<void> {
156
+ if (Platform.OS !== "android") return Promise.resolve()
157
+ return Promise.resolve(
158
+ BluetoothSdk.uploadPhoneNotification({
159
+ notificationId: String(event.notificationId ?? ""),
160
+ packageName: String(event.packageName ?? ""),
161
+ appName: String(event.app ?? ""),
162
+ title: String(event.title ?? ""),
163
+ subtitle: "",
164
+ body: String(event.content ?? ""),
165
+ timestampMs: Number(event.timestamp) || Date.now(),
104
166
  }),
105
- ).catch((err: unknown) =>
106
- console.warn(`PhoneNotificationsSync: notification config push failed: ${(err as Error)?.message ?? err}`),
107
167
  )
108
168
  }
109
169
 
170
+ function pushListenerConfig(): void {
171
+ if (Platform.OS !== "android") return
172
+ const s = useSettingsStore.getState()
173
+ const listenerEnabled = Boolean(s.getSetting(SETTINGS.android_notification_listener_enabled.key))
174
+ const blocklist = s.getSetting(SETTINGS.notifications_blocklist.key)
175
+ CrustModule.setNotificationConfig(listenerEnabled, Array.isArray(blocklist) ? blocklist : []).catch((err: unknown) =>
176
+ console.warn(`PhoneNotificationsSync: setNotificationConfig failed: ${(err as Error)?.message ?? err}`),
177
+ )
178
+ }
179
+
180
+ function pushGlassesConfig(): void {
181
+ if (!nativeNotificationsSupported()) return
182
+ if (!isGlassesConnected(useGlassesStore.getState().connection)) return
183
+ void Promise.resolve(BluetoothSdk.setGlassesNotificationConfig(desiredGlassesNotificationConfig())).catch(
184
+ (err: unknown) =>
185
+ console.warn(`PhoneNotificationsSync: glasses notification config failed: ${(err as Error)?.message ?? err}`),
186
+ )
187
+ }
188
+
189
+ function pushAll(): void {
190
+ pushListenerConfig()
191
+ pushGlassesConfig()
192
+ }
193
+
110
194
  /** Record a glasses-reported source app. Writes only on new app / renamed app. */
111
195
  function recordSeenApp(event: NotificationAppSeenEvent): void {
112
196
  if (!event.appId) return
@@ -117,46 +201,44 @@ function recordSeenApp(event: NotificationAppSeenEvent): void {
117
201
  const next = seen
118
202
  .filter((app) => app.appId !== event.appId)
119
203
  .concat([{appId: event.appId, displayName, lastSeen: event.timestamp || Date.now()}])
120
- useSettingsStore.getState().setSetting(SETTINGS.ios_notification_seen_apps.key, next)
204
+ useSettingsStore.getState().setSetting(SETTINGS.notification_seen_apps.key, next)
121
205
  }
122
206
 
123
207
  export function startPhoneNotificationsSync(): void {
124
- if (unsubscribe) return
125
-
126
- if (Platform.OS === "android") {
127
- pushAndroidConfig() // initial sync so the listener has the current config
128
- unsubscribe = useSettingsStore.subscribe(
129
- (state) => ({
130
- listenerEnabled: state.getSetting(SETTINGS.android_notification_listener_enabled.key),
131
- blocklist: state.getSetting(SETTINGS.notifications_blocklist.key),
132
- }),
133
- () => pushAndroidConfig(),
208
+ if (unsubscribers.length) return
209
+ pushAll()
210
+ const seenApps = BluetoothSdk.addListener("notification_app_seen", recordSeenApp)
211
+ unsubscribers = [
212
+ useSettingsStore.subscribe(
213
+ (state) =>
214
+ [
215
+ SETTINGS.android_notification_listener_enabled,
216
+ SETTINGS.notifications_blocklist,
217
+ SETTINGS.notification_seen_apps,
218
+ SETTINGS.notifications_enabled,
219
+ SETTINGS.notifications_popups,
220
+ SETTINGS.notifications_popup_seconds,
221
+ SETTINGS.notifications_hold_during_apps,
222
+ SETTINGS.notifications_ignore_while_active,
223
+ ].map((setting) => state.getSetting(setting.key)),
224
+ pushAll,
134
225
  {equalityFn: shallow},
135
- )
136
- return
137
- }
138
-
139
- if (Platform.OS !== "ios") return
140
-
141
- pushIosConfig()
142
- unsubscribe = useSettingsStore.subscribe(
143
- (state) => ({
144
- blocklist: state.getSetting(SETTINGS.notifications_blocklist.key),
145
- seenApps: state.getSetting(SETTINGS.ios_notification_seen_apps.key),
146
- enabled: state.getSetting(SETTINGS.g2_notifications_enabled.key),
147
- autoDisplay: state.getSetting(SETTINGS.g2_notification_auto_display.key),
148
- dispTime: state.getSetting(SETTINGS.g2_notification_disp_time.key),
149
- avoidDisturb: state.getSetting(SETTINGS.g2_notification_avoid_disturb.key),
150
- }),
151
- () => pushIosConfig(),
152
- {equalityFn: shallow},
153
- )
154
- seenAppsSubscription = BluetoothSdk.addListener("notification_app_seen", recordSeenApp)
226
+ ),
227
+ // A (re)connected driver gets the current config; the SDK dedupes nothing
228
+ // here, so only connection state and model are watched, not every field.
229
+ useGlassesStore.subscribe(
230
+ (state) => ({model: state.deviceModel, connected: isGlassesConnected(state.connection)}),
231
+ pushGlassesConfig,
232
+ {equalityFn: shallow},
233
+ ),
234
+ // Lock / foreground changes flip the effective popups flag for firmware
235
+ // that pops notifications up by itself.
236
+ onPhoneActivityChange(pushGlassesConfig),
237
+ () => seenApps.remove(),
238
+ ]
155
239
  }
156
240
 
157
241
  export function stopPhoneNotificationsSync(): void {
158
- unsubscribe?.()
159
- unsubscribe = null
160
- seenAppsSubscription?.remove()
161
- seenAppsSubscription = null
242
+ for (const unsubscribe of unsubscribers) unsubscribe()
243
+ unsubscribers = []
162
244
  }
@@ -24,6 +24,8 @@ import {cloudClientService} from "./CloudClientService"
24
24
  import {isGlassesConnected} from "./GlassesReadiness"
25
25
  import {useGlassesStore} from "../stores/glasses"
26
26
 
27
+ import {BgTimer} from "../utils/timers"
28
+
27
29
  interface PhotoResult {
28
30
  photoUrl: string
29
31
  mimeType: string
@@ -144,10 +146,7 @@ export class PhonePhotoCoordinator {
144
146
  private readonly activeRequests = new Map<string, ActiveRequest>()
145
147
  /** Short BLE correlation id (4-char hex) → full cloud requestId. */
146
148
  private readonly bleIdToCloud = new Map<string, string>()
147
- private readonly activeWarmUps = new Map<
148
- string,
149
- {requestId: string; durationMs: number; expiryTimer?: ReturnType<typeof setTimeout>}
150
- >()
149
+ private readonly activeWarmUps = new Map<string, {requestId: string; durationMs: number; expiryTimer?: number}>()
151
150
 
152
151
  /** Report-safe camera ownership snapshot for incident diagnostics. */
153
152
  getDiagnosticSnapshot(): Record<string, unknown> {
@@ -232,7 +231,7 @@ export class PhonePhotoCoordinator {
232
231
  // Last-resort watchdog for a wedged pipeline. The managed-photo ready push
233
232
  // normally resolves or rejects first; this only prevents an indefinite hang
234
233
  // if both the native terminal response and cloud push disappear.
235
- const captureWatchdog = setTimeout(() => {
234
+ const captureWatchdog = BgTimer.setTimeout(() => {
236
235
  const e = this.activeRequests.get(requestId)
237
236
  if (!e) return
238
237
  e.abort.abort()
@@ -248,7 +247,7 @@ export class PhonePhotoCoordinator {
248
247
  // Clear the watchdog on BOTH arms. Not `.finally()`: that would mint a new
249
248
  // promise that re-rejects unobserved whenever the photo fails (the caller
250
249
  // only awaits `outcome` itself), i.e. an unhandled rejection per failure.
251
- const clearWatchdog = () => clearTimeout(captureWatchdog)
250
+ const clearWatchdog = () => BgTimer.clearTimeout(captureWatchdog)
252
251
  void outcome.then(clearWatchdog, clearWatchdog)
253
252
 
254
253
  // 3) Drive glasses over BLE. requestPhoto now resolves at terminal
@@ -354,7 +353,7 @@ export class PhonePhotoCoordinator {
354
353
  throw new PhotoError("GLASSES_NOT_CONNECTED", "Glasses are not connected", "command", "ble")
355
354
  }
356
355
 
357
- let lease: {requestId: string; durationMs: number; expiryTimer?: ReturnType<typeof setTimeout>} | undefined
356
+ let lease: {requestId: string; durationMs: number; expiryTimer?: number} | undefined
358
357
  try {
359
358
  await this.stopWarmUpForApp(packageName)
360
359
  const requestId = mintBleRequestId()
@@ -375,7 +374,7 @@ export class PhonePhotoCoordinator {
375
374
  ...(opts.mfnr != null ? {mfnr: opts.mfnr} : {}),
376
375
  })
377
376
  if (this.activeWarmUps.get(packageName) === lease) {
378
- lease.expiryTimer = setTimeout(() => {
377
+ lease.expiryTimer = BgTimer.setTimeout(() => {
379
378
  if (this.activeWarmUps.get(packageName) === lease) {
380
379
  this.activeWarmUps.delete(packageName)
381
380
  }
@@ -383,7 +382,7 @@ export class PhonePhotoCoordinator {
383
382
  }
384
383
  } catch (err) {
385
384
  if (lease && this.activeWarmUps.get(packageName) === lease) {
386
- if (lease.expiryTimer) clearTimeout(lease.expiryTimer)
385
+ if (lease.expiryTimer) BgTimer.clearTimeout(lease.expiryTimer)
387
386
  this.activeWarmUps.delete(packageName)
388
387
  }
389
388
  throw this.toPhotoError(err, "WARM_UP_FAILED", "command", "ble")
@@ -397,7 +396,7 @@ export class PhonePhotoCoordinator {
397
396
  await BluetoothSdk.stopCameraWarmUp(active.requestId)
398
397
  if (this.activeWarmUps.get(packageName) === active) {
399
398
  this.activeWarmUps.delete(packageName)
400
- if (active.expiryTimer) clearTimeout(active.expiryTimer)
399
+ if (active.expiryTimer) BgTimer.clearTimeout(active.expiryTimer)
401
400
  }
402
401
  }
403
402
 
@@ -49,6 +49,8 @@ import {
49
49
  type RestreamDestinationInput,
50
50
  } from "./cloudStreamApi"
51
51
 
52
+ import {BgTimer} from "../utils/timers"
53
+
52
54
  /**
53
55
  * Default cadence + thresholds. Exposed via {@link CoordinatorTimings} so tests
54
56
  * can shorten them; production code should never override these.
@@ -159,8 +161,8 @@ interface ManagedEntry {
159
161
  hlsReady: boolean
160
162
  hlsReadyResolvers: Array<(result: ManagedStartResult) => void>
161
163
  hlsReadyRejecters: Array<(err: Error) => void>
162
- cloudflareTimer?: ReturnType<typeof setTimeout>
163
- hlsTimer?: ReturnType<typeof setInterval>
164
+ cloudflareTimer?: number
165
+ hlsTimer?: number
164
166
  hlsAttempts: number
165
167
  /** Cloudflare status probes made during this stream session. */
166
168
  cloudflareAttempts: number
@@ -593,7 +595,7 @@ export class PhoneStreamCoordinator {
593
595
  this.timings.cloudflareStartupPollInitialMs * 2 ** Math.min(Math.max(0, entry.cloudflareAttempts - 1), 10),
594
596
  )
595
597
  const delayMs = waitingForWebRtc ? Math.min(startupDelayMs, remainingMs) : this.timings.cloudflareStatusPollMs
596
- entry.cloudflareTimer = setTimeout(() => void poll(), delayMs)
598
+ entry.cloudflareTimer = BgTimer.setTimeout(() => void poll(), delayMs)
597
599
  }
598
600
 
599
601
  const poll = async () => {
@@ -706,7 +708,7 @@ export class PhoneStreamCoordinator {
706
708
  elapsedMs: Date.now() - entry.startupStartedAtMs,
707
709
  })
708
710
  if (entry.hlsTimer) {
709
- clearInterval(entry.hlsTimer)
711
+ BgTimer.clearInterval(entry.hlsTimer)
710
712
  entry.hlsTimer = undefined
711
713
  }
712
714
  const result = managedStartResult(entry)
@@ -726,7 +728,7 @@ export class PhoneStreamCoordinator {
726
728
  }
727
729
  if (entry.hlsAttempts >= this.timings.hlsReadinessMaxAttempts) {
728
730
  if (entry.hlsTimer) {
729
- clearInterval(entry.hlsTimer)
731
+ BgTimer.clearInterval(entry.hlsTimer)
730
732
  entry.hlsTimer = undefined
731
733
  }
732
734
  const err = new Error(
@@ -748,10 +750,10 @@ export class PhoneStreamCoordinator {
748
750
  })
749
751
  }
750
752
  }
751
- setTimeout(() => {
753
+ BgTimer.setTimeout(() => {
752
754
  // Guard: stream may have been torn down during the initial delay.
753
755
  if (this.current !== entry) return
754
- entry.hlsTimer = setInterval(tick, this.timings.hlsReadinessPollMs)
756
+ entry.hlsTimer = BgTimer.setInterval(tick, this.timings.hlsReadinessPollMs)
755
757
  }, this.timings.hlsReadinessInitialDelayMs)
756
758
  }
757
759
 
@@ -789,8 +791,8 @@ export class PhoneStreamCoordinator {
789
791
  this.lifecycle = null
790
792
 
791
793
  if (entry.kind === "managed") {
792
- if (entry.cloudflareTimer) clearTimeout(entry.cloudflareTimer)
793
- if (entry.hlsTimer) clearInterval(entry.hlsTimer)
794
+ if (entry.cloudflareTimer) BgTimer.clearTimeout(entry.cloudflareTimer)
795
+ if (entry.hlsTimer) BgTimer.clearInterval(entry.hlsTimer)
794
796
  // Reject any still-pending HLS readiness waiters.
795
797
  const pendingErr = new Error(`Stream torn down: ${reason}`)
796
798
  for (const reject of entry.hlsReadyRejecters) reject(pendingErr)
@@ -845,8 +847,8 @@ function pickIngestUrl(p: ProvisionResult, preference?: "srt" | "whip" | "rtmp")
845
847
  preference === "whip"
846
848
  ? p.webrtcPublishUrl || p.srtUrl || p.rtmpUrl
847
849
  : preference === "rtmp"
848
- ? p.rtmpUrl || p.srtUrl || p.webrtcPublishUrl
849
- : p.srtUrl || p.rtmpUrl || p.webrtcPublishUrl
850
+ ? p.rtmpUrl || p.srtUrl || p.webrtcPublishUrl
851
+ : p.srtUrl || p.rtmpUrl || p.webrtcPublishUrl
850
852
  if (!url) {
851
853
  throw new Error("Cloudflare provision returned no usable ingest URL")
852
854
  }
@@ -41,6 +41,7 @@ class STTModelManager {
41
41
  private static instance: STTModelManager
42
42
  private downloadJobId?: number
43
43
  private currentLanguage = DEFAULT_LANGUAGE
44
+ private modelReadyListeners = new Set<() => void>()
44
45
  private modelBaseUrl = "https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/"
45
46
 
46
47
  private languages: Record<string, LanguageConfig> = {
@@ -405,7 +406,20 @@ class STTModelManager {
405
406
  }
406
407
 
407
408
  private async setNativeModelPath(path: string, languageCode: string): Promise<void> {
408
- BluetoothSdk.setSttModelDetails(path, languageCode)
409
+ await BluetoothSdk.setSttModelDetails(path, languageCode)
410
+ for (const listener of this.modelReadyListeners) {
411
+ try {
412
+ listener()
413
+ } catch (error) {
414
+ console.warn("STTModelManager: model-ready listener failed:", error)
415
+ }
416
+ }
417
+ }
418
+
419
+ /** Fired after a downloaded/selected model's path has reached native. */
420
+ onModelReady(listener: () => void): () => void {
421
+ this.modelReadyListeners.add(listener)
422
+ return () => this.modelReadyListeners.delete(listener)
409
423
  }
410
424
 
411
425
  async getStorageInfo(): Promise<{free: number; total: number}> {