@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
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
* This runtime handles request dispatch, stream fan-out, and lifecycle
|
|
9
9
|
* management (connect/disconnect/ping).
|
|
10
10
|
*/
|
|
11
|
+
import { mirrorService } from "./MirrorService";
|
|
11
12
|
import { AppState, Linking } from "react-native";
|
|
13
|
+
import { logBuffer } from "../utils/devLogging";
|
|
14
|
+
import { collectDisplayDiagnostics } from "./DisplayDiagnostics";
|
|
12
15
|
import Share from "react-native-share";
|
|
13
16
|
import * as Battery from "expo-battery";
|
|
14
17
|
import * as Clipboard from "expo-clipboard";
|
|
@@ -33,9 +36,17 @@ import { createAnthropicProvider, createGeminiProvider, createOpenAiProvider, }
|
|
|
33
36
|
import { normalizeAiTier, resolveAiTier } from "./AiTierResolution";
|
|
34
37
|
import { HttpError } from "@glassly/cloud-client";
|
|
35
38
|
import localDisplayManager from "./LocalDisplayManager";
|
|
36
|
-
import {
|
|
39
|
+
import { dropGestureClaims, emptyGestureClaims, gestureClaimant, hasGestureClaim, setGestureClaims, } from "./gestureClaims";
|
|
40
|
+
import overlayPages from "./pages/OverlayPages";
|
|
41
|
+
import dashboardOpenTrace from "./debug/DashboardOpenTrace";
|
|
42
|
+
import { isAppForegrounded, isPhoneActive, onAppForegroundChange, onPhoneActivityChange } from "./PhoneActivity";
|
|
43
|
+
import { installedNotificationApps } from "./PhoneNotificationsSync";
|
|
44
|
+
import { DERIVED_SETTINGS_KEYS, SETTINGS_BRIDGE_KEYS, isDerivedSettingsKey, ringBatteryFrom, selectSettingsBridgeKeys, validateSettingsSet, } from "./settingsBridge";
|
|
45
|
+
import { addOverlayApp, displayViewsFor, isOverlayApp, removeOverlayApp, setOverlayViewer } from "./pages/overlayApps";
|
|
46
|
+
import { pagesEligible } from "./pages/pageEligibility";
|
|
37
47
|
import nativeNavigationService from "./NativeNavigationService";
|
|
38
48
|
import headingService from "./HeadingService";
|
|
49
|
+
import glassesSensorService from "./GlassesSensorService";
|
|
39
50
|
import localSttFallbackCoordinator from "./LocalSttFallbackCoordinator";
|
|
40
51
|
import speakerLabelResolver from "./SpeakerLabelResolver";
|
|
41
52
|
import micStateCoordinator from "./MicStateCoordinator";
|
|
@@ -117,9 +128,12 @@ const SYSTEM_MINIAPP_PACKAGES = new Set([
|
|
|
117
128
|
"com.glassly.simulated",
|
|
118
129
|
"com.glassly.mirror",
|
|
119
130
|
"com.glassly.ai",
|
|
120
|
-
"cloud.augmentos.notify",
|
|
121
131
|
"com.glassly.feedback",
|
|
122
132
|
"com.glassly.miniappdev",
|
|
133
|
+
// The dashboard: the settings bridge and the miniapp list/start/stop are its side menu and settings page.
|
|
134
|
+
"com.glassly.dashboard",
|
|
135
|
+
// The notifications viewer: the settings bridge and the notification app list are its settings page.
|
|
136
|
+
"com.glassly.notifications",
|
|
123
137
|
]);
|
|
124
138
|
const PING_INTERVAL_MS = 5_000;
|
|
125
139
|
// Min gap between "transcription limit reached" notices on the glasses. A
|
|
@@ -194,6 +208,7 @@ const PERMISSION_TYPE_TO_CANONICAL = {
|
|
|
194
208
|
LOCATION: "location",
|
|
195
209
|
BACKGROUND_LOCATION: "location",
|
|
196
210
|
READ_NOTIFICATIONS: "notifications",
|
|
211
|
+
DISPLAY_MIRROR: "displayMirror",
|
|
197
212
|
POST_NOTIFICATIONS: "notifications",
|
|
198
213
|
CALENDAR: "calendar",
|
|
199
214
|
API_KEYS: "apiKeys",
|
|
@@ -298,6 +313,7 @@ const ALL_CANONICAL_PERMISSIONS = [
|
|
|
298
313
|
"memory",
|
|
299
314
|
"ai",
|
|
300
315
|
"speakers",
|
|
316
|
+
"displayMirror",
|
|
301
317
|
];
|
|
302
318
|
/**
|
|
303
319
|
* Build the {location, microphone, camera, notifications, calendar, apiKeys}
|
|
@@ -400,8 +416,8 @@ class LocalMiniappRuntime {
|
|
|
400
416
|
llmQuotaBlocked = false;
|
|
401
417
|
/** Connected miniapps keyed by packageName. */
|
|
402
418
|
connectedApps = new Map();
|
|
403
|
-
/**
|
|
404
|
-
gestureClaims =
|
|
419
|
+
/** Claimed gestures (CLAIM_GESTURES): a stack per gesture, the most recent claimer holding it. */
|
|
420
|
+
gestureClaims = emptyGestureClaims();
|
|
405
421
|
/**
|
|
406
422
|
* Packages that have completed their CONNECT handshake (sent
|
|
407
423
|
* `miniapp_connect`, got `CONNECT_ACK`). Distinct from `connectedApps`,
|
|
@@ -419,6 +435,10 @@ class LocalMiniappRuntime {
|
|
|
419
435
|
cloudResultsWired = false;
|
|
420
436
|
cloudStatusWired = false;
|
|
421
437
|
capabilitiesWired = false;
|
|
438
|
+
preferencesWired = false;
|
|
439
|
+
settingsBridgeWired = false;
|
|
440
|
+
/** Last derived read-only values pushed on the settings stream, for change detection. */
|
|
441
|
+
derivedSettings = new Map();
|
|
422
442
|
cloudAudioSubscriptionSync = new CloudAudioSubscriptionSync();
|
|
423
443
|
/**
|
|
424
444
|
* Per-miniapp language hints from TRANSCRIPTION_CONFIG (issue 021 WP3).
|
|
@@ -529,6 +549,23 @@ class LocalMiniappRuntime {
|
|
|
529
549
|
}
|
|
530
550
|
}
|
|
531
551
|
}
|
|
552
|
+
if (this.streamSubscribers.has(MiniappStreamType.MIRROR_UPDATE)) {
|
|
553
|
+
if (!this.mirrorUnsubscribe)
|
|
554
|
+
this.mirrorUnsubscribe = mirrorService.subscribe((snapshot) => {
|
|
555
|
+
for (const pkg of this.streamSubscribers.get(MiniappStreamType.MIRROR_UPDATE) ?? []) {
|
|
556
|
+
if (this.hasMirrorPermission(pkg))
|
|
557
|
+
this.sendToMiniapp(pkg, {
|
|
558
|
+
type: MiniappResponseType.EVENT,
|
|
559
|
+
streamType: MiniappStreamType.MIRROR_UPDATE,
|
|
560
|
+
data: snapshot,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
this.mirrorUnsubscribe?.();
|
|
567
|
+
this.mirrorUnsubscribe = null;
|
|
568
|
+
}
|
|
532
569
|
this.publishTranscriptionDebugSubscribers();
|
|
533
570
|
}
|
|
534
571
|
/** Mirror the live transcription/translation subscriber sets into the debug store. */
|
|
@@ -639,6 +676,11 @@ class LocalMiniappRuntime {
|
|
|
639
676
|
}
|
|
640
677
|
return LocalMiniappRuntime.instance;
|
|
641
678
|
}
|
|
679
|
+
mirrorUnsubscribe = null;
|
|
680
|
+
hasMirrorPermission(packageName) {
|
|
681
|
+
return (this.connectedApps.get(packageName)?.installedManifest?.permissions?.some((p) => p.type === "DISPLAY_MIRROR") ===
|
|
682
|
+
true);
|
|
683
|
+
}
|
|
642
684
|
initialized = false;
|
|
643
685
|
/**
|
|
644
686
|
* Initialize the runtime. Called from MantleManager.init().
|
|
@@ -650,6 +692,16 @@ class LocalMiniappRuntime {
|
|
|
650
692
|
this.initialized = true;
|
|
651
693
|
console.log(`${LOG_TAG}: initialize()`);
|
|
652
694
|
this.ensurePingLoop();
|
|
695
|
+
mirrorService.initialize();
|
|
696
|
+
// The overlay apps' pages relay through the runtime: the slot going to
|
|
697
|
+
// and from an app arrives as its display_view events.
|
|
698
|
+
overlayPages.setSink({
|
|
699
|
+
send: (packageName, event) => this.sendToMiniapp(packageName, {
|
|
700
|
+
type: MiniappResponseType.EVENT,
|
|
701
|
+
streamType: MiniappStreamType.DISPLAY_VIEW,
|
|
702
|
+
data: event,
|
|
703
|
+
}),
|
|
704
|
+
});
|
|
653
705
|
}
|
|
654
706
|
/**
|
|
655
707
|
* Handle an incoming cloud message relayed from the v2 cloud session
|
|
@@ -729,7 +781,7 @@ class LocalMiniappRuntime {
|
|
|
729
781
|
// ===========================================================================
|
|
730
782
|
// App registration
|
|
731
783
|
// ===========================================================================
|
|
732
|
-
registerApp(packageName, sendFn, installedManifest) {
|
|
784
|
+
registerApp(packageName, sendFn, installedManifest, launchSource) {
|
|
733
785
|
console.log(`${LOG_TAG}: registerApp(${packageName})`);
|
|
734
786
|
this.clearForegroundProbe(packageName);
|
|
735
787
|
// Fresh spawn → fresh handshake. Clear any prior handshake flag so
|
|
@@ -740,6 +792,9 @@ class LocalMiniappRuntime {
|
|
|
740
792
|
// dangling references. The WebView will re-subscribe after its CONNECT.
|
|
741
793
|
if (this.connectedApps.has(packageName)) {
|
|
742
794
|
const existing = this.connectedApps.get(packageName);
|
|
795
|
+
void glassesSensorService.release(packageName).catch((error) => {
|
|
796
|
+
console.warn(`${LOG_TAG}: sensor cleanup failed on respawn for ${packageName}`, error);
|
|
797
|
+
});
|
|
743
798
|
this.cancelSpeech(packageName);
|
|
744
799
|
// A crash respawn replaces the ConnectedMiniapp without going through
|
|
745
800
|
// unregisterApp(). Abort the old incarnation's native PCM player before
|
|
@@ -778,6 +833,7 @@ class LocalMiniappRuntime {
|
|
|
778
833
|
authDelivered: false,
|
|
779
834
|
speakerState: "idle",
|
|
780
835
|
requestedLocationRate: null,
|
|
836
|
+
launchSource,
|
|
781
837
|
});
|
|
782
838
|
// If we just clobbered an existing entry, its requestedLocationRate is
|
|
783
839
|
// now gone — recompute so the aggregate doesn't include a stale rate.
|
|
@@ -785,6 +841,8 @@ class LocalMiniappRuntime {
|
|
|
785
841
|
this.recomputeLocationTier();
|
|
786
842
|
this.ensureCloudStatusWired();
|
|
787
843
|
this.ensureCapabilitiesWired();
|
|
844
|
+
this.ensurePreferencesWired();
|
|
845
|
+
this.ensureSettingsBridgeWired();
|
|
788
846
|
this.ensurePingLoop();
|
|
789
847
|
// Show the system boot message ("Starting <name>…") on the glasses for the
|
|
790
848
|
// bounded boot window, mirroring the cloud DisplayManager boot screen. The
|
|
@@ -810,14 +868,14 @@ class LocalMiniappRuntime {
|
|
|
810
868
|
if (settled)
|
|
811
869
|
return;
|
|
812
870
|
settled = true;
|
|
813
|
-
clearTimeout(timer);
|
|
871
|
+
BgTimer.clearTimeout(timer);
|
|
814
872
|
this.connectWaiters.get(packageName)?.delete(waiter);
|
|
815
873
|
if (err)
|
|
816
874
|
reject(err);
|
|
817
875
|
else
|
|
818
876
|
resolve();
|
|
819
877
|
};
|
|
820
|
-
const timer = setTimeout(() => {
|
|
878
|
+
const timer = BgTimer.setTimeout(() => {
|
|
821
879
|
waiter(new Error(`waitForConnect: ${packageName} did not connect within ${timeoutMs}ms`));
|
|
822
880
|
}, timeoutMs);
|
|
823
881
|
let set = this.connectWaiters.get(packageName);
|
|
@@ -887,7 +945,7 @@ class LocalMiniappRuntime {
|
|
|
887
945
|
// 50 ms: imperceptible to the user, plenty of time for the SDK's
|
|
888
946
|
// synchronous `beforeDisconnect` handlers to flush a final
|
|
889
947
|
// sendOneShot through the still-open transport.
|
|
890
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
948
|
+
await new Promise((resolve) => BgTimer.setTimeout(resolve, 50));
|
|
891
949
|
this.unregisterApp(packageName);
|
|
892
950
|
}
|
|
893
951
|
unregisterApp(packageName, opts) {
|
|
@@ -904,6 +962,14 @@ class LocalMiniappRuntime {
|
|
|
904
962
|
// Drop this app's transcription hints; the cloud subscription rebuild
|
|
905
963
|
// below (via replaceStreamSubscribers) re-derives the hint union without it.
|
|
906
964
|
this.transcriptionHintsByApp.delete(packageName);
|
|
965
|
+
// An overlay app is going: release the slot if it holds it, and drop the
|
|
966
|
+
// dashboard view from its capabilities record.
|
|
967
|
+
if (isOverlayApp(packageName)) {
|
|
968
|
+
overlayPages.remove(packageName);
|
|
969
|
+
removeOverlayApp(packageName);
|
|
970
|
+
}
|
|
971
|
+
// Its gesture claims go back to whoever claimed them before.
|
|
972
|
+
this.applyGestureClaimChanges(dropGestureClaims(this.gestureClaims, packageName));
|
|
907
973
|
// Warm-up is a request-owned camera lease. Cancel it even if the app record was already
|
|
908
974
|
// removed so a close racing the camera-open promise cannot leave the sensor running.
|
|
909
975
|
// Keep camera teardown ordered: restoring FOV can restart the HAL, so the warm-up lease must
|
|
@@ -962,11 +1028,15 @@ class LocalMiniappRuntime {
|
|
|
962
1028
|
else {
|
|
963
1029
|
this.navigationHandlers.onDisconnect(packageName);
|
|
964
1030
|
}
|
|
1031
|
+
void glassesSensorService.release(packageName).catch((error) => {
|
|
1032
|
+
console.warn(`${LOG_TAG}: sensor cleanup failed for ${packageName}`, error);
|
|
1033
|
+
});
|
|
965
1034
|
// Recompute heading subscription — if this app was the last subscriber,
|
|
966
1035
|
// the sensor will stop.
|
|
967
1036
|
this.recomputeHeadingSubscription();
|
|
968
|
-
// Same for the IMU/accelerometer
|
|
1037
|
+
// Same for the IMU/accelerometer and glasses compass streams.
|
|
969
1038
|
this.recomputeImuSubscription();
|
|
1039
|
+
this.recomputeCompassSubscription();
|
|
970
1040
|
// Drop this app's location-tier request before recomputing so the
|
|
971
1041
|
// aggregate falls back down if it was the strictest. Done before
|
|
972
1042
|
// `connectedApps.delete` below so it doesn't matter that the iter
|
|
@@ -984,7 +1054,6 @@ class LocalMiniappRuntime {
|
|
|
984
1054
|
// current on-glasses frame, this clears the glasses (or restores the
|
|
985
1055
|
// core app's saved frame).
|
|
986
1056
|
localDisplayManager.onUnmount(packageName);
|
|
987
|
-
this.gestureClaims.delete(packageName);
|
|
988
1057
|
this.connectedApps.delete(packageName);
|
|
989
1058
|
this.recomputeMicRequirements();
|
|
990
1059
|
if (releasedMicGateOverride) {
|
|
@@ -1061,9 +1130,32 @@ class LocalMiniappRuntime {
|
|
|
1061
1130
|
case MiniappRequestType.DISPLAY:
|
|
1062
1131
|
this.handleDisplay(packageName, payload, requestId);
|
|
1063
1132
|
break;
|
|
1133
|
+
case MiniappRequestType.MIRROR_GET:
|
|
1134
|
+
if (!this.hasMirrorPermission(packageName)) {
|
|
1135
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
1136
|
+
code: MiniappErrorCode.PERMISSION_NOT_DECLARED,
|
|
1137
|
+
message: "DISPLAY_MIRROR permission not declared in miniapp.json",
|
|
1138
|
+
permission: "DISPLAY_MIRROR",
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
else
|
|
1142
|
+
this.sendResult(packageName, requestId, true, mirrorService.current());
|
|
1143
|
+
break;
|
|
1064
1144
|
case MiniappRequestType.RENDER:
|
|
1065
1145
|
this.handleRender(packageName, payload, requestId);
|
|
1066
1146
|
break;
|
|
1147
|
+
case MiniappRequestType.SHOW_VIEW:
|
|
1148
|
+
this.handleShowView(packageName, payload, requestId);
|
|
1149
|
+
break;
|
|
1150
|
+
case MiniappRequestType.SETTINGS_GET:
|
|
1151
|
+
this.handleSettingsGet(packageName, payload, requestId);
|
|
1152
|
+
break;
|
|
1153
|
+
case MiniappRequestType.SETTINGS_SET:
|
|
1154
|
+
void this.handleSettingsSet(packageName, payload, requestId);
|
|
1155
|
+
break;
|
|
1156
|
+
case MiniappRequestType.NOTIFICATION_APPS_LIST:
|
|
1157
|
+
void this.handleNotificationAppsList(packageName, requestId);
|
|
1158
|
+
break;
|
|
1067
1159
|
case MiniappRequestType.NATIVE_NAV:
|
|
1068
1160
|
this.handleNativeNav(packageName, payload, requestId);
|
|
1069
1161
|
break;
|
|
@@ -1195,6 +1287,19 @@ class LocalMiniappRuntime {
|
|
|
1195
1287
|
case MiniappRequestType.SET_WIFI_ADB_STATE:
|
|
1196
1288
|
void this.handleSetWifiAdbState(packageName, payload, requestId);
|
|
1197
1289
|
break;
|
|
1290
|
+
case MiniappRequestType.GLASSES_SENSOR_CONTROL:
|
|
1291
|
+
if (!this.connectedApps.has(packageName)) {
|
|
1292
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
1293
|
+
code: MiniappErrorCode.NOT_CONNECTED,
|
|
1294
|
+
message: "Miniapp disconnected",
|
|
1295
|
+
});
|
|
1296
|
+
break;
|
|
1297
|
+
}
|
|
1298
|
+
void glassesSensorService.request(packageName, payload).then(() => this.sendResult(packageName, requestId, true), (error) => this.sendResult(packageName, requestId, false, undefined, {
|
|
1299
|
+
code: error.code || MiniappErrorCode.INTERNAL,
|
|
1300
|
+
message: error instanceof Error ? error.message : "Sensor control failed",
|
|
1301
|
+
}));
|
|
1302
|
+
break;
|
|
1198
1303
|
case MiniappRequestType.IMU_SET_ENABLED:
|
|
1199
1304
|
this.handleImuSetEnabled(packageName, payload, requestId);
|
|
1200
1305
|
break;
|
|
@@ -1219,6 +1324,15 @@ class LocalMiniappRuntime {
|
|
|
1219
1324
|
case MiniappRequestType.OPEN_URL:
|
|
1220
1325
|
this.handleOpenUrl(packageName, payload);
|
|
1221
1326
|
break;
|
|
1327
|
+
case MiniappRequestType.DISPLAY_DIAGNOSTICS: {
|
|
1328
|
+
const enabled = useSettingsStore.getState().getSetting(SETTINGS.debug_console.key) === true;
|
|
1329
|
+
this.sendResult(packageName, requestId, true, {
|
|
1330
|
+
enabled,
|
|
1331
|
+
generatedAt: Date.now(),
|
|
1332
|
+
records: enabled ? collectDisplayDiagnostics(logBuffer.getRecentLogs()) : [],
|
|
1333
|
+
});
|
|
1334
|
+
break;
|
|
1335
|
+
}
|
|
1222
1336
|
case MiniappRequestType.COPY_CLIPBOARD:
|
|
1223
1337
|
this.handleCopyClipboard(packageName, payload, requestId);
|
|
1224
1338
|
break;
|
|
@@ -1365,7 +1479,11 @@ class LocalMiniappRuntime {
|
|
|
1365
1479
|
// Update lastPongAt so it doesn't time out right away
|
|
1366
1480
|
existing.lastPongAt = Date.now();
|
|
1367
1481
|
existing.unansweredPingRounds = 0;
|
|
1368
|
-
|
|
1482
|
+
// A system_dashboard app may take the overlay slot: its capabilities
|
|
1483
|
+
// carry the dashboard view from the start.
|
|
1484
|
+
if (existing.installedManifest?.type === "system_dashboard")
|
|
1485
|
+
addOverlayApp(packageName);
|
|
1486
|
+
const capabilities = this.capabilitiesFor(packageName);
|
|
1369
1487
|
// Build the declared-permission record for the SDK's session.permissions
|
|
1370
1488
|
// module. Lower-cased to match v3's PermissionType union (microphone,
|
|
1371
1489
|
// camera, location, notifications, calendar). Missing permissions default
|
|
@@ -1379,7 +1497,7 @@ class LocalMiniappRuntime {
|
|
|
1379
1497
|
this.clearMiniappAuthDeliveryRetry(packageName);
|
|
1380
1498
|
const authPromise = this.requestMiniappAuth(packageName);
|
|
1381
1499
|
const initialAuth = await withTimeout(authPromise, 1_500);
|
|
1382
|
-
const userId = initialAuth?.
|
|
1500
|
+
const userId = initialAuth?.userId ?? "";
|
|
1383
1501
|
if (initialAuth) {
|
|
1384
1502
|
existing.authDelivered = true;
|
|
1385
1503
|
this.scheduleMiniappAuthRefresh(packageName, initialAuth);
|
|
@@ -1389,7 +1507,10 @@ class LocalMiniappRuntime {
|
|
|
1389
1507
|
userId,
|
|
1390
1508
|
packageName,
|
|
1391
1509
|
capabilities,
|
|
1510
|
+
preferences: this.currentPreferences(),
|
|
1511
|
+
visibility: this.currentVisibility(),
|
|
1392
1512
|
permissions: declaredPermissions,
|
|
1513
|
+
...(existing.launchSource ? { launchSource: existing.launchSource } : {}),
|
|
1393
1514
|
...(initialAuth ? { auth: initialAuth } : {}),
|
|
1394
1515
|
}, requestId);
|
|
1395
1516
|
if (!initialAuth) {
|
|
@@ -1606,11 +1727,10 @@ class LocalMiniappRuntime {
|
|
|
1606
1727
|
}
|
|
1607
1728
|
/**
|
|
1608
1729
|
* CLAIM_GESTURES (session.input.setClaimedGestures): the app declares which
|
|
1609
|
-
* touch gestures it handles itself, replacing its previous claim set.
|
|
1610
|
-
*
|
|
1611
|
-
*
|
|
1612
|
-
*
|
|
1613
|
-
* {@link foregroundClaimsGesture}. Cleared on app stop.
|
|
1730
|
+
* touch gestures it handles itself, replacing its previous claim set. The
|
|
1731
|
+
* most recent claimer of a gesture holds it and gets it alone; releasing
|
|
1732
|
+
* hands it back to the previous claimer, and both hear the change on the
|
|
1733
|
+
* gesture_claim stream. Cleared on app stop.
|
|
1614
1734
|
*/
|
|
1615
1735
|
handleClaimGestures(packageName, payload, requestId) {
|
|
1616
1736
|
if (!this.connectedApps.has(packageName)) {
|
|
@@ -1619,15 +1739,29 @@ class LocalMiniappRuntime {
|
|
|
1619
1739
|
}
|
|
1620
1740
|
const raw = payload.gestures;
|
|
1621
1741
|
const gestures = Array.isArray(raw) ? raw.filter((g) => typeof g === "string") : [];
|
|
1622
|
-
if (
|
|
1623
|
-
this.
|
|
1624
|
-
|
|
1625
|
-
|
|
1742
|
+
if (payload.scope !== undefined && (typeof payload.scope !== "string" || payload.scope.length === 0)) {
|
|
1743
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
1744
|
+
code: MiniappErrorCode.INVALID_ARGUMENT,
|
|
1745
|
+
message: "Gesture claim scope must be a nonempty string",
|
|
1746
|
+
});
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
this.applyGestureClaimChanges(setGestureClaims(this.gestureClaims, packageName, gestures, payload.scope));
|
|
1626
1750
|
this.sendResult(packageName, requestId, true);
|
|
1627
1751
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1752
|
+
applyGestureClaimChanges(result) {
|
|
1753
|
+
this.gestureClaims = result.state;
|
|
1754
|
+
for (const change of result.changes) {
|
|
1755
|
+
this.forwardEvent(MiniappStreamType.GESTURE_CLAIM, { gesture: change.gesture, held: change.held }, undefined, change.packageName);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
/** The app holding `gesture` (the most recent claimer), or null when it is unclaimed. */
|
|
1759
|
+
gestureClaimant(gesture) {
|
|
1760
|
+
return gestureClaimant(this.gestureClaims, gesture);
|
|
1761
|
+
}
|
|
1762
|
+
/** Has this app registered the gesture, even if a later claimant currently receives it? */
|
|
1763
|
+
hasGestureClaim(packageName, gesture) {
|
|
1764
|
+
return hasGestureClaim(this.gestureClaims, packageName, gesture);
|
|
1631
1765
|
}
|
|
1632
1766
|
handleSubscribe(packageName, payload, requestId) {
|
|
1633
1767
|
const app = this.connectedApps.get(packageName);
|
|
@@ -1674,11 +1808,13 @@ class LocalMiniappRuntime {
|
|
|
1674
1808
|
// the whole subscribe with PERMISSION_NOT_DECLARED.
|
|
1675
1809
|
const declaredTypes = new Set((app.installedManifest?.permissions ?? []).map((p) => p.type?.toUpperCase()));
|
|
1676
1810
|
const permissionForStream = (s) => {
|
|
1811
|
+
if (s === MiniappStreamType.MIRROR_UPDATE)
|
|
1812
|
+
return "DISPLAY_MIRROR";
|
|
1677
1813
|
if (s === "audio_chunk" || s === "vad")
|
|
1678
1814
|
return "MICROPHONE";
|
|
1679
1815
|
if (s.startsWith("transcription") || s.startsWith("translation"))
|
|
1680
1816
|
return "MICROPHONE";
|
|
1681
|
-
if (s === "location_update")
|
|
1817
|
+
if (s === "location_update" || s === "heading_update")
|
|
1682
1818
|
return "LOCATION";
|
|
1683
1819
|
if (s === "phone_notification")
|
|
1684
1820
|
return "READ_NOTIFICATIONS";
|
|
@@ -1701,16 +1837,29 @@ class LocalMiniappRuntime {
|
|
|
1701
1837
|
return;
|
|
1702
1838
|
}
|
|
1703
1839
|
}
|
|
1840
|
+
// The settings stream carries the wearer's settings: system apps only.
|
|
1841
|
+
if (streams.includes(MiniappStreamType.SETTINGS_CHANGED) && !this.isSystemPackage(packageName)) {
|
|
1842
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
1843
|
+
code: MiniappErrorCode.NOT_PERMITTED,
|
|
1844
|
+
message: "The settings stream is restricted to system apps",
|
|
1845
|
+
});
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1704
1848
|
// Add new subscriptions
|
|
1705
1849
|
const previousSubscriptions = app.subscriptions;
|
|
1706
1850
|
app.subscriptions = new Set(streams);
|
|
1707
1851
|
app.forceLocalTranscriptionStreams = new Set([...forceLocalTranscriptionStreams].filter((stream) => app.subscriptions.has(stream)));
|
|
1708
1852
|
app.cloudTranscriptionStreams = new Set([...cloudTranscriptionStreams].filter((stream) => app.subscriptions.has(stream)));
|
|
1709
1853
|
this.replaceStreamSubscribers(packageName, previousSubscriptions, app.subscriptions);
|
|
1854
|
+
// An overlay app that listens to phone notifications presents them on the glasses.
|
|
1855
|
+
if (isOverlayApp(packageName)) {
|
|
1856
|
+
setOverlayViewer(packageName, app.subscriptions.has(MiniappStreamType.PHONE_NOTIFICATION));
|
|
1857
|
+
}
|
|
1710
1858
|
this.recomputeMicRequirements();
|
|
1711
1859
|
this.updateCloudSubscriptions();
|
|
1712
1860
|
this.recomputeHeadingSubscription();
|
|
1713
1861
|
this.recomputeImuSubscription();
|
|
1862
|
+
this.recomputeCompassSubscription();
|
|
1714
1863
|
// Persist this app's requested rate (or clear it if SUBSCRIBE didn't
|
|
1715
1864
|
// include `location_stream` this time), then ask the host for the
|
|
1716
1865
|
// strictest rate across all connected apps.
|
|
@@ -1761,7 +1910,14 @@ class LocalMiniappRuntime {
|
|
|
1761
1910
|
};
|
|
1762
1911
|
const isSimulated = (glassesState.deviceModel || "").toLowerCase().includes("simulated");
|
|
1763
1912
|
for (const stream of streams) {
|
|
1764
|
-
if (stream ===
|
|
1913
|
+
if (stream === MiniappStreamType.MIRROR_UPDATE && this.hasMirrorPermission(packageName)) {
|
|
1914
|
+
this.sendToMiniapp(packageName, {
|
|
1915
|
+
type: MiniappResponseType.EVENT,
|
|
1916
|
+
streamType: MiniappStreamType.MIRROR_UPDATE,
|
|
1917
|
+
data: mirrorService.current(),
|
|
1918
|
+
});
|
|
1919
|
+
}
|
|
1920
|
+
else if (stream === "glasses_battery") {
|
|
1765
1921
|
// Simulated glasses have no real battery; mirror the phone's battery
|
|
1766
1922
|
// so miniapps see a sensible value during development.
|
|
1767
1923
|
if (isSimulated) {
|
|
@@ -1812,6 +1968,16 @@ class LocalMiniappRuntime {
|
|
|
1812
1968
|
},
|
|
1813
1969
|
});
|
|
1814
1970
|
}
|
|
1971
|
+
else if (stream === MiniappStreamType.SETTINGS_CHANGED) {
|
|
1972
|
+
// Replay every bridged key so a mirror can be built from the stream alone.
|
|
1973
|
+
for (const key of selectSettingsBridgeKeys(undefined)) {
|
|
1974
|
+
this.sendToMiniapp(packageName, {
|
|
1975
|
+
type: MiniappResponseType.EVENT,
|
|
1976
|
+
streamType: MiniappStreamType.SETTINGS_CHANGED,
|
|
1977
|
+
data: { key, value: this.settingsBridgeValue(key) },
|
|
1978
|
+
});
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1815
1981
|
else if (stream === "head_position") {
|
|
1816
1982
|
// The glasses store has no headUp field (same on the pre-engine host
|
|
1817
1983
|
// hook), so this stays a no-emit until head state lands in the store.
|
|
@@ -1908,6 +2074,16 @@ class LocalMiniappRuntime {
|
|
|
1908
2074
|
});
|
|
1909
2075
|
return;
|
|
1910
2076
|
}
|
|
2077
|
+
// The dashboard view is the overlay apps' alone; anyone else's frame
|
|
2078
|
+
// is dropped, reported rather than silently lost.
|
|
2079
|
+
if (payload.view === "dashboard" && !isOverlayApp(packageName)) {
|
|
2080
|
+
this.sendResult(packageName, requestId, true, {
|
|
2081
|
+
status: "displayed",
|
|
2082
|
+
presented: false,
|
|
2083
|
+
reason: "not the dashboard app",
|
|
2084
|
+
});
|
|
2085
|
+
return;
|
|
2086
|
+
}
|
|
1911
2087
|
localDisplayManager.request(packageName, {
|
|
1912
2088
|
view: payload.view ?? "main",
|
|
1913
2089
|
scene: payload.elements,
|
|
@@ -1922,6 +2098,160 @@ class LocalMiniappRuntime {
|
|
|
1922
2098
|
});
|
|
1923
2099
|
}
|
|
1924
2100
|
}
|
|
2101
|
+
/**
|
|
2102
|
+
* display.showView: the designated dashboard app takes or releases the
|
|
2103
|
+
* overlay slot. Refused (NOT_PERMITTED) for any other app; "unsupported"
|
|
2104
|
+
* while the glasses cannot show the dashboard view. Idempotent either way;
|
|
2105
|
+
* the slot's state comes back to the app as a display_view change.
|
|
2106
|
+
*/
|
|
2107
|
+
handleShowView(packageName, payload, requestId) {
|
|
2108
|
+
if (!this.connectedApps.has(packageName)) {
|
|
2109
|
+
this.sendResult(packageName, requestId, true, { status: "unsupported", reason: "app stopped" });
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
const view = payload.view;
|
|
2113
|
+
if (view !== "main" && view !== "dashboard") {
|
|
2114
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2115
|
+
code: MiniappErrorCode.INVALID_ARGUMENT,
|
|
2116
|
+
message: 'showView takes "main" or "dashboard"',
|
|
2117
|
+
});
|
|
2118
|
+
return;
|
|
2119
|
+
}
|
|
2120
|
+
if (!isOverlayApp(packageName)) {
|
|
2121
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2122
|
+
code: MiniappErrorCode.NOT_PERMITTED,
|
|
2123
|
+
message: "The dashboard view belongs to system_dashboard apps",
|
|
2124
|
+
});
|
|
2125
|
+
return;
|
|
2126
|
+
}
|
|
2127
|
+
if (view === "main") {
|
|
2128
|
+
overlayPages.hide(packageName);
|
|
2129
|
+
this.sendResult(packageName, requestId, true, { status: "shown" });
|
|
2130
|
+
return;
|
|
2131
|
+
}
|
|
2132
|
+
if (!pagesEligible()) {
|
|
2133
|
+
this.sendResult(packageName, requestId, true, {
|
|
2134
|
+
status: "unsupported",
|
|
2135
|
+
reason: "glasses cannot show the dashboard",
|
|
2136
|
+
});
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
dashboardOpenTrace.showViewRequested(packageName);
|
|
2140
|
+
const shown = overlayPages.show(packageName);
|
|
2141
|
+
if (shown)
|
|
2142
|
+
dashboardOpenTrace.slotGranted();
|
|
2143
|
+
this.sendResult(packageName, requestId, true, shown ? { status: "shown" } : { status: "unsupported", reason: "the overlay slot was refused" });
|
|
2144
|
+
}
|
|
2145
|
+
// ---------------------------------------------------------------------------
|
|
2146
|
+
// Settings bridge (session.settings) — system apps only
|
|
2147
|
+
// ---------------------------------------------------------------------------
|
|
2148
|
+
requireSystemForSettings(packageName, requestId) {
|
|
2149
|
+
if (this.isSystemPackage(packageName))
|
|
2150
|
+
return true;
|
|
2151
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2152
|
+
code: MiniappErrorCode.NOT_PERMITTED,
|
|
2153
|
+
message: "The settings bridge is restricted to system apps",
|
|
2154
|
+
});
|
|
2155
|
+
return false;
|
|
2156
|
+
}
|
|
2157
|
+
/** A bridged key's current value: the store's, or the engine's for a derived key. */
|
|
2158
|
+
settingsBridgeValue(key) {
|
|
2159
|
+
if (isDerivedSettingsKey(key))
|
|
2160
|
+
return this.derivedSettingValue(key);
|
|
2161
|
+
return useSettingsStore.getState().getSetting(key) ?? null;
|
|
2162
|
+
}
|
|
2163
|
+
derivedSettingValue(key) {
|
|
2164
|
+
switch (key) {
|
|
2165
|
+
case "phone_active":
|
|
2166
|
+
return isPhoneActive();
|
|
2167
|
+
case "foreground_app_on_screen":
|
|
2168
|
+
return localDisplayManager.foregroundAppOnScreen();
|
|
2169
|
+
case "ring_battery":
|
|
2170
|
+
return ringBatteryFrom(useGlassesStore.getState());
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
handleSettingsGet(packageName, payload, requestId) {
|
|
2174
|
+
if (!this.requireSystemForSettings(packageName, requestId))
|
|
2175
|
+
return;
|
|
2176
|
+
const values = {};
|
|
2177
|
+
for (const key of selectSettingsBridgeKeys(payload.keys))
|
|
2178
|
+
values[key] = this.settingsBridgeValue(key);
|
|
2179
|
+
this.sendResult(packageName, requestId, true, { values });
|
|
2180
|
+
}
|
|
2181
|
+
async handleSettingsSet(packageName, payload, requestId) {
|
|
2182
|
+
if (!this.requireSystemForSettings(packageName, requestId))
|
|
2183
|
+
return;
|
|
2184
|
+
const validated = validateSettingsSet(payload);
|
|
2185
|
+
if (!validated.ok) {
|
|
2186
|
+
this.sendResult(packageName, requestId, false, undefined, { code: validated.code, message: validated.message });
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2189
|
+
// Through the store, so persistence, server sync and the Bluetooth sync
|
|
2190
|
+
// of glasses settings behave as if a phone screen wrote it.
|
|
2191
|
+
const result = await useSettingsStore.getState().setSetting(validated.key, validated.value);
|
|
2192
|
+
if (result.is_error()) {
|
|
2193
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2194
|
+
code: MiniappErrorCode.INTERNAL,
|
|
2195
|
+
message: result.error.message,
|
|
2196
|
+
});
|
|
2197
|
+
return;
|
|
2198
|
+
}
|
|
2199
|
+
this.sendResult(packageName, requestId, true);
|
|
2200
|
+
}
|
|
2201
|
+
async handleNotificationAppsList(packageName, requestId) {
|
|
2202
|
+
if (!this.requireSystemForSettings(packageName, requestId))
|
|
2203
|
+
return;
|
|
2204
|
+
try {
|
|
2205
|
+
this.sendResult(packageName, requestId, true, await installedNotificationApps());
|
|
2206
|
+
}
|
|
2207
|
+
catch (err) {
|
|
2208
|
+
this.sendResult(packageName, requestId, false, undefined, {
|
|
2209
|
+
code: MiniappErrorCode.INTERNAL,
|
|
2210
|
+
message: err instanceof Error ? err.message : "Failed to list notification apps",
|
|
2211
|
+
});
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
/**
|
|
2215
|
+
* Push bridged settings as they change: stored keys from the store, the
|
|
2216
|
+
* derived keys whenever their inputs move (phone activity, the display,
|
|
2217
|
+
* the apps store, the ring). Subscribers are system apps only (gated at
|
|
2218
|
+
* SUBSCRIBE), so this is a no-op fan-out for everyone else.
|
|
2219
|
+
*/
|
|
2220
|
+
ensureSettingsBridgeWired() {
|
|
2221
|
+
if (this.settingsBridgeWired)
|
|
2222
|
+
return;
|
|
2223
|
+
this.settingsBridgeWired = true;
|
|
2224
|
+
const storedKeys = Object.keys(SETTINGS_BRIDGE_KEYS);
|
|
2225
|
+
const emit = (key, value) => this.forwardEvent(MiniappStreamType.SETTINGS_CHANGED, { key, value });
|
|
2226
|
+
useSettingsStore.subscribe((s) => storedKeys.map((key) => JSON.stringify(s.getSetting(key) ?? null)), (next, previous) => {
|
|
2227
|
+
storedKeys.forEach((key, i) => {
|
|
2228
|
+
if (next[i] !== previous[i])
|
|
2229
|
+
emit(key, this.settingsBridgeValue(key));
|
|
2230
|
+
});
|
|
2231
|
+
}, { equalityFn: (a, b) => a.length === b.length && a.every((value, i) => value === b[i]) });
|
|
2232
|
+
const pushDerived = () => {
|
|
2233
|
+
for (const key of DERIVED_SETTINGS_KEYS) {
|
|
2234
|
+
const value = this.derivedSettingValue(key);
|
|
2235
|
+
const encoded = JSON.stringify(value ?? null);
|
|
2236
|
+
if (this.derivedSettings.get(key) === encoded)
|
|
2237
|
+
continue;
|
|
2238
|
+
this.derivedSettings.set(key, encoded);
|
|
2239
|
+
emit(key, value);
|
|
2240
|
+
}
|
|
2241
|
+
};
|
|
2242
|
+
for (const key of DERIVED_SETTINGS_KEYS) {
|
|
2243
|
+
this.derivedSettings.set(key, JSON.stringify(this.derivedSettingValue(key) ?? null));
|
|
2244
|
+
}
|
|
2245
|
+
onPhoneActivityChange(pushDerived);
|
|
2246
|
+
// App foreground/background drives VISIBILITY_CHANGE. Background execution
|
|
2247
|
+
// limits (timer coalescing, BLE credit polling) follow the app's own
|
|
2248
|
+
// foreground bit, not `isPhoneActive()` — which counts an unlocked phone as
|
|
2249
|
+
// active even while the app is suspended behind it.
|
|
2250
|
+
onAppForegroundChange((foregrounded) => this.broadcastVisibility(foregrounded));
|
|
2251
|
+
localDisplayManager.onActiveDisplayChange(pushDerived);
|
|
2252
|
+
useAppStatusStore.subscribe(pushDerived);
|
|
2253
|
+
useGlassesStore.subscribe((s) => `${s.ringConnected}:${s.ringBatteryLevel}:${s.controllerConnected}:${s.controllerBatteryLevel}`, pushDerived);
|
|
2254
|
+
}
|
|
1925
2255
|
/**
|
|
1926
2256
|
* Native nav UI feed (display.sendNativeNav*). Gated on the device's nav
|
|
1927
2257
|
* mode being active (trip-scoped); the miniapp's first pushes can race the
|
|
@@ -1935,6 +2265,8 @@ class LocalMiniappRuntime {
|
|
|
1935
2265
|
return;
|
|
1936
2266
|
}
|
|
1937
2267
|
const sent = nativeNavigationService.handleMiniappRequest(payload);
|
|
2268
|
+
if (sent)
|
|
2269
|
+
mirrorService.invalidate("firmware-navigation");
|
|
1938
2270
|
this.sendResult(packageName, requestId, true, {
|
|
1939
2271
|
status: sent ? "sent" : "unsupported",
|
|
1940
2272
|
...(sent ? {} : { reason: "native navigation unavailable" }),
|
|
@@ -1964,6 +2296,7 @@ class LocalMiniappRuntime {
|
|
|
1964
2296
|
this.sendResult(packageName, requestId, true, { status: "unsupported", reason: "no glasses connected" });
|
|
1965
2297
|
return;
|
|
1966
2298
|
}
|
|
2299
|
+
mirrorService.invalidate("firmware-dashboard");
|
|
1967
2300
|
void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {
|
|
1968
2301
|
console.error(`${LOG_TAG}: showDashboard failed:`, err);
|
|
1969
2302
|
});
|
|
@@ -2541,12 +2874,12 @@ class LocalMiniappRuntime {
|
|
|
2541
2874
|
*/
|
|
2542
2875
|
blobStore = new BlobStore({
|
|
2543
2876
|
sendResult: (packageName, requestId, ok, result, error) => this.sendResult(packageName, requestId, ok, result, error),
|
|
2544
|
-
getUserId: () => cloudClientService.
|
|
2877
|
+
getUserId: () => cloudClientService.getUserId(),
|
|
2545
2878
|
});
|
|
2546
2879
|
blobRequestQueues = new Map();
|
|
2547
2880
|
simpleStorage = new LocalMiniappStorage({
|
|
2548
2881
|
backend: localMiniappStorageBackend,
|
|
2549
|
-
getUserId: () => cloudClientService.
|
|
2882
|
+
getUserId: () => cloudClientService.resolveUserId(),
|
|
2550
2883
|
});
|
|
2551
2884
|
/**
|
|
2552
2885
|
* BlobStore's file helpers are synchronous once a user namespace is selected,
|
|
@@ -2558,7 +2891,7 @@ class LocalMiniappRuntime {
|
|
|
2558
2891
|
const previous = this.blobRequestQueues.get(packageName) ?? Promise.resolve();
|
|
2559
2892
|
const queued = previous.then(async () => {
|
|
2560
2893
|
try {
|
|
2561
|
-
await cloudClientService.
|
|
2894
|
+
await cloudClientService.resolveUserId();
|
|
2562
2895
|
}
|
|
2563
2896
|
catch (err) {
|
|
2564
2897
|
console.error(`${LOG_TAG}: blob identity error:`, err);
|
|
@@ -2600,7 +2933,7 @@ class LocalMiniappRuntime {
|
|
|
2600
2933
|
});
|
|
2601
2934
|
}
|
|
2602
2935
|
/**
|
|
2603
|
-
*
|
|
2936
|
+
* Phone heading is a sensor stream — start the phone compass when any mini
|
|
2604
2937
|
* app is subscribed to "heading_update", stop it when none are.
|
|
2605
2938
|
*/
|
|
2606
2939
|
headingUnsub = null;
|
|
@@ -2631,6 +2964,17 @@ class LocalMiniappRuntime {
|
|
|
2631
2964
|
this.imuEnabled = wantsImu;
|
|
2632
2965
|
void BluetoothSdk.setImuEnabled(wantsImu);
|
|
2633
2966
|
}
|
|
2967
|
+
/**
|
|
2968
|
+
* Glasses compass is demand-driven: GlassesSensorService runs it while any
|
|
2969
|
+
* miniapp is subscribed to "glasses_compass" (custom firmware), serving the
|
|
2970
|
+
* tightest sampling any subscriber asked for via session.compass.start().
|
|
2971
|
+
*/
|
|
2972
|
+
recomputeCompassSubscription() {
|
|
2973
|
+
const subscribers = this.streamSubscribers.get(MiniappStreamType.GLASSES_COMPASS) ?? new Set();
|
|
2974
|
+
void glassesSensorService.setCompassSubscribers(subscribers).catch((error) => {
|
|
2975
|
+
console.warn(`${LOG_TAG}: compass subscription update failed`, error);
|
|
2976
|
+
});
|
|
2977
|
+
}
|
|
2634
2978
|
/**
|
|
2635
2979
|
* Last rate we asked the host for. Lets us skip the cross-process call
|
|
2636
2980
|
* when nothing actually changed (most SUBSCRIBE / unregister churn
|
|
@@ -3298,7 +3642,7 @@ class LocalMiniappRuntime {
|
|
|
3298
3642
|
data: { progressToken, activity: status.activity, timestamp: Date.now() },
|
|
3299
3643
|
});
|
|
3300
3644
|
}
|
|
3301
|
-
await new Promise((resolve) => setTimeout(resolve, GENERATE_JOB_POLL_MS));
|
|
3645
|
+
await new Promise((resolve) => BgTimer.setTimeout(resolve, GENERATE_JOB_POLL_MS));
|
|
3302
3646
|
}
|
|
3303
3647
|
}
|
|
3304
3648
|
// ---------------------------------------------------------------------------
|
|
@@ -3847,6 +4191,9 @@ class LocalMiniappRuntime {
|
|
|
3847
4191
|
return { ok: false, error: "MICROPHONE permission not declared in miniapp.json" };
|
|
3848
4192
|
}
|
|
3849
4193
|
}
|
|
4194
|
+
if (streams.includes(MiniappStreamType.MIRROR_UPDATE) && !this.hasMirrorPermission(packageName)) {
|
|
4195
|
+
return { ok: false, error: "DISPLAY_MIRROR permission not declared" };
|
|
4196
|
+
}
|
|
3850
4197
|
// Add new subscriptions
|
|
3851
4198
|
const previousSubscriptions = app.subscriptions;
|
|
3852
4199
|
app.subscriptions = new Set(streams);
|
|
@@ -4209,10 +4556,46 @@ class LocalMiniappRuntime {
|
|
|
4209
4556
|
if (this.capabilitiesWired)
|
|
4210
4557
|
return;
|
|
4211
4558
|
this.capabilitiesWired = true;
|
|
4212
|
-
|
|
4213
|
-
|
|
4559
|
+
const broadcast = () => this.broadcastCapabilities();
|
|
4560
|
+
// Connection, model and firmware also decide the dashboard view's eligibility.
|
|
4561
|
+
useGlassesStore.subscribe((s) => `${s.sceneCanvasWidth ?? 0}x${s.sceneCanvasHeight ?? 0}:${s.sceneVector === true}:${s.firmwareVersion}:${s.connection.state}:${s.deviceModel}`, broadcast);
|
|
4562
|
+
// The debug knob flips hasNativeNavigation on custom firmware.
|
|
4563
|
+
useSettingsStore.subscribe((s) => s.getSetting(SETTINGS.cfw_native_navigation.key), broadcast);
|
|
4564
|
+
// The dashboard master switch flips the dashboard view.
|
|
4565
|
+
useSettingsStore.subscribe((s) => s.getSetting(SETTINGS.custom_dashboard_enabled.key), broadcast);
|
|
4566
|
+
}
|
|
4567
|
+
/** Capabilities as `packageName` sees them: the model profile plus the views this app may draw. */
|
|
4568
|
+
capabilitiesFor(packageName) {
|
|
4569
|
+
const capabilities = this.currentCapabilities();
|
|
4570
|
+
if (!capabilities.display)
|
|
4571
|
+
return capabilities;
|
|
4572
|
+
const views = displayViewsFor(packageName, pagesEligible());
|
|
4573
|
+
return { ...capabilities, display: { ...capabilities.display, views } };
|
|
4574
|
+
}
|
|
4575
|
+
broadcastCapabilities() {
|
|
4576
|
+
for (const packageName of this.handshookApps) {
|
|
4577
|
+
this.sendToMiniapp(packageName, {
|
|
4578
|
+
type: MiniappResponseType.CAPABILITIES_UPDATE,
|
|
4579
|
+
capabilities: this.capabilitiesFor(packageName),
|
|
4580
|
+
});
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
/** Host user preferences miniapps follow by default (Settings > Appearance). */
|
|
4584
|
+
currentPreferences() {
|
|
4585
|
+
const settings = useSettingsStore.getState();
|
|
4586
|
+
return {
|
|
4587
|
+
unitSystem: settings.getSetting(SETTINGS.metric_system.key) === true ? "metric" : "imperial",
|
|
4588
|
+
twelveHourTime: settings.getSetting(SETTINGS.twelve_hour_time.key) === true,
|
|
4589
|
+
};
|
|
4590
|
+
}
|
|
4591
|
+
ensurePreferencesWired() {
|
|
4592
|
+
if (this.preferencesWired)
|
|
4593
|
+
return;
|
|
4594
|
+
this.preferencesWired = true;
|
|
4595
|
+
useSettingsStore.subscribe((s) => `${s.getSetting(SETTINGS.metric_system.key) === true}:${s.getSetting(SETTINGS.twelve_hour_time.key) === true}`, () => {
|
|
4596
|
+
const preferences = this.currentPreferences();
|
|
4214
4597
|
for (const packageName of this.handshookApps) {
|
|
4215
|
-
this.sendToMiniapp(packageName, { type: MiniappResponseType.
|
|
4598
|
+
this.sendToMiniapp(packageName, { type: MiniappResponseType.PREFERENCES_UPDATE, preferences });
|
|
4216
4599
|
}
|
|
4217
4600
|
});
|
|
4218
4601
|
}
|
|
@@ -4251,7 +4634,9 @@ class LocalMiniappRuntime {
|
|
|
4251
4634
|
* - Cloud sends "head_up" → miniapp protocol uses "head_position" (HEAD_POSITION)
|
|
4252
4635
|
* - Cloud sends "VAD" (uppercase) → miniapp protocol uses "vad" (lowercase)
|
|
4253
4636
|
*/
|
|
4254
|
-
forwardEvent(streamType, data, transcriptionSource
|
|
4637
|
+
forwardEvent(streamType, data, transcriptionSource,
|
|
4638
|
+
/** Deliver to this subscriber alone (the designated dashboard app's gestures while it shows). */
|
|
4639
|
+
only) {
|
|
4255
4640
|
// Local sherpa results enter the runtime only through here (DeviceEventRouter's
|
|
4256
4641
|
// local_transcription listener); cloud/direct are marked at their onTranscript
|
|
4257
4642
|
// wiring, which never passes "local".
|
|
@@ -4364,6 +4749,8 @@ class LocalMiniappRuntime {
|
|
|
4364
4749
|
if (matchedSubs.size === 0 && !perGestureStream)
|
|
4365
4750
|
return;
|
|
4366
4751
|
for (const packageName of matchedSubs) {
|
|
4752
|
+
if (only !== undefined && packageName !== only)
|
|
4753
|
+
continue;
|
|
4367
4754
|
let transcriptionRoute;
|
|
4368
4755
|
if (normalizedStream.startsWith("transcription:") && transcriptionSource) {
|
|
4369
4756
|
const routes = this.appTranscriptionRoutesForEvent(packageName, normalizedStream);
|
|
@@ -4398,6 +4785,8 @@ class LocalMiniappRuntime {
|
|
|
4398
4785
|
const gestureSubs = this.streamSubscribers.get(perGestureStream);
|
|
4399
4786
|
if (gestureSubs) {
|
|
4400
4787
|
for (const packageName of gestureSubs) {
|
|
4788
|
+
if (only !== undefined && packageName !== only)
|
|
4789
|
+
continue;
|
|
4401
4790
|
this.sendToMiniapp(packageName, {
|
|
4402
4791
|
type: MiniappResponseType.EVENT,
|
|
4403
4792
|
streamType: perGestureStream,
|
|
@@ -4624,6 +5013,7 @@ class LocalMiniappRuntime {
|
|
|
4624
5013
|
name: app.name,
|
|
4625
5014
|
version: app.version ?? "",
|
|
4626
5015
|
running: app.running,
|
|
5016
|
+
hidden: app.hidden === true,
|
|
4627
5017
|
compatibility,
|
|
4628
5018
|
actions: app.actions ?? [],
|
|
4629
5019
|
};
|
|
@@ -4970,6 +5360,22 @@ class LocalMiniappRuntime {
|
|
|
4970
5360
|
visibility,
|
|
4971
5361
|
});
|
|
4972
5362
|
}
|
|
5363
|
+
/**
|
|
5364
|
+
* Push the app's foreground state to every connected miniapp. Miniapps that
|
|
5365
|
+
* pace their own work (streaming a scene, polling a sensor) need to know when
|
|
5366
|
+
* the host process is backgrounded, because that is when iOS coalesces their
|
|
5367
|
+
* timers and the BLE writer falls back to credit polling.
|
|
5368
|
+
*/
|
|
5369
|
+
broadcastVisibility(foregrounded) {
|
|
5370
|
+
const visibility = foregrounded ? "foreground" : "background";
|
|
5371
|
+
for (const packageName of this.connectedApps.keys()) {
|
|
5372
|
+
this.sendVisibilityChange(packageName, visibility);
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
/** Foreground state a miniapp is given at CONNECT_ACK, before any transition fires. */
|
|
5376
|
+
currentVisibility() {
|
|
5377
|
+
return isAppForegrounded() ? "foreground" : "background";
|
|
5378
|
+
}
|
|
4973
5379
|
/**
|
|
4974
5380
|
* Fast foreground liveness check used when a local miniapp UI is opened or
|
|
4975
5381
|
* resumed. The normal watchdog intentionally waits ~30s to avoid killing a
|