@glassly/engine 0.1.0-dev.1 → 0.1.0-dev.100

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 (343) hide show
  1. package/README.md +57 -19
  2. package/build/bluetooth-sdk/debug.d.ts +2 -0
  3. package/build/bluetooth-sdk/debug.d.ts.map +1 -0
  4. package/build/bluetooth-sdk/debug.js +2 -0
  5. package/build/bluetooth-sdk/debug.js.map +1 -0
  6. package/build/bluetooth-sdk/index.d.ts +3 -0
  7. package/build/bluetooth-sdk/index.d.ts.map +1 -0
  8. package/build/bluetooth-sdk/index.js +3 -0
  9. package/build/bluetooth-sdk/index.js.map +1 -0
  10. package/build/bluetooth-sdk/ota-transport.d.ts +2 -0
  11. package/build/bluetooth-sdk/ota-transport.d.ts.map +1 -0
  12. package/build/bluetooth-sdk/ota-transport.js +2 -0
  13. package/build/bluetooth-sdk/ota-transport.js.map +1 -0
  14. package/build/bluetooth-sdk/photo-receiver.d.ts +3 -0
  15. package/build/bluetooth-sdk/photo-receiver.d.ts.map +1 -0
  16. package/build/bluetooth-sdk/photo-receiver.js +3 -0
  17. package/build/bluetooth-sdk/photo-receiver.js.map +1 -0
  18. package/build/bluetooth-sdk/react.d.ts +2 -0
  19. package/build/bluetooth-sdk/react.d.ts.map +1 -0
  20. package/build/bluetooth-sdk/react.js +2 -0
  21. package/build/bluetooth-sdk/react.js.map +1 -0
  22. package/build/bluetooth-sdk/types.d.ts +2 -0
  23. package/build/bluetooth-sdk/types.d.ts.map +1 -0
  24. package/build/bluetooth-sdk/types.js +2 -0
  25. package/build/bluetooth-sdk/types.js.map +1 -0
  26. package/build/engine.d.ts +30 -18
  27. package/build/engine.d.ts.map +1 -1
  28. package/build/engine.js +12 -3
  29. package/build/engine.js.map +1 -1
  30. package/build/facades/dev.d.ts +1 -1
  31. package/build/facades/display.d.ts +11 -4
  32. package/build/facades/display.d.ts.map +1 -1
  33. package/build/facades/display.js +12 -2
  34. package/build/facades/display.js.map +1 -1
  35. package/build/facades/displayMirror.d.ts +2 -6
  36. package/build/facades/displayMirror.d.ts.map +1 -1
  37. package/build/facades/displayMirror.js +7 -14
  38. package/build/facades/displayMirror.js.map +1 -1
  39. package/build/facades/glasses.d.ts +6 -13
  40. package/build/facades/glasses.d.ts.map +1 -1
  41. package/build/facades/glasses.js +7 -3
  42. package/build/facades/glasses.js.map +1 -1
  43. package/build/facades/ota.d.ts +21 -21
  44. package/build/facades/ota.d.ts.map +1 -1
  45. package/build/facades/ota.js +26 -10
  46. package/build/facades/ota.js.map +1 -1
  47. package/build/facades/pairing.d.ts +11 -5
  48. package/build/facades/pairing.d.ts.map +1 -1
  49. package/build/facades/pairing.js +93 -17
  50. package/build/facades/pairing.js.map +1 -1
  51. package/build/facades/phoneNotifications.d.ts +12 -2
  52. package/build/facades/phoneNotifications.d.ts.map +1 -1
  53. package/build/facades/phoneNotifications.js +30 -10
  54. package/build/facades/phoneNotifications.js.map +1 -1
  55. package/build/facades/speakers.d.ts +1 -1
  56. package/build/facades/speakers.d.ts.map +1 -1
  57. package/build/facades/speakers.js.map +1 -1
  58. package/build/facades/speech.d.ts +7 -6
  59. package/build/facades/speech.d.ts.map +1 -1
  60. package/build/facades/speech.js +1 -1
  61. package/build/facades/speech.js.map +1 -1
  62. package/build/generated/releaseMetadata.d.ts +12 -0
  63. package/build/generated/releaseMetadata.d.ts.map +1 -0
  64. package/build/generated/releaseMetadata.js +10 -0
  65. package/build/generated/releaseMetadata.js.map +1 -0
  66. package/build/index.d.ts +9 -6
  67. package/build/index.d.ts.map +1 -1
  68. package/build/index.js +7 -5
  69. package/build/index.js.map +1 -1
  70. package/build/react/MentraLiveOtaFlow.d.ts +44 -0
  71. package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
  72. package/build/react/MentraLiveOtaFlow.js +322 -0
  73. package/build/react/MentraLiveOtaFlow.js.map +1 -0
  74. package/build/react/index.d.ts +3 -0
  75. package/build/react/index.d.ts.map +1 -0
  76. package/build/react/index.js +3 -0
  77. package/build/react/index.js.map +1 -0
  78. package/build/react/useEngineSnapshot.d.ts +2 -0
  79. package/build/react/useEngineSnapshot.d.ts.map +1 -0
  80. package/build/react/useEngineSnapshot.js +14 -0
  81. package/build/react/useEngineSnapshot.js.map +1 -0
  82. package/build/react/useMentraLiveOta.d.ts +84 -0
  83. package/build/react/useMentraLiveOta.d.ts.map +1 -0
  84. package/build/react/useMentraLiveOta.js +627 -0
  85. package/build/react/useMentraLiveOta.js.map +1 -0
  86. package/build/services/AppRegistry.d.ts +8 -0
  87. package/build/services/AppRegistry.d.ts.map +1 -1
  88. package/build/services/AppRegistry.js +15 -0
  89. package/build/services/AppRegistry.js.map +1 -1
  90. package/build/services/BlobStore.d.ts +2 -0
  91. package/build/services/BlobStore.d.ts.map +1 -1
  92. package/build/services/BlobStore.js +63 -10
  93. package/build/services/BlobStore.js.map +1 -1
  94. package/build/services/CustomDashboardModel.d.ts +48 -0
  95. package/build/services/CustomDashboardModel.d.ts.map +1 -0
  96. package/build/services/CustomDashboardModel.js +73 -0
  97. package/build/services/CustomDashboardModel.js.map +1 -0
  98. package/build/services/CustomDashboardService.d.ts +55 -0
  99. package/build/services/CustomDashboardService.d.ts.map +1 -0
  100. package/build/services/CustomDashboardService.js +492 -0
  101. package/build/services/CustomDashboardService.js.map +1 -0
  102. package/build/services/DashboardCoordinator.d.ts +26 -0
  103. package/build/services/DashboardCoordinator.d.ts.map +1 -0
  104. package/build/services/DashboardCoordinator.js +125 -0
  105. package/build/services/DashboardCoordinator.js.map +1 -0
  106. package/build/services/DeviceEventRouter.d.ts.map +1 -1
  107. package/build/services/DeviceEventRouter.js +45 -6
  108. package/build/services/DeviceEventRouter.js.map +1 -1
  109. package/build/services/DisplayProcessor.d.ts +3 -3
  110. package/build/services/DisplayProcessor.js +3 -3
  111. package/build/services/DisplayProcessor.js.map +1 -1
  112. package/build/services/GestureDotsService.d.ts +40 -0
  113. package/build/services/GestureDotsService.d.ts.map +1 -0
  114. package/build/services/GestureDotsService.js +167 -0
  115. package/build/services/GestureDotsService.js.map +1 -0
  116. package/build/services/GlassesStatusProjection.d.ts +15 -1
  117. package/build/services/GlassesStatusProjection.d.ts.map +1 -1
  118. package/build/services/GlassesStatusProjection.js +18 -11
  119. package/build/services/GlassesStatusProjection.js.map +1 -1
  120. package/build/services/HotspotOtaTransport.d.ts.map +1 -1
  121. package/build/services/HotspotOtaTransport.js +8 -7
  122. package/build/services/HotspotOtaTransport.js.map +1 -1
  123. package/build/services/LocalDisplayManager.d.ts +55 -3
  124. package/build/services/LocalDisplayManager.d.ts.map +1 -1
  125. package/build/services/LocalDisplayManager.js +196 -16
  126. package/build/services/LocalDisplayManager.js.map +1 -1
  127. package/build/services/LocalMiniappRuntime.d.ts +13 -0
  128. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  129. package/build/services/LocalMiniappRuntime.js +32 -0
  130. package/build/services/LocalMiniappRuntime.js.map +1 -1
  131. package/build/services/MiniappExitGesture.d.ts +33 -0
  132. package/build/services/MiniappExitGesture.d.ts.map +1 -0
  133. package/build/services/MiniappExitGesture.js +54 -0
  134. package/build/services/MiniappExitGesture.js.map +1 -0
  135. package/build/services/OtaAutoChain.d.ts +41 -0
  136. package/build/services/OtaAutoChain.d.ts.map +1 -0
  137. package/build/services/OtaAutoChain.js +91 -0
  138. package/build/services/OtaAutoChain.js.map +1 -0
  139. package/build/services/OtaErrorMapping.d.ts +18 -0
  140. package/build/services/OtaErrorMapping.d.ts.map +1 -0
  141. package/build/services/OtaErrorMapping.js +63 -0
  142. package/build/services/OtaErrorMapping.js.map +1 -0
  143. package/build/services/OtaInstallCoordinator.d.ts +26 -3
  144. package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
  145. package/build/services/OtaInstallCoordinator.js +38 -13
  146. package/build/services/OtaInstallCoordinator.js.map +1 -1
  147. package/build/services/OtaService.d.ts.map +1 -1
  148. package/build/services/OtaService.js +1 -1
  149. package/build/services/OtaService.js.map +1 -1
  150. package/build/services/OtaUpdateCheckService.d.ts +4 -1
  151. package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
  152. package/build/services/OtaUpdateCheckService.js +28 -16
  153. package/build/services/OtaUpdateCheckService.js.map +1 -1
  154. package/build/services/PhoneNotificationsSync.d.ts +13 -0
  155. package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
  156. package/build/services/PhoneNotificationsSync.js +101 -9
  157. package/build/services/PhoneNotificationsSync.js.map +1 -1
  158. package/build/services/PhonePhotoCoordinator.js +1 -1
  159. package/build/services/PhonePhotoCoordinator.js.map +1 -1
  160. package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
  161. package/build/services/PhoneStreamCoordinator.js +9 -6
  162. package/build/services/PhoneStreamCoordinator.js.map +1 -1
  163. package/build/services/SceneRenderer.d.ts.map +1 -1
  164. package/build/services/SceneRenderer.js +5 -0
  165. package/build/services/SceneRenderer.js.map +1 -1
  166. package/build/services/StreamLifecycleController.d.ts +4 -0
  167. package/build/services/StreamLifecycleController.d.ts.map +1 -1
  168. package/build/services/StreamLifecycleController.js +4 -0
  169. package/build/services/StreamLifecycleController.js.map +1 -1
  170. package/build/services/asg/localNetworkTransport.d.ts.map +1 -1
  171. package/build/services/asg/localNetworkTransport.js +13 -12
  172. package/build/services/asg/localNetworkTransport.js.map +1 -1
  173. package/build/services/effectiveCapabilities.d.ts +1 -1
  174. package/build/services/effectiveCapabilities.d.ts.map +1 -1
  175. package/build/services/effectiveCapabilities.js +26 -7
  176. package/build/services/effectiveCapabilities.js.map +1 -1
  177. package/build/services/gestureClaims.d.ts +18 -0
  178. package/build/services/gestureClaims.d.ts.map +1 -0
  179. package/build/services/gestureClaims.js +24 -0
  180. package/build/services/gestureClaims.js.map +1 -0
  181. package/build/services/gestureDotGlyphs.d.ts +8 -0
  182. package/build/services/gestureDotGlyphs.d.ts.map +1 -0
  183. package/build/services/gestureDotGlyphs.js +13 -0
  184. package/build/services/gestureDotGlyphs.js.map +1 -0
  185. package/build/services/glassesClockSync.d.ts.map +1 -1
  186. package/build/services/glassesClockSync.js +5 -1
  187. package/build/services/glassesClockSync.js.map +1 -1
  188. package/build/services/iosNotificationAppCatalog.d.ts +13 -0
  189. package/build/services/iosNotificationAppCatalog.d.ts.map +1 -0
  190. package/build/services/iosNotificationAppCatalog.js +28 -0
  191. package/build/services/iosNotificationAppCatalog.js.map +1 -0
  192. package/build/services/otaDisplayState.d.ts +1 -1
  193. package/build/services/otaDisplayState.d.ts.map +1 -1
  194. package/build/services/otaDisplayState.js.map +1 -1
  195. package/build/services/otaInstallPolicy.d.ts +5 -1
  196. package/build/services/otaInstallPolicy.d.ts.map +1 -1
  197. package/build/services/otaInstallPolicy.js +4 -0
  198. package/build/services/otaInstallPolicy.js.map +1 -1
  199. package/build/services/otaLegacyMapping.d.ts +1 -1
  200. package/build/services/otaLegacyMapping.d.ts.map +1 -1
  201. package/build/services/otaLegacyMapping.js.map +1 -1
  202. package/build/services/otaManifestPolicy.d.ts +14 -0
  203. package/build/services/otaManifestPolicy.d.ts.map +1 -0
  204. package/build/services/otaManifestPolicy.js +20 -0
  205. package/build/services/otaManifestPolicy.js.map +1 -0
  206. package/build/services/otaManifestUrl.d.ts +2 -1
  207. package/build/services/otaManifestUrl.d.ts.map +1 -1
  208. package/build/services/otaManifestUrl.js +24 -32
  209. package/build/services/otaManifestUrl.js.map +1 -1
  210. package/build/services/otaReleaseVersion.d.ts +10 -0
  211. package/build/services/otaReleaseVersion.d.ts.map +1 -0
  212. package/build/services/otaReleaseVersion.js +14 -0
  213. package/build/services/otaReleaseVersion.js.map +1 -0
  214. package/build/stores/appVisibility.d.ts +3 -0
  215. package/build/stores/appVisibility.d.ts.map +1 -0
  216. package/build/stores/appVisibility.js +3 -0
  217. package/build/stores/appVisibility.js.map +1 -0
  218. package/build/stores/apps.d.ts.map +1 -1
  219. package/build/stores/apps.js +7 -1
  220. package/build/stores/apps.js.map +1 -1
  221. package/build/stores/core.d.ts +3 -3
  222. package/build/stores/core.d.ts.map +1 -1
  223. package/build/stores/core.js.map +1 -1
  224. package/build/stores/display.d.ts +4 -4
  225. package/build/stores/display.d.ts.map +1 -1
  226. package/build/stores/display.js +12 -36
  227. package/build/stores/display.js.map +1 -1
  228. package/build/stores/glasses.d.ts +10 -4
  229. package/build/stores/glasses.d.ts.map +1 -1
  230. package/build/stores/glasses.js +2 -0
  231. package/build/stores/glasses.js.map +1 -1
  232. package/build/stores/settings.d.ts.map +1 -1
  233. package/build/stores/settings.js +140 -5
  234. package/build/stores/settings.js.map +1 -1
  235. package/build/types/applet.d.ts +3 -1
  236. package/build/types/applet.d.ts.map +1 -1
  237. package/build/types/applet.js +0 -3
  238. package/build/types/applet.js.map +1 -1
  239. package/build/types/capabilities/even-realities-g2.d.ts.map +1 -1
  240. package/build/types/capabilities/even-realities-g2.js +2 -2
  241. package/build/types/capabilities/even-realities-g2.js.map +1 -1
  242. package/build/types/enums.d.ts +1 -5
  243. package/build/types/enums.d.ts.map +1 -1
  244. package/build/types/enums.js +1 -8
  245. package/build/types/enums.js.map +1 -1
  246. package/build/types/hardware.d.ts +1 -1
  247. package/build/types/hardware.d.ts.map +1 -1
  248. package/build/types/hardware.js +1 -0
  249. package/build/types/hardware.js.map +1 -1
  250. package/build/types/index.d.ts +3 -7
  251. package/build/types/index.d.ts.map +1 -1
  252. package/build/types/index.js +3 -7
  253. package/build/types/index.js.map +1 -1
  254. package/build/utils/display/composer/ColumnComposer.d.ts +1 -1
  255. package/build/utils/display/composer/ColumnComposer.js +1 -1
  256. package/build/utils/display/composer/ColumnComposer.js.map +1 -1
  257. package/build/utils/display/scene/process.d.ts.map +1 -1
  258. package/build/utils/display/scene/process.js +4 -3
  259. package/build/utils/display/scene/process.js.map +1 -1
  260. package/build/utils/display/scene/types.d.ts +6 -2
  261. package/build/utils/display/scene/types.d.ts.map +1 -1
  262. package/build/utils/display/scene/types.js.map +1 -1
  263. package/package.json +69 -35
  264. package/src/bluetooth-sdk/debug.ts +1 -0
  265. package/src/bluetooth-sdk/index.ts +2 -0
  266. package/src/bluetooth-sdk/ota-transport.ts +1 -0
  267. package/src/bluetooth-sdk/photo-receiver.ts +2 -0
  268. package/src/bluetooth-sdk/react.ts +1 -0
  269. package/src/bluetooth-sdk/types.ts +1 -0
  270. package/src/engine.ts +12 -3
  271. package/src/facades/display.ts +12 -2
  272. package/src/facades/displayMirror.ts +7 -15
  273. package/src/facades/glasses.ts +8 -4
  274. package/src/facades/ota.ts +36 -11
  275. package/src/facades/pairing.ts +103 -23
  276. package/src/facades/phoneNotifications.ts +32 -10
  277. package/src/facades/speakers.ts +1 -1
  278. package/src/facades/speech.ts +21 -7
  279. package/src/generated/releaseMetadata.ts +20 -0
  280. package/src/index.ts +31 -5
  281. package/src/react/MentraLiveOtaFlow.tsx +754 -0
  282. package/src/react/index.ts +21 -0
  283. package/src/react/useEngineSnapshot.ts +16 -0
  284. package/src/react/useMentraLiveOta.ts +793 -0
  285. package/src/services/AppRegistry.ts +16 -0
  286. package/src/services/BlobStore.ts +57 -10
  287. package/src/services/CustomDashboardModel.ts +83 -0
  288. package/src/services/CustomDashboardService.ts +516 -0
  289. package/src/services/DashboardCoordinator.ts +121 -0
  290. package/src/services/DeviceEventRouter.ts +48 -8
  291. package/src/services/DisplayProcessor.ts +3 -3
  292. package/src/services/GestureDotsService.ts +164 -0
  293. package/src/services/GlassesStatusProjection.ts +20 -11
  294. package/src/services/HotspotOtaTransport.ts +8 -7
  295. package/src/services/LocalDisplayManager.ts +198 -18
  296. package/src/services/LocalMiniappRuntime.ts +37 -0
  297. package/src/services/MiniappExitGesture.ts +76 -0
  298. package/src/services/OtaAutoChain.ts +130 -0
  299. package/src/services/OtaErrorMapping.ts +80 -0
  300. package/src/services/OtaInstallCoordinator.ts +40 -13
  301. package/src/services/OtaService.ts +1 -2
  302. package/src/services/OtaUpdateCheckService.ts +33 -19
  303. package/src/services/PhoneNotificationsSync.ts +125 -9
  304. package/src/services/PhonePhotoCoordinator.ts +1 -1
  305. package/src/services/PhoneStreamCoordinator.ts +10 -6
  306. package/src/services/SceneRenderer.ts +4 -0
  307. package/src/services/StreamLifecycleController.ts +4 -0
  308. package/src/services/asg/localNetworkTransport.ts +20 -19
  309. package/src/services/effectiveCapabilities.ts +27 -7
  310. package/src/services/gestureClaims.ts +28 -0
  311. package/src/services/gestureDotGlyphs.ts +15 -0
  312. package/src/services/glassesClockSync.ts +5 -1
  313. package/src/services/iosNotificationAppCatalog.ts +39 -0
  314. package/src/services/otaDisplayState.ts +1 -1
  315. package/src/services/otaInstallPolicy.ts +5 -1
  316. package/src/services/otaLegacyMapping.ts +1 -1
  317. package/src/services/otaManifestPolicy.ts +43 -0
  318. package/src/services/otaManifestUrl.ts +27 -36
  319. package/src/services/otaReleaseVersion.ts +22 -0
  320. package/src/stores/appVisibility.ts +3 -0
  321. package/src/stores/apps.ts +7 -1
  322. package/src/stores/core.ts +4 -4
  323. package/src/stores/display.ts +16 -48
  324. package/src/stores/glasses.ts +15 -6
  325. package/src/stores/settings.ts +140 -5
  326. package/src/types/applet.ts +3 -1
  327. package/src/types/capabilities/even-realities-g2.ts +3 -2
  328. package/src/types/enums.ts +1 -9
  329. package/src/types/hardware.ts +2 -1
  330. package/src/types/index.ts +3 -7
  331. package/src/utils/display/composer/ColumnComposer.ts +1 -1
  332. package/src/utils/display/scene/process.ts +4 -3
  333. package/src/utils/display/scene/types.ts +0 -0
  334. package/build/devtools.d.ts +0 -11
  335. package/build/devtools.d.ts.map +0 -1
  336. package/build/devtools.js +0 -13
  337. package/build/devtools.js.map +0 -1
  338. package/build/internal.d.ts +0 -67
  339. package/build/internal.d.ts.map +0 -1
  340. package/build/internal.js +0 -90
  341. package/build/internal.js.map +0 -1
  342. package/src/devtools.ts +0 -13
  343. package/src/internal.ts +0 -155
@@ -1,12 +1,19 @@
1
1
  /**
2
2
  * Effective device capabilities — the static model profile plus what the
3
- * connected firmware reports at runtime. Today the only runtime override is
4
- * the scene canvas: Glassly CFW on the G2 rasterizes scenes phone-side
5
- * straight into the 640×480 panel, so the drawable canvas grows past stock's
6
- * 576×288. Native publishes the canvas into the glasses status (0 = none).
3
+ * connected firmware reports at runtime. The runtime override is the scene
4
+ * canvas: Glassly CFW on the G2 rasterizes scenes phone-side straight into
5
+ * the 640×480 panel, so the drawable canvas grows past stock's 576×288.
6
+ * Native publishes the canvas into the glasses status (0 = none). Because
7
+ * that path is phone-side rasterization, the stock firmware's container
8
+ * pools (6 text / 4 image) don't bound a CFW frame either — element caps are
9
+ * lifted alongside the canvas, bounded only to keep frames sane.
7
10
  */
8
11
  import {useGlassesStore} from "../stores/glasses"
9
- import {getModelCapabilities, type Capabilities, type DeviceTypes} from "../types"
12
+ import {DeviceTypes, getModelCapabilities, type Capabilities} from "../types"
13
+ import {isGlasslyCfwFirmwareVersion} from "./CustomDashboardModel"
14
+
15
+ const CFW_MAX_TEXT_ELEMENTS = 24
16
+ const CFW_MAX_IMAGE_ELEMENTS = 16
10
17
 
11
18
  export interface SceneCanvasSize {
12
19
  width: number
@@ -22,6 +29,19 @@ export function runtimeSceneCanvas(): SceneCanvasSize | null {
22
29
  export function getEffectiveCapabilities(model: DeviceTypes): Capabilities {
23
30
  const base = getModelCapabilities(model)
24
31
  const canvas = runtimeSceneCanvas()
25
- if (!base.display || !canvas) return base
26
- return {...base, display: {...base.display, width: canvas.width, height: canvas.height}}
32
+ // The firmware marker lifts the caps even when no canvas has been published:
33
+ // CFW classification rides the version string, and a G2 running Glassly CFW
34
+ // always rasterizes phone-side regardless of whether native reported dims.
35
+ const cfw = model === DeviceTypes.G2 && isGlasslyCfwFirmwareVersion(useGlassesStore.getState().firmwareVersion)
36
+ if (!base.display || (!canvas && !cfw)) return base
37
+ return {
38
+ ...base,
39
+ display: {
40
+ ...base.display,
41
+ width: canvas?.width ?? base.display.width,
42
+ height: canvas?.height ?? base.display.height,
43
+ maxTextElements: Math.max(base.display.maxTextElements ?? 0, CFW_MAX_TEXT_ELEMENTS),
44
+ maxImageElements: Math.max(base.display.maxImageElements ?? 0, CFW_MAX_IMAGE_ELEMENTS),
45
+ },
46
+ }
27
47
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Gesture-claim arbitration (CLAIM_GESTURES), split out of
3
+ * LocalMiniappRuntime so it is unit-testable — the runtime module itself
4
+ * pulls a native import surface bun can't parse.
5
+ */
6
+
7
+ /**
8
+ * True iff the miniapp in front of the user has claimed `gesture`.
9
+ *
10
+ * "In front" spans both screens. Most claiming apps are glasses-side: the
11
+ * terminal runs as a background miniapp with the phone pocketed, so gating on
12
+ * the phone's Compositor foreground alone left its double_tap claim inert and
13
+ * the system dashboard kept opening mid-session. Glasses ownership is the
14
+ * primary signal; the phone foreground is still honored for apps driven from
15
+ * the handset. A claimer that owns neither screen is background and never
16
+ * hijacks a system gesture.
17
+ */
18
+ export function claimsGesture(
19
+ claims: ReadonlyMap<string, ReadonlySet<string>>,
20
+ gesture: string,
21
+ glassesOwner: string | null,
22
+ phoneForeground: string | null,
23
+ ): boolean {
24
+ for (const pkg of [glassesOwner, phoneForeground]) {
25
+ if (pkg && claims.get(pkg)?.has(gesture) === true) return true
26
+ }
27
+ return false
28
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * GENERATED by scripts/gen-gesture-dot-glyphs.mjs — do not edit by hand.
3
+ * 24×24 8-bit grayscale PNGs (white on black) for the gesture-dots indicator.
4
+ */
5
+ export const GESTURE_DOT_GLYPH_SIZE = 24
6
+
7
+ export type GestureDotGlyph = "dot" | "up" | "down" | "hold" | "blank"
8
+
9
+ export const GESTURE_DOT_GLYPHS: Record<GestureDotGlyph, string> = {
10
+ dot: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAALklEQVR4nM2QsQ0AAAjC/P/pmrhqZ+xIF6DqBQyWbwO3gduAmKjQuj7QL/ETEzQmMptl7Q9NBAAAAABJRU5ErkJggg==",
11
+ up: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAMElEQVR4nGNgoCv4////f1zi2GT+/4ciTHE4RhdHIlDFUUhkcTQKQx9WBw8PCVoBAIcbOcf3xeeBAAAAAElFTkSuQmCC",
12
+ down: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAALUlEQVR4nGNgoC/4/3+4SkBFUCkkNjKJIoMg0GRgGEMGgrC4CQSwuxanR2gEAO1/Ocfgp8uvAAAAAElFTkSuQmCC",
13
+ hold: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAR0lEQVR4nGNgIAj+gwF2UUy5//+xyyDzcLGRedjMhTEwXAKl0Z0Lof7DKbgMhBpQCZzOxedBHEGCMxAJBTXhKGRAA9hFMQEANr7jHQU9fO0AAAAASUVORK5CYII=",
14
+ blank: "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAAAAADFHGIkAAAAD0lEQVR4nGNgGAWjgPoAAAJYAAGgxYwDAAAAAElFTkSuQmCC",
15
+ }
@@ -2,7 +2,7 @@
2
2
  * Push phone time to glasses only when clock skew is detected (gallery sync, OTA, etc.).
3
3
  */
4
4
 
5
- import BluetoothSdk from "@glassly/bluetooth-sdk/internal"
5
+ import BluetoothSdk from "@glassly/bluetooth-sdk"
6
6
  import {BgTimer} from "../utils/timers"
7
7
  import {useGlassesStore} from "../stores/glasses"
8
8
 
@@ -87,6 +87,10 @@ export async function handleOtaClockSkewFromGlasses(
87
87
  lastOtaClockFixAt = Date.now()
88
88
  const {buildNumber, otaVersionUrl} = useGlassesStore.getState()
89
89
  const manifestUrl = resolveOtaManifestUrl(otaVersionUrl, buildNumber)
90
+ if (!manifestUrl) {
91
+ console.warn("[GlassesClockSync] OTA restart skipped because this build has no manifest pin")
92
+ return false
93
+ }
90
94
  console.log("[GlassesClockSync] ⏰ Restarting OTA with ota_start after clock fix")
91
95
  await BluetoothSdk.startOtaUpdate(manifestUrl)
92
96
  return true
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Seeded catalog of common iOS apps that post notifications, keyed by bundle
3
+ * id. iOS has no installed-apps enumeration — the filter UI shows this catalog
4
+ * plus apps the glasses have actually observed via ANCS — and the on-glass
5
+ * allowlist push needs known ids so a blocked app doesn't take every
6
+ * not-yet-seen app down with it (the firmware filter is allow-based).
7
+ */
8
+ export interface IosNotificationApp {
9
+ appId: string
10
+ displayName: string
11
+ }
12
+
13
+ export const IOS_NOTIFICATION_APP_CATALOG: IosNotificationApp[] = [
14
+ {appId: "com.apple.MobileSMS", displayName: "Messages"},
15
+ {appId: "com.apple.mobilephone", displayName: "Phone"},
16
+ {appId: "com.apple.mobilemail", displayName: "Mail"},
17
+ {appId: "com.apple.mobilecal", displayName: "Calendar"},
18
+ {appId: "com.apple.reminders", displayName: "Reminders"},
19
+ {appId: "com.apple.facetime", displayName: "FaceTime"},
20
+ {appId: "net.whatsapp.WhatsApp", displayName: "WhatsApp"},
21
+ {appId: "ph.telegra.Telegraph", displayName: "Telegram"},
22
+ {appId: "org.whispersystems.signal", displayName: "Signal"},
23
+ {appId: "com.google.Gmail", displayName: "Gmail"},
24
+ {appId: "com.microsoft.Office.Outlook", displayName: "Outlook"},
25
+ {appId: "com.tinyspeck.chatlyio", displayName: "Slack"},
26
+ {appId: "com.hammerandchisel.discord", displayName: "Discord"},
27
+ {appId: "com.microsoft.skype.teams", displayName: "Teams"},
28
+ {appId: "com.facebook.Messenger", displayName: "Messenger"},
29
+ {appId: "com.facebook.Facebook", displayName: "Facebook"},
30
+ {appId: "com.burbn.instagram", displayName: "Instagram"},
31
+ {appId: "com.atebits.Tweetie2", displayName: "X"},
32
+ {appId: "com.zhiliaoapp.musically", displayName: "TikTok"},
33
+ {appId: "com.toyopagroup.picaboo", displayName: "Snapchat"},
34
+ {appId: "com.linkedin.LinkedIn", displayName: "LinkedIn"},
35
+ {appId: "com.google.ios.youtube", displayName: "YouTube"},
36
+ {appId: "com.spotify.client", displayName: "Spotify"},
37
+ {appId: "com.ubercab.UberClient", displayName: "Uber"},
38
+ {appId: "com.venmo.TouchFree", displayName: "Venmo"},
39
+ ]
@@ -1,4 +1,4 @@
1
- import type {OtaProgress, OtaStatus} from "@glassly/bluetooth-sdk/internal"
1
+ import type {OtaProgress, OtaStatus} from "@glassly/bluetooth-sdk"
2
2
 
3
3
  import {isLegacyShapedOtaStatus} from "./otaInstallPolicy"
4
4
 
@@ -1,5 +1,5 @@
1
1
  /** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */
2
- import type {OtaProgress, OtaStatus} from "@glassly/bluetooth-sdk/internal"
2
+ import type {OtaProgress, OtaStatus} from "@glassly/bluetooth-sdk"
3
3
 
4
4
  /**
5
5
  * First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified
@@ -32,6 +32,8 @@ export const PING_INTERVAL_MS = 10_000
32
32
  export const QUERY_REPLY_TIMEOUT_MS = 6000
33
33
  /** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */
34
34
  export const BES_CONTINUE_LOCKOUT_MS = 15_000
35
+ /** Fail closed if a BES reboot never reconnects; normal restarts complete in a fraction of this window. */
36
+ export const BES_RESTART_TIMEOUT_MS = 120_000
35
37
 
36
38
  // --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---
37
39
  //
@@ -51,6 +53,7 @@ export const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXT
51
53
  export const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS
52
54
  export const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS
53
55
  export const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS
56
+ export const LEGACY_BES_RESTART_TIMEOUT_MS = BES_RESTART_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS
54
57
  /**
55
58
  * After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the
56
59
  * completed state for 12s (+20s pad) so the ASG process restart settles (and fresh
@@ -122,6 +125,7 @@ export function selectOtaProtocolProfile(
122
125
  export const OtaProgressMessages = {
123
126
  stalledOrStuck: "Update may have failed. Ensure glasses have internet access and try again.",
124
127
  globalTimeout: "Update took too long. Please try again.",
128
+ restartTimeout: "Glasses did not finish restarting. Restart them before trying the update again.",
125
129
  sendOtaStartFailed: "Failed to communicate with glasses.",
126
130
  hotspotArtifactDownloadFailed: "Could not download the update to your phone. Check phone internet and try again.",
127
131
  hotspotArtifactVerifyFailed: "The update package could not be verified. Please try again later.",
@@ -1,4 +1,4 @@
1
- import type {OtaProgress, OtaProgressStatus, OtaStatus} from "@glassly/bluetooth-sdk/internal"
1
+ import type {OtaProgress, OtaProgressStatus, OtaStatus} from "@glassly/bluetooth-sdk"
2
2
 
3
3
  /** Normalized ota_status fields (snake_case) after bridging Core/expo (snake or camel). */
4
4
  export type NormalizedOtaStatusEvent = {
@@ -0,0 +1,43 @@
1
+ // Legacy production manifest — pre-39 glasses install from this (they ignore ota_start's URL).
2
+ const OTA_VERSION_URL_LEGACY_PROD = "https://ota.glassly.ai/prod_live_version.json"
3
+
4
+ function trimmed(value?: string | null): string | null {
5
+ const result = value?.trim()
6
+ return result || null
7
+ }
8
+
9
+ export function isLegacyAsgOtaStartBuild(glassesBuildNumber?: string | null): boolean {
10
+ const buildNumber = Number.parseInt(glassesBuildNumber ?? "", 10)
11
+ return Number.isFinite(buildNumber) && buildNumber < 39
12
+ }
13
+
14
+ export function selectModernOtaManifestPin({
15
+ developerOverride,
16
+ hostReleasePin,
17
+ engineReleasePin,
18
+ }: {
19
+ developerOverride?: string | null
20
+ hostReleasePin?: string | null
21
+ engineReleasePin?: string | null
22
+ }): string | null {
23
+ return trimmed(developerOverride) || trimmed(hostReleasePin) || trimmed(engineReleasePin)
24
+ }
25
+
26
+ export function resolveOtaManifestPolicy({
27
+ glassesUrl,
28
+ glassesBuildNumber,
29
+ developerOverride,
30
+ hostReleasePin,
31
+ engineReleasePin,
32
+ }: {
33
+ glassesUrl?: string | null
34
+ glassesBuildNumber?: string | null
35
+ developerOverride?: string | null
36
+ hostReleasePin?: string | null
37
+ engineReleasePin?: string | null
38
+ }): string | null {
39
+ if (isLegacyAsgOtaStartBuild(glassesBuildNumber)) {
40
+ return trimmed(glassesUrl) || OTA_VERSION_URL_LEGACY_PROD
41
+ }
42
+ return selectModernOtaManifestPin({developerOverride, hostReleasePin, engineReleasePin})
43
+ }
@@ -1,20 +1,6 @@
1
- import {sdkPinnedOtaManifestUrl} from "@glassly/bluetooth-sdk/internal"
2
-
1
+ import {ENGINE_RELEASE_METADATA} from "../generated/releaseMetadata"
3
2
  import {SETTINGS, useSettingsStore} from "../stores/settings"
4
-
5
- // Legacy production manifest — pre-39 glasses install from this (they ignore ota_start's URL).
6
- const OTA_VERSION_URL_LEGACY_PROD = "https://ota.glassly.ai/prod_live_version.json"
7
- // Modern production fleet manifest (v2). Only a last-resort fallback when the SDK-derived pin
8
- // URL is somehow unavailable; modern glasses honor ota_start's URL, so this must be the v2
9
- // artifact, not the legacy v1 rescue manifest.
10
- const OTA_VERSION_URL_PROD = "https://ota.glassly.ai/prod_live_version_v2.json"
11
-
12
- function isLegacyAsgOtaStartBuild(glassesBuildNumber?: string | null): boolean {
13
- const buildNumber = Number.parseInt(glassesBuildNumber ?? "", 10)
14
- // ASG builds before 39 ignore ota_start.ota_version_url, so compare against
15
- // the URL they will actually use.
16
- return Number.isFinite(buildNumber) && buildNumber < 39
17
- }
3
+ import {resolveOtaManifestPolicy, selectModernOtaManifestPin} from "./otaManifestPolicy"
18
4
 
19
5
  function getOtaVersionUrlDevOverride(): string | null {
20
6
  // Super mode only: a wrong OTA manifest can brick glasses, so a saved
@@ -27,27 +13,32 @@ function getOtaVersionUrlDevOverride(): string | null {
27
13
  return trimmed || null
28
14
  }
29
15
 
30
- export function resolveOtaManifestUrl(glassesUrl?: string | null, glassesBuildNumber?: string | null): string {
31
- const deviceUrl = glassesUrl?.trim()
32
- if (isLegacyAsgOtaStartBuild(glassesBuildNumber)) {
33
- // Legacy glasses ignore ota_start.ota_version_url and install from their
34
- // compiled default, so the developer override does not apply to them either.
35
- return deviceUrl || OTA_VERSION_URL_LEGACY_PROD
36
- }
16
+ function getHostReleasePin(): string | null {
17
+ const value = process.env.EXPO_PUBLIC_ASG_OTA_VERSION_URL?.trim()
18
+ return value || null
19
+ }
37
20
 
38
- const devOverrideUrl = getOtaVersionUrlDevOverride()
39
- if (devOverrideUrl) {
40
- return devOverrideUrl
41
- }
21
+ function getEmbeddedEngineReleasePin(): string | null {
22
+ const value = ENGINE_RELEASE_METADATA.otaManifestUrl?.trim()
23
+ return value || null
24
+ }
42
25
 
43
- const envUrl = process.env.EXPO_PUBLIC_ASG_OTA_VERSION_URL?.trim()
44
- if (envUrl) {
45
- return envUrl
46
- }
26
+ export function hasConfiguredModernOtaManifestPin(): boolean {
27
+ return Boolean(
28
+ selectModernOtaManifestPin({
29
+ developerOverride: getOtaVersionUrlDevOverride(),
30
+ hostReleasePin: getHostReleasePin(),
31
+ engineReleasePin: getEmbeddedEngineReleasePin(),
32
+ }),
33
+ )
34
+ }
47
35
 
48
- // The phone owns manifest selection: modern glasses are driven with the manifest pinned to
49
- // this app's Bluetooth SDK version. Modern ASG builds report no manifest URL of their own;
50
- // a glasses-reported URL (older modern builds advertising their baked fleet default) is only
51
- // a last resort when the SDK version is somehow unavailable.
52
- return sdkPinnedOtaManifestUrl() || deviceUrl || OTA_VERSION_URL_PROD
36
+ export function resolveOtaManifestUrl(glassesUrl?: string | null, glassesBuildNumber?: string | null): string | null {
37
+ return resolveOtaManifestPolicy({
38
+ glassesUrl,
39
+ glassesBuildNumber,
40
+ developerOverride: getOtaVersionUrlDevOverride(),
41
+ hostReleasePin: getHostReleasePin(),
42
+ engineReleasePin: getEmbeddedEngineReleasePin(),
43
+ })
53
44
  }
@@ -0,0 +1,22 @@
1
+ const COORDINATED_RELEASE_VERSION = /^\d+\.\d+\.\d+(?:-(?:dev|beta)\.[1-9]\d*)?$/
2
+
3
+ type OtaReleaseVersionInput = {
4
+ manifestReleaseVersion?: string | null
5
+ manifestUrl: string
6
+ packagedManifestUrl?: string | null
7
+ packagedReleaseIdentity?: string | null
8
+ }
9
+
10
+ function validReleaseVersion(version: string | null | undefined): string | null {
11
+ const trimmed = version?.trim()
12
+ return trimmed && COORDINATED_RELEASE_VERSION.test(trimmed) ? trimmed : null
13
+ }
14
+
15
+ /** Resolve the label for the selected OTA pin, including stable promotion of exact beta OTA bytes. */
16
+ export function resolveOtaReleaseVersion(input: OtaReleaseVersionInput): string | null {
17
+ const packagedRelease = validReleaseVersion(input.packagedReleaseIdentity)
18
+ if (packagedRelease && input.packagedManifestUrl?.trim() === input.manifestUrl.trim()) {
19
+ return packagedRelease
20
+ }
21
+ return validReleaseVersion(input.manifestReleaseVersion)
22
+ }
@@ -0,0 +1,3 @@
1
+ /** Combine registry-enforced visibility with the user's home-screen choice. */
2
+ export const resolveHiddenStatus = (registryHidden: boolean, userHidden: boolean): boolean =>
3
+ registryHidden || userHidden
@@ -25,6 +25,7 @@ import {islandNotifications} from "../services/NotificationsEmitter"
25
25
  import sttModelManager from "../services/STTModelManager"
26
26
  import {miniappLauncher} from "../services/MiniappLauncher"
27
27
  import {miniappRunningRegistry} from "../services/MiniappRunningRegistry"
28
+ import {resolveHiddenStatus} from "./appVisibility"
28
29
  import {SETTINGS, useSettingsStore} from "./settings"
29
30
  import BluetoothSdk from "@glassly/bluetooth-sdk"
30
31
 
@@ -221,7 +222,12 @@ function projectApps(previousState: AppStatusState, localApps: ClientApp[]): Cli
221
222
  ...app,
222
223
  screenshot: previousByPackage.get(app.packageName)?.screenshot ?? app.screenshot,
223
224
  compatibility: HardwareCompatibility.checkCompatibility(app.hardwareRequirements, capabilities),
224
- hidden: previousState.getHiddenStatus(app.packageName),
225
+ // A registry source can force an app off the primary home screen (for
226
+ // example, Miniapp Developer while its home-screen setting is disabled).
227
+ // Compose that gate with the user's persisted home-screen layout instead
228
+ // of replacing it, otherwise a default-false persisted value makes a
229
+ // source-hidden app visible again during projection.
230
+ hidden: resolveHiddenStatus(app.hidden, previousState.getHiddenStatus(app.packageName)),
225
231
  // Derive the foreground flag from the store's single source of truth
226
232
  // (`foregroundedPackage`), NOT from the previous snapshot. Carrying it over
227
233
  // per-app meant a refresh that momentarily omitted an app (e.g. the
@@ -1,13 +1,13 @@
1
1
  import {create} from "zustand"
2
2
  import {subscribeWithSelector} from "zustand/middleware"
3
- import type {BluetoothStatus} from "@glassly/bluetooth-sdk/internal"
3
+ import type {PublicBluetoothStatus} from "@glassly/bluetooth-sdk"
4
4
 
5
- export interface CoreState extends BluetoothStatus {
6
- setCoreInfo: (info: Partial<BluetoothStatus>) => void
5
+ export interface CoreState extends PublicBluetoothStatus {
6
+ setCoreInfo: (info: Partial<PublicBluetoothStatus>) => void
7
7
  reset: () => void
8
8
  }
9
9
 
10
- const initialState: BluetoothStatus = {
10
+ const initialState: PublicBluetoothStatus = {
11
11
  // state:
12
12
  searching: false,
13
13
  searchingController: false,
@@ -29,54 +29,34 @@ const DISPLAY_COALESCE_MS = 150
29
29
 
30
30
  type DisplayEvent = Record<string, unknown> & {view?: string}
31
31
 
32
- function applyDisplayEvent(
33
- set: (partial: Partial<DisplayStore>) => void,
34
- get: () => DisplayStore,
35
- event: DisplayEvent,
36
- ) {
37
- const currentView = get().view
38
- const targetBucket = event.view === "dashboard" ? "dashboardEvent" : "mainEvent"
39
-
40
- const updates: Partial<DisplayStore> = {
41
- [targetBucket]: event,
42
- }
43
-
44
- // also update the current event if the view is the same:
45
- if (event.view === currentView) {
46
- updates.currentEvent = event
47
- }
48
-
49
- const visibleEvent = (updates.currentEvent ?? event) as DisplayEvent
50
- const textLines = extractDisplayText(visibleEvent)
32
+ function applyDisplayEvent(set: (partial: Partial<DisplayStore>) => void, event: DisplayEvent) {
33
+ const textLines = extractDisplayText(event)
51
34
  if (textLines.some((line) => line.trim() !== "")) {
52
35
  logE2EMetric("display_store_update", {
53
- view: visibleEvent.view ?? currentView,
54
- layout_type: (visibleEvent.layout as {layoutType?: string} | undefined)?.layoutType ?? "",
36
+ view: event.view ?? "main",
37
+ layout_type: (event.layout as {layoutType?: string} | undefined)?.layoutType ?? "",
55
38
  text_lines: textLines,
56
39
  })
57
40
  }
58
-
59
- set(updates)
41
+ set({currentEvent: event})
60
42
  }
61
43
 
62
44
  export interface DisplayStore {
45
+ /** The frame currently on the glasses — the mirror renders this. */
63
46
  currentEvent: any
64
- dashboardEvent: any
65
- mainEvent: any
47
+ /** True while the dashboard covers the main content (see DashboardCoordinator). */
48
+ dashboardActive: boolean
66
49
  setDisplayEvent: (event: DisplayEvent | string) => void
67
- view: string
68
- setView: (view: string) => void
50
+ setDashboardActive: (active: boolean) => void
69
51
  }
70
52
 
71
53
  let pendingDisplayEvent: DisplayEvent | null = null
72
54
  let displayCoalesceTimer: ReturnType<typeof BgTimer.setTimeout> | null = null
73
55
 
74
56
  export const useDisplayStore = create<DisplayStore>()(
75
- subscribeWithSelector((set, get) => ({
57
+ subscribeWithSelector((set) => ({
76
58
  currentEvent: {} as any,
77
- dashboardEvent: {} as any,
78
- mainEvent: {} as any,
79
- view: "main",
59
+ dashboardActive: false,
80
60
  setDisplayEvent: (event: DisplayEvent | string) => {
81
61
  const parsed: DisplayEvent = typeof event === "string" ? JSON.parse(event) : event
82
62
  pendingDisplayEvent = parsed
@@ -85,24 +65,12 @@ export const useDisplayStore = create<DisplayStore>()(
85
65
  displayCoalesceTimer = null
86
66
  const next = pendingDisplayEvent
87
67
  pendingDisplayEvent = null
88
- if (next) applyDisplayEvent(set, get, next)
68
+ if (next) applyDisplayEvent(set, next)
89
69
  }, DISPLAY_COALESCE_MS)
90
70
  },
91
- setView: (view: string) => {
92
- const currentView = get().view
93
- if (view === currentView) {
94
- return
95
- }
96
-
97
- // update the view and the currentEvent with the corresponding event:
98
- let newEvent
99
- if (view === "dashboard") {
100
- newEvent = get().dashboardEvent
101
- } else {
102
- newEvent = get().mainEvent
103
- }
104
- logE2EMetric("display_view_changed", {view})
105
- set({view, currentEvent: newEvent})
71
+ setDashboardActive: (active: boolean) => {
72
+ logE2EMetric("display_view_changed", {view: active ? "dashboard" : "main"})
73
+ set({dashboardActive: active})
106
74
  },
107
75
  })),
108
76
  )
@@ -116,6 +84,6 @@ export function flushDisplayCoalesceForTests(): void {
116
84
  if (pendingDisplayEvent) {
117
85
  const event = pendingDisplayEvent
118
86
  pendingDisplayEvent = null
119
- applyDisplayEvent(useDisplayStore.setState, useDisplayStore.getState, event)
87
+ applyDisplayEvent(useDisplayStore.setState, event)
120
88
  }
121
89
  }
@@ -1,12 +1,12 @@
1
1
  import type {
2
2
  GlassesConnectionStatus,
3
- GlassesStatus,
4
3
  HotspotStatus,
5
4
  OtaProgress,
6
5
  OtaStatus,
7
6
  OtaUpdateInfo,
7
+ PublicGlassesStatus,
8
8
  WifiStatus,
9
- } from "@glassly/bluetooth-sdk/internal"
9
+ } from "@glassly/bluetooth-sdk"
10
10
  import {isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady} from "../services/GlassesReadiness"
11
11
  import {create} from "zustand"
12
12
  import {subscribeWithSelector} from "zustand/middleware"
@@ -20,7 +20,14 @@ export const selectGlassesConnected = (state: {connection: GlassesConnectionStat
20
20
 
21
21
  export const selectGlassesReady = (state: {connection: GlassesConnectionStatus}) => isGlassesReady(state.connection)
22
22
 
23
- export interface GlassesState extends GlassesStatus {
23
+ type EngineGlassesStatus = PublicGlassesStatus & {
24
+ otaUpdateAvailable: OtaUpdateInfo | null
25
+ otaProgress: OtaProgress | null
26
+ otaInProgress: boolean
27
+ otaVersionUrl: string
28
+ }
29
+
30
+ export interface GlassesState extends EngineGlassesStatus {
24
31
  systemTimeMs: number
25
32
  wifiStatusKnown: boolean
26
33
  setGlassesInfo: (info: GlassesInfoUpdate) => void
@@ -53,7 +60,7 @@ type LegacyHotspotFields = {
53
60
  hotspotLocalIp?: string
54
61
  }
55
62
 
56
- type GlassesInfoUpdate = Partial<GlassesStatus> & LegacyWifiFields & LegacyHotspotFields
63
+ type GlassesInfoUpdate = Partial<EngineGlassesStatus> & LegacyWifiFields & LegacyHotspotFields
57
64
 
58
65
  function wifiFromLegacyFields(info: LegacyWifiFields): WifiStatus | null {
59
66
  if (info.wifiConnected === true) {
@@ -80,7 +87,7 @@ function hotspotFromLegacyFields(info: LegacyHotspotFields): HotspotStatus | nul
80
87
  return null
81
88
  }
82
89
 
83
- export const getGlasesInfoPartial = (state: GlassesStatus) => {
90
+ export const getGlasesInfoPartial = (state: EngineGlassesStatus) => {
84
91
  const wifi = state.wifi
85
92
  const connected = isGlassesConnected(state.connection)
86
93
  return {
@@ -98,7 +105,7 @@ export const getGlasesInfoPartial = (state: GlassesStatus) => {
98
105
  }
99
106
  }
100
107
 
101
- interface GlassesStore extends GlassesStatus {
108
+ interface GlassesStore extends EngineGlassesStatus {
102
109
  systemTimeMs: number
103
110
  mtkUpdatedThisSession: boolean
104
111
  wifiStatusKnown: boolean
@@ -158,6 +165,8 @@ const initialState: GlassesStore = {
158
165
  controllerMacAddress: "",
159
166
  controllerBatteryLevel: -1,
160
167
  controllerSignalStrength: -1,
168
+ // iOS ANCS consent (G2 consumes notifications on-firmware):
169
+ ancsAuthorized: false,
161
170
  }
162
171
 
163
172
  export const useGlassesStore = create<GlassesState>()(