@glassly/engine 0.1.0-dev.98 → 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
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import type {KeyboardKeyEvent} from "@glassly/bluetooth-sdk"
|
|
2
|
+
|
|
3
|
+
import localMiniappRuntime from "./LocalMiniappRuntime"
|
|
4
|
+
import {BgTimer} from "../utils/timers"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Keyboard event as miniapps receive it on the `keyboard_event` stream. The
|
|
8
|
+
* shape mirrors the DOM: `key` is the logical key (layout applied, US only for
|
|
9
|
+
* now), `code` the physical key, `text` the printable character the press
|
|
10
|
+
* produces (down/repeat only), `repeat` a synthesized auto-repeat of a held key.
|
|
11
|
+
*/
|
|
12
|
+
export interface KeyboardEventPayload {
|
|
13
|
+
phase: "down" | "up"
|
|
14
|
+
key: string
|
|
15
|
+
code: string
|
|
16
|
+
modifiers: {shift: boolean; ctrl: boolean; alt: boolean; meta: boolean}
|
|
17
|
+
text?: string
|
|
18
|
+
repeat: boolean
|
|
19
|
+
timestamp: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface Timers {
|
|
23
|
+
setTimeout: (callback: () => void, delayMs: number) => number
|
|
24
|
+
clearTimeout: (id: number) => void
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface KeyboardInputOptions {
|
|
28
|
+
forward: (payload: KeyboardEventPayload) => void
|
|
29
|
+
timers?: Timers
|
|
30
|
+
now?: () => number
|
|
31
|
+
/** Typematic delay before the first repeat and the interval between repeats. */
|
|
32
|
+
repeatDelayMs?: number
|
|
33
|
+
repeatIntervalMs?: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const REPEAT_DELAY_MS = 400
|
|
37
|
+
const REPEAT_INTERVAL_MS = 50
|
|
38
|
+
|
|
39
|
+
/** [unshifted, shifted] for US layout punctuation on the keyboard page. */
|
|
40
|
+
const PUNCTUATION: Record<number, [string, string, string]> = {
|
|
41
|
+
45: ["-", "_", "Minus"],
|
|
42
|
+
46: ["=", "+", "Equal"],
|
|
43
|
+
47: ["[", "{", "BracketLeft"],
|
|
44
|
+
48: ["]", "}", "BracketRight"],
|
|
45
|
+
49: ["\\", "|", "Backslash"],
|
|
46
|
+
50: ["#", "~", "IntlHash"],
|
|
47
|
+
51: [";", ":", "Semicolon"],
|
|
48
|
+
52: ["'", '"', "Quote"],
|
|
49
|
+
53: ["`", "~", "Backquote"],
|
|
50
|
+
54: [",", "<", "Comma"],
|
|
51
|
+
55: [".", ">", "Period"],
|
|
52
|
+
56: ["/", "?", "Slash"],
|
|
53
|
+
100: ["\\", "|", "IntlBackslash"],
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const SHIFTED_DIGITS = "!@#$%^&*()"
|
|
57
|
+
const DIGITS = "1234567890"
|
|
58
|
+
|
|
59
|
+
const NAMED: Record<number, [string, string]> = {
|
|
60
|
+
40: ["Enter", "Enter"],
|
|
61
|
+
41: ["Escape", "Escape"],
|
|
62
|
+
42: ["Backspace", "Backspace"],
|
|
63
|
+
43: ["Tab", "Tab"],
|
|
64
|
+
57: ["CapsLock", "CapsLock"],
|
|
65
|
+
70: ["PrintScreen", "PrintScreen"],
|
|
66
|
+
71: ["ScrollLock", "ScrollLock"],
|
|
67
|
+
72: ["Pause", "Pause"],
|
|
68
|
+
73: ["Insert", "Insert"],
|
|
69
|
+
74: ["Home", "Home"],
|
|
70
|
+
75: ["PageUp", "PageUp"],
|
|
71
|
+
76: ["Delete", "Delete"],
|
|
72
|
+
77: ["End", "End"],
|
|
73
|
+
78: ["PageDown", "PageDown"],
|
|
74
|
+
79: ["ArrowRight", "ArrowRight"],
|
|
75
|
+
80: ["ArrowLeft", "ArrowLeft"],
|
|
76
|
+
81: ["ArrowDown", "ArrowDown"],
|
|
77
|
+
82: ["ArrowUp", "ArrowUp"],
|
|
78
|
+
83: ["NumLock", "NumLock"],
|
|
79
|
+
88: ["Enter", "NumpadEnter"],
|
|
80
|
+
101: ["ContextMenu", "ContextMenu"],
|
|
81
|
+
102: ["Power", "Power"],
|
|
82
|
+
224: ["Control", "ControlLeft"],
|
|
83
|
+
225: ["Shift", "ShiftLeft"],
|
|
84
|
+
226: ["Alt", "AltLeft"],
|
|
85
|
+
227: ["Meta", "MetaLeft"],
|
|
86
|
+
228: ["Control", "ControlRight"],
|
|
87
|
+
229: ["Shift", "ShiftRight"],
|
|
88
|
+
230: ["Alt", "AltRight"],
|
|
89
|
+
231: ["Meta", "MetaRight"],
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const NUMPAD: Record<number, [string, string]> = {
|
|
93
|
+
84: ["/", "NumpadDivide"],
|
|
94
|
+
85: ["*", "NumpadMultiply"],
|
|
95
|
+
86: ["-", "NumpadSubtract"],
|
|
96
|
+
87: ["+", "NumpadAdd"],
|
|
97
|
+
99: [".", "NumpadDecimal"],
|
|
98
|
+
103: ["=", "NumpadEqual"],
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const CONSUMER: Record<number, string> = {
|
|
102
|
+
0xe9: "AudioVolumeUp",
|
|
103
|
+
0xea: "AudioVolumeDown",
|
|
104
|
+
0xe2: "AudioVolumeMute",
|
|
105
|
+
0xcd: "MediaPlayPause",
|
|
106
|
+
0xb0: "MediaPlay",
|
|
107
|
+
0xb1: "MediaPause",
|
|
108
|
+
0xb5: "MediaTrackNext",
|
|
109
|
+
0xb6: "MediaTrackPrevious",
|
|
110
|
+
0xb7: "MediaStop",
|
|
111
|
+
0x6f: "BrightnessUp",
|
|
112
|
+
0x70: "BrightnessDown",
|
|
113
|
+
0x221: "BrowserSearch",
|
|
114
|
+
0x223: "BrowserHome",
|
|
115
|
+
0x224: "BrowserBack",
|
|
116
|
+
0x225: "BrowserForward",
|
|
117
|
+
0x18a: "LaunchMail",
|
|
118
|
+
0x192: "LaunchApplication2",
|
|
119
|
+
0x194: "LaunchApplication1",
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
interface Translated {
|
|
123
|
+
key: string
|
|
124
|
+
code: string
|
|
125
|
+
text?: string
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Map one HID usage to DOM-style key/code/text under the US layout. Exported
|
|
130
|
+
* for tests; `shift` is the effective shift (Shift XOR CapsLock for letters).
|
|
131
|
+
*/
|
|
132
|
+
export function translateUsage(page: number, usage: number, shift: boolean, capsLock: boolean): Translated {
|
|
133
|
+
if (page === 7) {
|
|
134
|
+
if (usage >= 4 && usage <= 29) {
|
|
135
|
+
const lower = String.fromCharCode(97 + usage - 4)
|
|
136
|
+
const upper = shift !== capsLock
|
|
137
|
+
const key = upper ? lower.toUpperCase() : lower
|
|
138
|
+
return {key, code: `Key${lower.toUpperCase()}`, text: key}
|
|
139
|
+
}
|
|
140
|
+
if (usage >= 30 && usage <= 39) {
|
|
141
|
+
const index = usage - 30
|
|
142
|
+
const key = shift ? SHIFTED_DIGITS[index]! : DIGITS[index]!
|
|
143
|
+
return {key, code: `Digit${DIGITS[index]}`, text: key}
|
|
144
|
+
}
|
|
145
|
+
if (usage === 44) return {key: " ", code: "Space", text: " "}
|
|
146
|
+
const punctuation = PUNCTUATION[usage]
|
|
147
|
+
if (punctuation) {
|
|
148
|
+
const key = shift ? punctuation[1] : punctuation[0]
|
|
149
|
+
return {key, code: punctuation[2], text: key}
|
|
150
|
+
}
|
|
151
|
+
if (usage >= 58 && usage <= 69) return {key: `F${usage - 57}`, code: `F${usage - 57}`}
|
|
152
|
+
if (usage >= 104 && usage <= 115) return {key: `F${usage - 91}`, code: `F${usage - 91}`}
|
|
153
|
+
if (usage >= 89 && usage <= 97) {
|
|
154
|
+
const digit = String(usage - 88)
|
|
155
|
+
return {key: digit, code: `Numpad${digit}`, text: digit}
|
|
156
|
+
}
|
|
157
|
+
if (usage === 98) return {key: "0", code: "Numpad0", text: "0"}
|
|
158
|
+
const numpad = NUMPAD[usage]
|
|
159
|
+
if (numpad) return {key: numpad[0], code: numpad[1], text: numpad[0]}
|
|
160
|
+
const named = NAMED[usage]
|
|
161
|
+
if (named) return {key: named[0], code: named[1]}
|
|
162
|
+
return {key: "Unidentified", code: `Usage${usage.toString(16).padStart(2, "0")}`}
|
|
163
|
+
}
|
|
164
|
+
if (page === 12) {
|
|
165
|
+
const name = CONSUMER[usage]
|
|
166
|
+
return name ? {key: name, code: name} : {key: "Unidentified", code: `Consumer${usage.toString(16)}`}
|
|
167
|
+
}
|
|
168
|
+
return {key: "Unidentified", code: `Page${page.toString(16)}Usage${usage.toString(16)}`}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const MODIFIER_USAGES = new Set([224, 225, 226, 227, 228, 229, 230, 231])
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Turns the native bridge's raw HID transitions into layout-translated
|
|
175
|
+
* keyboard events and synthesizes typematic auto-repeat, which BLE HID
|
|
176
|
+
* keyboards never send (the report just stays asserted). Modifier state is
|
|
177
|
+
* derived from the same stream, so a lost release (the bridge emits an `up`
|
|
178
|
+
* for every gap) always clears it.
|
|
179
|
+
*/
|
|
180
|
+
export class GlassesKeyboardInput {
|
|
181
|
+
private readonly forward: (payload: KeyboardEventPayload) => void
|
|
182
|
+
private readonly timers: Timers
|
|
183
|
+
private readonly now: () => number
|
|
184
|
+
private readonly repeatDelayMs: number
|
|
185
|
+
private readonly repeatIntervalMs: number
|
|
186
|
+
private held = new Map<string, {page: number; usage: number}>()
|
|
187
|
+
private modifiers = {shift: false, ctrl: false, alt: false, meta: false}
|
|
188
|
+
private capsLock = false
|
|
189
|
+
private repeatTimer: number | null = null
|
|
190
|
+
private repeating: {page: number; usage: number} | null = null
|
|
191
|
+
|
|
192
|
+
constructor(options: KeyboardInputOptions) {
|
|
193
|
+
this.forward = options.forward
|
|
194
|
+
this.timers = options.timers ?? {
|
|
195
|
+
setTimeout: (callback, delay) => BgTimer.setTimeout(callback, delay),
|
|
196
|
+
clearTimeout: (id) => BgTimer.clearTimeout(id),
|
|
197
|
+
}
|
|
198
|
+
this.now = options.now ?? (() => Date.now())
|
|
199
|
+
this.repeatDelayMs = options.repeatDelayMs ?? REPEAT_DELAY_MS
|
|
200
|
+
this.repeatIntervalMs = options.repeatIntervalMs ?? REPEAT_INTERVAL_MS
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** One raw transition from the `keyboard_key` native event. */
|
|
204
|
+
handle(event: KeyboardKeyEvent): void {
|
|
205
|
+
const id = `${event.page}:${event.usage}`
|
|
206
|
+
if (event.down) {
|
|
207
|
+
if (this.held.has(id)) return // duplicate report; the firmware already de-duplicates
|
|
208
|
+
this.held.set(id, {page: event.page, usage: event.usage})
|
|
209
|
+
this.applyModifier(event.page, event.usage, true)
|
|
210
|
+
if (event.page === 7 && event.usage === 57) this.capsLock = !this.capsLock
|
|
211
|
+
this.emit("down", event.page, event.usage, false, event.timestamp)
|
|
212
|
+
if (!(event.page === 7 && MODIFIER_USAGES.has(event.usage))) this.startRepeat(event.page, event.usage)
|
|
213
|
+
} else {
|
|
214
|
+
if (!this.held.delete(id)) return
|
|
215
|
+
this.applyModifier(event.page, event.usage, false)
|
|
216
|
+
if (this.repeating?.page === event.page && this.repeating.usage === event.usage) this.stopRepeat()
|
|
217
|
+
this.emit("up", event.page, event.usage, false, event.timestamp)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Link lost or keyboard dropped: forget everything without emitting. */
|
|
222
|
+
reset(): void {
|
|
223
|
+
this.stopRepeat()
|
|
224
|
+
this.held.clear()
|
|
225
|
+
this.modifiers = {shift: false, ctrl: false, alt: false, meta: false}
|
|
226
|
+
this.capsLock = false
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private applyModifier(page: number, usage: number, down: boolean): void {
|
|
230
|
+
if (page !== 7) return
|
|
231
|
+
switch (usage) {
|
|
232
|
+
case 224:
|
|
233
|
+
case 228:
|
|
234
|
+
this.modifiers.ctrl = down || this.otherHeld(usage === 224 ? 228 : 224)
|
|
235
|
+
break
|
|
236
|
+
case 225:
|
|
237
|
+
case 229:
|
|
238
|
+
this.modifiers.shift = down || this.otherHeld(usage === 225 ? 229 : 225)
|
|
239
|
+
break
|
|
240
|
+
case 226:
|
|
241
|
+
case 230:
|
|
242
|
+
this.modifiers.alt = down || this.otherHeld(usage === 226 ? 230 : 226)
|
|
243
|
+
break
|
|
244
|
+
case 227:
|
|
245
|
+
case 231:
|
|
246
|
+
this.modifiers.meta = down || this.otherHeld(usage === 227 ? 231 : 227)
|
|
247
|
+
break
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
private otherHeld(usage: number): boolean {
|
|
252
|
+
return this.held.has(`7:${usage}`)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private emit(phase: "down" | "up", page: number, usage: number, repeat: boolean, timestamp: number): void {
|
|
256
|
+
const translated = translateUsage(page, usage, this.modifiers.shift, this.capsLock)
|
|
257
|
+
const payload: KeyboardEventPayload = {
|
|
258
|
+
phase,
|
|
259
|
+
key: translated.key,
|
|
260
|
+
code: translated.code,
|
|
261
|
+
modifiers: {...this.modifiers},
|
|
262
|
+
repeat,
|
|
263
|
+
timestamp,
|
|
264
|
+
}
|
|
265
|
+
// Text only for plain presses: Ctrl/Alt/Meta chords are commands, not typing.
|
|
266
|
+
if (
|
|
267
|
+
phase === "down" &&
|
|
268
|
+
translated.text !== undefined &&
|
|
269
|
+
!this.modifiers.ctrl &&
|
|
270
|
+
!this.modifiers.alt &&
|
|
271
|
+
!this.modifiers.meta
|
|
272
|
+
) {
|
|
273
|
+
payload.text = translated.text
|
|
274
|
+
}
|
|
275
|
+
this.forward(payload)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private startRepeat(page: number, usage: number): void {
|
|
279
|
+
this.stopRepeat()
|
|
280
|
+
this.repeating = {page, usage}
|
|
281
|
+
this.repeatTimer = this.timers.setTimeout(() => this.repeatTick(), this.repeatDelayMs)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private repeatTick(): void {
|
|
285
|
+
const key = this.repeating
|
|
286
|
+
if (!key || !this.held.has(`${key.page}:${key.usage}`)) {
|
|
287
|
+
this.stopRepeat()
|
|
288
|
+
return
|
|
289
|
+
}
|
|
290
|
+
this.emit("down", key.page, key.usage, true, this.now())
|
|
291
|
+
this.repeatTimer = this.timers.setTimeout(() => this.repeatTick(), this.repeatIntervalMs)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private stopRepeat(): void {
|
|
295
|
+
if (this.repeatTimer !== null) this.timers.clearTimeout(this.repeatTimer)
|
|
296
|
+
this.repeatTimer = null
|
|
297
|
+
this.repeating = null
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** Engine singleton: fans translated events out to subscribed miniapps. */
|
|
302
|
+
const glassesKeyboardInput = new GlassesKeyboardInput({
|
|
303
|
+
forward: (payload) => localMiniappRuntime.forwardEvent("keyboard_event", payload),
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
export default glassesKeyboardInput
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import BluetoothSdk from "@glassly/bluetooth-sdk/internal"
|
|
2
|
+
import {MiniappErrorCode} from "@glassly/miniapp/protocol"
|
|
3
|
+
import {BgTimer} from "../utils/timers"
|
|
4
|
+
|
|
5
|
+
type Sensor = "light" | "compass"
|
|
6
|
+
type Operation = "query" | "start" | "stop"
|
|
7
|
+
type Options = Record<string, number>
|
|
8
|
+
type Control = (sensor: Sensor, operation: Operation, options: Options) => Promise<boolean>
|
|
9
|
+
type Owner = {app: string; options: Options}
|
|
10
|
+
|
|
11
|
+
const RANGES: Record<Sensor, Record<string, [number, number]>> = {
|
|
12
|
+
light: {intervalMs: [100, 5000], minDelta: [0, 65535], heartbeatMs: [0, 65535]},
|
|
13
|
+
compass: {intervalMs: [50, 2000], minChangeDegrees: [0, 359]},
|
|
14
|
+
}
|
|
15
|
+
const COMPASS_DEFAULTS: Options = {intervalMs: 1000, minChangeDegrees: 5}
|
|
16
|
+
const COMPASS_RETRY_MS = [2000, 4000, 8000]
|
|
17
|
+
|
|
18
|
+
function fail(code: MiniappErrorCode, message: string): never {
|
|
19
|
+
throw Object.assign(new Error(message), {code})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function sameOptions(a: Options | null, b: Options | null): boolean {
|
|
23
|
+
if (!a || !b) return a === b
|
|
24
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)])
|
|
25
|
+
for (const key of keys) if (a[key] !== b[key]) return false
|
|
26
|
+
return true
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Light: explicit, miniapp-scoped ownership. A subscriber alone never changes auto brightness.
|
|
31
|
+
* Compass: demand-driven. It runs while any miniapp is subscribed; `start(options)` only
|
|
32
|
+
* records that miniapp's override and everyone is served the smallest interval and
|
|
33
|
+
* threshold requested. Native navigation temporarily borrows both; its stock configuration wins.
|
|
34
|
+
*/
|
|
35
|
+
export class GlassesSensorService {
|
|
36
|
+
private lightOwner: Owner | null = null
|
|
37
|
+
private compassSubscribers = new Set<string>()
|
|
38
|
+
private compassOverrides = new Map<string, Options>()
|
|
39
|
+
/** Options the firmware currently runs; null while stopped. */
|
|
40
|
+
private compassApplied: Options | null = null
|
|
41
|
+
private compassRetry: number | null = null
|
|
42
|
+
private compassRetryAttempt = 0
|
|
43
|
+
private pending: Promise<unknown> = Promise.resolve()
|
|
44
|
+
private navigationActive = false
|
|
45
|
+
private generation = 0
|
|
46
|
+
|
|
47
|
+
constructor(private readonly control: Control) {}
|
|
48
|
+
|
|
49
|
+
private serial<T>(work: () => Promise<T>): Promise<T> {
|
|
50
|
+
const next = this.pending.then(work)
|
|
51
|
+
this.pending = next.catch(() => {})
|
|
52
|
+
return next
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private validate(payload: Record<string, unknown>): {sensor: Sensor; operation: Operation; options: Options} {
|
|
56
|
+
const sensor = payload.sensor
|
|
57
|
+
const operation = payload.operation
|
|
58
|
+
if (sensor !== "light" && sensor !== "compass") fail(MiniappErrorCode.INVALID_ARGUMENT, "Unknown sensor")
|
|
59
|
+
if (operation !== "start" && operation !== "stop" && !(sensor === "light" && operation === "query")) {
|
|
60
|
+
fail(MiniappErrorCode.INVALID_ARGUMENT, "Unknown sensor operation")
|
|
61
|
+
}
|
|
62
|
+
const raw = payload.options ?? {}
|
|
63
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw))
|
|
64
|
+
fail(MiniappErrorCode.INVALID_ARGUMENT, "Invalid sensor options")
|
|
65
|
+
const ranges = RANGES[sensor]
|
|
66
|
+
const options: Options = {}
|
|
67
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
68
|
+
const range = Object.prototype.hasOwnProperty.call(ranges, key) ? ranges[key] : undefined
|
|
69
|
+
if (!range || typeof value !== "number" || !Number.isInteger(value) || value < range[0] || value > range[1]) {
|
|
70
|
+
fail(MiniappErrorCode.INVALID_ARGUMENT, `Invalid ${key}`)
|
|
71
|
+
}
|
|
72
|
+
options[key] = value
|
|
73
|
+
}
|
|
74
|
+
return {sensor, operation, options}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
request(app: string, payload: Record<string, unknown>): Promise<void> {
|
|
78
|
+
const generation = this.generation
|
|
79
|
+
return this.serial(async () => {
|
|
80
|
+
if (generation !== this.generation) fail(MiniappErrorCode.NOT_CONNECTED, "Glasses disconnected")
|
|
81
|
+
const {sensor, operation, options} = this.validate(payload)
|
|
82
|
+
if (sensor === "compass") {
|
|
83
|
+
if (operation === "start") this.compassOverrides.set(app, options)
|
|
84
|
+
else this.compassOverrides.delete(app)
|
|
85
|
+
if (this.navigationActive) return
|
|
86
|
+
await this.applyCompass(generation, true)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
const owner = this.lightOwner
|
|
90
|
+
if (operation !== "query" && owner && owner.app !== app) {
|
|
91
|
+
fail(MiniappErrorCode.INVALID_ARGUMENT, "This sensor is controlled by another miniapp")
|
|
92
|
+
}
|
|
93
|
+
if (operation === "stop" && !owner) return
|
|
94
|
+
if (this.navigationActive) {
|
|
95
|
+
if (operation === "stop") {
|
|
96
|
+
this.lightOwner = null
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
fail(MiniappErrorCode.INVALID_ARGUMENT, "Native navigation currently owns the glasses sensors")
|
|
100
|
+
}
|
|
101
|
+
// Keep cleanup ownership even after an ambiguous transport failure: the firmware
|
|
102
|
+
// may have applied the command before its ACK was lost.
|
|
103
|
+
if (operation === "start") this.lightOwner = {app, options}
|
|
104
|
+
if (!(await this.control("light", operation, options))) this.commandFailed()
|
|
105
|
+
if (generation !== this.generation) fail(MiniappErrorCode.NOT_CONNECTED, "Glasses disconnected")
|
|
106
|
+
if (operation === "stop") this.lightOwner = null
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private commandFailed(): never {
|
|
111
|
+
fail(
|
|
112
|
+
MiniappErrorCode.INTERNAL,
|
|
113
|
+
"Sensor command failed: connect G2 custom firmware and keep its miniapp display active",
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Miniapps currently subscribed to the glasses compass stream. Replaces the previous set. */
|
|
118
|
+
setCompassSubscribers(apps: Iterable<string>): Promise<void> {
|
|
119
|
+
const generation = this.generation
|
|
120
|
+
return this.serial(async () => {
|
|
121
|
+
this.compassSubscribers = new Set(apps)
|
|
122
|
+
if (generation !== this.generation || this.navigationActive) return
|
|
123
|
+
await this.applyCompass(generation, false)
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private compassDemand(): Options | null {
|
|
128
|
+
if (this.compassSubscribers.size === 0 && this.compassOverrides.size === 0) return null
|
|
129
|
+
const requests = [...this.compassOverrides.values()].map((o) => ({...COMPASS_DEFAULTS, ...o}))
|
|
130
|
+
for (const app of this.compassSubscribers) if (!this.compassOverrides.has(app)) requests.push(COMPASS_DEFAULTS)
|
|
131
|
+
const demand: Options = {}
|
|
132
|
+
for (const key of Object.keys(COMPASS_DEFAULTS)) demand[key] = Math.min(...requests.map((r) => r[key]))
|
|
133
|
+
return demand
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Bring the firmware in line with current demand. Explicit requests surface failures;
|
|
138
|
+
* subscription-driven applies stay silent (stock firmware, no CFW carrier yet) and retry
|
|
139
|
+
* a few times so a compass subscribed before firmware classification still starts.
|
|
140
|
+
*/
|
|
141
|
+
private async applyCompass(generation: number, explicit: boolean): Promise<void> {
|
|
142
|
+
this.clearCompassRetry()
|
|
143
|
+
const demand = this.compassDemand()
|
|
144
|
+
if (sameOptions(demand, this.compassApplied)) return
|
|
145
|
+
if (!demand) {
|
|
146
|
+
const ok = await this.control("compass", "stop", {})
|
|
147
|
+
if (generation === this.generation) this.compassApplied = null
|
|
148
|
+
if (!ok && explicit) this.commandFailed()
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
const ok = await this.control("compass", "start", demand)
|
|
152
|
+
if (generation !== this.generation) {
|
|
153
|
+
if (explicit) fail(MiniappErrorCode.NOT_CONNECTED, "Glasses disconnected")
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
if (ok) {
|
|
157
|
+
this.compassApplied = demand
|
|
158
|
+
this.compassRetryAttempt = 0
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
if (explicit) this.commandFailed()
|
|
162
|
+
const delay = COMPASS_RETRY_MS[this.compassRetryAttempt]
|
|
163
|
+
if (delay === undefined) return
|
|
164
|
+
this.compassRetryAttempt++
|
|
165
|
+
this.compassRetry = BgTimer.setTimeout(() => {
|
|
166
|
+
this.compassRetry = null
|
|
167
|
+
void this.resync()
|
|
168
|
+
}, delay)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private clearCompassRetry(): void {
|
|
172
|
+
if (this.compassRetry != null) BgTimer.clearTimeout(this.compassRetry)
|
|
173
|
+
this.compassRetry = null
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Re-apply compass demand after the glasses connect or their firmware is classified. */
|
|
177
|
+
resync(): Promise<void> {
|
|
178
|
+
const generation = this.generation
|
|
179
|
+
return this.serial(async () => {
|
|
180
|
+
if (generation !== this.generation || this.navigationActive) return
|
|
181
|
+
await this.applyCompass(generation, false).catch(() => {})
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
release(app: string): Promise<void> {
|
|
186
|
+
const generation = this.generation
|
|
187
|
+
return this.serial(async () => {
|
|
188
|
+
if (generation !== this.generation) return
|
|
189
|
+
const hadSubscription = this.compassSubscribers.delete(app)
|
|
190
|
+
const hadOverride = this.compassOverrides.delete(app)
|
|
191
|
+
const hadCompass = hadSubscription || hadOverride
|
|
192
|
+
if (this.lightOwner?.app === app) {
|
|
193
|
+
if (!this.navigationActive) await this.control("light", "stop", {}).catch(() => false)
|
|
194
|
+
this.lightOwner = null
|
|
195
|
+
}
|
|
196
|
+
if (hadCompass && !this.navigationActive) await this.applyCompass(generation, false).catch(() => {})
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
setNavigationActive(active: boolean): Promise<void> {
|
|
201
|
+
const generation = this.generation
|
|
202
|
+
return this.serial(async () => {
|
|
203
|
+
if (generation !== this.generation) return
|
|
204
|
+
if (this.navigationActive === active) return
|
|
205
|
+
this.navigationActive = active
|
|
206
|
+
this.clearCompassRetry()
|
|
207
|
+
if (active) {
|
|
208
|
+
if (this.lightOwner) await this.control("light", "stop", {}).catch(() => false)
|
|
209
|
+
if (this.compassApplied) await this.control("compass", "stop", {}).catch(() => false)
|
|
210
|
+
this.compassApplied = null
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
if (this.lightOwner) await this.control("light", "start", this.lightOwner.options).catch(() => false)
|
|
214
|
+
this.compassRetryAttempt = 0
|
|
215
|
+
await this.applyCompass(generation, false).catch(() => {})
|
|
216
|
+
})
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Never replay requests from an old miniapp connection onto a new pair of glasses. */
|
|
220
|
+
disconnected(): void {
|
|
221
|
+
this.generation++
|
|
222
|
+
this.clearCompassRetry()
|
|
223
|
+
this.compassRetryAttempt = 0
|
|
224
|
+
this.lightOwner = null
|
|
225
|
+
this.compassApplied = null
|
|
226
|
+
this.navigationActive = false
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const glassesSensorService = new GlassesSensorService((sensor, operation, options) =>
|
|
231
|
+
BluetoothSdk.glassesSensorControl(sensor, operation, options),
|
|
232
|
+
)
|
|
233
|
+
export default glassesSensorService
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import {useDisplayStore} from "../stores/display"
|
|
2
|
+
import {DeviceModels, type TouchEvent} from "@glassly/bluetooth-sdk"
|
|
3
|
+
import BluetoothSdk from "@glassly/bluetooth-sdk/internal"
|
|
4
|
+
|
|
5
|
+
import {useAppStatusStore} from "../stores/apps"
|
|
6
|
+
import {useGlassesStore} from "../stores/glasses"
|
|
7
|
+
import {BgTimer} from "../utils/timers"
|
|
8
|
+
import dashboardOpenTrace from "./debug/DashboardOpenTrace"
|
|
9
|
+
import gestureDotsService from "./GestureDotsService"
|
|
10
|
+
import localDisplayManager from "./LocalDisplayManager"
|
|
11
|
+
import localMiniappRuntime from "./LocalMiniappRuntime"
|
|
12
|
+
import {MiniappExitGesture} from "./MiniappExitGesture"
|
|
13
|
+
import nativeNavigationService from "./NativeNavigationService"
|
|
14
|
+
import {isOverlayApp} from "./pages/overlayApps"
|
|
15
|
+
|
|
16
|
+
const miniappExitGesture = new MiniappExitGesture({
|
|
17
|
+
getState: () => useAppStatusStore.getState(),
|
|
18
|
+
getVisiblePackageName: () => localDisplayManager.getVisibleMiniappPackageName(),
|
|
19
|
+
beginExitNotice: (packageName, text) => localDisplayManager.beginMiniappExit(packageName, text),
|
|
20
|
+
finishExitNotice: (packageName) => localDisplayManager.finishMiniappExit(packageName),
|
|
21
|
+
cancelExitNotice: (packageName) => localDisplayManager.cancelMiniappExit(packageName),
|
|
22
|
+
setTimeout: (callback, delay) => BgTimer.setTimeout(callback, delay),
|
|
23
|
+
clearTimeout: (timerId) => BgTimer.clearTimeout(timerId),
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
// Raw CFW ring reports include every scroll step. Rate-limit scroll actions
|
|
27
|
+
// separately from press/release recognition, using native receipt timestamps
|
|
28
|
+
// so a JS backlog does not collapse otherwise separate gestures.
|
|
29
|
+
const RING_SCROLL_INTERVAL_MS = 100
|
|
30
|
+
let lastRingScrollAt: number | null = null
|
|
31
|
+
|
|
32
|
+
function shouldForwardScroll(event: TouchEvent): boolean {
|
|
33
|
+
if (
|
|
34
|
+
event.deviceModel !== DeviceModels.G2 ||
|
|
35
|
+
event.source !== 2 ||
|
|
36
|
+
(event.gestureName !== "swipe_up" && event.gestureName !== "swipe_down")
|
|
37
|
+
)
|
|
38
|
+
return true
|
|
39
|
+
const elapsed = lastRingScrollAt === null ? null : event.timestamp - lastRingScrollAt
|
|
40
|
+
if (elapsed !== null && elapsed >= 0 && elapsed < RING_SCROLL_INTERVAL_MS) return false
|
|
41
|
+
lastRingScrollAt = event.timestamp
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Route both real glasses input and phone mirror controls through the same
|
|
47
|
+
* policy. A claimed gesture goes to the app holding the claim, alone; an
|
|
48
|
+
* unclaimed one goes to every subscriber and then the engine's default. The
|
|
49
|
+
* one rule ahead of the claims: an unclaimed double tap on a miniapp whose
|
|
50
|
+
* frame is visibly on the glasses leaves that app, whoever else claimed the
|
|
51
|
+
* gesture — the dashboard's claim is for the empty screen.
|
|
52
|
+
*/
|
|
53
|
+
export function dispatchTouchEvent(event: TouchEvent): void {
|
|
54
|
+
const gesture = event.gestureName
|
|
55
|
+
const claimant = localMiniappRuntime.gestureClaimant(gesture)
|
|
56
|
+
|
|
57
|
+
if (gesture === "double_tap") {
|
|
58
|
+
// A visible main miniapp opts out of OS exit by registering double tap (the
|
|
59
|
+
// terminal's back-to-menu). The latest claimant still receives it. Otherwise
|
|
60
|
+
// the tap means "leave the app". The controller shows the bounded OS
|
|
61
|
+
// notice first, then uses the normal
|
|
62
|
+
// store stop path (and closes its phone overlay).
|
|
63
|
+
const visible = localDisplayManager.getVisibleMiniappPackageName()
|
|
64
|
+
if (
|
|
65
|
+
visible !== null &&
|
|
66
|
+
!localMiniappRuntime.hasGestureClaim(visible, gesture) &&
|
|
67
|
+
miniappExitGesture.tryExitVisibleMiniapp()
|
|
68
|
+
) {
|
|
69
|
+
gestureDotsService.noteGesture(gesture, true)
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (claimant !== null) {
|
|
75
|
+
// An overlay app claims the double tap on an empty screen to open the dashboard.
|
|
76
|
+
if (gesture === "double_tap" && isOverlayApp(claimant)) dashboardOpenTrace.trigger("double-tap", event.timestamp)
|
|
77
|
+
// The press may have started before this app claimed its release edge.
|
|
78
|
+
gestureDotsService.noteGesture(gesture, true)
|
|
79
|
+
if (!shouldForwardScroll(event)) return
|
|
80
|
+
localMiniappRuntime.forwardEvent("touch_event", event, undefined, claimant)
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Gesture-dots debug indicator (any device, gated by its setting). It
|
|
85
|
+
// only paints while the screen is otherwise empty. Process even suppressed
|
|
86
|
+
// scroll repeats here so their completion still clears a held dot.
|
|
87
|
+
gestureDotsService.noteGesture(gesture)
|
|
88
|
+
|
|
89
|
+
if (!shouldForwardScroll(event)) return
|
|
90
|
+
localMiniappRuntime.forwardEvent("touch_event", event)
|
|
91
|
+
|
|
92
|
+
// Nobody claimed a double tap: the glasses' own dashboard. On eligible
|
|
93
|
+
// Glassly CFW glasses the dashboard miniapp claims it while it runs
|
|
94
|
+
// (ADR-0006); stock firmware keeps its native dashboard (ADR-0002). The
|
|
95
|
+
// modal nav UI owns the screen; showDashboard would fight it.
|
|
96
|
+
if (gesture === "double_tap" && !nativeNavigationService.isActive) {
|
|
97
|
+
useDisplayStore.getState().setDisplayEvent({layout: {layoutType: "unavailable", reason: "firmware-dashboard"}})
|
|
98
|
+
void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {
|
|
99
|
+
console.error("DeviceEventRouter: showDashboard failed:", err)
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function resetTouchInput(): void {
|
|
105
|
+
miniappExitGesture.reset()
|
|
106
|
+
lastRingScrollAt = null
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Phone mirror input uses the same dashboard/miniapp policy as real glasses. */
|
|
110
|
+
export function sendGesture(
|
|
111
|
+
gestureName:
|
|
112
|
+
| "single_tap"
|
|
113
|
+
| "tap_start"
|
|
114
|
+
| "double_tap"
|
|
115
|
+
| "tap_end"
|
|
116
|
+
| "tap_then_hold"
|
|
117
|
+
| "touch_down"
|
|
118
|
+
| "swipe_up"
|
|
119
|
+
| "swipe_down",
|
|
120
|
+
): void {
|
|
121
|
+
const model = useGlassesStore.getState().deviceModel
|
|
122
|
+
dispatchTouchEvent({
|
|
123
|
+
type: "touch_event",
|
|
124
|
+
gestureName,
|
|
125
|
+
deviceModel: Object.values(DeviceModels).find((candidate) => candidate === model) ?? DeviceModels.Simulated,
|
|
126
|
+
timestamp: Date.now(),
|
|
127
|
+
})
|
|
128
|
+
}
|