@glassly/engine 0.1.0-dev.1 → 0.1.0-dev.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -19
- package/build/bluetooth-sdk/debug.d.ts +2 -0
- package/build/bluetooth-sdk/debug.d.ts.map +1 -0
- package/build/bluetooth-sdk/debug.js +2 -0
- package/build/bluetooth-sdk/debug.js.map +1 -0
- package/build/bluetooth-sdk/index.d.ts +3 -0
- package/build/bluetooth-sdk/index.d.ts.map +1 -0
- package/build/bluetooth-sdk/index.js +3 -0
- package/build/bluetooth-sdk/index.js.map +1 -0
- package/build/bluetooth-sdk/ota-transport.d.ts +2 -0
- package/build/bluetooth-sdk/ota-transport.d.ts.map +1 -0
- package/build/bluetooth-sdk/ota-transport.js +2 -0
- package/build/bluetooth-sdk/ota-transport.js.map +1 -0
- package/build/bluetooth-sdk/photo-receiver.d.ts +3 -0
- package/build/bluetooth-sdk/photo-receiver.d.ts.map +1 -0
- package/build/bluetooth-sdk/photo-receiver.js +3 -0
- package/build/bluetooth-sdk/photo-receiver.js.map +1 -0
- package/build/bluetooth-sdk/react.d.ts +2 -0
- package/build/bluetooth-sdk/react.d.ts.map +1 -0
- package/build/bluetooth-sdk/react.js +2 -0
- package/build/bluetooth-sdk/react.js.map +1 -0
- package/build/bluetooth-sdk/types.d.ts +2 -0
- package/build/bluetooth-sdk/types.d.ts.map +1 -0
- package/build/bluetooth-sdk/types.js +2 -0
- package/build/bluetooth-sdk/types.js.map +1 -0
- package/build/engine.d.ts +30 -18
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +12 -3
- package/build/engine.js.map +1 -1
- package/build/facades/dev.d.ts +1 -1
- package/build/facades/display.d.ts +11 -4
- package/build/facades/display.d.ts.map +1 -1
- package/build/facades/display.js +12 -2
- package/build/facades/display.js.map +1 -1
- package/build/facades/displayMirror.d.ts +2 -6
- package/build/facades/displayMirror.d.ts.map +1 -1
- package/build/facades/displayMirror.js +7 -14
- package/build/facades/displayMirror.js.map +1 -1
- package/build/facades/glasses.d.ts +6 -13
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +7 -3
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/ota.d.ts +21 -21
- package/build/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +26 -10
- package/build/facades/ota.js.map +1 -1
- package/build/facades/pairing.d.ts +11 -5
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +93 -17
- package/build/facades/pairing.js.map +1 -1
- package/build/facades/phoneNotifications.d.ts +12 -2
- package/build/facades/phoneNotifications.d.ts.map +1 -1
- package/build/facades/phoneNotifications.js +30 -10
- package/build/facades/phoneNotifications.js.map +1 -1
- package/build/facades/speakers.d.ts +1 -1
- package/build/facades/speakers.d.ts.map +1 -1
- package/build/facades/speakers.js.map +1 -1
- package/build/facades/speech.d.ts +7 -6
- package/build/facades/speech.d.ts.map +1 -1
- package/build/facades/speech.js +1 -1
- package/build/facades/speech.js.map +1 -1
- package/build/generated/releaseMetadata.d.ts +12 -0
- package/build/generated/releaseMetadata.d.ts.map +1 -0
- package/build/generated/releaseMetadata.js +10 -0
- package/build/generated/releaseMetadata.js.map +1 -0
- package/build/index.d.ts +9 -6
- package/build/index.d.ts.map +1 -1
- package/build/index.js +7 -5
- package/build/index.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.d.ts +44 -0
- package/build/react/MentraLiveOtaFlow.d.ts.map +1 -0
- package/build/react/MentraLiveOtaFlow.js +322 -0
- package/build/react/MentraLiveOtaFlow.js.map +1 -0
- package/build/react/index.d.ts +3 -0
- package/build/react/index.d.ts.map +1 -0
- package/build/react/index.js +3 -0
- package/build/react/index.js.map +1 -0
- package/build/react/useEngineSnapshot.d.ts +2 -0
- package/build/react/useEngineSnapshot.d.ts.map +1 -0
- package/build/react/useEngineSnapshot.js +14 -0
- package/build/react/useEngineSnapshot.js.map +1 -0
- package/build/react/useMentraLiveOta.d.ts +84 -0
- package/build/react/useMentraLiveOta.d.ts.map +1 -0
- package/build/react/useMentraLiveOta.js +627 -0
- package/build/react/useMentraLiveOta.js.map +1 -0
- package/build/services/AppRegistry.d.ts +8 -0
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +15 -0
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/BlobStore.d.ts +2 -0
- package/build/services/BlobStore.d.ts.map +1 -1
- package/build/services/BlobStore.js +63 -10
- package/build/services/BlobStore.js.map +1 -1
- package/build/services/CustomDashboardModel.d.ts +48 -0
- package/build/services/CustomDashboardModel.d.ts.map +1 -0
- package/build/services/CustomDashboardModel.js +73 -0
- package/build/services/CustomDashboardModel.js.map +1 -0
- package/build/services/CustomDashboardService.d.ts +55 -0
- package/build/services/CustomDashboardService.d.ts.map +1 -0
- package/build/services/CustomDashboardService.js +492 -0
- package/build/services/CustomDashboardService.js.map +1 -0
- package/build/services/DashboardCoordinator.d.ts +26 -0
- package/build/services/DashboardCoordinator.d.ts.map +1 -0
- package/build/services/DashboardCoordinator.js +125 -0
- package/build/services/DashboardCoordinator.js.map +1 -0
- package/build/services/DeviceEventRouter.d.ts.map +1 -1
- package/build/services/DeviceEventRouter.js +45 -6
- package/build/services/DeviceEventRouter.js.map +1 -1
- package/build/services/DisplayProcessor.d.ts +3 -3
- package/build/services/DisplayProcessor.js +3 -3
- package/build/services/DisplayProcessor.js.map +1 -1
- package/build/services/GestureDotsService.d.ts +40 -0
- package/build/services/GestureDotsService.d.ts.map +1 -0
- package/build/services/GestureDotsService.js +167 -0
- package/build/services/GestureDotsService.js.map +1 -0
- package/build/services/GlassesStatusProjection.d.ts +15 -1
- package/build/services/GlassesStatusProjection.d.ts.map +1 -1
- package/build/services/GlassesStatusProjection.js +18 -11
- package/build/services/GlassesStatusProjection.js.map +1 -1
- package/build/services/HotspotOtaTransport.d.ts.map +1 -1
- package/build/services/HotspotOtaTransport.js +8 -7
- package/build/services/HotspotOtaTransport.js.map +1 -1
- package/build/services/LocalDisplayManager.d.ts +55 -3
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +196 -16
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +13 -0
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +32 -0
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/MiniappExitGesture.d.ts +33 -0
- package/build/services/MiniappExitGesture.d.ts.map +1 -0
- package/build/services/MiniappExitGesture.js +54 -0
- package/build/services/MiniappExitGesture.js.map +1 -0
- package/build/services/OtaAutoChain.d.ts +41 -0
- package/build/services/OtaAutoChain.d.ts.map +1 -0
- package/build/services/OtaAutoChain.js +91 -0
- package/build/services/OtaAutoChain.js.map +1 -0
- package/build/services/OtaErrorMapping.d.ts +18 -0
- package/build/services/OtaErrorMapping.d.ts.map +1 -0
- package/build/services/OtaErrorMapping.js +63 -0
- package/build/services/OtaErrorMapping.js.map +1 -0
- package/build/services/OtaInstallCoordinator.d.ts +26 -3
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +38 -13
- package/build/services/OtaInstallCoordinator.js.map +1 -1
- package/build/services/OtaService.d.ts.map +1 -1
- package/build/services/OtaService.js +1 -1
- package/build/services/OtaService.js.map +1 -1
- package/build/services/OtaUpdateCheckService.d.ts +4 -1
- package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
- package/build/services/OtaUpdateCheckService.js +28 -16
- package/build/services/OtaUpdateCheckService.js.map +1 -1
- package/build/services/PhoneNotificationsSync.d.ts +13 -0
- package/build/services/PhoneNotificationsSync.d.ts.map +1 -1
- package/build/services/PhoneNotificationsSync.js +101 -9
- package/build/services/PhoneNotificationsSync.js.map +1 -1
- package/build/services/PhonePhotoCoordinator.js +1 -1
- package/build/services/PhonePhotoCoordinator.js.map +1 -1
- package/build/services/PhoneStreamCoordinator.d.ts.map +1 -1
- package/build/services/PhoneStreamCoordinator.js +9 -6
- package/build/services/PhoneStreamCoordinator.js.map +1 -1
- package/build/services/SceneRenderer.d.ts.map +1 -1
- package/build/services/SceneRenderer.js +5 -0
- package/build/services/SceneRenderer.js.map +1 -1
- package/build/services/StreamLifecycleController.d.ts +4 -0
- package/build/services/StreamLifecycleController.d.ts.map +1 -1
- package/build/services/StreamLifecycleController.js +4 -0
- package/build/services/StreamLifecycleController.js.map +1 -1
- package/build/services/asg/localNetworkTransport.d.ts.map +1 -1
- package/build/services/asg/localNetworkTransport.js +13 -12
- package/build/services/asg/localNetworkTransport.js.map +1 -1
- package/build/services/effectiveCapabilities.d.ts +1 -1
- package/build/services/effectiveCapabilities.d.ts.map +1 -1
- package/build/services/effectiveCapabilities.js +26 -7
- package/build/services/effectiveCapabilities.js.map +1 -1
- package/build/services/gestureClaims.d.ts +18 -0
- package/build/services/gestureClaims.d.ts.map +1 -0
- package/build/services/gestureClaims.js +24 -0
- package/build/services/gestureClaims.js.map +1 -0
- package/build/services/gestureDotGlyphs.d.ts +8 -0
- package/build/services/gestureDotGlyphs.d.ts.map +1 -0
- package/build/services/gestureDotGlyphs.js +13 -0
- package/build/services/gestureDotGlyphs.js.map +1 -0
- package/build/services/glassesClockSync.d.ts.map +1 -1
- package/build/services/glassesClockSync.js +5 -1
- package/build/services/glassesClockSync.js.map +1 -1
- package/build/services/iosNotificationAppCatalog.d.ts +13 -0
- package/build/services/iosNotificationAppCatalog.d.ts.map +1 -0
- package/build/services/iosNotificationAppCatalog.js +28 -0
- package/build/services/iosNotificationAppCatalog.js.map +1 -0
- package/build/services/otaDisplayState.d.ts +1 -1
- package/build/services/otaDisplayState.d.ts.map +1 -1
- package/build/services/otaDisplayState.js.map +1 -1
- package/build/services/otaInstallPolicy.d.ts +5 -1
- package/build/services/otaInstallPolicy.d.ts.map +1 -1
- package/build/services/otaInstallPolicy.js +4 -0
- package/build/services/otaInstallPolicy.js.map +1 -1
- package/build/services/otaLegacyMapping.d.ts +1 -1
- package/build/services/otaLegacyMapping.d.ts.map +1 -1
- package/build/services/otaLegacyMapping.js.map +1 -1
- package/build/services/otaManifestPolicy.d.ts +14 -0
- package/build/services/otaManifestPolicy.d.ts.map +1 -0
- package/build/services/otaManifestPolicy.js +20 -0
- package/build/services/otaManifestPolicy.js.map +1 -0
- package/build/services/otaManifestUrl.d.ts +2 -1
- package/build/services/otaManifestUrl.d.ts.map +1 -1
- package/build/services/otaManifestUrl.js +24 -32
- package/build/services/otaManifestUrl.js.map +1 -1
- package/build/services/otaReleaseVersion.d.ts +10 -0
- package/build/services/otaReleaseVersion.d.ts.map +1 -0
- package/build/services/otaReleaseVersion.js +14 -0
- package/build/services/otaReleaseVersion.js.map +1 -0
- package/build/stores/appVisibility.d.ts +3 -0
- package/build/stores/appVisibility.d.ts.map +1 -0
- package/build/stores/appVisibility.js +3 -0
- package/build/stores/appVisibility.js.map +1 -0
- package/build/stores/apps.d.ts.map +1 -1
- package/build/stores/apps.js +7 -1
- package/build/stores/apps.js.map +1 -1
- package/build/stores/core.d.ts +3 -3
- package/build/stores/core.d.ts.map +1 -1
- package/build/stores/core.js.map +1 -1
- package/build/stores/display.d.ts +4 -4
- package/build/stores/display.d.ts.map +1 -1
- package/build/stores/display.js +12 -36
- package/build/stores/display.js.map +1 -1
- package/build/stores/glasses.d.ts +10 -4
- package/build/stores/glasses.d.ts.map +1 -1
- package/build/stores/glasses.js +2 -0
- package/build/stores/glasses.js.map +1 -1
- package/build/stores/settings.d.ts.map +1 -1
- package/build/stores/settings.js +140 -5
- package/build/stores/settings.js.map +1 -1
- package/build/types/applet.d.ts +3 -1
- package/build/types/applet.d.ts.map +1 -1
- package/build/types/applet.js +0 -3
- 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 +2 -2
- package/build/types/capabilities/even-realities-g2.js.map +1 -1
- package/build/types/enums.d.ts +1 -5
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +1 -8
- package/build/types/enums.js.map +1 -1
- package/build/types/hardware.d.ts +1 -1
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +1 -0
- package/build/types/hardware.js.map +1 -1
- package/build/types/index.d.ts +3 -7
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js +3 -7
- package/build/types/index.js.map +1 -1
- package/build/utils/display/composer/ColumnComposer.d.ts +1 -1
- package/build/utils/display/composer/ColumnComposer.js +1 -1
- package/build/utils/display/composer/ColumnComposer.js.map +1 -1
- package/build/utils/display/scene/process.d.ts.map +1 -1
- package/build/utils/display/scene/process.js +4 -3
- package/build/utils/display/scene/process.js.map +1 -1
- package/build/utils/display/scene/types.d.ts +6 -2
- package/build/utils/display/scene/types.d.ts.map +1 -1
- package/build/utils/display/scene/types.js.map +1 -1
- package/package.json +69 -35
- package/src/bluetooth-sdk/debug.ts +1 -0
- package/src/bluetooth-sdk/index.ts +2 -0
- package/src/bluetooth-sdk/ota-transport.ts +1 -0
- package/src/bluetooth-sdk/photo-receiver.ts +2 -0
- package/src/bluetooth-sdk/react.ts +1 -0
- package/src/bluetooth-sdk/types.ts +1 -0
- package/src/engine.ts +12 -3
- package/src/facades/display.ts +12 -2
- package/src/facades/displayMirror.ts +7 -15
- package/src/facades/glasses.ts +8 -4
- package/src/facades/ota.ts +36 -11
- package/src/facades/pairing.ts +103 -23
- package/src/facades/phoneNotifications.ts +32 -10
- package/src/facades/speakers.ts +1 -1
- package/src/facades/speech.ts +21 -7
- package/src/generated/releaseMetadata.ts +20 -0
- package/src/index.ts +31 -5
- package/src/react/MentraLiveOtaFlow.tsx +754 -0
- package/src/react/index.ts +21 -0
- package/src/react/useEngineSnapshot.ts +16 -0
- package/src/react/useMentraLiveOta.ts +793 -0
- package/src/services/AppRegistry.ts +16 -0
- package/src/services/BlobStore.ts +57 -10
- package/src/services/CustomDashboardModel.ts +83 -0
- package/src/services/CustomDashboardService.ts +516 -0
- package/src/services/DashboardCoordinator.ts +121 -0
- package/src/services/DeviceEventRouter.ts +48 -8
- package/src/services/DisplayProcessor.ts +3 -3
- package/src/services/GestureDotsService.ts +164 -0
- package/src/services/GlassesStatusProjection.ts +20 -11
- package/src/services/HotspotOtaTransport.ts +8 -7
- package/src/services/LocalDisplayManager.ts +198 -18
- package/src/services/LocalMiniappRuntime.ts +37 -0
- package/src/services/MiniappExitGesture.ts +76 -0
- package/src/services/OtaAutoChain.ts +130 -0
- package/src/services/OtaErrorMapping.ts +80 -0
- package/src/services/OtaInstallCoordinator.ts +40 -13
- package/src/services/OtaService.ts +1 -2
- package/src/services/OtaUpdateCheckService.ts +33 -19
- package/src/services/PhoneNotificationsSync.ts +125 -9
- package/src/services/PhonePhotoCoordinator.ts +1 -1
- package/src/services/PhoneStreamCoordinator.ts +10 -6
- package/src/services/SceneRenderer.ts +4 -0
- package/src/services/StreamLifecycleController.ts +4 -0
- package/src/services/asg/localNetworkTransport.ts +20 -19
- package/src/services/effectiveCapabilities.ts +27 -7
- package/src/services/gestureClaims.ts +28 -0
- package/src/services/gestureDotGlyphs.ts +15 -0
- package/src/services/glassesClockSync.ts +5 -1
- package/src/services/iosNotificationAppCatalog.ts +39 -0
- package/src/services/otaDisplayState.ts +1 -1
- package/src/services/otaInstallPolicy.ts +5 -1
- package/src/services/otaLegacyMapping.ts +1 -1
- package/src/services/otaManifestPolicy.ts +43 -0
- package/src/services/otaManifestUrl.ts +27 -36
- package/src/services/otaReleaseVersion.ts +22 -0
- package/src/stores/appVisibility.ts +3 -0
- package/src/stores/apps.ts +7 -1
- package/src/stores/core.ts +4 -4
- package/src/stores/display.ts +16 -48
- package/src/stores/glasses.ts +15 -6
- package/src/stores/settings.ts +140 -5
- package/src/types/applet.ts +3 -1
- package/src/types/capabilities/even-realities-g2.ts +3 -2
- package/src/types/enums.ts +1 -9
- package/src/types/hardware.ts +2 -1
- package/src/types/index.ts +3 -7
- package/src/utils/display/composer/ColumnComposer.ts +1 -1
- package/src/utils/display/scene/process.ts +4 -3
- package/src/utils/display/scene/types.ts +0 -0
- package/build/devtools.d.ts +0 -11
- package/build/devtools.d.ts.map +0 -1
- package/build/devtools.js +0 -13
- package/build/devtools.js.map +0 -1
- package/build/internal.d.ts +0 -67
- package/build/internal.d.ts.map +0 -1
- package/build/internal.js +0 -90
- package/build/internal.js.map +0 -1
- package/src/devtools.ts +0 -13
- package/src/internal.ts +0 -155
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
declare class GestureDotsService {
|
|
2
|
+
private started;
|
|
3
|
+
private flash;
|
|
4
|
+
private flashTimer;
|
|
5
|
+
/** Finger currently on the touch bar (tap_start..tap_end; the CFW forwards holds as these edges). */
|
|
6
|
+
private held;
|
|
7
|
+
/**
|
|
8
|
+
* The CFW's tap_then_hold fired during this press (discrete recognition
|
|
9
|
+
* event; the tap_end that follows on release is what clears it).
|
|
10
|
+
*/
|
|
11
|
+
private holdRecognized;
|
|
12
|
+
/** Whether the indicator scene currently has anything on it (needs a clear when the flash ends). */
|
|
13
|
+
private visible;
|
|
14
|
+
private unsubs;
|
|
15
|
+
start(): void;
|
|
16
|
+
stop(): void;
|
|
17
|
+
private enabled;
|
|
18
|
+
/**
|
|
19
|
+
* Flash a gesture on the indicator. Other gesture names are ignored. The
|
|
20
|
+
* device-event router calls this after the CFW dashboard had its chance to
|
|
21
|
+
* consume the gesture, so dashboard navigation does not flash.
|
|
22
|
+
*/
|
|
23
|
+
noteGesture(gestureName: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Paint or clear the indicator. Nothing is drawn while anything else is on
|
|
26
|
+
* the glasses (miniapp frame or system screen) or when no gesture was just
|
|
27
|
+
* received. The top-right anchor resolves against the device's real canvas,
|
|
28
|
+
* so no size math here.
|
|
29
|
+
*
|
|
30
|
+
* Between flashes the element STAYS in the scene with the blank glyph:
|
|
31
|
+
* removing it would tear down the firmware image container and rebuild the
|
|
32
|
+
* page on every flash (a rebuild storm on stock firmware). Only disabling
|
|
33
|
+
* the setting removes the element outright.
|
|
34
|
+
*/
|
|
35
|
+
private render;
|
|
36
|
+
}
|
|
37
|
+
declare const gestureDotsService: GestureDotsService;
|
|
38
|
+
export default gestureDotsService;
|
|
39
|
+
export { GestureDotsService };
|
|
40
|
+
//# sourceMappingURL=GestureDotsService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GestureDotsService.d.ts","sourceRoot":"","sources":["../../src/services/GestureDotsService.ts"],"names":[],"mappings":"AA2BA,cAAM,kBAAkB;IACtB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,UAAU,CAAsB;IACxC,qGAAqG;IACrG,OAAO,CAAC,IAAI,CAAQ;IACpB;;;OAGG;IACH,OAAO,CAAC,cAAc,CAAQ;IAC9B,oGAAoG;IACpG,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,MAAM,CAAwB;IAEtC,KAAK,IAAI,IAAI;IAcb,IAAI,IAAI,IAAI;IAaZ,OAAO,CAAC,OAAO;IAIf;;;;OAIG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAyCtC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM;CA6Bf;AAED,QAAA,MAAM,kBAAkB,oBAA2B,CAAA;AACnD,eAAe,kBAAkB,CAAA;AACjC,OAAO,EAAC,kBAAkB,EAAC,CAAA"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gesture dots — a debug indicator that flashes a small glyph top-right on the
|
|
3
|
+
* glasses when a touch gesture arrives, while nothing else is on the display:
|
|
4
|
+
* a filled circle for a single tap, an arrow for a swipe (cleared after a
|
|
5
|
+
* short pulse), a bullseye while a CFW tap-then-hold is held. Extracted from
|
|
6
|
+
* the CFW dashboard service; it renders through
|
|
7
|
+
* the ordinary scene pipeline, so it works on any positioning device (stock
|
|
8
|
+
* G2 included), and is gated by the gesture_dots debug setting.
|
|
9
|
+
*
|
|
10
|
+
* The glyphs are pre-baked images (not text): the stock firmware's builtin
|
|
11
|
+
* font has no ●/↑/↓, and a single image element with a stable id and box maps
|
|
12
|
+
* to ONE re-used firmware image container — flash and idle swap its bytes
|
|
13
|
+
* (data-only update, no page rebuild) instead of creating/removing containers.
|
|
14
|
+
*/
|
|
15
|
+
import { SETTINGS, useSettingsStore } from "../stores/settings";
|
|
16
|
+
import { BgTimer } from "../utils/timers";
|
|
17
|
+
import { GESTURE_DOT_GLYPHS, GESTURE_DOT_GLYPH_SIZE } from "./gestureDotGlyphs";
|
|
18
|
+
import localDisplayManager from "./LocalDisplayManager";
|
|
19
|
+
import sceneRenderer from "./SceneRenderer";
|
|
20
|
+
const DOTS_APP_ID = "system.gesture-dots";
|
|
21
|
+
/** How long a gesture stays on the indicator. */
|
|
22
|
+
const GESTURE_FLASH_MS = 700;
|
|
23
|
+
const MARGIN_X = 16;
|
|
24
|
+
const MARGIN_TOP = 10;
|
|
25
|
+
class GestureDotsService {
|
|
26
|
+
started = false;
|
|
27
|
+
flash = null;
|
|
28
|
+
flashTimer = null;
|
|
29
|
+
/** Finger currently on the touch bar (tap_start..tap_end; the CFW forwards holds as these edges). */
|
|
30
|
+
held = false;
|
|
31
|
+
/**
|
|
32
|
+
* The CFW's tap_then_hold fired during this press (discrete recognition
|
|
33
|
+
* event; the tap_end that follows on release is what clears it).
|
|
34
|
+
*/
|
|
35
|
+
holdRecognized = false;
|
|
36
|
+
/** Whether the indicator scene currently has anything on it (needs a clear when the flash ends). */
|
|
37
|
+
visible = false;
|
|
38
|
+
unsubs = [];
|
|
39
|
+
start() {
|
|
40
|
+
if (this.started)
|
|
41
|
+
return;
|
|
42
|
+
this.started = true;
|
|
43
|
+
this.unsubs.push(
|
|
44
|
+
// The indicator owns the screen only while it is empty: drop our
|
|
45
|
+
// retained state when something else takes over, and clear any
|
|
46
|
+
// leftover flash when the display empties again.
|
|
47
|
+
localDisplayManager.onActiveDisplayChange((active) => {
|
|
48
|
+
if (active)
|
|
49
|
+
this.visible = false;
|
|
50
|
+
else
|
|
51
|
+
this.render();
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
stop() {
|
|
55
|
+
for (const unsub of this.unsubs)
|
|
56
|
+
unsub();
|
|
57
|
+
this.unsubs = [];
|
|
58
|
+
if (this.flashTimer !== null)
|
|
59
|
+
BgTimer.clearTimeout(this.flashTimer);
|
|
60
|
+
this.flashTimer = null;
|
|
61
|
+
this.flash = null;
|
|
62
|
+
this.held = false;
|
|
63
|
+
this.holdRecognized = false;
|
|
64
|
+
this.visible = false;
|
|
65
|
+
this.started = false;
|
|
66
|
+
sceneRenderer.clearApp(DOTS_APP_ID);
|
|
67
|
+
}
|
|
68
|
+
enabled() {
|
|
69
|
+
return useSettingsStore.getState().getSetting(SETTINGS.gesture_dots.key) === true;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Flash a gesture on the indicator. Other gesture names are ignored. The
|
|
73
|
+
* device-event router calls this after the CFW dashboard had its chance to
|
|
74
|
+
* consume the gesture, so dashboard navigation does not flash.
|
|
75
|
+
*/
|
|
76
|
+
noteGesture(gestureName) {
|
|
77
|
+
if (!this.started || !this.enabled())
|
|
78
|
+
return;
|
|
79
|
+
// Tap edges show a steady circle for as long as the finger is down (on
|
|
80
|
+
// CFW these arrive for holds: ET_LONG/ET_REL forwarded as
|
|
81
|
+
// tap_start/tap_end), with no timer — tap_end clears it.
|
|
82
|
+
if (gestureName === "tap_start" || gestureName === "tap_end") {
|
|
83
|
+
const held = gestureName === "tap_start";
|
|
84
|
+
if (this.held === held)
|
|
85
|
+
return;
|
|
86
|
+
this.held = held;
|
|
87
|
+
if (!held)
|
|
88
|
+
this.holdRecognized = false;
|
|
89
|
+
this.render();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// CFW tap-then-hold (the stock Menu gesture): swap the steady dot for the
|
|
93
|
+
// bullseye until release. Recognition arrives mid-press, but set held too
|
|
94
|
+
// in case the tap_start edge was missed — the release edge still clears.
|
|
95
|
+
if (gestureName === "tap_then_hold") {
|
|
96
|
+
this.held = true;
|
|
97
|
+
this.holdRecognized = true;
|
|
98
|
+
this.render();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const flash = gestureName === "single_tap"
|
|
102
|
+
? "dot"
|
|
103
|
+
: gestureName === "swipe_up"
|
|
104
|
+
? "up"
|
|
105
|
+
: gestureName === "swipe_down"
|
|
106
|
+
? "down"
|
|
107
|
+
: null;
|
|
108
|
+
if (!flash)
|
|
109
|
+
return;
|
|
110
|
+
this.flash = flash;
|
|
111
|
+
if (this.flashTimer !== null)
|
|
112
|
+
BgTimer.clearTimeout(this.flashTimer);
|
|
113
|
+
this.flashTimer = BgTimer.setTimeout(() => {
|
|
114
|
+
this.flashTimer = null;
|
|
115
|
+
this.flash = null;
|
|
116
|
+
this.render();
|
|
117
|
+
}, GESTURE_FLASH_MS);
|
|
118
|
+
this.render();
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Paint or clear the indicator. Nothing is drawn while anything else is on
|
|
122
|
+
* the glasses (miniapp frame or system screen) or when no gesture was just
|
|
123
|
+
* received. The top-right anchor resolves against the device's real canvas,
|
|
124
|
+
* so no size math here.
|
|
125
|
+
*
|
|
126
|
+
* Between flashes the element STAYS in the scene with the blank glyph:
|
|
127
|
+
* removing it would tear down the firmware image container and rebuild the
|
|
128
|
+
* page on every flash (a rebuild storm on stock firmware). Only disabling
|
|
129
|
+
* the setting removes the element outright.
|
|
130
|
+
*/
|
|
131
|
+
render() {
|
|
132
|
+
if (!this.started)
|
|
133
|
+
return;
|
|
134
|
+
if (localDisplayManager.hasActiveDisplay())
|
|
135
|
+
return;
|
|
136
|
+
const shown = this.flash ?? (this.held ? (this.holdRecognized ? "hold" : "dot") : null);
|
|
137
|
+
if (!this.enabled()) {
|
|
138
|
+
if (this.visible) {
|
|
139
|
+
this.visible = false;
|
|
140
|
+
sceneRenderer.emitScene(DOTS_APP_ID, "main", []);
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (!shown && !this.visible)
|
|
145
|
+
return;
|
|
146
|
+
const elements = [
|
|
147
|
+
{
|
|
148
|
+
type: "image",
|
|
149
|
+
id: "gesture-dot",
|
|
150
|
+
box: {
|
|
151
|
+
x: MARGIN_X,
|
|
152
|
+
y: MARGIN_TOP,
|
|
153
|
+
w: GESTURE_DOT_GLYPH_SIZE,
|
|
154
|
+
h: GESTURE_DOT_GLYPH_SIZE,
|
|
155
|
+
anchor: "top-right",
|
|
156
|
+
},
|
|
157
|
+
data: GESTURE_DOT_GLYPHS[shown ?? "blank"],
|
|
158
|
+
},
|
|
159
|
+
];
|
|
160
|
+
this.visible = true;
|
|
161
|
+
sceneRenderer.emitScene(DOTS_APP_ID, "main", elements);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const gestureDotsService = new GestureDotsService();
|
|
165
|
+
export default gestureDotsService;
|
|
166
|
+
export { GestureDotsService };
|
|
167
|
+
//# sourceMappingURL=GestureDotsService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GestureDotsService.js","sourceRoot":"","sources":["../../src/services/GestureDotsService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Gesture dots — a debug indicator that flashes a small glyph top-right on the\n * glasses when a touch gesture arrives, while nothing else is on the display:\n * a filled circle for a single tap, an arrow for a swipe (cleared after a\n * short pulse), a bullseye while a CFW tap-then-hold is held. Extracted from\n * the CFW dashboard service; it renders through\n * the ordinary scene pipeline, so it works on any positioning device (stock\n * G2 included), and is gated by the gesture_dots debug setting.\n *\n * The glyphs are pre-baked images (not text): the stock firmware's builtin\n * font has no ●/↑/↓, and a single image element with a stable id and box maps\n * to ONE re-used firmware image container — flash and idle swap its bytes\n * (data-only update, no page rebuild) instead of creating/removing containers.\n */\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\nimport type {SceneElementInput} from \"../utils/display/scene\"\nimport {BgTimer} from \"../utils/timers\"\nimport {GESTURE_DOT_GLYPHS, GESTURE_DOT_GLYPH_SIZE, type GestureDotGlyph} from \"./gestureDotGlyphs\"\nimport localDisplayManager from \"./LocalDisplayManager\"\nimport sceneRenderer from \"./SceneRenderer\"\n\nconst DOTS_APP_ID = \"system.gesture-dots\"\n/** How long a gesture stays on the indicator. */\nconst GESTURE_FLASH_MS = 700\nconst MARGIN_X = 16\nconst MARGIN_TOP = 10\n\nclass GestureDotsService {\n private started = false\n private flash: GestureDotGlyph | null = null\n private flashTimer: number | null = null\n /** Finger currently on the touch bar (tap_start..tap_end; the CFW forwards holds as these edges). */\n private held = false\n /**\n * The CFW's tap_then_hold fired during this press (discrete recognition\n * event; the tap_end that follows on release is what clears it).\n */\n private holdRecognized = false\n /** Whether the indicator scene currently has anything on it (needs a clear when the flash ends). */\n private visible = false\n private unsubs: Array<() => void> = []\n\n start(): void {\n if (this.started) return\n this.started = true\n this.unsubs.push(\n // The indicator owns the screen only while it is empty: drop our\n // retained state when something else takes over, and clear any\n // leftover flash when the display empties again.\n localDisplayManager.onActiveDisplayChange((active) => {\n if (active) this.visible = false\n else this.render()\n }),\n )\n }\n\n stop(): void {\n for (const unsub of this.unsubs) unsub()\n this.unsubs = []\n if (this.flashTimer !== null) BgTimer.clearTimeout(this.flashTimer)\n this.flashTimer = null\n this.flash = null\n this.held = false\n this.holdRecognized = false\n this.visible = false\n this.started = false\n sceneRenderer.clearApp(DOTS_APP_ID)\n }\n\n private enabled(): boolean {\n return useSettingsStore.getState().getSetting(SETTINGS.gesture_dots.key) === true\n }\n\n /**\n * Flash a gesture on the indicator. Other gesture names are ignored. The\n * device-event router calls this after the CFW dashboard had its chance to\n * consume the gesture, so dashboard navigation does not flash.\n */\n noteGesture(gestureName: string): void {\n if (!this.started || !this.enabled()) return\n // Tap edges show a steady circle for as long as the finger is down (on\n // CFW these arrive for holds: ET_LONG/ET_REL forwarded as\n // tap_start/tap_end), with no timer — tap_end clears it.\n if (gestureName === \"tap_start\" || gestureName === \"tap_end\") {\n const held = gestureName === \"tap_start\"\n if (this.held === held) return\n this.held = held\n if (!held) this.holdRecognized = false\n this.render()\n return\n }\n // CFW tap-then-hold (the stock Menu gesture): swap the steady dot for the\n // bullseye until release. Recognition arrives mid-press, but set held too\n // in case the tap_start edge was missed — the release edge still clears.\n if (gestureName === \"tap_then_hold\") {\n this.held = true\n this.holdRecognized = true\n this.render()\n return\n }\n const flash: GestureDotGlyph | null =\n gestureName === \"single_tap\"\n ? \"dot\"\n : gestureName === \"swipe_up\"\n ? \"up\"\n : gestureName === \"swipe_down\"\n ? \"down\"\n : null\n if (!flash) return\n this.flash = flash\n if (this.flashTimer !== null) BgTimer.clearTimeout(this.flashTimer)\n this.flashTimer = BgTimer.setTimeout(() => {\n this.flashTimer = null\n this.flash = null\n this.render()\n }, GESTURE_FLASH_MS)\n this.render()\n }\n\n /**\n * Paint or clear the indicator. Nothing is drawn while anything else is on\n * the glasses (miniapp frame or system screen) or when no gesture was just\n * received. The top-right anchor resolves against the device's real canvas,\n * so no size math here.\n *\n * Between flashes the element STAYS in the scene with the blank glyph:\n * removing it would tear down the firmware image container and rebuild the\n * page on every flash (a rebuild storm on stock firmware). Only disabling\n * the setting removes the element outright.\n */\n private render(): void {\n if (!this.started) return\n if (localDisplayManager.hasActiveDisplay()) return\n const shown = this.flash ?? (this.held ? (this.holdRecognized ? \"hold\" : \"dot\") : null)\n if (!this.enabled()) {\n if (this.visible) {\n this.visible = false\n sceneRenderer.emitScene(DOTS_APP_ID, \"main\", [])\n }\n return\n }\n if (!shown && !this.visible) return\n const elements: SceneElementInput[] = [\n {\n type: \"image\",\n id: \"gesture-dot\",\n box: {\n x: MARGIN_X,\n y: MARGIN_TOP,\n w: GESTURE_DOT_GLYPH_SIZE,\n h: GESTURE_DOT_GLYPH_SIZE,\n anchor: \"top-right\",\n },\n data: GESTURE_DOT_GLYPHS[shown ?? \"blank\"],\n },\n ]\n this.visible = true\n sceneRenderer.emitScene(DOTS_APP_ID, \"main\", elements)\n }\n}\n\nconst gestureDotsService = new GestureDotsService()\nexport default gestureDotsService\nexport {GestureDotsService}\n"]}
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Glasses status projection — engine-owned. Subscribes to the native bluetooth-sdk
|
|
3
|
+
* status events and projects them into the engine device stores, so engine's own
|
|
4
|
+
* services (which react to those stores) work for ANY host — not just the first-party
|
|
5
|
+
* Glassly app, where this used to live in MantleManager.
|
|
6
|
+
*
|
|
7
|
+
* This is the INBOUND mirror of GlassesSettingsSync: that pushes the settings store
|
|
8
|
+
* OUT to the device; this pulls device status IN to the stores. It's the feed that
|
|
9
|
+
* the rest of the engine runtime depends on (MicStateCoordinator, the settings-sync
|
|
10
|
+
* on-connect trigger, the facade read-models all read these stores).
|
|
11
|
+
*
|
|
12
|
+
* Started by `engine.start()`. Idempotent.
|
|
13
|
+
*/
|
|
14
|
+
import { type PublicGlassesStatus } from "@glassly/bluetooth-sdk";
|
|
15
|
+
export declare function startGlassesStatusProjection(forwarder?: (status: Partial<PublicGlassesStatus>) => void): Promise<void>;
|
|
2
16
|
export declare function stopGlassesStatusProjection(): void;
|
|
3
17
|
//# sourceMappingURL=GlassesStatusProjection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlassesStatusProjection.d.ts","sourceRoot":"","sources":["../../src/services/GlassesStatusProjection.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GlassesStatusProjection.d.ts","sourceRoot":"","sources":["../../src/services/GlassesStatusProjection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAqB,EAAC,KAAK,mBAAmB,EAAC,MAAM,wBAAwB,CAAA;AAS7E,wBAAgB,4BAA4B,CAC1C,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,mBAAmB,CAAC,KAAK,IAAI,GACzD,OAAO,CAAC,IAAI,CAAC,CAiDf;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAMlD"}
|
|
@@ -11,19 +11,22 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Started by `engine.start()`. Idempotent.
|
|
13
13
|
*/
|
|
14
|
-
import BluetoothSdk from "@glassly/bluetooth-sdk
|
|
14
|
+
import BluetoothSdk from "@glassly/bluetooth-sdk";
|
|
15
15
|
import { useCoreStore } from "../stores/core";
|
|
16
16
|
import { useGlassesStore } from "../stores/glasses";
|
|
17
|
-
import localMiniappRuntime from "./LocalMiniappRuntime";
|
|
18
17
|
let unsubs = [];
|
|
19
18
|
let projectionRunId = 0;
|
|
20
|
-
|
|
19
|
+
let glassesStatusForwarder = null;
|
|
20
|
+
let hydrationPromise = null;
|
|
21
|
+
export function startGlassesStatusProjection(forwarder) {
|
|
22
|
+
if (forwarder)
|
|
23
|
+
glassesStatusForwarder = forwarder;
|
|
21
24
|
if (unsubs.length)
|
|
22
|
-
return;
|
|
25
|
+
return hydrationPromise ?? Promise.resolve();
|
|
23
26
|
const runId = ++projectionRunId;
|
|
24
27
|
let bluetoothEventSeen = false;
|
|
25
28
|
let glassesEventSeen = false;
|
|
26
|
-
|
|
29
|
+
const bluetoothHydration = BluetoothSdk.getBluetoothStatus()
|
|
27
30
|
.then((status) => {
|
|
28
31
|
if (runId !== projectionRunId || bluetoothEventSeen)
|
|
29
32
|
return;
|
|
@@ -32,7 +35,7 @@ export function startGlassesStatusProjection() {
|
|
|
32
35
|
.catch((error) => {
|
|
33
36
|
console.warn("GlassesStatusProjection: getBluetoothStatus failed", error);
|
|
34
37
|
});
|
|
35
|
-
|
|
38
|
+
const glassesHydration = BluetoothSdk.getGlassesStatus()
|
|
36
39
|
.then((status) => {
|
|
37
40
|
if (runId !== projectionRunId || glassesEventSeen)
|
|
38
41
|
return;
|
|
@@ -42,24 +45,28 @@ export function startGlassesStatusProjection() {
|
|
|
42
45
|
console.warn("GlassesStatusProjection: getGlassesStatus failed", error);
|
|
43
46
|
});
|
|
44
47
|
// Bluetooth-adapter status -> core store.
|
|
45
|
-
unsubs.push(BluetoothSdk.
|
|
48
|
+
unsubs.push(BluetoothSdk.subscribeBluetoothStatus((changed) => {
|
|
46
49
|
bluetoothEventSeen = true;
|
|
47
50
|
useCoreStore.getState().setCoreInfo(changed);
|
|
48
51
|
}));
|
|
49
|
-
// Glasses status -> glasses store (+
|
|
50
|
-
// OTA-available flag on disconnect).
|
|
51
|
-
unsubs.push(BluetoothSdk.
|
|
52
|
+
// Glasses status -> glasses store (+ optional full-runtime forwarding to local
|
|
53
|
+
// miniapps; clear any stale OTA-available flag on disconnect).
|
|
54
|
+
unsubs.push(BluetoothSdk.subscribeGlassesStatus((changed) => {
|
|
52
55
|
glassesEventSeen = true;
|
|
53
56
|
useGlassesStore.getState().setGlassesInfo(changed);
|
|
54
|
-
|
|
57
|
+
glassesStatusForwarder?.(changed);
|
|
55
58
|
if (changed.connection?.state === "disconnected") {
|
|
56
59
|
useGlassesStore.getState().setOtaUpdateAvailable(null);
|
|
57
60
|
}
|
|
58
61
|
}));
|
|
62
|
+
hydrationPromise = Promise.allSettled([bluetoothHydration, glassesHydration]).then(() => undefined);
|
|
63
|
+
return hydrationPromise;
|
|
59
64
|
}
|
|
60
65
|
export function stopGlassesStatusProjection() {
|
|
61
66
|
projectionRunId++;
|
|
62
67
|
unsubs.forEach((unsub) => unsub());
|
|
63
68
|
unsubs = [];
|
|
69
|
+
glassesStatusForwarder = null;
|
|
70
|
+
hydrationPromise = null;
|
|
64
71
|
}
|
|
65
72
|
//# sourceMappingURL=GlassesStatusProjection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlassesStatusProjection.js","sourceRoot":"","sources":["../../src/services/GlassesStatusProjection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"GlassesStatusProjection.js","sourceRoot":"","sources":["../../src/services/GlassesStatusProjection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,YAAwC,MAAM,wBAAwB,CAAA;AAC7E,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAA;AAEjD,IAAI,MAAM,GAAsB,EAAE,CAAA;AAClC,IAAI,eAAe,GAAG,CAAC,CAAA;AACvB,IAAI,sBAAsB,GAA4D,IAAI,CAAA;AAC1F,IAAI,gBAAgB,GAAyB,IAAI,CAAA;AAEjD,MAAM,UAAU,4BAA4B,CAC1C,SAA0D;IAE1D,IAAI,SAAS;QAAE,sBAAsB,GAAG,SAAS,CAAA;IACjD,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,gBAAgB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAA;IAE/D,MAAM,KAAK,GAAG,EAAE,eAAe,CAAA;IAC/B,IAAI,kBAAkB,GAAG,KAAK,CAAA;IAC9B,IAAI,gBAAgB,GAAG,KAAK,CAAA;IAE5B,MAAM,kBAAkB,GAAG,YAAY,CAAC,kBAAkB,EAAE;SACzD,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACf,IAAI,KAAK,KAAK,eAAe,IAAI,kBAAkB;YAAE,OAAM;QAC3D,YAAY,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;IAC7C,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACf,OAAO,CAAC,IAAI,CAAC,oDAAoD,EAAE,KAAK,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEJ,MAAM,gBAAgB,GAAG,YAAY,CAAC,gBAAgB,EAAE;SACrD,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACf,IAAI,KAAK,KAAK,eAAe,IAAI,gBAAgB;YAAE,OAAM;QACzD,eAAe,CAAC,QAAQ,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,CAAA;IACnD,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACf,OAAO,CAAC,IAAI,CAAC,kDAAkD,EAAE,KAAK,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;IAEJ,0CAA0C;IAC1C,MAAM,CAAC,IAAI,CACT,YAAY,CAAC,wBAAwB,CAAC,CAAC,OAAO,EAAE,EAAE;QAChD,kBAAkB,GAAG,IAAI,CAAA;QACzB,YAAY,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IAC9C,CAAC,CAAC,CACH,CAAA;IAED,+EAA+E;IAC/E,+DAA+D;IAC/D,MAAM,CAAC,IAAI,CACT,YAAY,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9C,gBAAgB,GAAG,IAAI,CAAA;QACvB,eAAe,CAAC,QAAQ,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;QAClD,sBAAsB,EAAE,CAAC,OAAO,CAAC,CAAA;QACjC,IAAI,OAAO,CAAC,UAAU,EAAE,KAAK,KAAK,cAAc,EAAE,CAAC;YACjD,eAAe,CAAC,QAAQ,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAA;QACxD,CAAC;IACH,CAAC,CAAC,CACH,CAAA;IAED,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IACnG,OAAO,gBAAgB,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,eAAe,EAAE,CAAA;IACjB,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,CAAA;IAClC,MAAM,GAAG,EAAE,CAAA;IACX,sBAAsB,GAAG,IAAI,CAAA;IAC7B,gBAAgB,GAAG,IAAI,CAAA;AACzB,CAAC","sourcesContent":["/**\n * Glasses status projection — engine-owned. Subscribes to the native bluetooth-sdk\n * status events and projects them into the engine device stores, so engine's own\n * services (which react to those stores) work for ANY host — not just the first-party\n * Glassly app, where this used to live in MantleManager.\n *\n * This is the INBOUND mirror of GlassesSettingsSync: that pushes the settings store\n * OUT to the device; this pulls device status IN to the stores. It's the feed that\n * the rest of the engine runtime depends on (MicStateCoordinator, the settings-sync\n * on-connect trigger, the facade read-models all read these stores).\n *\n * Started by `engine.start()`. Idempotent.\n */\nimport BluetoothSdk, {type PublicGlassesStatus} from \"@glassly/bluetooth-sdk\"\nimport {useCoreStore} from \"../stores/core\"\nimport {useGlassesStore} from \"../stores/glasses\"\n\nlet unsubs: Array<() => void> = []\nlet projectionRunId = 0\nlet glassesStatusForwarder: ((status: Partial<PublicGlassesStatus>) => void) | null = null\nlet hydrationPromise: Promise<void> | null = null\n\nexport function startGlassesStatusProjection(\n forwarder?: (status: Partial<PublicGlassesStatus>) => void,\n): Promise<void> {\n if (forwarder) glassesStatusForwarder = forwarder\n if (unsubs.length) return hydrationPromise ?? Promise.resolve()\n\n const runId = ++projectionRunId\n let bluetoothEventSeen = false\n let glassesEventSeen = false\n\n const bluetoothHydration = BluetoothSdk.getBluetoothStatus()\n .then((status) => {\n if (runId !== projectionRunId || bluetoothEventSeen) return\n useCoreStore.getState().setCoreInfo(status)\n })\n .catch((error) => {\n console.warn(\"GlassesStatusProjection: getBluetoothStatus failed\", error)\n })\n\n const glassesHydration = BluetoothSdk.getGlassesStatus()\n .then((status) => {\n if (runId !== projectionRunId || glassesEventSeen) return\n useGlassesStore.getState().setGlassesInfo(status)\n })\n .catch((error) => {\n console.warn(\"GlassesStatusProjection: getGlassesStatus failed\", error)\n })\n\n // Bluetooth-adapter status -> core store.\n unsubs.push(\n BluetoothSdk.subscribeBluetoothStatus((changed) => {\n bluetoothEventSeen = true\n useCoreStore.getState().setCoreInfo(changed)\n }),\n )\n\n // Glasses status -> glasses store (+ optional full-runtime forwarding to local\n // miniapps; clear any stale OTA-available flag on disconnect).\n unsubs.push(\n BluetoothSdk.subscribeGlassesStatus((changed) => {\n glassesEventSeen = true\n useGlassesStore.getState().setGlassesInfo(changed)\n glassesStatusForwarder?.(changed)\n if (changed.connection?.state === \"disconnected\") {\n useGlassesStore.getState().setOtaUpdateAvailable(null)\n }\n }),\n )\n\n hydrationPromise = Promise.allSettled([bluetoothHydration, glassesHydration]).then(() => undefined)\n return hydrationPromise\n}\n\nexport function stopGlassesStatusProjection(): void {\n projectionRunId++\n unsubs.forEach((unsub) => unsub())\n unsubs = []\n glassesStatusForwarder = null\n hydrationPromise = null\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HotspotOtaTransport.d.ts","sourceRoot":"","sources":["../../src/services/HotspotOtaTransport.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HotspotOtaTransport.d.ts","sourceRoot":"","sources":["../../src/services/HotspotOtaTransport.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,4BAA4B,EAAC,MAAM,yBAAyB,CAAA;AACzE,OAAO,EAML,KAAK,2BAA2B,EAEjC,MAAM,yBAAyB,CAAA;AAIhC,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,aAAa,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,SAAS,CAAA;AAEzG,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,eAAe,CAAA;IACtB,QAAQ,CAAC,EAAE,2BAA2B,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,mBAAmB,GAC3B,gCAAgC,GAChC,sBAAsB,GACtB,qBAAqB,GACrB,uBAAuB,CAAA;AAE3B,qBAAa,wBAAyB,SAAQ,KAAK;aAE/B,IAAI,EAAE,mBAAmB;gBAAzB,IAAI,EAAE,mBAAmB,EACzC,OAAO,EAAE,MAAM;CAKlB;AAED,yFAAyF;AACzF,cAAM,mBAAmB;IACvB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,qBAAqB,CAAQ;IACrC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,eAAe,CAA6B;IAE9C,OAAO,CACX,WAAW,EAAE,4BAA4B,EACzC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,GAClD,OAAO,CAAC,MAAM,CAAC;IAuElB,gGAAgG;YAClF,2BAA2B;IAczC,OAAO,CAAC,mBAAmB,CAa1B;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CA4BhC;AAED,eAAO,MAAM,mBAAmB,qBAA4B,CAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import BluetoothSdk, { isEnabledHotspotStatus
|
|
1
|
+
import BluetoothSdk, { isEnabledHotspotStatus } from "@glassly/bluetooth-sdk";
|
|
2
|
+
import { otaServer } from "@glassly/bluetooth-sdk/ota-transport";
|
|
2
3
|
// One coordinator selects the native Android or iOS staging implementation at runtime.
|
|
3
4
|
// eslint-disable-next-line react-native/split-platform-components
|
|
4
5
|
import { PermissionsAndroid, Platform } from "react-native";
|
|
@@ -49,7 +50,7 @@ class HotspotOtaTransport {
|
|
|
49
50
|
let localAddress = scopedAddress;
|
|
50
51
|
if (Platform.OS === "ios") {
|
|
51
52
|
try {
|
|
52
|
-
localAddress = await
|
|
53
|
+
localAddress = await otaServer.waitForWifiAddress(hotspot.localIp, 15_000);
|
|
53
54
|
}
|
|
54
55
|
catch (error) {
|
|
55
56
|
throw new HotspotOtaTransportError("hotspot_join_failed", error instanceof Error ? error.message : String(error));
|
|
@@ -58,10 +59,10 @@ class HotspotOtaTransport {
|
|
|
58
59
|
const artifactPaths = Object.fromEntries(this.prepared.map((artifact) => [artifact.sha256, artifact.filePath]));
|
|
59
60
|
// Start exactly one native listener to learn its selected port, then atomically replace
|
|
60
61
|
// the placeholder with the immutable rewritten manifest before ota_start is sent.
|
|
61
|
-
const server = await
|
|
62
|
+
const server = await otaServer.start("{}", artifactPaths, localAddress);
|
|
62
63
|
this.serverStarted = true;
|
|
63
64
|
const manifest = rewriteManifestForLocalServer(checkResult.manifestBody, this.prepared, server.baseUrl);
|
|
64
|
-
const published = await
|
|
65
|
+
const published = await otaServer.start(manifest, artifactPaths, server.host);
|
|
65
66
|
if (published.manifestUrl !== server.manifestUrl) {
|
|
66
67
|
throw new Error("Local OTA server endpoint changed while publishing the manifest");
|
|
67
68
|
}
|
|
@@ -98,12 +99,12 @@ class HotspotOtaTransport {
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
downloadIosArtifact = async (entry, destination, onProgress) => {
|
|
101
|
-
const subscription =
|
|
102
|
+
const subscription = otaServer.onArtifactDownloadProgress((event) => {
|
|
102
103
|
if (event.destination === destination)
|
|
103
104
|
onProgress?.(event.bytesWritten, event.contentLength);
|
|
104
105
|
});
|
|
105
106
|
try {
|
|
106
|
-
return await
|
|
107
|
+
return await otaServer.downloadArtifact(entry.url, destination);
|
|
107
108
|
}
|
|
108
109
|
finally {
|
|
109
110
|
subscription.remove();
|
|
@@ -124,7 +125,7 @@ class HotspotOtaTransport {
|
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
if (this.serverStarted)
|
|
127
|
-
await
|
|
128
|
+
await otaServer.stop().catch(() => { });
|
|
128
129
|
if (this.localNetworkConnected)
|
|
129
130
|
await localNetworkTransport.disconnect().catch(() => { });
|
|
130
131
|
await cleanupArtifacts().catch(() => { });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HotspotOtaTransport.js","sourceRoot":"","sources":["../../src/services/HotspotOtaTransport.ts"],"names":[],"mappings":"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","sourcesContent":["import BluetoothSdk, {isEnabledHotspotStatus, OtaServer} from \"@glassly/bluetooth-sdk/internal\"\n// One coordinator selects the native Android or iOS staging implementation at runtime.\n// eslint-disable-next-line react-native/split-platform-components\nimport {PermissionsAndroid, Platform} from \"react-native\"\nimport type {OtaCheckCurrentGlassesResult} from \"./OtaUpdateCheckService\"\nimport {\n cleanupArtifacts,\n OtaArtifactError,\n planArtifacts,\n prepareArtifacts,\n rewriteManifestForLocalServer,\n type OtaArtifactDownloadProgress,\n type PreparedOtaArtifact,\n} from \"./OtaArtifactDownloader\"\nimport {disableHotspotWithRetry} from \"./HotspotShutdown\"\nimport {localNetworkTransport} from \"./asg/localNetworkTransport\"\n\nexport type HotspotOtaPhase = \"idle\" | \"downloading\" | \"starting_hotspot\" | \"joining_hotspot\" | \"serving\"\n\nexport type HotspotOtaProgress = {\n phase: HotspotOtaPhase\n artifact?: OtaArtifactDownloadProgress\n}\n\nexport type HotspotOtaErrorCode =\n | \"hotspot_wifi_permission_denied\"\n | \"hotspot_start_failed\"\n | \"hotspot_join_failed\"\n | \"hotspot_server_failed\"\n\nexport class HotspotOtaTransportError extends Error {\n constructor(\n public readonly code: HotspotOtaErrorCode,\n message: string,\n ) {\n super(message)\n this.name = \"HotspotOtaTransportError\"\n }\n}\n\n/** Owns the single phone-side endpoint and network lease for one hotspot OTA attempt. */\nclass HotspotOtaTransport {\n private active = false\n private prepared: PreparedOtaArtifact[] = []\n private hotspotRequested = false\n private localNetworkConnected = false\n private serverStarted = false\n private teardownPromise: Promise<void> | null = null\n\n async prepare(\n checkResult: OtaCheckCurrentGlassesResult,\n onProgress?: (progress: HotspotOtaProgress) => void,\n ): Promise<string> {\n if (this.teardownPromise) await this.teardownPromise\n if (this.active) {\n throw new Error(\"A hotspot OTA transport is already active\")\n }\n if (!checkResult.manifestBody) {\n throw new Error(\"The selected OTA check has no manifest body\")\n }\n\n let phase: HotspotOtaPhase = \"downloading\"\n try {\n await this.ensureAndroidWifiPermission()\n onProgress?.({phase: \"downloading\"})\n this.prepared = await prepareArtifacts(\n planArtifacts(checkResult),\n (artifact) => onProgress?.({phase: \"downloading\", artifact}),\n Platform.OS === \"ios\" ? this.downloadIosArtifact : undefined,\n )\n\n phase = \"starting_hotspot\"\n onProgress?.({phase: \"starting_hotspot\"})\n this.hotspotRequested = true\n const hotspot = await BluetoothSdk.setHotspotState(true)\n if (!isEnabledHotspotStatus(hotspot)) {\n throw new HotspotOtaTransportError(\"hotspot_start_failed\", \"Mentra Live did not return hotspot credentials\")\n }\n phase = \"joining_hotspot\"\n onProgress?.({phase: \"joining_hotspot\"})\n const scopedAddress = await localNetworkTransport.connect(hotspot.ssid, hotspot.password)\n this.localNetworkConnected = true\n let localAddress = scopedAddress\n if (Platform.OS === \"ios\") {\n try {\n localAddress = await OtaServer.waitForWifiAddress(hotspot.localIp, 15_000)\n } catch (error) {\n throw new HotspotOtaTransportError(\n \"hotspot_join_failed\",\n error instanceof Error ? error.message : String(error),\n )\n }\n }\n const artifactPaths = Object.fromEntries(this.prepared.map((artifact) => [artifact.sha256, artifact.filePath]))\n // Start exactly one native listener to learn its selected port, then atomically replace\n // the placeholder with the immutable rewritten manifest before ota_start is sent.\n const server = await OtaServer.startOtaServer(\"{}\", artifactPaths, localAddress)\n this.serverStarted = true\n const manifest = rewriteManifestForLocalServer(checkResult.manifestBody, this.prepared, server.baseUrl)\n const published = await OtaServer.startOtaServer(manifest, artifactPaths, server.host)\n if (published.manifestUrl !== server.manifestUrl) {\n throw new Error(\"Local OTA server endpoint changed while publishing the manifest\")\n }\n this.active = true\n onProgress?.({phase: \"serving\"})\n return published.manifestUrl\n } catch (error) {\n const joined = this.localNetworkConnected\n await this.teardown()\n if (error instanceof OtaArtifactError || error instanceof HotspotOtaTransportError) {\n throw error\n }\n const message = error instanceof Error ? error.message : String(error)\n if (phase === \"starting_hotspot\") {\n throw new HotspotOtaTransportError(\"hotspot_start_failed\", message)\n }\n if (phase === \"joining_hotspot\" && !joined) {\n throw new HotspotOtaTransportError(\"hotspot_join_failed\", message)\n }\n throw new HotspotOtaTransportError(\"hotspot_server_failed\", message)\n }\n }\n\n /** Android 13+ requires the nearby-WiFi runtime grant before WifiNetworkSpecifier is usable. */\n private async ensureAndroidWifiPermission(): Promise<void> {\n if (Platform.OS !== \"android\") return\n\n const permission = PermissionsAndroid.PERMISSIONS.NEARBY_WIFI_DEVICES\n if (await PermissionsAndroid.check(permission)) return\n const result = await PermissionsAndroid.request(permission)\n if (result !== PermissionsAndroid.RESULTS.GRANTED) {\n throw new HotspotOtaTransportError(\n \"hotspot_wifi_permission_denied\",\n \"Nearby devices permission is required to connect to the glasses hotspot\",\n )\n }\n }\n\n private downloadIosArtifact = async (\n entry: {url: string},\n destination: string,\n onProgress?: (bytesWritten: number, contentLength: number) => void,\n ): Promise<{statusCode: number}> => {\n const subscription = OtaServer.addListener(\"artifactDownloadProgress\", (event) => {\n if (event.destination === destination) onProgress?.(event.bytesWritten, event.contentLength)\n })\n try {\n return await OtaServer.downloadArtifact(entry.url, destination)\n } finally {\n subscription.remove()\n }\n }\n\n async teardown(): Promise<void> {\n if (this.teardownPromise) return this.teardownPromise\n this.teardownPromise = (async () => {\n if (this.hotspotRequested) {\n const hotspotStopped = await disableHotspotWithRetry(() => BluetoothSdk.setHotspotState(false), {\n // A completed APK step has just replaced ASG. Let the new command path\n // settle before asking it to tear down the SystemUI-owned access point.\n initialDelayMs: this.serverStarted ? 750 : 0,\n })\n if (!hotspotStopped) {\n console.warn(\"[OTA_PROGRESS] glasses hotspot shutdown was not confirmed after bounded retries\")\n }\n }\n if (this.serverStarted) await OtaServer.stopOtaServer().catch(() => {})\n if (this.localNetworkConnected) await localNetworkTransport.disconnect().catch(() => {})\n await cleanupArtifacts().catch(() => {})\n this.prepared = []\n this.active = false\n this.serverStarted = false\n this.localNetworkConnected = false\n this.hotspotRequested = false\n })()\n try {\n await this.teardownPromise\n } finally {\n this.teardownPromise = null\n }\n }\n}\n\nexport const hotspotOtaTransport = new HotspotOtaTransport()\n"]}
|
|
1
|
+
{"version":3,"file":"HotspotOtaTransport.js","sourceRoot":"","sources":["../../src/services/HotspotOtaTransport.ts"],"names":[],"mappings":"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","sourcesContent":["import BluetoothSdk, {isEnabledHotspotStatus} from \"@glassly/bluetooth-sdk\"\nimport {otaServer} from \"@glassly/bluetooth-sdk/ota-transport\"\n// One coordinator selects the native Android or iOS staging implementation at runtime.\n// eslint-disable-next-line react-native/split-platform-components\nimport {PermissionsAndroid, Platform} from \"react-native\"\nimport type {OtaCheckCurrentGlassesResult} from \"./OtaUpdateCheckService\"\nimport {\n cleanupArtifacts,\n OtaArtifactError,\n planArtifacts,\n prepareArtifacts,\n rewriteManifestForLocalServer,\n type OtaArtifactDownloadProgress,\n type PreparedOtaArtifact,\n} from \"./OtaArtifactDownloader\"\nimport {disableHotspotWithRetry} from \"./HotspotShutdown\"\nimport {localNetworkTransport} from \"./asg/localNetworkTransport\"\n\nexport type HotspotOtaPhase = \"idle\" | \"downloading\" | \"starting_hotspot\" | \"joining_hotspot\" | \"serving\"\n\nexport type HotspotOtaProgress = {\n phase: HotspotOtaPhase\n artifact?: OtaArtifactDownloadProgress\n}\n\nexport type HotspotOtaErrorCode =\n | \"hotspot_wifi_permission_denied\"\n | \"hotspot_start_failed\"\n | \"hotspot_join_failed\"\n | \"hotspot_server_failed\"\n\nexport class HotspotOtaTransportError extends Error {\n constructor(\n public readonly code: HotspotOtaErrorCode,\n message: string,\n ) {\n super(message)\n this.name = \"HotspotOtaTransportError\"\n }\n}\n\n/** Owns the single phone-side endpoint and network lease for one hotspot OTA attempt. */\nclass HotspotOtaTransport {\n private active = false\n private prepared: PreparedOtaArtifact[] = []\n private hotspotRequested = false\n private localNetworkConnected = false\n private serverStarted = false\n private teardownPromise: Promise<void> | null = null\n\n async prepare(\n checkResult: OtaCheckCurrentGlassesResult,\n onProgress?: (progress: HotspotOtaProgress) => void,\n ): Promise<string> {\n if (this.teardownPromise) await this.teardownPromise\n if (this.active) {\n throw new Error(\"A hotspot OTA transport is already active\")\n }\n if (!checkResult.manifestBody) {\n throw new Error(\"The selected OTA check has no manifest body\")\n }\n\n let phase: HotspotOtaPhase = \"downloading\"\n try {\n await this.ensureAndroidWifiPermission()\n onProgress?.({phase: \"downloading\"})\n this.prepared = await prepareArtifacts(\n planArtifacts(checkResult),\n (artifact) => onProgress?.({phase: \"downloading\", artifact}),\n Platform.OS === \"ios\" ? this.downloadIosArtifact : undefined,\n )\n\n phase = \"starting_hotspot\"\n onProgress?.({phase: \"starting_hotspot\"})\n this.hotspotRequested = true\n const hotspot = await BluetoothSdk.setHotspotState(true)\n if (!isEnabledHotspotStatus(hotspot)) {\n throw new HotspotOtaTransportError(\"hotspot_start_failed\", \"Mentra Live did not return hotspot credentials\")\n }\n phase = \"joining_hotspot\"\n onProgress?.({phase: \"joining_hotspot\"})\n const scopedAddress = await localNetworkTransport.connect(hotspot.ssid, hotspot.password)\n this.localNetworkConnected = true\n let localAddress = scopedAddress\n if (Platform.OS === \"ios\") {\n try {\n localAddress = await otaServer.waitForWifiAddress(hotspot.localIp, 15_000)\n } catch (error) {\n throw new HotspotOtaTransportError(\n \"hotspot_join_failed\",\n error instanceof Error ? error.message : String(error),\n )\n }\n }\n const artifactPaths = Object.fromEntries(this.prepared.map((artifact) => [artifact.sha256, artifact.filePath]))\n // Start exactly one native listener to learn its selected port, then atomically replace\n // the placeholder with the immutable rewritten manifest before ota_start is sent.\n const server = await otaServer.start(\"{}\", artifactPaths, localAddress)\n this.serverStarted = true\n const manifest = rewriteManifestForLocalServer(checkResult.manifestBody, this.prepared, server.baseUrl)\n const published = await otaServer.start(manifest, artifactPaths, server.host)\n if (published.manifestUrl !== server.manifestUrl) {\n throw new Error(\"Local OTA server endpoint changed while publishing the manifest\")\n }\n this.active = true\n onProgress?.({phase: \"serving\"})\n return published.manifestUrl\n } catch (error) {\n const joined = this.localNetworkConnected\n await this.teardown()\n if (error instanceof OtaArtifactError || error instanceof HotspotOtaTransportError) {\n throw error\n }\n const message = error instanceof Error ? error.message : String(error)\n if (phase === \"starting_hotspot\") {\n throw new HotspotOtaTransportError(\"hotspot_start_failed\", message)\n }\n if (phase === \"joining_hotspot\" && !joined) {\n throw new HotspotOtaTransportError(\"hotspot_join_failed\", message)\n }\n throw new HotspotOtaTransportError(\"hotspot_server_failed\", message)\n }\n }\n\n /** Android 13+ requires the nearby-WiFi runtime grant before WifiNetworkSpecifier is usable. */\n private async ensureAndroidWifiPermission(): Promise<void> {\n if (Platform.OS !== \"android\") return\n\n const permission = PermissionsAndroid.PERMISSIONS.NEARBY_WIFI_DEVICES\n if (await PermissionsAndroid.check(permission)) return\n const result = await PermissionsAndroid.request(permission)\n if (result !== PermissionsAndroid.RESULTS.GRANTED) {\n throw new HotspotOtaTransportError(\n \"hotspot_wifi_permission_denied\",\n \"Nearby devices permission is required to connect to the glasses hotspot\",\n )\n }\n }\n\n private downloadIosArtifact = async (\n entry: {url: string},\n destination: string,\n onProgress?: (bytesWritten: number, contentLength: number) => void,\n ): Promise<{statusCode: number}> => {\n const subscription = otaServer.onArtifactDownloadProgress((event) => {\n if (event.destination === destination) onProgress?.(event.bytesWritten, event.contentLength)\n })\n try {\n return await otaServer.downloadArtifact(entry.url, destination)\n } finally {\n subscription.remove()\n }\n }\n\n async teardown(): Promise<void> {\n if (this.teardownPromise) return this.teardownPromise\n this.teardownPromise = (async () => {\n if (this.hotspotRequested) {\n const hotspotStopped = await disableHotspotWithRetry(() => BluetoothSdk.setHotspotState(false), {\n // A completed APK step has just replaced ASG. Let the new command path\n // settle before asking it to tear down the SystemUI-owned access point.\n initialDelayMs: this.serverStarted ? 750 : 0,\n })\n if (!hotspotStopped) {\n console.warn(\"[OTA_PROGRESS] glasses hotspot shutdown was not confirmed after bounded retries\")\n }\n }\n if (this.serverStarted) await otaServer.stop().catch(() => {})\n if (this.localNetworkConnected) await localNetworkTransport.disconnect().catch(() => {})\n await cleanupArtifacts().catch(() => {})\n this.prepared = []\n this.active = false\n this.serverStarted = false\n this.localNetworkConnected = false\n this.hotspotRequested = false\n })()\n try {\n await this.teardownPromise\n } finally {\n this.teardownPromise = null\n }\n }\n}\n\nexport const hotspotOtaTransport = new HotspotOtaTransport()\n"]}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* LocalDisplayManager
|
|
3
3
|
*
|
|
4
4
|
* Phone-side arbiter for display requests originating from LOCAL miniapps
|
|
5
|
-
* (the @glassly/miniapp SDK).
|
|
6
|
-
*
|
|
5
|
+
* (the @glassly/miniapp SDK). Preserves the retired cloud display manager's
|
|
6
|
+
* user-facing behavior for the features that matter on the phone:
|
|
7
7
|
*
|
|
8
8
|
* - boot message ("Starting <AppName>…") with a bounded window
|
|
9
9
|
* - durationMs auto-clear
|
|
@@ -49,10 +49,22 @@ declare class LocalDisplayManager {
|
|
|
49
49
|
private static instance;
|
|
50
50
|
private coreApp;
|
|
51
51
|
private coreAppDisplay;
|
|
52
|
-
private
|
|
52
|
+
private _currentDisplay;
|
|
53
53
|
private backgroundLock;
|
|
54
|
+
/** Fired when the display transitions between empty and occupied (any package, system screens included). */
|
|
55
|
+
private activeDisplayListeners;
|
|
56
|
+
private get currentDisplay();
|
|
57
|
+
private set currentDisplay(value);
|
|
58
|
+
/** True while anything (miniapp or system screen) is on the glasses display. */
|
|
59
|
+
hasActiveDisplay(): boolean;
|
|
60
|
+
/** Subscribe to empty↔occupied display transitions. Returns an unsubscribe. */
|
|
61
|
+
onActiveDisplayChange(listener: (active: boolean) => void): () => void;
|
|
54
62
|
private bootingApp;
|
|
55
63
|
private bootQueue;
|
|
64
|
+
/** While true the dashboard owns the glasses: main frames are retained but not sent. */
|
|
65
|
+
private dashboardActive;
|
|
66
|
+
/** Miniapp whose visible frame is temporarily covered by an OS exit notice. */
|
|
67
|
+
private exitingApp;
|
|
56
68
|
private expiryTimerId;
|
|
57
69
|
/** Reconnect-replay subscription state (attachToRuntime). */
|
|
58
70
|
private runtimeAttached;
|
|
@@ -82,12 +94,51 @@ declare class LocalDisplayManager {
|
|
|
82
94
|
* miniapp is foreground.
|
|
83
95
|
*/
|
|
84
96
|
onCoreAppChange(packageName: string | null): void;
|
|
97
|
+
/**
|
|
98
|
+
* The package that currently owns the glasses screen, for gesture-claim
|
|
99
|
+
* arbitration (see LocalMiniappRuntime.foregroundClaimsGesture). This is
|
|
100
|
+
* glasses ownership, not the phone's Compositor foreground: a background
|
|
101
|
+
* miniapp rendering to the glasses with the phone pocketed is the owner.
|
|
102
|
+
*
|
|
103
|
+
* The live frame's owner wins; a background app that holds the display lock
|
|
104
|
+
* but has no frame up right now (between renders) still counts. System
|
|
105
|
+
* frames (boot, notices) own nothing claimable. Returns null when the
|
|
106
|
+
* glasses are idle.
|
|
107
|
+
*/
|
|
108
|
+
getGestureOwner(): string | null;
|
|
109
|
+
/**
|
|
110
|
+
* The miniapp whose frame is visibly on the glasses right now.
|
|
111
|
+
*
|
|
112
|
+
* Unlike getGestureOwner(), this deliberately does not fall back to a
|
|
113
|
+
* background display lock: a lock holder with no live frame is not visible
|
|
114
|
+
* and therefore must not be closed by the system double-tap gesture.
|
|
115
|
+
*/
|
|
116
|
+
getVisibleMiniappPackageName(): string | null;
|
|
117
|
+
/**
|
|
118
|
+
* Cover the currently visible miniapp with a persistent system exit notice.
|
|
119
|
+
* While it is up, miniapp display traffic is held off so a streaming app
|
|
120
|
+
* cannot immediately overwrite the notice. The caller completes the normal
|
|
121
|
+
* stop flow and then calls finishMiniappExit(); onUnmount does the same as a
|
|
122
|
+
* safety net.
|
|
123
|
+
*/
|
|
124
|
+
beginMiniappExit(packageName: string, text: string): boolean;
|
|
125
|
+
/** Remove an exit notice and resume the display state normal app teardown leaves behind. */
|
|
126
|
+
finishMiniappExit(packageName: string): void;
|
|
127
|
+
/** Cancel the handoff and put back the frame the exit notice covered. */
|
|
128
|
+
cancelMiniappExit(packageName: string): void;
|
|
85
129
|
/** Report-safe ownership snapshot for incident diagnostics. */
|
|
86
130
|
getDiagnosticSnapshot(): Record<string, unknown>;
|
|
87
131
|
/**
|
|
88
132
|
* A local miniapp is going away. Clean up all state associated with it.
|
|
89
133
|
*/
|
|
90
134
|
onUnmount(packageName: string): void;
|
|
135
|
+
/**
|
|
136
|
+
* Dashboard cover state. On deactivate the retained main frame repaints
|
|
137
|
+
* (scenes replay create-based; legacy re-sends), or the glasses clear.
|
|
138
|
+
*/
|
|
139
|
+
setDashboardActive(active: boolean): void;
|
|
140
|
+
/** Dashboard renderers only; bypasses arbitration and main ownership state. */
|
|
141
|
+
renderDashboard(packageName: string, payload: DisplayPayload): void;
|
|
91
142
|
/**
|
|
92
143
|
* A miniapp requested a display. Routes through boot queue, arbitration,
|
|
93
144
|
* and throttle. This is the only public entry point for miniapp display
|
|
@@ -120,6 +171,7 @@ declare class LocalDisplayManager {
|
|
|
120
171
|
*/
|
|
121
172
|
private sendScene;
|
|
122
173
|
private sendToNative;
|
|
174
|
+
private pushToNative;
|
|
123
175
|
private handleExpiry;
|
|
124
176
|
private tryRestoreCoreDisplay;
|
|
125
177
|
private sendClear;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalDisplayManager.d.ts","sourceRoot":"","sources":["../../src/services/LocalDisplayManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,wBAAwB,CAAA;AAO7D,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAA;IACpC,kFAAkF;IAClF,MAAM,CAAC,EAAE;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAC,CAAA;IACrD,qEAAqE;IACrE,KAAK,CAAC,EAAE,iBAAiB,EAAE,CAAA;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,+EAA+E;AAC/E,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,MAAM,sBAAsB,GAAG,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAA;AAsD3E,cAAM,mBAAmB;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmC;IAE1D,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"LocalDisplayManager.d.ts","sourceRoot":"","sources":["../../src/services/LocalDisplayManager.ts"],"names":[],"mappings":"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"}
|