@glassly/engine 0.1.0-dev.99 → 0.2.8-dev.445
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.
- package/README.md +28 -0
- package/build/engine.d.ts +32 -10
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +24 -16
- package/build/engine.js.map +1 -1
- package/build/facades/dev.d.ts +9 -0
- package/build/facades/dev.d.ts.map +1 -1
- package/build/facades/dev.js +9 -0
- package/build/facades/dev.js.map +1 -1
- package/build/facades/display.d.ts +10 -3
- package/build/facades/display.d.ts.map +1 -1
- package/build/facades/display.js +22 -8
- package/build/facades/display.js.map +1 -1
- package/build/facades/displayMirror.d.ts +11 -0
- package/build/facades/displayMirror.d.ts.map +1 -1
- package/build/facades/displayMirror.js +22 -0
- package/build/facades/displayMirror.js.map +1 -1
- package/build/facades/glasses.d.ts +31 -1
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +51 -0
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/memory.d.ts +0 -6
- package/build/facades/memory.d.ts.map +1 -1
- package/build/facades/memory.js +1 -9
- package/build/facades/memory.js.map +1 -1
- package/build/facades/miniapps.d.ts +3 -1
- package/build/facades/miniapps.d.ts.map +1 -1
- package/build/facades/miniapps.js +3 -1
- package/build/facades/miniapps.js.map +1 -1
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +5 -4
- package/build/facades/pairing.js.map +1 -1
- package/build/facades/permissions.d.ts +2 -0
- package/build/facades/permissions.d.ts.map +1 -1
- package/build/facades/permissions.js +48 -0
- package/build/facades/permissions.js.map +1 -1
- package/build/facades/phoneNotifications.d.ts +20 -9
- package/build/facades/phoneNotifications.d.ts.map +1 -1
- package/build/facades/phoneNotifications.js +33 -26
- package/build/facades/phoneNotifications.js.map +1 -1
- package/build/facades/settings.d.ts.map +1 -1
- package/build/facades/settings.js +1 -2
- package/build/facades/settings.js.map +1 -1
- package/build/generated/releaseMetadata.js +4 -4
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +6 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +5 -4
- package/build/index.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.js +2 -2
- package/build/react/MentraLiveOtaFlow.js.map +1 -1
- package/build/react/useMentraLiveOta.d.ts.map +1 -1
- package/build/react/useMentraLiveOta.js +8 -7
- package/build/react/useMentraLiveOta.js.map +1 -1
- package/build/runtime/config.d.ts +1 -1
- package/build/runtime/config.d.ts.map +1 -1
- package/build/runtime/config.js.map +1 -1
- package/build/services/AppRegistry.d.ts +4 -1
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +21 -1
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/BlobStore.d.ts +2 -2
- package/build/services/BlobStore.js +3 -3
- package/build/services/BlobStore.js.map +1 -1
- package/build/services/CloudClientService.d.ts +7 -3
- package/build/services/CloudClientService.d.ts.map +1 -1
- package/build/services/CloudClientService.js +34 -9
- package/build/services/CloudClientService.js.map +1 -1
- package/build/services/DevServerBridge.d.ts +1 -18
- package/build/services/DevServerBridge.d.ts.map +1 -1
- package/build/services/DevServerBridge.js +9 -8
- package/build/services/DevServerBridge.js.map +1 -1
- package/build/services/DeviceEventRouter.d.ts.map +1 -1
- package/build/services/DeviceEventRouter.js +58 -71
- package/build/services/DeviceEventRouter.js.map +1 -1
- package/build/services/DisplayDiagnostics.d.ts +5 -0
- package/build/services/DisplayDiagnostics.d.ts.map +1 -0
- package/build/services/DisplayDiagnostics.js +105 -0
- package/build/services/DisplayDiagnostics.js.map +1 -0
- package/build/services/DisplayProcessor.d.ts +6 -7
- package/build/services/DisplayProcessor.d.ts.map +1 -1
- package/build/services/DisplayProcessor.js +17 -45
- package/build/services/DisplayProcessor.js.map +1 -1
- package/build/services/GestureDotsService.d.ts +10 -4
- package/build/services/GestureDotsService.d.ts.map +1 -1
- package/build/services/GestureDotsService.js +70 -16
- package/build/services/GestureDotsService.js.map +1 -1
- package/build/services/GlassesKeyboardInput.d.ts +77 -0
- package/build/services/GlassesKeyboardInput.d.ts.map +1 -0
- package/build/services/GlassesKeyboardInput.js +261 -0
- package/build/services/GlassesKeyboardInput.js.map +1 -0
- package/build/services/GlassesSensorService.d.ts +47 -0
- package/build/services/GlassesSensorService.d.ts.map +1 -0
- package/build/services/GlassesSensorService.js +242 -0
- package/build/services/GlassesSensorService.js.map +1 -0
- package/build/services/GlassesTouchInput.d.ts +14 -0
- package/build/services/GlassesTouchInput.d.ts.map +1 -0
- package/build/services/GlassesTouchInput.js +107 -0
- package/build/services/GlassesTouchInput.js.map +1 -0
- package/build/services/HeadingService.d.ts +0 -6
- package/build/services/HeadingService.d.ts.map +1 -1
- package/build/services/HeadingService.js +0 -27
- package/build/services/HeadingService.js.map +1 -1
- package/build/services/HotspotShutdown.d.ts.map +1 -1
- package/build/services/HotspotShutdown.js +2 -1
- package/build/services/HotspotShutdown.js.map +1 -1
- package/build/services/JSCrashloopReportService.js +2 -2
- package/build/services/JSCrashloopReportService.js.map +1 -1
- package/build/services/JSRouter.d.ts +6 -4
- package/build/services/JSRouter.d.ts.map +1 -1
- package/build/services/JSRouter.js +15 -13
- package/build/services/JSRouter.js.map +1 -1
- package/build/services/LocalDisplayManager.d.ts +35 -7
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +105 -27
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/LocalMiniappDataMigration.d.ts +1 -1
- package/build/services/LocalMiniappDataMigration.js +1 -1
- package/build/services/LocalMiniappDataMigration.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +64 -11
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +441 -35
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.d.ts +3 -0
- package/build/services/LocalSttFallbackCoordinator.d.ts.map +1 -1
- package/build/services/LocalSttFallbackCoordinator.js +27 -8
- package/build/services/LocalSttFallbackCoordinator.js.map +1 -1
- package/build/services/MemoryStore.d.ts +8 -33
- package/build/services/MemoryStore.d.ts.map +1 -1
- package/build/services/MemoryStore.js +30 -56
- package/build/services/MemoryStore.js.map +1 -1
- package/build/services/MiniappEngine.d.ts +3 -3
- package/build/services/MiniappEngine.js +7 -7
- package/build/services/MiniappEngine.js.map +1 -1
- package/build/services/MiniappLauncher.d.ts +8 -0
- package/build/services/MiniappLauncher.d.ts.map +1 -1
- package/build/services/MiniappLauncher.js +19 -1
- package/build/services/MiniappLauncher.js.map +1 -1
- package/build/services/MirrorService.d.ts +24 -0
- package/build/services/MirrorService.d.ts.map +1 -0
- package/build/services/MirrorService.js +132 -0
- package/build/services/MirrorService.js.map +1 -0
- package/build/services/NativeNavigationService.d.ts +2 -3
- package/build/services/NativeNavigationService.d.ts.map +1 -1
- package/build/services/NativeNavigationService.js +24 -21
- package/build/services/NativeNavigationService.js.map +1 -1
- package/build/services/NavigationHandlers.d.ts.map +1 -1
- package/build/services/NavigationHandlers.js +10 -5
- package/build/services/NavigationHandlers.js.map +1 -1
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +24 -23
- package/build/services/OtaInstallCoordinator.js.map +1 -1
- package/build/services/PairedGlassesLatch.d.ts +7 -0
- package/build/services/PairedGlassesLatch.d.ts.map +1 -0
- package/build/services/PairedGlassesLatch.js +38 -0
- package/build/services/PairedGlassesLatch.js.map +1 -0
- package/build/services/PhoneActivity.d.ts +23 -0
- package/build/services/PhoneActivity.d.ts.map +1 -0
- package/build/services/PhoneActivity.js +111 -0
- package/build/services/PhoneActivity.js.map +1 -0
- package/build/services/PhoneCameraFovCoordinator.d.ts.map +1 -1
- package/build/services/PhoneCameraFovCoordinator.js +4 -3
- package/build/services/PhoneCameraFovCoordinator.js.map +1 -1
- package/build/services/PhoneNotificationsSync.d.ts +40 -6
- package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
- package/build/services/PhoneNotificationsSync.js +160 -84
- package/build/services/PhoneNotificationsSync.js.map +1 -1
- package/build/services/PhonePhotoCoordinator.d.ts.map +1 -1
- package/build/services/PhonePhotoCoordinator.js +6 -5
- package/build/services/PhonePhotoCoordinator.js.map +1 -1
- package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
- package/build/services/PhoneStreamCoordinator.js +8 -7
- package/build/services/PhoneStreamCoordinator.js.map +1 -1
- package/build/services/STTModelManager.d.ts +3 -0
- package/build/services/STTModelManager.d.ts.map +1 -1
- package/build/services/STTModelManager.js +15 -1
- package/build/services/STTModelManager.js.map +1 -1
- package/build/services/SceneRenderer.d.ts +43 -2
- package/build/services/SceneRenderer.d.ts.map +1 -1
- package/build/services/SceneRenderer.js +123 -8
- package/build/services/SceneRenderer.js.map +1 -1
- package/build/services/StreamLifecycleController.d.ts.map +1 -1
- package/build/services/StreamLifecycleController.js +6 -14
- package/build/services/StreamLifecycleController.js.map +1 -1
- package/build/services/TTSModelManager.js +1 -1
- package/build/services/TTSModelManager.js.map +1 -1
- package/build/services/UIRouter.d.ts +2 -2
- package/build/services/UIRouter.js +5 -5
- package/build/services/UIRouter.js.map +1 -1
- package/build/services/asg/galleryPathMigration.js +1 -1
- package/build/services/asg/galleryPathMigration.js.map +1 -1
- package/build/services/asg/gallerySyncService.js +2 -2
- package/build/services/asg/gallerySyncService.js.map +1 -1
- package/build/services/asg/localStorageService.d.ts.map +1 -1
- package/build/services/asg/localStorageService.js +3 -3
- package/build/services/asg/localStorageService.js.map +1 -1
- package/build/services/debug/DashboardOpenTrace.d.ts +32 -0
- package/build/services/debug/DashboardOpenTrace.d.ts.map +1 -0
- package/build/services/debug/DashboardOpenTrace.js +128 -0
- package/build/services/debug/DashboardOpenTrace.js.map +1 -0
- package/build/services/debug/dashboardOpenTimeline.d.ts +77 -0
- package/build/services/debug/dashboardOpenTimeline.d.ts.map +1 -0
- package/build/services/debug/dashboardOpenTimeline.js +195 -0
- package/build/services/debug/dashboardOpenTimeline.js.map +1 -0
- package/build/services/effectiveCapabilities.d.ts.map +1 -1
- package/build/services/effectiveCapabilities.js +25 -13
- package/build/services/effectiveCapabilities.js.map +1 -1
- package/build/services/gestureClaims.d.ts +34 -15
- package/build/services/gestureClaims.d.ts.map +1 -1
- package/build/services/gestureClaims.js +42 -21
- package/build/services/gestureClaims.js.map +1 -1
- package/build/services/manifestFields.d.ts +9 -0
- package/build/services/manifestFields.d.ts.map +1 -0
- package/build/services/manifestFields.js +26 -0
- package/build/services/manifestFields.js.map +1 -0
- package/build/services/memoryStoreInstance.d.ts +0 -10
- package/build/services/memoryStoreInstance.d.ts.map +1 -1
- package/build/services/memoryStoreInstance.js +2 -31
- package/build/services/memoryStoreInstance.js.map +1 -1
- package/build/services/mirrorSnapshot.d.ts +16 -0
- package/build/services/mirrorSnapshot.d.ts.map +1 -0
- package/build/services/mirrorSnapshot.js +102 -0
- package/build/services/mirrorSnapshot.js.map +1 -0
- package/build/services/nativeNavigationGate.d.ts +8 -0
- package/build/services/nativeNavigationGate.d.ts.map +1 -0
- package/build/services/nativeNavigationGate.js +12 -0
- package/build/services/nativeNavigationGate.js.map +1 -0
- package/build/services/notificationAppCatalog.d.ts +7 -0
- package/build/services/notificationAppCatalog.d.ts.map +1 -0
- package/build/services/notificationAppCatalog.js +16 -0
- package/build/services/notificationAppCatalog.js.map +1 -0
- package/build/services/notifications/notificationPolicy.d.ts +55 -0
- package/build/services/notifications/notificationPolicy.d.ts.map +1 -0
- package/build/services/notifications/notificationPolicy.js +41 -0
- package/build/services/notifications/notificationPolicy.js.map +1 -0
- package/build/services/pages/OverlayPages.d.ts +26 -0
- package/build/services/pages/OverlayPages.d.ts.map +1 -0
- package/build/services/pages/OverlayPages.js +80 -0
- package/build/services/pages/OverlayPages.js.map +1 -0
- package/build/services/pages/PageHost.d.ts +32 -0
- package/build/services/pages/PageHost.d.ts.map +1 -0
- package/build/services/pages/PageHost.js +99 -0
- package/build/services/pages/PageHost.js.map +1 -0
- package/build/services/pages/overlayApps.d.ts +25 -0
- package/build/services/pages/overlayApps.d.ts.map +1 -0
- package/build/services/pages/overlayApps.js +66 -0
- package/build/services/pages/overlayApps.js.map +1 -0
- package/build/services/pages/pageEligibility.d.ts +9 -0
- package/build/services/pages/pageEligibility.d.ts.map +1 -0
- package/build/services/pages/pageEligibility.js +27 -0
- package/build/services/pages/pageEligibility.js.map +1 -0
- package/build/services/settingsBridge.d.ts +58 -0
- package/build/services/settingsBridge.d.ts.map +1 -0
- package/build/services/settingsBridge.js +90 -0
- package/build/services/settingsBridge.js.map +1 -0
- package/build/services/speakerProfileStoreInstance.js +1 -1
- package/build/services/speakerProfileStoreInstance.js.map +1 -1
- package/build/services/uiShim.d.ts +1 -1
- package/build/services/uiShim.js +4 -4
- package/build/services/uiShim.js.map +1 -1
- package/build/stores/appVisibility.d.ts +28 -0
- package/build/stores/appVisibility.d.ts.map +1 -1
- package/build/stores/appVisibility.js +34 -0
- package/build/stores/appVisibility.js.map +1 -1
- package/build/stores/apps.d.ts +13 -0
- package/build/stores/apps.d.ts.map +1 -1
- package/build/stores/apps.js +66 -12
- package/build/stores/apps.js.map +1 -1
- package/build/stores/bluetoothSettingKeys.js +1 -1
- package/build/stores/bluetoothSettingKeys.js.map +1 -1
- package/build/stores/display.d.ts +3 -3
- package/build/stores/display.d.ts.map +1 -1
- package/build/stores/display.js +16 -4
- package/build/stores/display.js.map +1 -1
- package/build/stores/glasses.d.ts.map +1 -1
- package/build/stores/glasses.js +14 -1
- package/build/stores/glasses.js.map +1 -1
- package/build/stores/settings.d.ts +1 -0
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +170 -44
- package/build/stores/settings.js.map +1 -1
- package/build/types/applet.d.ts +14 -1
- package/build/types/applet.d.ts.map +1 -1
- package/build/types/applet.js.map +1 -1
- package/build/types/capabilities/even-realities-g2.d.ts.map +1 -1
- package/build/types/capabilities/even-realities-g2.js +5 -0
- package/build/types/capabilities/even-realities-g2.js.map +1 -1
- package/build/types/capabilities/simulated-glasses.d.ts +1 -1
- package/build/types/capabilities/simulated-glasses.d.ts.map +1 -1
- package/build/types/capabilities/simulated-glasses.js +7 -4
- package/build/types/capabilities/simulated-glasses.js.map +1 -1
- package/build/types/hardware.d.ts +20 -1
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +2 -0
- package/build/types/hardware.js.map +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js +1 -0
- package/build/types/index.js.map +1 -1
- package/build/utils/debouncedPatch.d.ts +3 -1
- package/build/utils/debouncedPatch.d.ts.map +1 -1
- package/build/utils/debouncedPatch.js +6 -3
- package/build/utils/debouncedPatch.js.map +1 -1
- package/build/utils/devMiniappLaunch.d.ts.map +1 -1
- package/build/utils/devMiniappLaunch.js +4 -3
- package/build/utils/devMiniappLaunch.js.map +1 -1
- package/build/utils/display/measurer/TextMeasurer.d.ts +2 -159
- package/build/utils/display/measurer/TextMeasurer.d.ts.map +1 -1
- package/build/utils/display/measurer/TextMeasurer.js +2 -272
- package/build/utils/display/measurer/TextMeasurer.js.map +1 -1
- package/build/utils/display/measurer/script-detection.d.ts +1 -52
- package/build/utils/display/measurer/script-detection.d.ts.map +1 -1
- package/build/utils/display/measurer/script-detection.js +2 -183
- package/build/utils/display/measurer/script-detection.js.map +1 -1
- package/build/utils/display/pixelArt.d.ts +3 -0
- package/build/utils/display/pixelArt.d.ts.map +1 -0
- package/build/utils/display/pixelArt.js +3 -0
- package/build/utils/display/pixelArt.js.map +1 -0
- package/build/utils/display/profiles/g1.d.ts +1 -32
- package/build/utils/display/profiles/g1.d.ts.map +1 -1
- package/build/utils/display/profiles/g1.js +2 -212
- package/build/utils/display/profiles/g1.js.map +1 -1
- package/build/utils/display/profiles/g2.d.ts +1 -12
- package/build/utils/display/profiles/g2.d.ts.map +1 -1
- package/build/utils/display/profiles/g2.js +2 -33
- package/build/utils/display/profiles/g2.js.map +1 -1
- package/build/utils/display/profiles/nex.d.ts +1 -9
- package/build/utils/display/profiles/nex.d.ts.map +1 -1
- package/build/utils/display/profiles/nex.js +2 -149
- package/build/utils/display/profiles/nex.js.map +1 -1
- package/build/utils/display/profiles/types.d.ts +1 -102
- package/build/utils/display/profiles/types.d.ts.map +1 -1
- package/build/utils/display/profiles/types.js.map +1 -1
- package/build/utils/display/profiles/z100.d.ts +1 -32
- package/build/utils/display/profiles/z100.d.ts.map +1 -1
- package/build/utils/display/profiles/z100.js +2 -181
- package/build/utils/display/profiles/z100.js.map +1 -1
- package/build/utils/display/scene/degrade.d.ts.map +1 -1
- package/build/utils/display/scene/degrade.js +4 -1
- package/build/utils/display/scene/degrade.js.map +1 -1
- package/build/utils/display/scene/differ.d.ts +13 -1
- package/build/utils/display/scene/differ.d.ts.map +1 -1
- package/build/utils/display/scene/differ.js +22 -0
- package/build/utils/display/scene/differ.js.map +1 -1
- package/build/utils/display/scene/index.d.ts +1 -1
- package/build/utils/display/scene/index.d.ts.map +1 -1
- package/build/utils/display/scene/index.js.map +1 -1
- package/build/utils/display/scene/process.d.ts.map +1 -1
- package/build/utils/display/scene/process.js +183 -11
- package/build/utils/display/scene/process.js.map +1 -1
- package/build/utils/display/scene/store.d.ts +1 -1
- package/build/utils/display/scene/store.d.ts.map +1 -1
- package/build/utils/display/scene/store.js +0 -0
- package/build/utils/display/scene/store.js.map +1 -1
- package/build/utils/display/scene/svgPath.d.ts +9 -0
- package/build/utils/display/scene/svgPath.d.ts.map +1 -0
- package/build/utils/display/scene/svgPath.js +167 -0
- package/build/utils/display/scene/svgPath.js.map +1 -0
- package/build/utils/display/scene/types.d.ts +2 -142
- package/build/utils/display/scene/types.d.ts.map +1 -1
- package/build/utils/display/scene/types.js +0 -0
- package/build/utils/display/scene/types.js.map +1 -1
- package/build/utils/display/wrapper/TextWrapper.d.ts +1 -101
- package/build/utils/display/wrapper/TextWrapper.d.ts.map +1 -1
- package/build/utils/display/wrapper/TextWrapper.js +2 -470
- package/build/utils/display/wrapper/TextWrapper.js.map +1 -1
- package/build/utils/display/wrapper/types.d.ts +2 -74
- package/build/utils/display/wrapper/types.d.ts.map +1 -1
- package/build/utils/display/wrapper/types.js +2 -10
- package/build/utils/display/wrapper/types.js.map +1 -1
- package/build/utils/hardware/hardware.js +1 -1
- package/build/utils/hardware/hardware.js.map +1 -1
- package/build/utils/timers/timers.d.ts.map +1 -1
- package/build/utils/timers/timers.js +26 -4
- package/build/utils/timers/timers.js.map +1 -1
- package/package.json +8 -8
- package/src/engine.ts +24 -15
- package/src/facades/dev.ts +10 -0
- package/src/facades/display.ts +21 -8
- package/src/facades/displayMirror.ts +29 -0
- package/src/facades/glasses.ts +61 -1
- package/src/facades/memory.ts +1 -12
- package/src/facades/miniapps.ts +4 -1
- package/src/facades/pairing.ts +8 -6
- package/src/facades/permissions.ts +46 -0
- package/src/facades/phoneNotifications.ts +45 -26
- package/src/facades/settings.ts +1 -2
- package/src/generated/releaseMetadata.ts +4 -4
- package/src/index.ts +6 -9
- package/src/react/MentraLiveOtaFlow.tsx +2 -2
- package/src/react/useMentraLiveOta.ts +14 -8
- package/src/runtime/config.ts +1 -1
- package/src/services/AppRegistry.ts +43 -7
- package/src/services/BlobStore.ts +3 -3
- package/src/services/CloudClientService.ts +37 -10
- package/src/services/DevServerBridge.ts +12 -10
- package/src/services/DeviceEventRouter.ts +73 -74
- package/src/services/DisplayDiagnostics.ts +107 -0
- package/src/services/DisplayProcessor.ts +20 -55
- package/src/services/GestureDotsService.ts +77 -16
- package/src/services/GlassesKeyboardInput.ts +306 -0
- package/src/services/GlassesSensorService.ts +233 -0
- package/src/services/GlassesTouchInput.ts +128 -0
- package/src/services/HeadingService.ts +0 -24
- package/src/services/HotspotShutdown.ts +3 -1
- package/src/services/JSCrashloopReportService.ts +2 -2
- package/src/services/JSRouter.ts +29 -14
- package/src/services/LocalDisplayManager.ts +112 -26
- package/src/services/LocalMiniappDataMigration.ts +1 -1
- package/src/services/LocalMiniappRuntime.ts +500 -43
- package/src/services/LocalSttFallbackCoordinator.ts +28 -7
- package/src/services/MemoryStore.ts +32 -80
- package/src/services/MiniappEngine.ts +7 -7
- package/src/services/MiniappLauncher.ts +25 -1
- package/src/services/MirrorService.ts +139 -0
- package/src/services/NativeNavigationService.ts +29 -25
- package/src/services/NavigationHandlers.ts +10 -5
- package/src/services/OtaInstallCoordinator.ts +36 -34
- package/src/services/PairedGlassesLatch.ts +39 -0
- package/src/services/PhoneActivity.ts +116 -0
- package/src/services/PhoneCameraFovCoordinator.ts +6 -4
- package/src/services/PhoneNotificationsSync.ts +185 -103
- package/src/services/PhonePhotoCoordinator.ts +9 -10
- package/src/services/PhoneStreamCoordinator.ts +13 -11
- package/src/services/STTModelManager.ts +15 -1
- package/src/services/SceneRenderer.ts +148 -10
- package/src/services/StreamLifecycleController.ts +9 -7
- package/src/services/TTSModelManager.ts +1 -1
- package/src/services/UIRouter.ts +5 -5
- package/src/services/asg/galleryPathMigration.ts +1 -1
- package/src/services/asg/gallerySyncService.ts +2 -2
- package/src/services/asg/localStorageService.ts +3 -3
- package/src/services/debug/DashboardOpenTrace.ts +153 -0
- package/src/services/debug/dashboardOpenTimeline.ts +237 -0
- package/src/services/effectiveCapabilities.ts +32 -13
- package/src/services/gestureClaims.ts +72 -23
- package/src/services/manifestFields.ts +23 -0
- package/src/services/memoryStoreInstance.ts +2 -34
- package/src/services/mirrorSnapshot.ts +116 -0
- package/src/services/nativeNavigationGate.ts +14 -0
- package/src/services/notificationAppCatalog.ts +21 -0
- package/src/services/notifications/notificationPolicy.ts +87 -0
- package/src/services/pages/OverlayPages.ts +86 -0
- package/src/services/pages/PageHost.ts +116 -0
- package/src/services/pages/overlayApps.ts +72 -0
- package/src/services/pages/pageEligibility.ts +30 -0
- package/src/services/settingsBridge.ts +111 -0
- package/src/services/speakerProfileStoreInstance.ts +1 -1
- package/src/services/uiShim.ts +4 -4
- package/src/stores/appVisibility.ts +45 -0
- package/src/stores/apps.ts +110 -32
- package/src/stores/bluetoothSettingKeys.ts +1 -1
- package/src/stores/display.ts +18 -7
- package/src/stores/glasses.ts +15 -1
- package/src/stores/settings.ts +175 -51
- package/src/types/applet.ts +14 -1
- package/src/types/capabilities/even-realities-g2.ts +6 -0
- package/src/types/capabilities/simulated-glasses.ts +8 -4
- package/src/types/hardware.ts +34 -1
- package/src/types/index.ts +1 -0
- package/src/utils/debouncedPatch.ts +8 -4
- package/src/utils/devMiniappLaunch.ts +5 -3
- package/src/utils/display/measurer/TextMeasurer.ts +3 -346
- package/src/utils/display/measurer/script-detection.ts +10 -218
- package/src/utils/display/pixelArt.ts +3 -0
- package/src/utils/display/profiles/g1.ts +2 -236
- package/src/utils/display/profiles/g2.ts +2 -39
- package/src/utils/display/profiles/nex.ts +2 -166
- package/src/utils/display/profiles/types.ts +9 -132
- package/src/utils/display/profiles/z100.ts +2 -198
- package/src/utils/display/scene/degrade.ts +4 -1
- package/src/utils/display/scene/differ.ts +25 -1
- package/src/utils/display/scene/index.ts +5 -0
- package/src/utils/display/scene/process.ts +196 -13
- package/src/utils/display/scene/store.ts +0 -0
- package/src/utils/display/scene/svgPath.ts +163 -0
- package/src/utils/display/scene/types.ts +0 -0
- package/src/utils/display/wrapper/TextWrapper.ts +2 -546
- package/src/utils/display/wrapper/types.ts +3 -102
- package/src/utils/hardware/hardware.ts +1 -1
- package/src/utils/timers/timers.ts +32 -4
- package/build/services/CustomDashboardModel.d.ts +0 -48
- package/build/services/CustomDashboardModel.d.ts.map +0 -1
- package/build/services/CustomDashboardModel.js +0 -73
- package/build/services/CustomDashboardModel.js.map +0 -1
- package/build/services/CustomDashboardService.d.ts +0 -63
- package/build/services/CustomDashboardService.d.ts.map +0 -1
- package/build/services/CustomDashboardService.js +0 -576
- package/build/services/CustomDashboardService.js.map +0 -1
- package/build/services/DashboardCoordinator.d.ts +0 -26
- package/build/services/DashboardCoordinator.d.ts.map +0 -1
- package/build/services/DashboardCoordinator.js +0 -125
- package/build/services/DashboardCoordinator.js.map +0 -1
- package/build/services/iosNotificationAppCatalog.d.ts +0 -13
- package/build/services/iosNotificationAppCatalog.d.ts.map +0 -1
- package/build/services/iosNotificationAppCatalog.js +0 -28
- package/build/services/iosNotificationAppCatalog.js.map +0 -1
- package/src/services/CustomDashboardModel.ts +0 -83
- package/src/services/CustomDashboardService.ts +0 -598
- package/src/services/DashboardCoordinator.ts +0 -121
- package/src/services/iosNotificationAppCatalog.ts +0 -39
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
* management (connect/disconnect/ping).
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import {mirrorService} from "./MirrorService"
|
|
12
13
|
import {AppState, Linking} from "react-native"
|
|
14
|
+
import {logBuffer} from "../utils/devLogging"
|
|
15
|
+
import {collectDisplayDiagnostics} from "./DisplayDiagnostics"
|
|
13
16
|
import Share from "react-native-share"
|
|
14
17
|
import * as Battery from "expo-battery"
|
|
15
18
|
import * as Clipboard from "expo-clipboard"
|
|
@@ -26,7 +29,7 @@ import {
|
|
|
26
29
|
parseEnvelope,
|
|
27
30
|
serializeEnvelope,
|
|
28
31
|
} from "@glassly/miniapp"
|
|
29
|
-
import type {MiniappEnvelope} from "@glassly/miniapp"
|
|
32
|
+
import type {MiniappEnvelope, MiniappLaunchSource, MiniappPreferences} from "@glassly/miniapp"
|
|
30
33
|
|
|
31
34
|
import {DeviceTypes, type Capabilities} from "../types"
|
|
32
35
|
import {getEffectiveCapabilities} from "./effectiveCapabilities"
|
|
@@ -52,10 +55,34 @@ import {normalizeAiTier, resolveAiTier} from "./AiTierResolution"
|
|
|
52
55
|
import type {AiTier, AiTierProvider, SavedLlmKeys} from "./AiTierResolution"
|
|
53
56
|
import {HttpError} from "@glassly/cloud-client"
|
|
54
57
|
import localDisplayManager from "./LocalDisplayManager"
|
|
55
|
-
import {
|
|
58
|
+
import {
|
|
59
|
+
dropGestureClaims,
|
|
60
|
+
emptyGestureClaims,
|
|
61
|
+
gestureClaimant,
|
|
62
|
+
hasGestureClaim,
|
|
63
|
+
setGestureClaims,
|
|
64
|
+
type GestureClaimChange,
|
|
65
|
+
type GestureClaimState,
|
|
66
|
+
} from "./gestureClaims"
|
|
67
|
+
import overlayPages from "./pages/OverlayPages"
|
|
68
|
+
import dashboardOpenTrace from "./debug/DashboardOpenTrace"
|
|
69
|
+
import {isAppForegrounded, isPhoneActive, onAppForegroundChange, onPhoneActivityChange} from "./PhoneActivity"
|
|
70
|
+
import {installedNotificationApps} from "./PhoneNotificationsSync"
|
|
71
|
+
import {
|
|
72
|
+
DERIVED_SETTINGS_KEYS,
|
|
73
|
+
SETTINGS_BRIDGE_KEYS,
|
|
74
|
+
isDerivedSettingsKey,
|
|
75
|
+
ringBatteryFrom,
|
|
76
|
+
selectSettingsBridgeKeys,
|
|
77
|
+
validateSettingsSet,
|
|
78
|
+
type DerivedSettingsKey,
|
|
79
|
+
} from "./settingsBridge"
|
|
80
|
+
import {addOverlayApp, displayViewsFor, isOverlayApp, removeOverlayApp, setOverlayViewer} from "./pages/overlayApps"
|
|
81
|
+
import {pagesEligible} from "./pages/pageEligibility"
|
|
56
82
|
import nativeNavigationService from "./NativeNavigationService"
|
|
57
83
|
import type {DisplayPayload} from "./LocalDisplayManager"
|
|
58
84
|
import headingService from "./HeadingService"
|
|
85
|
+
import glassesSensorService from "./GlassesSensorService"
|
|
59
86
|
import localSttFallbackCoordinator from "./LocalSttFallbackCoordinator"
|
|
60
87
|
import speakerLabelResolver from "./SpeakerLabelResolver"
|
|
61
88
|
import micStateCoordinator from "./MicStateCoordinator"
|
|
@@ -158,6 +185,8 @@ interface ConnectedMiniapp {
|
|
|
158
185
|
* see {@link LOCATION_RATE_PRIORITY}.
|
|
159
186
|
*/
|
|
160
187
|
requestedLocationRate: string | null
|
|
188
|
+
/** Who started the app; echoed in CONNECT_ACK. */
|
|
189
|
+
launchSource?: MiniappLaunchSource
|
|
161
190
|
}
|
|
162
191
|
|
|
163
192
|
interface SpeechRun {
|
|
@@ -222,9 +251,12 @@ const SYSTEM_MINIAPP_PACKAGES = new Set([
|
|
|
222
251
|
"com.glassly.simulated",
|
|
223
252
|
"com.glassly.mirror",
|
|
224
253
|
"com.glassly.ai",
|
|
225
|
-
"cloud.augmentos.notify",
|
|
226
254
|
"com.glassly.feedback",
|
|
227
255
|
"com.glassly.miniappdev",
|
|
256
|
+
// The dashboard: the settings bridge and the miniapp list/start/stop are its side menu and settings page.
|
|
257
|
+
"com.glassly.dashboard",
|
|
258
|
+
// The notifications viewer: the settings bridge and the notification app list are its settings page.
|
|
259
|
+
"com.glassly.notifications",
|
|
228
260
|
])
|
|
229
261
|
const PING_INTERVAL_MS = 5_000
|
|
230
262
|
// Min gap between "transcription limit reached" notices on the glasses. A
|
|
@@ -304,6 +336,7 @@ const PERMISSION_TYPE_TO_CANONICAL: Record<string, string> = {
|
|
|
304
336
|
LOCATION: "location",
|
|
305
337
|
BACKGROUND_LOCATION: "location",
|
|
306
338
|
READ_NOTIFICATIONS: "notifications",
|
|
339
|
+
DISPLAY_MIRROR: "displayMirror",
|
|
307
340
|
POST_NOTIFICATIONS: "notifications",
|
|
308
341
|
CALENDAR: "calendar",
|
|
309
342
|
API_KEYS: "apiKeys",
|
|
@@ -423,6 +456,7 @@ const ALL_CANONICAL_PERMISSIONS = [
|
|
|
423
456
|
"memory",
|
|
424
457
|
"ai",
|
|
425
458
|
"speakers",
|
|
459
|
+
"displayMirror",
|
|
426
460
|
] as const
|
|
427
461
|
|
|
428
462
|
/**
|
|
@@ -540,8 +574,8 @@ class LocalMiniappRuntime {
|
|
|
540
574
|
|
|
541
575
|
/** Connected miniapps keyed by packageName. */
|
|
542
576
|
private connectedApps: Map<string, ConnectedMiniapp> = new Map()
|
|
543
|
-
/**
|
|
544
|
-
private gestureClaims:
|
|
577
|
+
/** Claimed gestures (CLAIM_GESTURES): a stack per gesture, the most recent claimer holding it. */
|
|
578
|
+
private gestureClaims: GestureClaimState = emptyGestureClaims()
|
|
545
579
|
|
|
546
580
|
/**
|
|
547
581
|
* Packages that have completed their CONNECT handshake (sent
|
|
@@ -564,6 +598,10 @@ class LocalMiniappRuntime {
|
|
|
564
598
|
private cloudResultsWired = false
|
|
565
599
|
private cloudStatusWired = false
|
|
566
600
|
private capabilitiesWired = false
|
|
601
|
+
private preferencesWired = false
|
|
602
|
+
private settingsBridgeWired = false
|
|
603
|
+
/** Last derived read-only values pushed on the settings stream, for change detection. */
|
|
604
|
+
private derivedSettings = new Map<DerivedSettingsKey, string>()
|
|
567
605
|
private cloudAudioSubscriptionSync = new CloudAudioSubscriptionSync()
|
|
568
606
|
|
|
569
607
|
/**
|
|
@@ -692,6 +730,22 @@ class LocalMiniappRuntime {
|
|
|
692
730
|
}
|
|
693
731
|
}
|
|
694
732
|
|
|
733
|
+
if (this.streamSubscribers.has(MiniappStreamType.MIRROR_UPDATE)) {
|
|
734
|
+
if (!this.mirrorUnsubscribe)
|
|
735
|
+
this.mirrorUnsubscribe = mirrorService.subscribe((snapshot) => {
|
|
736
|
+
for (const pkg of this.streamSubscribers.get(MiniappStreamType.MIRROR_UPDATE) ?? []) {
|
|
737
|
+
if (this.hasMirrorPermission(pkg))
|
|
738
|
+
this.sendToMiniapp(pkg, {
|
|
739
|
+
type: MiniappResponseType.EVENT,
|
|
740
|
+
streamType: MiniappStreamType.MIRROR_UPDATE,
|
|
741
|
+
data: snapshot,
|
|
742
|
+
})
|
|
743
|
+
}
|
|
744
|
+
})
|
|
745
|
+
} else {
|
|
746
|
+
this.mirrorUnsubscribe?.()
|
|
747
|
+
this.mirrorUnsubscribe = null
|
|
748
|
+
}
|
|
695
749
|
this.publishTranscriptionDebugSubscribers()
|
|
696
750
|
}
|
|
697
751
|
|
|
@@ -802,6 +856,15 @@ class LocalMiniappRuntime {
|
|
|
802
856
|
return LocalMiniappRuntime.instance
|
|
803
857
|
}
|
|
804
858
|
|
|
859
|
+
private mirrorUnsubscribe: (() => void) | null = null
|
|
860
|
+
|
|
861
|
+
private hasMirrorPermission(packageName: string): boolean {
|
|
862
|
+
return (
|
|
863
|
+
this.connectedApps.get(packageName)?.installedManifest?.permissions?.some((p) => p.type === "DISPLAY_MIRROR") ===
|
|
864
|
+
true
|
|
865
|
+
)
|
|
866
|
+
}
|
|
867
|
+
|
|
805
868
|
private initialized = false
|
|
806
869
|
|
|
807
870
|
/**
|
|
@@ -813,6 +876,17 @@ class LocalMiniappRuntime {
|
|
|
813
876
|
this.initialized = true
|
|
814
877
|
console.log(`${LOG_TAG}: initialize()`)
|
|
815
878
|
this.ensurePingLoop()
|
|
879
|
+
mirrorService.initialize()
|
|
880
|
+
// The overlay apps' pages relay through the runtime: the slot going to
|
|
881
|
+
// and from an app arrives as its display_view events.
|
|
882
|
+
overlayPages.setSink({
|
|
883
|
+
send: (packageName, event) =>
|
|
884
|
+
this.sendToMiniapp(packageName, {
|
|
885
|
+
type: MiniappResponseType.EVENT,
|
|
886
|
+
streamType: MiniappStreamType.DISPLAY_VIEW,
|
|
887
|
+
data: event,
|
|
888
|
+
}),
|
|
889
|
+
})
|
|
816
890
|
}
|
|
817
891
|
|
|
818
892
|
/**
|
|
@@ -907,6 +981,7 @@ class LocalMiniappRuntime {
|
|
|
907
981
|
packageName: string,
|
|
908
982
|
sendFn: (raw: string) => void,
|
|
909
983
|
installedManifest?: InstalledMiniappManifest,
|
|
984
|
+
launchSource?: MiniappLaunchSource,
|
|
910
985
|
): void {
|
|
911
986
|
console.log(`${LOG_TAG}: registerApp(${packageName})`)
|
|
912
987
|
this.clearForegroundProbe(packageName)
|
|
@@ -918,6 +993,9 @@ class LocalMiniappRuntime {
|
|
|
918
993
|
// dangling references. The WebView will re-subscribe after its CONNECT.
|
|
919
994
|
if (this.connectedApps.has(packageName)) {
|
|
920
995
|
const existing = this.connectedApps.get(packageName)!
|
|
996
|
+
void glassesSensorService.release(packageName).catch((error) => {
|
|
997
|
+
console.warn(`${LOG_TAG}: sensor cleanup failed on respawn for ${packageName}`, error)
|
|
998
|
+
})
|
|
921
999
|
this.cancelSpeech(packageName)
|
|
922
1000
|
// A crash respawn replaces the ConnectedMiniapp without going through
|
|
923
1001
|
// unregisterApp(). Abort the old incarnation's native PCM player before
|
|
@@ -956,6 +1034,7 @@ class LocalMiniappRuntime {
|
|
|
956
1034
|
authDelivered: false,
|
|
957
1035
|
speakerState: "idle",
|
|
958
1036
|
requestedLocationRate: null,
|
|
1037
|
+
launchSource,
|
|
959
1038
|
})
|
|
960
1039
|
// If we just clobbered an existing entry, its requestedLocationRate is
|
|
961
1040
|
// now gone — recompute so the aggregate doesn't include a stale rate.
|
|
@@ -963,6 +1042,8 @@ class LocalMiniappRuntime {
|
|
|
963
1042
|
this.recomputeLocationTier()
|
|
964
1043
|
this.ensureCloudStatusWired()
|
|
965
1044
|
this.ensureCapabilitiesWired()
|
|
1045
|
+
this.ensurePreferencesWired()
|
|
1046
|
+
this.ensureSettingsBridgeWired()
|
|
966
1047
|
this.ensurePingLoop()
|
|
967
1048
|
|
|
968
1049
|
// Show the system boot message ("Starting <name>…") on the glasses for the
|
|
@@ -988,12 +1069,12 @@ class LocalMiniappRuntime {
|
|
|
988
1069
|
const waiter = (err?: Error) => {
|
|
989
1070
|
if (settled) return
|
|
990
1071
|
settled = true
|
|
991
|
-
clearTimeout(timer)
|
|
1072
|
+
BgTimer.clearTimeout(timer)
|
|
992
1073
|
this.connectWaiters.get(packageName)?.delete(waiter)
|
|
993
1074
|
if (err) reject(err)
|
|
994
1075
|
else resolve()
|
|
995
1076
|
}
|
|
996
|
-
const timer = setTimeout(() => {
|
|
1077
|
+
const timer = BgTimer.setTimeout(() => {
|
|
997
1078
|
waiter(new Error(`waitForConnect: ${packageName} did not connect within ${timeoutMs}ms`))
|
|
998
1079
|
}, timeoutMs)
|
|
999
1080
|
let set = this.connectWaiters.get(packageName)
|
|
@@ -1065,7 +1146,7 @@ class LocalMiniappRuntime {
|
|
|
1065
1146
|
// 50 ms: imperceptible to the user, plenty of time for the SDK's
|
|
1066
1147
|
// synchronous `beforeDisconnect` handlers to flush a final
|
|
1067
1148
|
// sendOneShot through the still-open transport.
|
|
1068
|
-
await new Promise<void>((resolve) => setTimeout(resolve, 50))
|
|
1149
|
+
await new Promise<void>((resolve) => BgTimer.setTimeout(resolve, 50))
|
|
1069
1150
|
this.unregisterApp(packageName)
|
|
1070
1151
|
}
|
|
1071
1152
|
|
|
@@ -1083,6 +1164,14 @@ class LocalMiniappRuntime {
|
|
|
1083
1164
|
// Drop this app's transcription hints; the cloud subscription rebuild
|
|
1084
1165
|
// below (via replaceStreamSubscribers) re-derives the hint union without it.
|
|
1085
1166
|
this.transcriptionHintsByApp.delete(packageName)
|
|
1167
|
+
// An overlay app is going: release the slot if it holds it, and drop the
|
|
1168
|
+
// dashboard view from its capabilities record.
|
|
1169
|
+
if (isOverlayApp(packageName)) {
|
|
1170
|
+
overlayPages.remove(packageName)
|
|
1171
|
+
removeOverlayApp(packageName)
|
|
1172
|
+
}
|
|
1173
|
+
// Its gesture claims go back to whoever claimed them before.
|
|
1174
|
+
this.applyGestureClaimChanges(dropGestureClaims(this.gestureClaims, packageName))
|
|
1086
1175
|
|
|
1087
1176
|
// Warm-up is a request-owned camera lease. Cancel it even if the app record was already
|
|
1088
1177
|
// removed so a close racing the camera-open promise cannot leave the sensor running.
|
|
@@ -1150,11 +1239,16 @@ class LocalMiniappRuntime {
|
|
|
1150
1239
|
this.navigationHandlers.onDisconnect(packageName)
|
|
1151
1240
|
}
|
|
1152
1241
|
|
|
1242
|
+
void glassesSensorService.release(packageName).catch((error) => {
|
|
1243
|
+
console.warn(`${LOG_TAG}: sensor cleanup failed for ${packageName}`, error)
|
|
1244
|
+
})
|
|
1245
|
+
|
|
1153
1246
|
// Recompute heading subscription — if this app was the last subscriber,
|
|
1154
1247
|
// the sensor will stop.
|
|
1155
1248
|
this.recomputeHeadingSubscription()
|
|
1156
|
-
// Same for the IMU/accelerometer
|
|
1249
|
+
// Same for the IMU/accelerometer and glasses compass streams.
|
|
1157
1250
|
this.recomputeImuSubscription()
|
|
1251
|
+
this.recomputeCompassSubscription()
|
|
1158
1252
|
|
|
1159
1253
|
// Drop this app's location-tier request before recomputing so the
|
|
1160
1254
|
// aggregate falls back down if it was the strictest. Done before
|
|
@@ -1176,7 +1270,6 @@ class LocalMiniappRuntime {
|
|
|
1176
1270
|
// core app's saved frame).
|
|
1177
1271
|
localDisplayManager.onUnmount(packageName)
|
|
1178
1272
|
|
|
1179
|
-
this.gestureClaims.delete(packageName)
|
|
1180
1273
|
this.connectedApps.delete(packageName)
|
|
1181
1274
|
this.recomputeMicRequirements()
|
|
1182
1275
|
if (releasedMicGateOverride) {
|
|
@@ -1261,9 +1354,30 @@ class LocalMiniappRuntime {
|
|
|
1261
1354
|
case MiniappRequestType.DISPLAY:
|
|
1262
1355
|
this.handleDisplay(packageName, payload, requestId)
|
|
1263
1356
|
break
|
|
1357
|
+
case MiniappRequestType.MIRROR_GET:
|
|
1358
|
+
if (!this.hasMirrorPermission(packageName)) {
|
|
1359
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
1360
|
+
code: MiniappErrorCode.PERMISSION_NOT_DECLARED,
|
|
1361
|
+
message: "DISPLAY_MIRROR permission not declared in miniapp.json",
|
|
1362
|
+
permission: "DISPLAY_MIRROR",
|
|
1363
|
+
})
|
|
1364
|
+
} else this.sendResult(packageName, requestId, true, mirrorService.current())
|
|
1365
|
+
break
|
|
1264
1366
|
case MiniappRequestType.RENDER:
|
|
1265
1367
|
this.handleRender(packageName, payload, requestId)
|
|
1266
1368
|
break
|
|
1369
|
+
case MiniappRequestType.SHOW_VIEW:
|
|
1370
|
+
this.handleShowView(packageName, payload, requestId)
|
|
1371
|
+
break
|
|
1372
|
+
case MiniappRequestType.SETTINGS_GET:
|
|
1373
|
+
this.handleSettingsGet(packageName, payload, requestId)
|
|
1374
|
+
break
|
|
1375
|
+
case MiniappRequestType.SETTINGS_SET:
|
|
1376
|
+
void this.handleSettingsSet(packageName, payload, requestId)
|
|
1377
|
+
break
|
|
1378
|
+
case MiniappRequestType.NOTIFICATION_APPS_LIST:
|
|
1379
|
+
void this.handleNotificationAppsList(packageName, requestId)
|
|
1380
|
+
break
|
|
1267
1381
|
case MiniappRequestType.NATIVE_NAV:
|
|
1268
1382
|
this.handleNativeNav(packageName, payload, requestId)
|
|
1269
1383
|
break
|
|
@@ -1395,6 +1509,23 @@ class LocalMiniappRuntime {
|
|
|
1395
1509
|
case MiniappRequestType.SET_WIFI_ADB_STATE:
|
|
1396
1510
|
void this.handleSetWifiAdbState(packageName, payload, requestId)
|
|
1397
1511
|
break
|
|
1512
|
+
case MiniappRequestType.GLASSES_SENSOR_CONTROL:
|
|
1513
|
+
if (!this.connectedApps.has(packageName)) {
|
|
1514
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
1515
|
+
code: MiniappErrorCode.NOT_CONNECTED,
|
|
1516
|
+
message: "Miniapp disconnected",
|
|
1517
|
+
})
|
|
1518
|
+
break
|
|
1519
|
+
}
|
|
1520
|
+
void glassesSensorService.request(packageName, payload).then(
|
|
1521
|
+
() => this.sendResult(packageName, requestId, true),
|
|
1522
|
+
(error: unknown) =>
|
|
1523
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
1524
|
+
code: (error as {code?: string}).code || MiniappErrorCode.INTERNAL,
|
|
1525
|
+
message: error instanceof Error ? error.message : "Sensor control failed",
|
|
1526
|
+
}),
|
|
1527
|
+
)
|
|
1528
|
+
break
|
|
1398
1529
|
case MiniappRequestType.IMU_SET_ENABLED:
|
|
1399
1530
|
this.handleImuSetEnabled(packageName, payload, requestId)
|
|
1400
1531
|
break
|
|
@@ -1420,6 +1551,15 @@ class LocalMiniappRuntime {
|
|
|
1420
1551
|
case MiniappRequestType.OPEN_URL:
|
|
1421
1552
|
this.handleOpenUrl(packageName, payload)
|
|
1422
1553
|
break
|
|
1554
|
+
case MiniappRequestType.DISPLAY_DIAGNOSTICS: {
|
|
1555
|
+
const enabled = useSettingsStore.getState().getSetting(SETTINGS.debug_console.key) === true
|
|
1556
|
+
this.sendResult(packageName, requestId, true, {
|
|
1557
|
+
enabled,
|
|
1558
|
+
generatedAt: Date.now(),
|
|
1559
|
+
records: enabled ? collectDisplayDiagnostics(logBuffer.getRecentLogs()) : [],
|
|
1560
|
+
})
|
|
1561
|
+
break
|
|
1562
|
+
}
|
|
1423
1563
|
case MiniappRequestType.COPY_CLIPBOARD:
|
|
1424
1564
|
this.handleCopyClipboard(packageName, payload, requestId)
|
|
1425
1565
|
break
|
|
@@ -1609,7 +1749,10 @@ class LocalMiniappRuntime {
|
|
|
1609
1749
|
existing.lastPongAt = Date.now()
|
|
1610
1750
|
existing.unansweredPingRounds = 0
|
|
1611
1751
|
|
|
1612
|
-
|
|
1752
|
+
// A system_dashboard app may take the overlay slot: its capabilities
|
|
1753
|
+
// carry the dashboard view from the start.
|
|
1754
|
+
if (existing.installedManifest?.type === "system_dashboard") addOverlayApp(packageName)
|
|
1755
|
+
const capabilities = this.capabilitiesFor(packageName)
|
|
1613
1756
|
|
|
1614
1757
|
// Build the declared-permission record for the SDK's session.permissions
|
|
1615
1758
|
// module. Lower-cased to match v3's PermissionType union (microphone,
|
|
@@ -1624,7 +1767,7 @@ class LocalMiniappRuntime {
|
|
|
1624
1767
|
this.clearMiniappAuthDeliveryRetry(packageName)
|
|
1625
1768
|
const authPromise = this.requestMiniappAuth(packageName)
|
|
1626
1769
|
const initialAuth = await withTimeout(authPromise, 1_500)
|
|
1627
|
-
const userId = initialAuth?.
|
|
1770
|
+
const userId = initialAuth?.userId ?? ""
|
|
1628
1771
|
if (initialAuth) {
|
|
1629
1772
|
existing.authDelivered = true
|
|
1630
1773
|
this.scheduleMiniappAuthRefresh(packageName, initialAuth)
|
|
@@ -1637,7 +1780,10 @@ class LocalMiniappRuntime {
|
|
|
1637
1780
|
userId,
|
|
1638
1781
|
packageName,
|
|
1639
1782
|
capabilities,
|
|
1783
|
+
preferences: this.currentPreferences(),
|
|
1784
|
+
visibility: this.currentVisibility(),
|
|
1640
1785
|
permissions: declaredPermissions,
|
|
1786
|
+
...(existing.launchSource ? {launchSource: existing.launchSource} : {}),
|
|
1641
1787
|
...(initialAuth ? {auth: initialAuth} : {}),
|
|
1642
1788
|
},
|
|
1643
1789
|
requestId,
|
|
@@ -1867,11 +2013,10 @@ class LocalMiniappRuntime {
|
|
|
1867
2013
|
|
|
1868
2014
|
/**
|
|
1869
2015
|
* CLAIM_GESTURES (session.input.setClaimedGestures): the app declares which
|
|
1870
|
-
* touch gestures it handles itself, replacing its previous claim set.
|
|
1871
|
-
*
|
|
1872
|
-
*
|
|
1873
|
-
*
|
|
1874
|
-
* {@link foregroundClaimsGesture}. Cleared on app stop.
|
|
2016
|
+
* touch gestures it handles itself, replacing its previous claim set. The
|
|
2017
|
+
* most recent claimer of a gesture holds it and gets it alone; releasing
|
|
2018
|
+
* hands it back to the previous claimer, and both hear the change on the
|
|
2019
|
+
* gesture_claim stream. Cleared on app stop.
|
|
1875
2020
|
*/
|
|
1876
2021
|
private handleClaimGestures(packageName: string, payload: Record<string, unknown>, requestId?: string): void {
|
|
1877
2022
|
if (!this.connectedApps.has(packageName)) {
|
|
@@ -1880,19 +2025,39 @@ class LocalMiniappRuntime {
|
|
|
1880
2025
|
}
|
|
1881
2026
|
const raw = payload.gestures
|
|
1882
2027
|
const gestures = Array.isArray(raw) ? raw.filter((g): g is string => typeof g === "string") : []
|
|
1883
|
-
if (
|
|
1884
|
-
|
|
2028
|
+
if (payload.scope !== undefined && (typeof payload.scope !== "string" || payload.scope.length === 0)) {
|
|
2029
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2030
|
+
code: MiniappErrorCode.INVALID_ARGUMENT,
|
|
2031
|
+
message: "Gesture claim scope must be a nonempty string",
|
|
2032
|
+
})
|
|
2033
|
+
return
|
|
2034
|
+
}
|
|
2035
|
+
this.applyGestureClaimChanges(
|
|
2036
|
+
setGestureClaims(this.gestureClaims, packageName, gestures, payload.scope as string | undefined),
|
|
2037
|
+
)
|
|
1885
2038
|
this.sendResult(packageName, requestId, true)
|
|
1886
2039
|
}
|
|
1887
2040
|
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
this.
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
2041
|
+
private applyGestureClaimChanges(result: {state: GestureClaimState; changes: GestureClaimChange[]}): void {
|
|
2042
|
+
this.gestureClaims = result.state
|
|
2043
|
+
for (const change of result.changes) {
|
|
2044
|
+
this.forwardEvent(
|
|
2045
|
+
MiniappStreamType.GESTURE_CLAIM,
|
|
2046
|
+
{gesture: change.gesture, held: change.held},
|
|
2047
|
+
undefined,
|
|
2048
|
+
change.packageName,
|
|
2049
|
+
)
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
/** The app holding `gesture` (the most recent claimer), or null when it is unclaimed. */
|
|
2054
|
+
public gestureClaimant(gesture: string): string | null {
|
|
2055
|
+
return gestureClaimant(this.gestureClaims, gesture)
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
/** Has this app registered the gesture, even if a later claimant currently receives it? */
|
|
2059
|
+
public hasGestureClaim(packageName: string, gesture: string): boolean {
|
|
2060
|
+
return hasGestureClaim(this.gestureClaims, packageName, gesture)
|
|
1896
2061
|
}
|
|
1897
2062
|
|
|
1898
2063
|
private handleSubscribe(packageName: string, payload: Record<string, unknown>, requestId?: string): void {
|
|
@@ -1944,9 +2109,10 @@ class LocalMiniappRuntime {
|
|
|
1944
2109
|
const declaredTypes = new Set((app.installedManifest?.permissions ?? []).map((p) => p.type?.toUpperCase()))
|
|
1945
2110
|
|
|
1946
2111
|
const permissionForStream = (s: string): string | null => {
|
|
2112
|
+
if (s === MiniappStreamType.MIRROR_UPDATE) return "DISPLAY_MIRROR"
|
|
1947
2113
|
if (s === "audio_chunk" || s === "vad") return "MICROPHONE"
|
|
1948
2114
|
if (s.startsWith("transcription") || s.startsWith("translation")) return "MICROPHONE"
|
|
1949
|
-
if (s === "location_update") return "LOCATION"
|
|
2115
|
+
if (s === "location_update" || s === "heading_update") return "LOCATION"
|
|
1950
2116
|
if (s === "phone_notification") return "READ_NOTIFICATIONS"
|
|
1951
2117
|
if (s === "phone_notification_dismissed") return "READ_NOTIFICATIONS"
|
|
1952
2118
|
return null
|
|
@@ -1968,6 +2134,15 @@ class LocalMiniappRuntime {
|
|
|
1968
2134
|
}
|
|
1969
2135
|
}
|
|
1970
2136
|
|
|
2137
|
+
// The settings stream carries the wearer's settings: system apps only.
|
|
2138
|
+
if (streams.includes(MiniappStreamType.SETTINGS_CHANGED) && !this.isSystemPackage(packageName)) {
|
|
2139
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2140
|
+
code: MiniappErrorCode.NOT_PERMITTED,
|
|
2141
|
+
message: "The settings stream is restricted to system apps",
|
|
2142
|
+
})
|
|
2143
|
+
return
|
|
2144
|
+
}
|
|
2145
|
+
|
|
1971
2146
|
// Add new subscriptions
|
|
1972
2147
|
const previousSubscriptions = app.subscriptions
|
|
1973
2148
|
app.subscriptions = new Set(streams)
|
|
@@ -1978,11 +2153,16 @@ class LocalMiniappRuntime {
|
|
|
1978
2153
|
[...cloudTranscriptionStreams].filter((stream) => app.subscriptions.has(stream)),
|
|
1979
2154
|
)
|
|
1980
2155
|
this.replaceStreamSubscribers(packageName, previousSubscriptions, app.subscriptions)
|
|
2156
|
+
// An overlay app that listens to phone notifications presents them on the glasses.
|
|
2157
|
+
if (isOverlayApp(packageName)) {
|
|
2158
|
+
setOverlayViewer(packageName, app.subscriptions.has(MiniappStreamType.PHONE_NOTIFICATION))
|
|
2159
|
+
}
|
|
1981
2160
|
|
|
1982
2161
|
this.recomputeMicRequirements()
|
|
1983
2162
|
this.updateCloudSubscriptions()
|
|
1984
2163
|
this.recomputeHeadingSubscription()
|
|
1985
2164
|
this.recomputeImuSubscription()
|
|
2165
|
+
this.recomputeCompassSubscription()
|
|
1986
2166
|
// Persist this app's requested rate (or clear it if SUBSCRIBE didn't
|
|
1987
2167
|
// include `location_stream` this time), then ask the host for the
|
|
1988
2168
|
// strictest rate across all connected apps.
|
|
@@ -2043,7 +2223,13 @@ class LocalMiniappRuntime {
|
|
|
2043
2223
|
const isSimulated = (glassesState.deviceModel || "").toLowerCase().includes("simulated")
|
|
2044
2224
|
|
|
2045
2225
|
for (const stream of streams) {
|
|
2046
|
-
if (stream ===
|
|
2226
|
+
if (stream === MiniappStreamType.MIRROR_UPDATE && this.hasMirrorPermission(packageName)) {
|
|
2227
|
+
this.sendToMiniapp(packageName, {
|
|
2228
|
+
type: MiniappResponseType.EVENT,
|
|
2229
|
+
streamType: MiniappStreamType.MIRROR_UPDATE,
|
|
2230
|
+
data: mirrorService.current(),
|
|
2231
|
+
})
|
|
2232
|
+
} else if (stream === "glasses_battery") {
|
|
2047
2233
|
// Simulated glasses have no real battery; mirror the phone's battery
|
|
2048
2234
|
// so miniapps see a sensible value during development.
|
|
2049
2235
|
if (isSimulated) {
|
|
@@ -2089,6 +2275,15 @@ class LocalMiniappRuntime {
|
|
|
2089
2275
|
timestamp: Date.now(),
|
|
2090
2276
|
},
|
|
2091
2277
|
})
|
|
2278
|
+
} else if (stream === MiniappStreamType.SETTINGS_CHANGED) {
|
|
2279
|
+
// Replay every bridged key so a mirror can be built from the stream alone.
|
|
2280
|
+
for (const key of selectSettingsBridgeKeys(undefined)) {
|
|
2281
|
+
this.sendToMiniapp(packageName, {
|
|
2282
|
+
type: MiniappResponseType.EVENT,
|
|
2283
|
+
streamType: MiniappStreamType.SETTINGS_CHANGED,
|
|
2284
|
+
data: {key, value: this.settingsBridgeValue(key)},
|
|
2285
|
+
})
|
|
2286
|
+
}
|
|
2092
2287
|
} else if (stream === "head_position") {
|
|
2093
2288
|
// The glasses store has no headUp field (same on the pre-engine host
|
|
2094
2289
|
// hook), so this stays a no-emit until head state lands in the store.
|
|
@@ -2191,6 +2386,16 @@ class LocalMiniappRuntime {
|
|
|
2191
2386
|
})
|
|
2192
2387
|
return
|
|
2193
2388
|
}
|
|
2389
|
+
// The dashboard view is the overlay apps' alone; anyone else's frame
|
|
2390
|
+
// is dropped, reported rather than silently lost.
|
|
2391
|
+
if (payload.view === "dashboard" && !isOverlayApp(packageName)) {
|
|
2392
|
+
this.sendResult(packageName, requestId, true, {
|
|
2393
|
+
status: "displayed",
|
|
2394
|
+
presented: false,
|
|
2395
|
+
reason: "not the dashboard app",
|
|
2396
|
+
})
|
|
2397
|
+
return
|
|
2398
|
+
}
|
|
2194
2399
|
|
|
2195
2400
|
localDisplayManager.request(
|
|
2196
2401
|
packageName,
|
|
@@ -2210,6 +2415,174 @@ class LocalMiniappRuntime {
|
|
|
2210
2415
|
}
|
|
2211
2416
|
}
|
|
2212
2417
|
|
|
2418
|
+
/**
|
|
2419
|
+
* display.showView: the designated dashboard app takes or releases the
|
|
2420
|
+
* overlay slot. Refused (NOT_PERMITTED) for any other app; "unsupported"
|
|
2421
|
+
* while the glasses cannot show the dashboard view. Idempotent either way;
|
|
2422
|
+
* the slot's state comes back to the app as a display_view change.
|
|
2423
|
+
*/
|
|
2424
|
+
private handleShowView(packageName: string, payload: Record<string, unknown>, requestId?: string): void {
|
|
2425
|
+
if (!this.connectedApps.has(packageName)) {
|
|
2426
|
+
this.sendResult(packageName, requestId, true, {status: "unsupported", reason: "app stopped"})
|
|
2427
|
+
return
|
|
2428
|
+
}
|
|
2429
|
+
const view = payload.view
|
|
2430
|
+
if (view !== "main" && view !== "dashboard") {
|
|
2431
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2432
|
+
code: MiniappErrorCode.INVALID_ARGUMENT,
|
|
2433
|
+
message: 'showView takes "main" or "dashboard"',
|
|
2434
|
+
})
|
|
2435
|
+
return
|
|
2436
|
+
}
|
|
2437
|
+
if (!isOverlayApp(packageName)) {
|
|
2438
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2439
|
+
code: MiniappErrorCode.NOT_PERMITTED,
|
|
2440
|
+
message: "The dashboard view belongs to system_dashboard apps",
|
|
2441
|
+
})
|
|
2442
|
+
return
|
|
2443
|
+
}
|
|
2444
|
+
if (view === "main") {
|
|
2445
|
+
overlayPages.hide(packageName)
|
|
2446
|
+
this.sendResult(packageName, requestId, true, {status: "shown"})
|
|
2447
|
+
return
|
|
2448
|
+
}
|
|
2449
|
+
if (!pagesEligible()) {
|
|
2450
|
+
this.sendResult(packageName, requestId, true, {
|
|
2451
|
+
status: "unsupported",
|
|
2452
|
+
reason: "glasses cannot show the dashboard",
|
|
2453
|
+
})
|
|
2454
|
+
return
|
|
2455
|
+
}
|
|
2456
|
+
dashboardOpenTrace.showViewRequested(packageName)
|
|
2457
|
+
const shown = overlayPages.show(packageName)
|
|
2458
|
+
if (shown) dashboardOpenTrace.slotGranted()
|
|
2459
|
+
this.sendResult(
|
|
2460
|
+
packageName,
|
|
2461
|
+
requestId,
|
|
2462
|
+
true,
|
|
2463
|
+
shown ? {status: "shown"} : {status: "unsupported", reason: "the overlay slot was refused"},
|
|
2464
|
+
)
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
// ---------------------------------------------------------------------------
|
|
2468
|
+
// Settings bridge (session.settings) — system apps only
|
|
2469
|
+
// ---------------------------------------------------------------------------
|
|
2470
|
+
|
|
2471
|
+
private requireSystemForSettings(packageName: string, requestId: string | undefined): boolean {
|
|
2472
|
+
if (this.isSystemPackage(packageName)) return true
|
|
2473
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2474
|
+
code: MiniappErrorCode.NOT_PERMITTED,
|
|
2475
|
+
message: "The settings bridge is restricted to system apps",
|
|
2476
|
+
})
|
|
2477
|
+
return false
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
/** A bridged key's current value: the store's, or the engine's for a derived key. */
|
|
2481
|
+
private settingsBridgeValue(key: string): unknown {
|
|
2482
|
+
if (isDerivedSettingsKey(key)) return this.derivedSettingValue(key)
|
|
2483
|
+
return useSettingsStore.getState().getSetting(key) ?? null
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
private derivedSettingValue(key: DerivedSettingsKey): unknown {
|
|
2487
|
+
switch (key) {
|
|
2488
|
+
case "phone_active":
|
|
2489
|
+
return isPhoneActive()
|
|
2490
|
+
case "foreground_app_on_screen":
|
|
2491
|
+
return localDisplayManager.foregroundAppOnScreen()
|
|
2492
|
+
case "ring_battery":
|
|
2493
|
+
return ringBatteryFrom(useGlassesStore.getState())
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
private handleSettingsGet(packageName: string, payload: Record<string, unknown>, requestId?: string): void {
|
|
2498
|
+
if (!this.requireSystemForSettings(packageName, requestId)) return
|
|
2499
|
+
const values: Record<string, unknown> = {}
|
|
2500
|
+
for (const key of selectSettingsBridgeKeys(payload.keys)) values[key] = this.settingsBridgeValue(key)
|
|
2501
|
+
this.sendResult(packageName, requestId, true, {values})
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
private async handleSettingsSet(
|
|
2505
|
+
packageName: string,
|
|
2506
|
+
payload: Record<string, unknown>,
|
|
2507
|
+
requestId?: string,
|
|
2508
|
+
): Promise<void> {
|
|
2509
|
+
if (!this.requireSystemForSettings(packageName, requestId)) return
|
|
2510
|
+
const validated = validateSettingsSet(payload)
|
|
2511
|
+
if (!validated.ok) {
|
|
2512
|
+
this.sendResult(packageName, requestId, false, undefined, {code: validated.code, message: validated.message})
|
|
2513
|
+
return
|
|
2514
|
+
}
|
|
2515
|
+
// Through the store, so persistence, server sync and the Bluetooth sync
|
|
2516
|
+
// of glasses settings behave as if a phone screen wrote it.
|
|
2517
|
+
const result = await useSettingsStore.getState().setSetting(validated.key, validated.value)
|
|
2518
|
+
if (result.is_error()) {
|
|
2519
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2520
|
+
code: MiniappErrorCode.INTERNAL,
|
|
2521
|
+
message: result.error.message,
|
|
2522
|
+
})
|
|
2523
|
+
return
|
|
2524
|
+
}
|
|
2525
|
+
this.sendResult(packageName, requestId, true)
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
private async handleNotificationAppsList(packageName: string, requestId?: string): Promise<void> {
|
|
2529
|
+
if (!this.requireSystemForSettings(packageName, requestId)) return
|
|
2530
|
+
try {
|
|
2531
|
+
this.sendResult(packageName, requestId, true, await installedNotificationApps())
|
|
2532
|
+
} catch (err) {
|
|
2533
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2534
|
+
code: MiniappErrorCode.INTERNAL,
|
|
2535
|
+
message: err instanceof Error ? err.message : "Failed to list notification apps",
|
|
2536
|
+
})
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
/**
|
|
2541
|
+
* Push bridged settings as they change: stored keys from the store, the
|
|
2542
|
+
* derived keys whenever their inputs move (phone activity, the display,
|
|
2543
|
+
* the apps store, the ring). Subscribers are system apps only (gated at
|
|
2544
|
+
* SUBSCRIBE), so this is a no-op fan-out for everyone else.
|
|
2545
|
+
*/
|
|
2546
|
+
private ensureSettingsBridgeWired(): void {
|
|
2547
|
+
if (this.settingsBridgeWired) return
|
|
2548
|
+
this.settingsBridgeWired = true
|
|
2549
|
+
const storedKeys = Object.keys(SETTINGS_BRIDGE_KEYS)
|
|
2550
|
+
const emit = (key: string, value: unknown) => this.forwardEvent(MiniappStreamType.SETTINGS_CHANGED, {key, value})
|
|
2551
|
+
useSettingsStore.subscribe(
|
|
2552
|
+
(s) => storedKeys.map((key) => JSON.stringify(s.getSetting(key) ?? null)),
|
|
2553
|
+
(next, previous) => {
|
|
2554
|
+
storedKeys.forEach((key, i) => {
|
|
2555
|
+
if (next[i] !== previous[i]) emit(key, this.settingsBridgeValue(key))
|
|
2556
|
+
})
|
|
2557
|
+
},
|
|
2558
|
+
{equalityFn: (a, b) => a.length === b.length && a.every((value, i) => value === b[i])},
|
|
2559
|
+
)
|
|
2560
|
+
const pushDerived = () => {
|
|
2561
|
+
for (const key of DERIVED_SETTINGS_KEYS) {
|
|
2562
|
+
const value = this.derivedSettingValue(key)
|
|
2563
|
+
const encoded = JSON.stringify(value ?? null)
|
|
2564
|
+
if (this.derivedSettings.get(key) === encoded) continue
|
|
2565
|
+
this.derivedSettings.set(key, encoded)
|
|
2566
|
+
emit(key, value)
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
for (const key of DERIVED_SETTINGS_KEYS) {
|
|
2570
|
+
this.derivedSettings.set(key, JSON.stringify(this.derivedSettingValue(key) ?? null))
|
|
2571
|
+
}
|
|
2572
|
+
onPhoneActivityChange(pushDerived)
|
|
2573
|
+
// App foreground/background drives VISIBILITY_CHANGE. Background execution
|
|
2574
|
+
// limits (timer coalescing, BLE credit polling) follow the app's own
|
|
2575
|
+
// foreground bit, not `isPhoneActive()` — which counts an unlocked phone as
|
|
2576
|
+
// active even while the app is suspended behind it.
|
|
2577
|
+
onAppForegroundChange((foregrounded) => this.broadcastVisibility(foregrounded))
|
|
2578
|
+
localDisplayManager.onActiveDisplayChange(pushDerived)
|
|
2579
|
+
useAppStatusStore.subscribe(pushDerived)
|
|
2580
|
+
useGlassesStore.subscribe(
|
|
2581
|
+
(s) => `${s.ringConnected}:${s.ringBatteryLevel}:${s.controllerConnected}:${s.controllerBatteryLevel}`,
|
|
2582
|
+
pushDerived,
|
|
2583
|
+
)
|
|
2584
|
+
}
|
|
2585
|
+
|
|
2213
2586
|
/**
|
|
2214
2587
|
* Native nav UI feed (display.sendNativeNav*). Gated on the device's nav
|
|
2215
2588
|
* mode being active (trip-scoped); the miniapp's first pushes can race the
|
|
@@ -2223,6 +2596,7 @@ class LocalMiniappRuntime {
|
|
|
2223
2596
|
return
|
|
2224
2597
|
}
|
|
2225
2598
|
const sent = nativeNavigationService.handleMiniappRequest(payload)
|
|
2599
|
+
if (sent) mirrorService.invalidate("firmware-navigation")
|
|
2226
2600
|
this.sendResult(packageName, requestId, true, {
|
|
2227
2601
|
status: sent ? "sent" : "unsupported",
|
|
2228
2602
|
...(sent ? {} : {reason: "native navigation unavailable"}),
|
|
@@ -2252,6 +2626,7 @@ class LocalMiniappRuntime {
|
|
|
2252
2626
|
this.sendResult(packageName, requestId, true, {status: "unsupported", reason: "no glasses connected"})
|
|
2253
2627
|
return
|
|
2254
2628
|
}
|
|
2629
|
+
mirrorService.invalidate("firmware-dashboard")
|
|
2255
2630
|
void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {
|
|
2256
2631
|
console.error(`${LOG_TAG}: showDashboard failed:`, err)
|
|
2257
2632
|
})
|
|
@@ -2923,13 +3298,13 @@ class LocalMiniappRuntime {
|
|
|
2923
3298
|
private readonly blobStore = new BlobStore({
|
|
2924
3299
|
sendResult: (packageName, requestId, ok, result, error) =>
|
|
2925
3300
|
this.sendResult(packageName, requestId, ok, result, error),
|
|
2926
|
-
getUserId: () => cloudClientService.
|
|
3301
|
+
getUserId: () => cloudClientService.getUserId(),
|
|
2927
3302
|
})
|
|
2928
3303
|
private readonly blobRequestQueues = new Map<string, Promise<void>>()
|
|
2929
3304
|
|
|
2930
3305
|
private readonly simpleStorage = new LocalMiniappStorage({
|
|
2931
3306
|
backend: localMiniappStorageBackend,
|
|
2932
|
-
getUserId: () => cloudClientService.
|
|
3307
|
+
getUserId: () => cloudClientService.resolveUserId(),
|
|
2933
3308
|
})
|
|
2934
3309
|
|
|
2935
3310
|
/**
|
|
@@ -2946,7 +3321,7 @@ class LocalMiniappRuntime {
|
|
|
2946
3321
|
const previous = this.blobRequestQueues.get(packageName) ?? Promise.resolve()
|
|
2947
3322
|
const queued = previous.then(async () => {
|
|
2948
3323
|
try {
|
|
2949
|
-
await cloudClientService.
|
|
3324
|
+
await cloudClientService.resolveUserId()
|
|
2950
3325
|
} catch (err) {
|
|
2951
3326
|
console.error(`${LOG_TAG}: blob identity error:`, err)
|
|
2952
3327
|
this.sendResult(packageName, requestId, false, undefined, {
|
|
@@ -2988,7 +3363,7 @@ class LocalMiniappRuntime {
|
|
|
2988
3363
|
}
|
|
2989
3364
|
|
|
2990
3365
|
/**
|
|
2991
|
-
*
|
|
3366
|
+
* Phone heading is a sensor stream — start the phone compass when any mini
|
|
2992
3367
|
* app is subscribed to "heading_update", stop it when none are.
|
|
2993
3368
|
*/
|
|
2994
3369
|
private headingUnsub: (() => void) | null = null
|
|
@@ -3019,6 +3394,18 @@ class LocalMiniappRuntime {
|
|
|
3019
3394
|
void BluetoothSdk.setImuEnabled(wantsImu)
|
|
3020
3395
|
}
|
|
3021
3396
|
|
|
3397
|
+
/**
|
|
3398
|
+
* Glasses compass is demand-driven: GlassesSensorService runs it while any
|
|
3399
|
+
* miniapp is subscribed to "glasses_compass" (custom firmware), serving the
|
|
3400
|
+
* tightest sampling any subscriber asked for via session.compass.start().
|
|
3401
|
+
*/
|
|
3402
|
+
private recomputeCompassSubscription(): void {
|
|
3403
|
+
const subscribers = this.streamSubscribers.get(MiniappStreamType.GLASSES_COMPASS) ?? new Set<string>()
|
|
3404
|
+
void glassesSensorService.setCompassSubscribers(subscribers).catch((error) => {
|
|
3405
|
+
console.warn(`${LOG_TAG}: compass subscription update failed`, error)
|
|
3406
|
+
})
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3022
3409
|
/**
|
|
3023
3410
|
* Last rate we asked the host for. Lets us skip the cross-process call
|
|
3024
3411
|
* when nothing actually changed (most SUBSCRIBE / unregister churn
|
|
@@ -3767,7 +4154,7 @@ class LocalMiniappRuntime {
|
|
|
3767
4154
|
})
|
|
3768
4155
|
}
|
|
3769
4156
|
|
|
3770
|
-
await new Promise((resolve) => setTimeout(resolve, GENERATE_JOB_POLL_MS))
|
|
4157
|
+
await new Promise<void>((resolve) => BgTimer.setTimeout(resolve, GENERATE_JOB_POLL_MS))
|
|
3771
4158
|
}
|
|
3772
4159
|
}
|
|
3773
4160
|
|
|
@@ -3935,11 +4322,7 @@ class LocalMiniappRuntime {
|
|
|
3935
4322
|
* session.system.scanQr — host camera overlay. Must not clear miniapp
|
|
3936
4323
|
* foreground; the host seam is responsible for presenting a Modal on top.
|
|
3937
4324
|
*/
|
|
3938
|
-
private async handleScanQr(
|
|
3939
|
-
packageName: string,
|
|
3940
|
-
payload: Record<string, unknown>,
|
|
3941
|
-
requestId?: string,
|
|
3942
|
-
): Promise<void> {
|
|
4325
|
+
private async handleScanQr(packageName: string, payload: Record<string, unknown>, requestId?: string): Promise<void> {
|
|
3943
4326
|
try {
|
|
3944
4327
|
const result = await invokeScanQrSeam(getUiSeams().scanQr, payload)
|
|
3945
4328
|
this.sendResult(packageName, requestId, true, result)
|
|
@@ -4403,6 +4786,10 @@ class LocalMiniappRuntime {
|
|
|
4403
4786
|
}
|
|
4404
4787
|
}
|
|
4405
4788
|
|
|
4789
|
+
if (streams.includes(MiniappStreamType.MIRROR_UPDATE) && !this.hasMirrorPermission(packageName)) {
|
|
4790
|
+
return {ok: false, error: "DISPLAY_MIRROR permission not declared"}
|
|
4791
|
+
}
|
|
4792
|
+
|
|
4406
4793
|
// Add new subscriptions
|
|
4407
4794
|
const previousSubscriptions = app.subscriptions
|
|
4408
4795
|
app.subscriptions = new Set(streams)
|
|
@@ -4799,12 +5186,55 @@ class LocalMiniappRuntime {
|
|
|
4799
5186
|
private ensureCapabilitiesWired(): void {
|
|
4800
5187
|
if (this.capabilitiesWired) return
|
|
4801
5188
|
this.capabilitiesWired = true
|
|
5189
|
+
const broadcast = () => this.broadcastCapabilities()
|
|
5190
|
+
// Connection, model and firmware also decide the dashboard view's eligibility.
|
|
4802
5191
|
useGlassesStore.subscribe(
|
|
4803
|
-
(s) =>
|
|
5192
|
+
(s) =>
|
|
5193
|
+
`${s.sceneCanvasWidth ?? 0}x${s.sceneCanvasHeight ?? 0}:${s.sceneVector === true}:${s.firmwareVersion}:${s.connection.state}:${s.deviceModel}`,
|
|
5194
|
+
broadcast,
|
|
5195
|
+
)
|
|
5196
|
+
// The debug knob flips hasNativeNavigation on custom firmware.
|
|
5197
|
+
useSettingsStore.subscribe((s) => s.getSetting(SETTINGS.cfw_native_navigation.key), broadcast)
|
|
5198
|
+
// The dashboard master switch flips the dashboard view.
|
|
5199
|
+
useSettingsStore.subscribe((s) => s.getSetting(SETTINGS.custom_dashboard_enabled.key), broadcast)
|
|
5200
|
+
}
|
|
5201
|
+
|
|
5202
|
+
/** Capabilities as `packageName` sees them: the model profile plus the views this app may draw. */
|
|
5203
|
+
private capabilitiesFor(packageName: string): Capabilities {
|
|
5204
|
+
const capabilities = this.currentCapabilities()
|
|
5205
|
+
if (!capabilities.display) return capabilities
|
|
5206
|
+
const views = displayViewsFor(packageName, pagesEligible())
|
|
5207
|
+
return {...capabilities, display: {...capabilities.display, views}}
|
|
5208
|
+
}
|
|
5209
|
+
|
|
5210
|
+
private broadcastCapabilities(): void {
|
|
5211
|
+
for (const packageName of this.handshookApps) {
|
|
5212
|
+
this.sendToMiniapp(packageName, {
|
|
5213
|
+
type: MiniappResponseType.CAPABILITIES_UPDATE,
|
|
5214
|
+
capabilities: this.capabilitiesFor(packageName),
|
|
5215
|
+
})
|
|
5216
|
+
}
|
|
5217
|
+
}
|
|
5218
|
+
|
|
5219
|
+
/** Host user preferences miniapps follow by default (Settings > Appearance). */
|
|
5220
|
+
private currentPreferences(): MiniappPreferences {
|
|
5221
|
+
const settings = useSettingsStore.getState()
|
|
5222
|
+
return {
|
|
5223
|
+
unitSystem: settings.getSetting(SETTINGS.metric_system.key) === true ? "metric" : "imperial",
|
|
5224
|
+
twelveHourTime: settings.getSetting(SETTINGS.twelve_hour_time.key) === true,
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
|
|
5228
|
+
private ensurePreferencesWired(): void {
|
|
5229
|
+
if (this.preferencesWired) return
|
|
5230
|
+
this.preferencesWired = true
|
|
5231
|
+
useSettingsStore.subscribe(
|
|
5232
|
+
(s) =>
|
|
5233
|
+
`${s.getSetting(SETTINGS.metric_system.key) === true}:${s.getSetting(SETTINGS.twelve_hour_time.key) === true}`,
|
|
4804
5234
|
() => {
|
|
4805
|
-
const
|
|
5235
|
+
const preferences = this.currentPreferences()
|
|
4806
5236
|
for (const packageName of this.handshookApps) {
|
|
4807
|
-
this.sendToMiniapp(packageName, {type: MiniappResponseType.
|
|
5237
|
+
this.sendToMiniapp(packageName, {type: MiniappResponseType.PREFERENCES_UPDATE, preferences})
|
|
4808
5238
|
}
|
|
4809
5239
|
},
|
|
4810
5240
|
)
|
|
@@ -4850,7 +5280,13 @@ class LocalMiniappRuntime {
|
|
|
4850
5280
|
* - Cloud sends "head_up" → miniapp protocol uses "head_position" (HEAD_POSITION)
|
|
4851
5281
|
* - Cloud sends "VAD" (uppercase) → miniapp protocol uses "vad" (lowercase)
|
|
4852
5282
|
*/
|
|
4853
|
-
public forwardEvent(
|
|
5283
|
+
public forwardEvent(
|
|
5284
|
+
streamType: string,
|
|
5285
|
+
data: unknown,
|
|
5286
|
+
transcriptionSource?: TranscriptionEventSource,
|
|
5287
|
+
/** Deliver to this subscriber alone (the designated dashboard app's gestures while it shows). */
|
|
5288
|
+
only?: string,
|
|
5289
|
+
): void {
|
|
4854
5290
|
// Local sherpa results enter the runtime only through here (DeviceEventRouter's
|
|
4855
5291
|
// local_transcription listener); cloud/direct are marked at their onTranscript
|
|
4856
5292
|
// wiring, which never passes "local".
|
|
@@ -4958,6 +5394,7 @@ class LocalMiniappRuntime {
|
|
|
4958
5394
|
if (matchedSubs.size === 0 && !perGestureStream) return
|
|
4959
5395
|
|
|
4960
5396
|
for (const packageName of matchedSubs) {
|
|
5397
|
+
if (only !== undefined && packageName !== only) continue
|
|
4961
5398
|
let transcriptionRoute: "default" | "forceLocal" | "all" | undefined
|
|
4962
5399
|
if (normalizedStream.startsWith("transcription:") && transcriptionSource) {
|
|
4963
5400
|
const routes = this.appTranscriptionRoutesForEvent(packageName, normalizedStream)
|
|
@@ -4996,6 +5433,7 @@ class LocalMiniappRuntime {
|
|
|
4996
5433
|
const gestureSubs = this.streamSubscribers.get(perGestureStream)
|
|
4997
5434
|
if (gestureSubs) {
|
|
4998
5435
|
for (const packageName of gestureSubs) {
|
|
5436
|
+
if (only !== undefined && packageName !== only) continue
|
|
4999
5437
|
this.sendToMiniapp(packageName, {
|
|
5000
5438
|
type: MiniappResponseType.EVENT,
|
|
5001
5439
|
streamType: perGestureStream,
|
|
@@ -5260,6 +5698,7 @@ class LocalMiniappRuntime {
|
|
|
5260
5698
|
name: app.name,
|
|
5261
5699
|
version: app.version ?? "",
|
|
5262
5700
|
running: app.running,
|
|
5701
|
+
hidden: app.hidden === true,
|
|
5263
5702
|
compatibility,
|
|
5264
5703
|
actions: app.actions ?? [],
|
|
5265
5704
|
}
|
|
@@ -5636,6 +6075,24 @@ class LocalMiniappRuntime {
|
|
|
5636
6075
|
})
|
|
5637
6076
|
}
|
|
5638
6077
|
|
|
6078
|
+
/**
|
|
6079
|
+
* Push the app's foreground state to every connected miniapp. Miniapps that
|
|
6080
|
+
* pace their own work (streaming a scene, polling a sensor) need to know when
|
|
6081
|
+
* the host process is backgrounded, because that is when iOS coalesces their
|
|
6082
|
+
* timers and the BLE writer falls back to credit polling.
|
|
6083
|
+
*/
|
|
6084
|
+
private broadcastVisibility(foregrounded: boolean): void {
|
|
6085
|
+
const visibility = foregrounded ? "foreground" : "background"
|
|
6086
|
+
for (const packageName of this.connectedApps.keys()) {
|
|
6087
|
+
this.sendVisibilityChange(packageName, visibility)
|
|
6088
|
+
}
|
|
6089
|
+
}
|
|
6090
|
+
|
|
6091
|
+
/** Foreground state a miniapp is given at CONNECT_ACK, before any transition fires. */
|
|
6092
|
+
public currentVisibility(): "foreground" | "background" {
|
|
6093
|
+
return isAppForegrounded() ? "foreground" : "background"
|
|
6094
|
+
}
|
|
6095
|
+
|
|
5639
6096
|
/**
|
|
5640
6097
|
* Fast foreground liveness check used when a local miniapp UI is opened or
|
|
5641
6098
|
* resumed. The normal watchdog intentionally waits ~30s to avoid killing a
|