@glassly/engine 0.1.0-dev.61 → 0.1.0-dev.89
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 +6 -2
- package/build/engine.d.ts +7 -2
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +3 -0
- package/build/engine.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 +11 -1
- 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 +1 -0
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +2 -0
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/ota.d.ts +3 -1
- package/build/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +4 -2
- package/build/facades/ota.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/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +2 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -2
- package/build/index.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.d.ts +6 -1
- package/build/react/MentraLiveOtaFlow.d.ts.map +1 -1
- package/build/react/MentraLiveOtaFlow.js +136 -14
- package/build/react/MentraLiveOtaFlow.js.map +1 -1
- package/build/react/useMentraLiveOta.d.ts +5 -1
- package/build/react/useMentraLiveOta.d.ts.map +1 -1
- package/build/react/useMentraLiveOta.js +135 -58
- package/build/react/useMentraLiveOta.js.map +1 -1
- package/build/services/CustomDashboardService.d.ts +11 -10
- package/build/services/CustomDashboardService.d.ts.map +1 -1
- package/build/services/CustomDashboardService.js +70 -69
- package/build/services/CustomDashboardService.js.map +1 -1
- 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 +5 -7
- 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/LocalDisplayManager.d.ts +12 -2
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +68 -14
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/OtaInstallCoordinator.d.ts +2 -0
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +21 -1
- package/build/services/OtaInstallCoordinator.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/effectiveCapabilities.d.ts +1 -1
- package/build/services/effectiveCapabilities.d.ts.map +1 -1
- package/build/services/effectiveCapabilities.js +9 -4
- package/build/services/effectiveCapabilities.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/otaInstallPolicy.d.ts +4 -0
- 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/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.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 +53 -2
- package/build/stores/settings.js.map +1 -1
- package/build/types/applet.d.ts +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 +2 -2
- package/build/types/capabilities/even-realities-g2.js.map +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 +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js +1 -1
- 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/package.json +8 -7
- package/src/engine.ts +3 -0
- package/src/facades/display.ts +11 -1
- package/src/facades/displayMirror.ts +7 -15
- package/src/facades/glasses.ts +2 -0
- package/src/facades/ota.ts +4 -2
- package/src/facades/phoneNotifications.ts +32 -10
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/index.ts +2 -1
- package/src/react/MentraLiveOtaFlow.tsx +226 -41
- package/src/react/useMentraLiveOta.ts +146 -60
- package/src/services/CustomDashboardService.ts +67 -66
- package/src/services/DashboardCoordinator.ts +121 -0
- package/src/services/DeviceEventRouter.ts +5 -7
- package/src/services/DisplayProcessor.ts +3 -3
- package/src/services/LocalDisplayManager.ts +68 -16
- package/src/services/OtaInstallCoordinator.ts +21 -0
- 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/effectiveCapabilities.ts +9 -4
- package/src/services/iosNotificationAppCatalog.ts +39 -0
- package/src/services/otaInstallPolicy.ts +4 -0
- package/src/stores/display.ts +16 -48
- package/src/stores/glasses.ts +2 -0
- package/src/stores/settings.ts +53 -2
- package/src/types/applet.ts +1 -1
- package/src/types/capabilities/even-realities-g2.ts +3 -2
- package/src/types/hardware.ts +1 -0
- package/src/types/index.ts +1 -1
- package/src/utils/display/composer/ColumnComposer.ts +1 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const IOS_NOTIFICATION_APP_CATALOG = [
|
|
2
|
+
{ appId: "com.apple.MobileSMS", displayName: "Messages" },
|
|
3
|
+
{ appId: "com.apple.mobilephone", displayName: "Phone" },
|
|
4
|
+
{ appId: "com.apple.mobilemail", displayName: "Mail" },
|
|
5
|
+
{ appId: "com.apple.mobilecal", displayName: "Calendar" },
|
|
6
|
+
{ appId: "com.apple.reminders", displayName: "Reminders" },
|
|
7
|
+
{ appId: "com.apple.facetime", displayName: "FaceTime" },
|
|
8
|
+
{ appId: "net.whatsapp.WhatsApp", displayName: "WhatsApp" },
|
|
9
|
+
{ appId: "ph.telegra.Telegraph", displayName: "Telegram" },
|
|
10
|
+
{ appId: "org.whispersystems.signal", displayName: "Signal" },
|
|
11
|
+
{ appId: "com.google.Gmail", displayName: "Gmail" },
|
|
12
|
+
{ appId: "com.microsoft.Office.Outlook", displayName: "Outlook" },
|
|
13
|
+
{ appId: "com.tinyspeck.chatlyio", displayName: "Slack" },
|
|
14
|
+
{ appId: "com.hammerandchisel.discord", displayName: "Discord" },
|
|
15
|
+
{ appId: "com.microsoft.skype.teams", displayName: "Teams" },
|
|
16
|
+
{ appId: "com.facebook.Messenger", displayName: "Messenger" },
|
|
17
|
+
{ appId: "com.facebook.Facebook", displayName: "Facebook" },
|
|
18
|
+
{ appId: "com.burbn.instagram", displayName: "Instagram" },
|
|
19
|
+
{ appId: "com.atebits.Tweetie2", displayName: "X" },
|
|
20
|
+
{ appId: "com.zhiliaoapp.musically", displayName: "TikTok" },
|
|
21
|
+
{ appId: "com.toyopagroup.picaboo", displayName: "Snapchat" },
|
|
22
|
+
{ appId: "com.linkedin.LinkedIn", displayName: "LinkedIn" },
|
|
23
|
+
{ appId: "com.google.ios.youtube", displayName: "YouTube" },
|
|
24
|
+
{ appId: "com.spotify.client", displayName: "Spotify" },
|
|
25
|
+
{ appId: "com.ubercab.UberClient", displayName: "Uber" },
|
|
26
|
+
{ appId: "com.venmo.TouchFree", displayName: "Venmo" },
|
|
27
|
+
];
|
|
28
|
+
//# sourceMappingURL=iosNotificationAppCatalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iosNotificationAppCatalog.js","sourceRoot":"","sources":["../../src/services/iosNotificationAppCatalog.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,4BAA4B,GAAyB;IAChE,EAAC,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,UAAU,EAAC;IACvD,EAAC,KAAK,EAAE,uBAAuB,EAAE,WAAW,EAAE,OAAO,EAAC;IACtD,EAAC,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,EAAC;IACpD,EAAC,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,UAAU,EAAC;IACvD,EAAC,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,WAAW,EAAC;IACxD,EAAC,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,UAAU,EAAC;IACtD,EAAC,KAAK,EAAE,uBAAuB,EAAE,WAAW,EAAE,UAAU,EAAC;IACzD,EAAC,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,UAAU,EAAC;IACxD,EAAC,KAAK,EAAE,2BAA2B,EAAE,WAAW,EAAE,QAAQ,EAAC;IAC3D,EAAC,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,OAAO,EAAC;IACjD,EAAC,KAAK,EAAE,8BAA8B,EAAE,WAAW,EAAE,SAAS,EAAC;IAC/D,EAAC,KAAK,EAAE,wBAAwB,EAAE,WAAW,EAAE,OAAO,EAAC;IACvD,EAAC,KAAK,EAAE,6BAA6B,EAAE,WAAW,EAAE,SAAS,EAAC;IAC9D,EAAC,KAAK,EAAE,2BAA2B,EAAE,WAAW,EAAE,OAAO,EAAC;IAC1D,EAAC,KAAK,EAAE,wBAAwB,EAAE,WAAW,EAAE,WAAW,EAAC;IAC3D,EAAC,KAAK,EAAE,uBAAuB,EAAE,WAAW,EAAE,UAAU,EAAC;IACzD,EAAC,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,WAAW,EAAC;IACxD,EAAC,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,GAAG,EAAC;IACjD,EAAC,KAAK,EAAE,0BAA0B,EAAE,WAAW,EAAE,QAAQ,EAAC;IAC1D,EAAC,KAAK,EAAE,yBAAyB,EAAE,WAAW,EAAE,UAAU,EAAC;IAC3D,EAAC,KAAK,EAAE,uBAAuB,EAAE,WAAW,EAAE,UAAU,EAAC;IACzD,EAAC,KAAK,EAAE,wBAAwB,EAAE,WAAW,EAAE,SAAS,EAAC;IACzD,EAAC,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,SAAS,EAAC;IACrD,EAAC,KAAK,EAAE,wBAAwB,EAAE,WAAW,EAAE,MAAM,EAAC;IACtD,EAAC,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,OAAO,EAAC;CACrD,CAAA","sourcesContent":["/**\n * Seeded catalog of common iOS apps that post notifications, keyed by bundle\n * id. iOS has no installed-apps enumeration — the filter UI shows this catalog\n * plus apps the glasses have actually observed via ANCS — and the on-glass\n * allowlist push needs known ids so a blocked app doesn't take every\n * not-yet-seen app down with it (the firmware filter is allow-based).\n */\nexport interface IosNotificationApp {\n appId: string\n displayName: string\n}\n\nexport const IOS_NOTIFICATION_APP_CATALOG: IosNotificationApp[] = [\n {appId: \"com.apple.MobileSMS\", displayName: \"Messages\"},\n {appId: \"com.apple.mobilephone\", displayName: \"Phone\"},\n {appId: \"com.apple.mobilemail\", displayName: \"Mail\"},\n {appId: \"com.apple.mobilecal\", displayName: \"Calendar\"},\n {appId: \"com.apple.reminders\", displayName: \"Reminders\"},\n {appId: \"com.apple.facetime\", displayName: \"FaceTime\"},\n {appId: \"net.whatsapp.WhatsApp\", displayName: \"WhatsApp\"},\n {appId: \"ph.telegra.Telegraph\", displayName: \"Telegram\"},\n {appId: \"org.whispersystems.signal\", displayName: \"Signal\"},\n {appId: \"com.google.Gmail\", displayName: \"Gmail\"},\n {appId: \"com.microsoft.Office.Outlook\", displayName: \"Outlook\"},\n {appId: \"com.tinyspeck.chatlyio\", displayName: \"Slack\"},\n {appId: \"com.hammerandchisel.discord\", displayName: \"Discord\"},\n {appId: \"com.microsoft.skype.teams\", displayName: \"Teams\"},\n {appId: \"com.facebook.Messenger\", displayName: \"Messenger\"},\n {appId: \"com.facebook.Facebook\", displayName: \"Facebook\"},\n {appId: \"com.burbn.instagram\", displayName: \"Instagram\"},\n {appId: \"com.atebits.Tweetie2\", displayName: \"X\"},\n {appId: \"com.zhiliaoapp.musically\", displayName: \"TikTok\"},\n {appId: \"com.toyopagroup.picaboo\", displayName: \"Snapchat\"},\n {appId: \"com.linkedin.LinkedIn\", displayName: \"LinkedIn\"},\n {appId: \"com.google.ios.youtube\", displayName: \"YouTube\"},\n {appId: \"com.spotify.client\", displayName: \"Spotify\"},\n {appId: \"com.ubercab.UberClient\", displayName: \"Uber\"},\n {appId: \"com.venmo.TouchFree\", displayName: \"Venmo\"},\n]\n"]}
|
|
@@ -30,6 +30,8 @@ export declare const PING_INTERVAL_MS = 10000;
|
|
|
30
30
|
export declare const QUERY_REPLY_TIMEOUT_MS = 6000;
|
|
31
31
|
/** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */
|
|
32
32
|
export declare const BES_CONTINUE_LOCKOUT_MS = 15000;
|
|
33
|
+
/** Fail closed if a BES reboot never reconnects; normal restarts complete in a fraction of this window. */
|
|
34
|
+
export declare const BES_RESTART_TIMEOUT_MS = 120000;
|
|
33
35
|
/** The uniform pad progress-legacy.tsx added to every duration for old builds. */
|
|
34
36
|
export declare const LEGACY_EXTRA_TIMEOUT_MS = 20000;
|
|
35
37
|
export declare const LEGACY_RETRY_INTERVAL_MS: number;
|
|
@@ -39,6 +41,7 @@ export declare const LEGACY_MTK_INSTALL_TIMEOUT_MS: number;
|
|
|
39
41
|
export declare const LEGACY_GLOBAL_OTA_TIMEOUT_MS: number;
|
|
40
42
|
export declare const LEGACY_PING_INTERVAL_MS: number;
|
|
41
43
|
export declare const LEGACY_BES_CONTINUE_LOCKOUT_MS: number;
|
|
44
|
+
export declare const LEGACY_BES_RESTART_TIMEOUT_MS: number;
|
|
42
45
|
/**
|
|
43
46
|
* After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the
|
|
44
47
|
* completed state for 12s (+20s pad) so the ASG process restart settles (and fresh
|
|
@@ -82,6 +85,7 @@ export declare function selectOtaProtocolProfile(otaStatus: OtaStatus | null, ot
|
|
|
82
85
|
export declare const OtaProgressMessages: {
|
|
83
86
|
readonly stalledOrStuck: "Update may have failed. Ensure glasses have internet access and try again.";
|
|
84
87
|
readonly globalTimeout: "Update took too long. Please try again.";
|
|
88
|
+
readonly restartTimeout: "Glasses did not finish restarting. Restart them before trying the update again.";
|
|
85
89
|
readonly sendOtaStartFailed: "Failed to communicate with glasses.";
|
|
86
90
|
readonly hotspotArtifactDownloadFailed: "Could not download the update to your phone. Check phone internet and try again.";
|
|
87
91
|
readonly hotspotArtifactVerifyFailed: "The update package could not be verified. Please try again later.";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otaInstallPolicy.d.ts","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,wBAAwB,CAAA;AAElE;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,OAAO,CAAA;AACrC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,SAAU,CAAA;AAC1C,kDAAkD;AAClD,eAAO,MAAM,yBAAyB,QAAS,CAAA;AAC/C,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,SAAU,CAAA;AAC7C,mCAAmC;AACnC,eAAO,MAAM,qBAAqB,QAAiB,CAAA;AACnD,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,QAAS,CAAA;AACtC;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAC1C,4FAA4F;AAC5F,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAW7C,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAC7C,eAAO,MAAM,wBAAwB,QAA8C,CAAA;AACnF,eAAO,MAAM,0BAA0B,QAAgD,CAAA;AACvF,eAAO,MAAM,gCAAgC,QAAsD,CAAA;AACnG,eAAO,MAAM,6BAA6B,QAAmD,CAAA;AAC7F,eAAO,MAAM,4BAA4B,QAAkD,CAAA;AAC3F,eAAO,MAAM,uBAAuB,QAA6C,CAAA;AACjF,eAAO,MAAM,8BAA8B,QAAoD,CAAA;AAC/F;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,QAAmC,CAAA;AAC/E;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAmC,CAAA;AAC1E,eAAO,MAAM,sBAAsB,QAAmC,CAAA;AACtE,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,4BAA4B,KAAK,CAAA;AAC9C,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAA;AAErD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,OAAO,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAKT;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,kBAAkB,GAAG,IAAI,CAQ3B;AAED,eAAO,MAAM,mBAAmB
|
|
1
|
+
{"version":3,"file":"otaInstallPolicy.d.ts","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,wBAAwB,CAAA;AAElE;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C,eAAO,MAAM,WAAW,IAAI,CAAA;AAC5B,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,OAAO,CAAA;AACrC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,SAAU,CAAA;AAC1C,kDAAkD;AAClD,eAAO,MAAM,yBAAyB,QAAS,CAAA;AAC/C,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,SAAU,CAAA;AAC7C,mCAAmC;AACnC,eAAO,MAAM,qBAAqB,QAAiB,CAAA;AACnD,+BAA+B;AAC/B,eAAO,MAAM,gBAAgB,QAAS,CAAA;AACtC;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAA;AAC1C,4FAA4F;AAC5F,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAC7C,2GAA2G;AAC3G,eAAO,MAAM,sBAAsB,SAAU,CAAA;AAW7C,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAC7C,eAAO,MAAM,wBAAwB,QAA8C,CAAA;AACnF,eAAO,MAAM,0BAA0B,QAAgD,CAAA;AACvF,eAAO,MAAM,gCAAgC,QAAsD,CAAA;AACnG,eAAO,MAAM,6BAA6B,QAAmD,CAAA;AAC7F,eAAO,MAAM,4BAA4B,QAAkD,CAAA;AAC3F,eAAO,MAAM,uBAAuB,QAA6C,CAAA;AACjF,eAAO,MAAM,8BAA8B,QAAoD,CAAA;AAC/F,eAAO,MAAM,6BAA6B,QAAmD,CAAA;AAC7F;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,QAAmC,CAAA;AAC/E;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,QAAmC,CAAA;AAC1E,eAAO,MAAM,sBAAsB,QAAmC,CAAA;AACtE,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,iCAAiC,KAAK,CAAA;AACnD,eAAO,MAAM,4BAA4B,KAAK,CAAA;AAC9C,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAA;AAErD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,OAAO,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAKT;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,kBAAkB,GAAG,IAAI,CAQ3B;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;CAWtB,CAAA"}
|
|
@@ -28,6 +28,8 @@ export const PING_INTERVAL_MS = 10_000;
|
|
|
28
28
|
export const QUERY_REPLY_TIMEOUT_MS = 6000;
|
|
29
29
|
/** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */
|
|
30
30
|
export const BES_CONTINUE_LOCKOUT_MS = 15_000;
|
|
31
|
+
/** Fail closed if a BES reboot never reconnects; normal restarts complete in a fraction of this window. */
|
|
32
|
+
export const BES_RESTART_TIMEOUT_MS = 120_000;
|
|
31
33
|
// --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---
|
|
32
34
|
//
|
|
33
35
|
// Ported verbatim from mobile/src/app/ota/progress-legacy.tsx, which padded EVERY
|
|
@@ -45,6 +47,7 @@ export const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXT
|
|
|
45
47
|
export const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS;
|
|
46
48
|
export const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS;
|
|
47
49
|
export const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS;
|
|
50
|
+
export const LEGACY_BES_RESTART_TIMEOUT_MS = BES_RESTART_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS;
|
|
48
51
|
/**
|
|
49
52
|
* After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the
|
|
50
53
|
* completed state for 12s (+20s pad) so the ASG process restart settles (and fresh
|
|
@@ -106,6 +109,7 @@ export function selectOtaProtocolProfile(otaStatus, otaProgress, buildNumber) {
|
|
|
106
109
|
export const OtaProgressMessages = {
|
|
107
110
|
stalledOrStuck: "Update may have failed. Ensure glasses have internet access and try again.",
|
|
108
111
|
globalTimeout: "Update took too long. Please try again.",
|
|
112
|
+
restartTimeout: "Glasses did not finish restarting. Restart them before trying the update again.",
|
|
109
113
|
sendOtaStartFailed: "Failed to communicate with glasses.",
|
|
110
114
|
hotspotArtifactDownloadFailed: "Could not download the update to your phone. Check phone internet and try again.",
|
|
111
115
|
hotspotArtifactVerifyFailed: "The update package could not be verified. Please try again later.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otaInstallPolicy.js","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["/** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */\nimport type {OtaProgress, OtaStatus} from \"@glassly/bluetooth-sdk\"\n\n/**\n * First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified\n * `ota_status` session UI. Strictly lower builds use `/ota/progress-legacy` (routed from\n * `check-for-updates.tsx` before navigation), and get the LEGACY_* padded policy below\n * in the unified OtaInstallCoordinator (WP 8C). Change only here.\n */\nexport const MINIMUM_OTA_STATUS_BUILD = 37\n\nexport const MAX_RETRIES = 3\n/** Wait between ended native ota_start requests; never overlaps a pending request. */\nexport const RETRY_INTERVAL_MS = 5000\n/** APK/BES and general install when progress events are expected */\nexport const PROGRESS_TIMEOUT_MS = 120_000\n/** Fail if still at 0% in starting/downloading */\nexport const DOWNLOAD_STUCK_TIMEOUT_MS = 70_000\n/** MTK system install often goes quiet for long periods */\nexport const MTK_INSTALL_TIMEOUT_MS = 300_000\n/** Whole multi-step session cap */\nexport const GLOBAL_OTA_TIMEOUT_MS = 20 * 60 * 1000\n/** BLE keepalive during OTA */\nexport const PING_INTERVAL_MS = 10_000\n/**\n * If we sent ota_query_status (e.g. on reconnect) and the glasses haven't\n * replied with an ota_status by then, fall back to ota_start. This recovers\n * from the case where the glasses process restarted between mount and\n * reconnect — the session is gone, ota_query_status returns nothing, and\n * the user would otherwise sit on the spinner forever.\n */\nexport const QUERY_REPLY_TIMEOUT_MS = 6000\n/** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */\nexport const BES_CONTINUE_LOCKOUT_MS = 15_000\n\n// --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---\n//\n// Ported verbatim from mobile/src/app/ota/progress-legacy.tsx, which padded EVERY\n// watchdog/timer by +20s for old ASG builds (\"Legacy OTA: +20s on every watchdog /\n// timer duration\"). Old builds respond slower on every path, so where the legacy\n// screen used a longer duration the coordinator applies the longer value whenever\n// the session is legacy-shaped (see isLegacyShapedOtaStatus / the coordinator's\n// session-shape check). Builds >= 37 keep the unpadded values above.\n\n/** The uniform pad progress-legacy.tsx added to every duration for old builds. */\nexport const LEGACY_EXTRA_TIMEOUT_MS = 20_000\nexport const LEGACY_RETRY_INTERVAL_MS = RETRY_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PROGRESS_TIMEOUT_MS = PROGRESS_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_DOWNLOAD_STUCK_TIMEOUT_MS = DOWNLOAD_STUCK_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the\n * completed state for 12s (+20s pad) so the ASG process restart settles (and fresh\n * version_info lands) before the user can continue.\n */\nexport const LEGACY_APK_COMPLETION_SETTLE_MS = 12_000 + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * Legacy MTK install stall simulation (display-only): the MTK system install typically\n * stalls around 49-50%. After LEGACY_MTK_STALL_DETECT_MS without a new event in the\n * [45, 55) zone, the legacy screen simulated +1% every LEGACY_MTK_SIM_TICK_MS starting\n * at max(stall+1, 51) and capped at 60%, purely to keep the user informed.\n */\nexport const LEGACY_MTK_STALL_DETECT_MS = 20_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_SIM_TICK_MS = 15_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_STALL_ZONE_MIN_PERCENT = 45\nexport const LEGACY_MTK_STALL_ZONE_MAX_PERCENT = 55\nexport const LEGACY_MTK_SIM_FLOOR_PERCENT = 51\nexport const LEGACY_MTK_SIM_CAP_PERCENT = 60\n\nexport type OtaProtocolProfile = \"legacy\" | \"unified\"\n\n/**\n * Legacy-shaped ota_status: old (< 37) ASG builds send `ota_progress`, which the SDK\n * (Android MentraLive.kt / iOS MentraLive.swift) maps to a unified ota_status with\n * sessionId \"\" and totalSteps 1, and FINISHED→\"complete\" regardless of phase. A real\n * (>= 37) session always carries a sessionId; an \"idle\" reply also has sessionId \"\" but\n * proves the glasses speak the unified protocol, so it is NOT legacy-shaped.\n */\nexport function isLegacyShapedOtaStatus(otaStatus: OtaStatus | null): boolean {\n return !!otaStatus && otaStatus.sessionId === \"\" && otaStatus.status !== \"idle\"\n}\n\n/**\n * Is the current install session legacy-shaped? Event shape wins when events exist\n * (per the WP 8C rule: key off legacy-shaped inputs, not a build flag, where possible);\n * before any event arrives only the glasses build number can tell.\n */\nexport function isLegacyShapedOtaSession(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): boolean {\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus)\n if (otaProgress) return true\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n return Number.isFinite(build) && build > 0 && build < MINIMUM_OTA_STATUS_BUILD\n}\n\n/**\n * Select the compatibility profile once at install-screen attach. The old split\n * routes made this decision from the pre-update build and kept it for the whole\n * mounted flow, even when an APK step restarted into a newer ASG build. Returning\n * null leaves the coordinator undecided until the first meaningful OTA event.\n */\nexport function selectOtaProtocolProfile(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): OtaProtocolProfile | null {\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n if (Number.isFinite(build) && build > 0) {\n return build < MINIMUM_OTA_STATUS_BUILD ? \"legacy\" : \"unified\"\n }\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus) ? \"legacy\" : \"unified\"\n if (otaProgress) return \"legacy\"\n return null\n}\n\nexport const OtaProgressMessages = {\n stalledOrStuck: \"Update may have failed. Ensure glasses have internet access and try again.\",\n globalTimeout: \"Update took too long. Please try again.\",\n sendOtaStartFailed: \"Failed to communicate with glasses.\",\n hotspotArtifactDownloadFailed: \"Could not download the update to your phone. Check phone internet and try again.\",\n hotspotArtifactVerifyFailed: \"The update package could not be verified. Please try again later.\",\n hotspotWifiPermissionDenied: \"Allow nearby devices access so the phone can connect to the glasses hotspot.\",\n hotspotStartFailed: \"Could not start the glasses hotspot. Please try again.\",\n hotspotJoinFailed: \"Could not connect the phone to the glasses hotspot. Please try again.\",\n hotspotServerFailed: \"Could not make the update available to the glasses. Please try again.\",\n} as const\n"]}
|
|
1
|
+
{"version":3,"file":"otaInstallPolicy.js","sourceRoot":"","sources":["../../src/services/otaInstallPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["/** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */\nimport type {OtaProgress, OtaStatus} from \"@glassly/bluetooth-sdk\"\n\n/**\n * First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified\n * `ota_status` session UI. Strictly lower builds use `/ota/progress-legacy` (routed from\n * `check-for-updates.tsx` before navigation), and get the LEGACY_* padded policy below\n * in the unified OtaInstallCoordinator (WP 8C). Change only here.\n */\nexport const MINIMUM_OTA_STATUS_BUILD = 37\n\nexport const MAX_RETRIES = 3\n/** Wait between ended native ota_start requests; never overlaps a pending request. */\nexport const RETRY_INTERVAL_MS = 5000\n/** APK/BES and general install when progress events are expected */\nexport const PROGRESS_TIMEOUT_MS = 120_000\n/** Fail if still at 0% in starting/downloading */\nexport const DOWNLOAD_STUCK_TIMEOUT_MS = 70_000\n/** MTK system install often goes quiet for long periods */\nexport const MTK_INSTALL_TIMEOUT_MS = 300_000\n/** Whole multi-step session cap */\nexport const GLOBAL_OTA_TIMEOUT_MS = 20 * 60 * 1000\n/** BLE keepalive during OTA */\nexport const PING_INTERVAL_MS = 10_000\n/**\n * If we sent ota_query_status (e.g. on reconnect) and the glasses haven't\n * replied with an ota_status by then, fall back to ota_start. This recovers\n * from the case where the glasses process restarted between mount and\n * reconnect — the session is gone, ota_query_status returns nothing, and\n * the user would otherwise sit on the spinner forever.\n */\nexport const QUERY_REPLY_TIMEOUT_MS = 6000\n/** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */\nexport const BES_CONTINUE_LOCKOUT_MS = 15_000\n/** Fail closed if a BES reboot never reconnects; normal restarts complete in a fraction of this window. */\nexport const BES_RESTART_TIMEOUT_MS = 120_000\n\n// --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---\n//\n// Ported verbatim from mobile/src/app/ota/progress-legacy.tsx, which padded EVERY\n// watchdog/timer by +20s for old ASG builds (\"Legacy OTA: +20s on every watchdog /\n// timer duration\"). Old builds respond slower on every path, so where the legacy\n// screen used a longer duration the coordinator applies the longer value whenever\n// the session is legacy-shaped (see isLegacyShapedOtaStatus / the coordinator's\n// session-shape check). Builds >= 37 keep the unpadded values above.\n\n/** The uniform pad progress-legacy.tsx added to every duration for old builds. */\nexport const LEGACY_EXTRA_TIMEOUT_MS = 20_000\nexport const LEGACY_RETRY_INTERVAL_MS = RETRY_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PROGRESS_TIMEOUT_MS = PROGRESS_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_DOWNLOAD_STUCK_TIMEOUT_MS = DOWNLOAD_STUCK_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_BES_RESTART_TIMEOUT_MS = BES_RESTART_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the\n * completed state for 12s (+20s pad) so the ASG process restart settles (and fresh\n * version_info lands) before the user can continue.\n */\nexport const LEGACY_APK_COMPLETION_SETTLE_MS = 12_000 + LEGACY_EXTRA_TIMEOUT_MS\n/**\n * Legacy MTK install stall simulation (display-only): the MTK system install typically\n * stalls around 49-50%. After LEGACY_MTK_STALL_DETECT_MS without a new event in the\n * [45, 55) zone, the legacy screen simulated +1% every LEGACY_MTK_SIM_TICK_MS starting\n * at max(stall+1, 51) and capped at 60%, purely to keep the user informed.\n */\nexport const LEGACY_MTK_STALL_DETECT_MS = 20_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_SIM_TICK_MS = 15_000 + LEGACY_EXTRA_TIMEOUT_MS\nexport const LEGACY_MTK_STALL_ZONE_MIN_PERCENT = 45\nexport const LEGACY_MTK_STALL_ZONE_MAX_PERCENT = 55\nexport const LEGACY_MTK_SIM_FLOOR_PERCENT = 51\nexport const LEGACY_MTK_SIM_CAP_PERCENT = 60\n\nexport type OtaProtocolProfile = \"legacy\" | \"unified\"\n\n/**\n * Legacy-shaped ota_status: old (< 37) ASG builds send `ota_progress`, which the SDK\n * (Android MentraLive.kt / iOS MentraLive.swift) maps to a unified ota_status with\n * sessionId \"\" and totalSteps 1, and FINISHED→\"complete\" regardless of phase. A real\n * (>= 37) session always carries a sessionId; an \"idle\" reply also has sessionId \"\" but\n * proves the glasses speak the unified protocol, so it is NOT legacy-shaped.\n */\nexport function isLegacyShapedOtaStatus(otaStatus: OtaStatus | null): boolean {\n return !!otaStatus && otaStatus.sessionId === \"\" && otaStatus.status !== \"idle\"\n}\n\n/**\n * Is the current install session legacy-shaped? Event shape wins when events exist\n * (per the WP 8C rule: key off legacy-shaped inputs, not a build flag, where possible);\n * before any event arrives only the glasses build number can tell.\n */\nexport function isLegacyShapedOtaSession(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): boolean {\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus)\n if (otaProgress) return true\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n return Number.isFinite(build) && build > 0 && build < MINIMUM_OTA_STATUS_BUILD\n}\n\n/**\n * Select the compatibility profile once at install-screen attach. The old split\n * routes made this decision from the pre-update build and kept it for the whole\n * mounted flow, even when an APK step restarted into a newer ASG build. Returning\n * null leaves the coordinator undecided until the first meaningful OTA event.\n */\nexport function selectOtaProtocolProfile(\n otaStatus: OtaStatus | null,\n otaProgress: OtaProgress | null,\n buildNumber: string | null | undefined,\n): OtaProtocolProfile | null {\n const build = Number.parseInt(buildNumber ?? \"\", 10)\n if (Number.isFinite(build) && build > 0) {\n return build < MINIMUM_OTA_STATUS_BUILD ? \"legacy\" : \"unified\"\n }\n if (otaStatus) return isLegacyShapedOtaStatus(otaStatus) ? \"legacy\" : \"unified\"\n if (otaProgress) return \"legacy\"\n return null\n}\n\nexport const OtaProgressMessages = {\n stalledOrStuck: \"Update may have failed. Ensure glasses have internet access and try again.\",\n globalTimeout: \"Update took too long. Please try again.\",\n restartTimeout: \"Glasses did not finish restarting. Restart them before trying the update again.\",\n sendOtaStartFailed: \"Failed to communicate with glasses.\",\n hotspotArtifactDownloadFailed: \"Could not download the update to your phone. Check phone internet and try again.\",\n hotspotArtifactVerifyFailed: \"The update package could not be verified. Please try again later.\",\n hotspotWifiPermissionDenied: \"Allow nearby devices access so the phone can connect to the glasses hotspot.\",\n hotspotStartFailed: \"Could not start the glasses hotspot. Please try again.\",\n hotspotJoinFailed: \"Could not connect the phone to the glasses hotspot. Please try again.\",\n hotspotServerFailed: \"Could not make the update available to the glasses. Please try again.\",\n} as const\n"]}
|
|
@@ -2,12 +2,12 @@ type DisplayEvent = Record<string, unknown> & {
|
|
|
2
2
|
view?: string;
|
|
3
3
|
};
|
|
4
4
|
export interface DisplayStore {
|
|
5
|
+
/** The frame currently on the glasses — the mirror renders this. */
|
|
5
6
|
currentEvent: any;
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
/** True while the dashboard covers the main content (see DashboardCoordinator). */
|
|
8
|
+
dashboardActive: boolean;
|
|
8
9
|
setDisplayEvent: (event: DisplayEvent | string) => void;
|
|
9
|
-
|
|
10
|
-
setView: (view: string) => void;
|
|
10
|
+
setDashboardActive: (active: boolean) => void;
|
|
11
11
|
}
|
|
12
12
|
export declare const useDisplayStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<DisplayStore>, "subscribe"> & {
|
|
13
13
|
subscribe: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/stores/display.ts"],"names":[],"mappings":"AA6BA,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/stores/display.ts"],"names":[],"mappings":"AA6BA,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAC,CAAA;AAc7D,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,YAAY,EAAE,GAAG,CAAA;IACjB,mFAAmF;IACnF,eAAe,EAAE,OAAO,CAAA;IACxB,eAAe,EAAE,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,KAAK,IAAI,CAAA;IACvD,kBAAkB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;CAC9C;AAKD,eAAO,MAAM,eAAe;;;;;;;;EAoB3B,CAAA;AAED,4EAA4E;AAC5E,wBAAgB,4BAA4B,IAAI,IAAI,CAUnD"}
|
package/build/stores/display.js
CHANGED
|
@@ -23,34 +23,22 @@ function extractDisplayText(displayEvent) {
|
|
|
23
23
|
}
|
|
24
24
|
/** Coalesce rapid caption updates (~3.3 Hz) into one store write per window. */
|
|
25
25
|
const DISPLAY_COALESCE_MS = 150;
|
|
26
|
-
function applyDisplayEvent(set,
|
|
27
|
-
const
|
|
28
|
-
const targetBucket = event.view === "dashboard" ? "dashboardEvent" : "mainEvent";
|
|
29
|
-
const updates = {
|
|
30
|
-
[targetBucket]: event,
|
|
31
|
-
};
|
|
32
|
-
// also update the current event if the view is the same:
|
|
33
|
-
if (event.view === currentView) {
|
|
34
|
-
updates.currentEvent = event;
|
|
35
|
-
}
|
|
36
|
-
const visibleEvent = (updates.currentEvent ?? event);
|
|
37
|
-
const textLines = extractDisplayText(visibleEvent);
|
|
26
|
+
function applyDisplayEvent(set, event) {
|
|
27
|
+
const textLines = extractDisplayText(event);
|
|
38
28
|
if (textLines.some((line) => line.trim() !== "")) {
|
|
39
29
|
logE2EMetric("display_store_update", {
|
|
40
|
-
view:
|
|
41
|
-
layout_type:
|
|
30
|
+
view: event.view ?? "main",
|
|
31
|
+
layout_type: event.layout?.layoutType ?? "",
|
|
42
32
|
text_lines: textLines,
|
|
43
33
|
});
|
|
44
34
|
}
|
|
45
|
-
set(
|
|
35
|
+
set({ currentEvent: event });
|
|
46
36
|
}
|
|
47
37
|
let pendingDisplayEvent = null;
|
|
48
38
|
let displayCoalesceTimer = null;
|
|
49
|
-
export const useDisplayStore = create()(subscribeWithSelector((set
|
|
39
|
+
export const useDisplayStore = create()(subscribeWithSelector((set) => ({
|
|
50
40
|
currentEvent: {},
|
|
51
|
-
|
|
52
|
-
mainEvent: {},
|
|
53
|
-
view: "main",
|
|
41
|
+
dashboardActive: false,
|
|
54
42
|
setDisplayEvent: (event) => {
|
|
55
43
|
const parsed = typeof event === "string" ? JSON.parse(event) : event;
|
|
56
44
|
pendingDisplayEvent = parsed;
|
|
@@ -61,24 +49,12 @@ export const useDisplayStore = create()(subscribeWithSelector((set, get) => ({
|
|
|
61
49
|
const next = pendingDisplayEvent;
|
|
62
50
|
pendingDisplayEvent = null;
|
|
63
51
|
if (next)
|
|
64
|
-
applyDisplayEvent(set,
|
|
52
|
+
applyDisplayEvent(set, next);
|
|
65
53
|
}, DISPLAY_COALESCE_MS);
|
|
66
54
|
},
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
// update the view and the currentEvent with the corresponding event:
|
|
73
|
-
let newEvent;
|
|
74
|
-
if (view === "dashboard") {
|
|
75
|
-
newEvent = get().dashboardEvent;
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
newEvent = get().mainEvent;
|
|
79
|
-
}
|
|
80
|
-
logE2EMetric("display_view_changed", { view });
|
|
81
|
-
set({ view, currentEvent: newEvent });
|
|
55
|
+
setDashboardActive: (active) => {
|
|
56
|
+
logE2EMetric("display_view_changed", { view: active ? "dashboard" : "main" });
|
|
57
|
+
set({ dashboardActive: active });
|
|
82
58
|
},
|
|
83
59
|
})));
|
|
84
60
|
/** Test helper — flush any pending coalesced display update immediately. */
|
|
@@ -90,7 +66,7 @@ export function flushDisplayCoalesceForTests() {
|
|
|
90
66
|
if (pendingDisplayEvent) {
|
|
91
67
|
const event = pendingDisplayEvent;
|
|
92
68
|
pendingDisplayEvent = null;
|
|
93
|
-
applyDisplayEvent(useDisplayStore.setState,
|
|
69
|
+
applyDisplayEvent(useDisplayStore.setState, event);
|
|
94
70
|
}
|
|
95
71
|
}
|
|
96
72
|
//# sourceMappingURL=display.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"display.js","sourceRoot":"","sources":["../../src/stores/display.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,SAAS,CAAA;AAC9B,OAAO,EAAC,qBAAqB,EAAC,MAAM,oBAAoB,CAAA;AAExD,OAAO,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAC,YAAY,EAAC,MAAM,qBAAqB,CAAA;AAEhD,SAAS,kBAAkB,CAAC,YAAiB;IAC3C,MAAM,MAAM,GAAG,YAAY,EAAE,MAAM,CAAA;IACnC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,EAAE,CAAA;IACX,CAAC;IACD,QAAQ,MAAM,CAAC,UAAU,EAAE,CAAC;QAC1B,KAAK,WAAW,CAAC;QACjB,KAAK,WAAW;YACd,OAAO,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACvE,KAAK,kBAAkB;YACrB,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAA;QAC1G,KAAK,WAAW;YACd,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC/B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAc,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC;gBACpF,CAAC,CAAC,EAAE,CAAA;QACR;YACE,OAAO,EAAE,CAAA;IACb,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,mBAAmB,GAAG,GAAG,CAAA;AAI/B,SAAS,iBAAiB,
|
|
1
|
+
{"version":3,"file":"display.js","sourceRoot":"","sources":["../../src/stores/display.ts"],"names":[],"mappings":"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","sourcesContent":["import {create} from \"zustand\"\nimport {subscribeWithSelector} from \"zustand/middleware\"\n\nimport {BgTimer} from \"../utils/timers\"\nimport {logE2EMetric} from \"../utils/e2eMetrics\"\n\nfunction extractDisplayText(displayEvent: any): string[] {\n const layout = displayEvent?.layout\n if (!layout || typeof layout !== \"object\") {\n return []\n }\n switch (layout.layoutType) {\n case \"text_wall\":\n case \"text_line\":\n return typeof layout.text === \"string\" ? layout.text.split(\"\\n\") : []\n case \"double_text_wall\":\n return [layout.topText, layout.bottomText].filter((value): value is string => typeof value === \"string\")\n case \"text_rows\":\n return Array.isArray(layout.text)\n ? layout.text.filter((value: unknown): value is string => typeof value === \"string\")\n : []\n default:\n return []\n }\n}\n\n/** Coalesce rapid caption updates (~3.3 Hz) into one store write per window. */\nconst DISPLAY_COALESCE_MS = 150\n\ntype DisplayEvent = Record<string, unknown> & {view?: string}\n\nfunction applyDisplayEvent(set: (partial: Partial<DisplayStore>) => void, event: DisplayEvent) {\n const textLines = extractDisplayText(event)\n if (textLines.some((line) => line.trim() !== \"\")) {\n logE2EMetric(\"display_store_update\", {\n view: event.view ?? \"main\",\n layout_type: (event.layout as {layoutType?: string} | undefined)?.layoutType ?? \"\",\n text_lines: textLines,\n })\n }\n set({currentEvent: event})\n}\n\nexport interface DisplayStore {\n /** The frame currently on the glasses — the mirror renders this. */\n currentEvent: any\n /** True while the dashboard covers the main content (see DashboardCoordinator). */\n dashboardActive: boolean\n setDisplayEvent: (event: DisplayEvent | string) => void\n setDashboardActive: (active: boolean) => void\n}\n\nlet pendingDisplayEvent: DisplayEvent | null = null\nlet displayCoalesceTimer: ReturnType<typeof BgTimer.setTimeout> | null = null\n\nexport const useDisplayStore = create<DisplayStore>()(\n subscribeWithSelector((set) => ({\n currentEvent: {} as any,\n dashboardActive: false,\n setDisplayEvent: (event: DisplayEvent | string) => {\n const parsed: DisplayEvent = typeof event === \"string\" ? JSON.parse(event) : event\n pendingDisplayEvent = parsed\n if (displayCoalesceTimer) return\n displayCoalesceTimer = BgTimer.setTimeout(() => {\n displayCoalesceTimer = null\n const next = pendingDisplayEvent\n pendingDisplayEvent = null\n if (next) applyDisplayEvent(set, next)\n }, DISPLAY_COALESCE_MS)\n },\n setDashboardActive: (active: boolean) => {\n logE2EMetric(\"display_view_changed\", {view: active ? \"dashboard\" : \"main\"})\n set({dashboardActive: active})\n },\n })),\n)\n\n/** Test helper — flush any pending coalesced display update immediately. */\nexport function flushDisplayCoalesceForTests(): void {\n if (displayCoalesceTimer) {\n BgTimer.clearTimeout(displayCoalesceTimer)\n displayCoalesceTimer = null\n }\n if (pendingDisplayEvent) {\n const event = pendingDisplayEvent\n pendingDisplayEvent = null\n applyDisplayEvent(useDisplayStore.setState, event)\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glasses.d.ts","sourceRoot":"","sources":["../../src/stores/glasses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EAEvB,WAAW,EACX,SAAS,EACT,aAAa,EACb,mBAAmB,EAEpB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAE,cAAc,EAAC,MAAM,8BAA8B,CAAA;AAMvG,OAAO,EAAC,kBAAkB,EAAE,sBAAsB,EAAE,cAAc,EAAC,CAAA;AAEnE,eAAO,MAAM,sBAAsB,GAAI,OAAO;IAAC,UAAU,EAAE,uBAAuB,CAAA;CAAC,YAC7C,CAAA;AAEtC,eAAO,MAAM,kBAAkB,GAAI,OAAO;IAAC,UAAU,EAAE,uBAAuB,CAAA;CAAC,YAAqC,CAAA;AAEpH,KAAK,mBAAmB,GAAG,mBAAmB,GAAG;IAC/C,kBAAkB,EAAE,aAAa,GAAG,IAAI,CAAA;IACxC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAA;IAC/B,aAAa,EAAE,OAAO,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,WAAW,YAAa,SAAQ,mBAAmB;IACvD,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,OAAO,CAAA;IACxB,cAAc,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACjD,cAAc,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,KAAK,IAAI,CAAA;IAClH,WAAW,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACvD,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAEtF,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;IAC3B,YAAY,EAAE,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAA;IAChD,qBAAqB,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAA;IAC3D,cAAc,EAAE,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;IACtD,gBAAgB,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAA;IAC/C,wBAAwB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IACpD,aAAa,EAAE,MAAM,IAAI,CAAA;IACzB,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,qBAAqB,EAAE,OAAO,CAAA;CAC/B;AAED,KAAK,gBAAgB,GAAG;IACtB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,KAAK,mBAAmB,GAAG;IACzB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,KAAK,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC,GAAG,gBAAgB,GAAG,mBAAmB,CAAA;AA2B9F,eAAO,MAAM,oBAAoB,GAAI,OAAO,mBAAmB;;;;;;;;;;CAgB9D,CAAA;
|
|
1
|
+
{"version":3,"file":"glasses.d.ts","sourceRoot":"","sources":["../../src/stores/glasses.ts"],"names":[],"mappings":"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"}
|
package/build/stores/glasses.js
CHANGED
|
@@ -99,6 +99,8 @@ const initialState = {
|
|
|
99
99
|
controllerMacAddress: "",
|
|
100
100
|
controllerBatteryLevel: -1,
|
|
101
101
|
controllerSignalStrength: -1,
|
|
102
|
+
// iOS ANCS consent (G2 consumes notifications on-firmware):
|
|
103
|
+
ancsAuthorized: false,
|
|
102
104
|
};
|
|
103
105
|
export const useGlassesStore = create()(subscribeWithSelector((set) => ({
|
|
104
106
|
...initialState,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glasses.js","sourceRoot":"","sources":["../../src/stores/glasses.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n GlassesConnectionStatus,\n HotspotStatus,\n OtaProgress,\n OtaStatus,\n OtaUpdateInfo,\n PublicGlassesStatus,\n WifiStatus,\n} from \"@glassly/bluetooth-sdk\"\nimport {isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady} from \"../services/GlassesReadiness\"\nimport {create} from \"zustand\"\nimport {subscribeWithSelector} from \"zustand/middleware\"\n\n// Re-export the connection predicates (single source of truth lives in\n// GlassesReadiness) so importers of this store keep getting them.\nexport {isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady}\n\nexport const selectGlassesConnected = (state: {connection: GlassesConnectionStatus}) =>\n isGlassesConnected(state.connection)\n\nexport const selectGlassesReady = (state: {connection: GlassesConnectionStatus}) => isGlassesReady(state.connection)\n\ntype EngineGlassesStatus = PublicGlassesStatus & {\n otaUpdateAvailable: OtaUpdateInfo | null\n otaProgress: OtaProgress | null\n otaInProgress: boolean\n otaVersionUrl: string\n}\n\nexport interface GlassesState extends EngineGlassesStatus {\n systemTimeMs: number\n wifiStatusKnown: boolean\n setGlassesInfo: (info: GlassesInfoUpdate) => void\n setBatteryInfo: (batteryLevel: number, charging: boolean, caseBatteryLevel: number, caseCharging: boolean) => void\n setWifiInfo: (connected: boolean, ssid: string) => void\n setHotspotInfo: (enabled: boolean, ssid: string, password: string, ip: string) => void\n // OTA methods\n otaStatus: OtaStatus | null\n setOtaStatus: (status: OtaStatus | null) => void\n setOtaUpdateAvailable: (info: OtaUpdateInfo | null) => void\n setOtaProgress: (progress: OtaProgress | null) => void\n setOtaInProgress: (inProgress: boolean) => void\n setMtkUpdatedThisSession: (updated: boolean) => void\n clearOtaState: () => void\n reset: () => void\n mtkUpdatedThisSession: boolean\n}\n\ntype LegacyWifiFields = {\n wifiConnected?: boolean\n wifiSsid?: string\n wifiLocalIp?: string\n}\n\ntype LegacyHotspotFields = {\n hotspotEnabled?: boolean\n hotspotSsid?: string\n hotspotPassword?: string\n hotspotGatewayIp?: string\n hotspotLocalIp?: string\n}\n\ntype GlassesInfoUpdate = Partial<EngineGlassesStatus> & LegacyWifiFields & LegacyHotspotFields\n\nfunction wifiFromLegacyFields(info: LegacyWifiFields): WifiStatus | null {\n if (info.wifiConnected === true) {\n const ssid = info.wifiSsid?.trim()\n const localIp = info.wifiLocalIp?.trim()\n return ssid ? {state: \"connected\", ssid, ...(localIp ? {localIp} : {})} : null\n }\n if (info.wifiConnected === false) {\n return {state: \"disconnected\"}\n }\n return null\n}\n\nfunction hotspotFromLegacyFields(info: LegacyHotspotFields): HotspotStatus | null {\n if (info.hotspotEnabled === true) {\n const ssid = info.hotspotSsid?.trim()\n const password = info.hotspotPassword?.trim()\n const localIp = (info.hotspotGatewayIp ?? info.hotspotLocalIp)?.trim()\n return ssid && password && localIp ? {state: \"enabled\", ssid, password, localIp} : null\n }\n if (info.hotspotEnabled === false) {\n return {state: \"disabled\"}\n }\n return null\n}\n\nexport const getGlasesInfoPartial = (state: EngineGlassesStatus) => {\n const wifi = state.wifi\n const connected = isGlassesConnected(state.connection)\n return {\n batteryLevel: state.batteryLevel,\n charging: state.charging,\n caseBatteryLevel: state.caseBatteryLevel,\n caseCharging: state.caseCharging,\n connected,\n wifiConnected: wifi.state === \"connected\",\n wifiSsid: wifi.state === \"connected\" ? wifi.ssid : \"\",\n deviceModel: state.deviceModel,\n // Cloud GlassesInfo uses modelName, map from deviceModel so the cloud\n // knows which device is connected when it receives connection state updates\n modelName: state.deviceModel || null,\n }\n}\n\ninterface GlassesStore extends EngineGlassesStatus {\n systemTimeMs: number\n mtkUpdatedThisSession: boolean\n wifiStatusKnown: boolean\n otaStatus: OtaStatus | null\n}\n\nconst initialState: GlassesStore = {\n // state:\n connection: {state: \"disconnected\"},\n micEnabled: false,\n bluetoothClassicConnected: false,\n signalStrength: -1,\n signalStrengthUpdatedAt: 0,\n voiceActivityDetectionEnabled: true,\n // device info\n deviceModel: \"\",\n androidVersion: \"\",\n firmwareVersion: \"\",\n bluetoothMacAddress: \"\",\n wifiMacAddress: \"\",\n leftMacAddress: \"\",\n rightMacAddress: \"\",\n buildNumber: \"\",\n systemTimeMs: 0,\n otaVersionUrl: \"\",\n appVersion: \"\",\n bluetoothName: \"\",\n serialNumber: \"\",\n style: \"\",\n color: \"\",\n mtkFirmwareVersion: \"\",\n besFirmwareVersion: \"\",\n hotspotOtaVersion: 0,\n sceneCanvasWidth: 0,\n sceneCanvasHeight: 0,\n // wifi info\n wifi: {state: \"disconnected\"},\n wifiStatusKnown: false,\n // battery info\n batteryLevel: -1,\n charging: false,\n caseBatteryLevel: -1,\n caseCharging: false,\n caseOpen: false,\n caseRemoved: true,\n // hotspot info\n hotspot: {state: \"disabled\"},\n // OTA update info\n otaStatus: null,\n otaUpdateAvailable: null,\n otaProgress: null,\n otaInProgress: false,\n mtkUpdatedThisSession: false,\n // ring:\n controllerConnected: false,\n controllerFullyBooted: false,\n controllerMacAddress: \"\",\n controllerBatteryLevel: -1,\n controllerSignalStrength: -1,\n}\n\nexport const useGlassesStore = create<GlassesState>()(\n subscribeWithSelector((set) => ({\n ...initialState,\n\n setGlassesInfo: (info) =>\n set((state) => {\n const {\n wifiConnected,\n wifiSsid,\n wifiLocalIp,\n hotspotEnabled,\n hotspotSsid,\n hotspotPassword,\n hotspotGatewayIp,\n hotspotLocalIp,\n wifi,\n hotspot,\n ...sdkInfo\n } = info\n const wifiUpdate = wifi ?? wifiFromLegacyFields({wifiConnected, wifiSsid, wifiLocalIp})\n const hotspotUpdate =\n hotspot ??\n hotspotFromLegacyFields({hotspotEnabled, hotspotSsid, hotspotPassword, hotspotGatewayIp, hotspotLocalIp})\n const hasWifiInfoUpdate =\n Object.prototype.hasOwnProperty.call(info, \"wifi\") ||\n Object.prototype.hasOwnProperty.call(info, \"wifiConnected\") ||\n Object.prototype.hasOwnProperty.call(info, \"wifiSsid\") ||\n Object.prototype.hasOwnProperty.call(info, \"wifiLocalIp\")\n const next = {\n ...state,\n ...sdkInfo,\n ...(wifiUpdate ? {wifi: wifiUpdate} : {}),\n ...(hotspotUpdate ? {hotspot: hotspotUpdate} : {}),\n ...(hasWifiInfoUpdate ? {wifiStatusKnown: true} : {}),\n }\n if (!isGlassesConnected(next.connection)) {\n next.wifiStatusKnown = false\n next.hotspotOtaVersion = 0\n }\n return next\n }),\n\n setBatteryInfo: (batteryLevel, charging, caseBatteryLevel, caseCharging) =>\n set({\n batteryLevel,\n charging,\n caseBatteryLevel,\n caseCharging,\n }),\n\n setWifiInfo: (connected, ssid) =>\n set(() => {\n const trimmedSsid = ssid.trim()\n if (connected && !trimmedSsid) {\n return {}\n }\n const wifi: WifiStatus = connected ? {state: \"connected\", ssid: trimmedSsid} : {state: \"disconnected\"}\n return {\n wifi,\n wifiStatusKnown: true,\n }\n }),\n\n setHotspotInfo: (enabled: boolean, ssid: string, password: string, ip: string) =>\n set(() => {\n const hotspot = hotspotFromLegacyFields({\n hotspotEnabled: enabled,\n hotspotSsid: ssid,\n hotspotPassword: password,\n hotspotGatewayIp: ip,\n })\n return hotspot ? {hotspot} : {}\n }),\n\n // OTA methods\n setOtaStatus: (status: OtaStatus | null) => set({otaStatus: status}),\n\n setOtaUpdateAvailable: (info: OtaUpdateInfo | null) => set({otaUpdateAvailable: info}),\n\n setOtaProgress: (progress: OtaProgress | null) =>\n set((state) => {\n const otaInProgress = progress !== null && progress.status !== \"FINISHED\" && progress.status !== \"FAILED\"\n console.log(\"🔍 GLASSES STORE: setOtaProgress called with:\", JSON.stringify(progress))\n console.log(\"🔍 GLASSES STORE: otaInProgress =\", otaInProgress)\n\n // Never allow progress to regress within the same stage+currentUpdate — except a new\n // work wave (STARTED) or the step after FINISHED (multi-hop APK: 27→31→36 re-downloads from 0).\n const prev = state.otaProgress\n const sameWave =\n progress &&\n prev &&\n progress.stage === prev.stage &&\n progress.currentUpdate === prev.currentUpdate &&\n progress.progress < prev.progress\n if (sameWave) {\n const nextIsNewWave = progress.status === \"STARTED\" || prev.status === \"FINISHED\"\n if (!nextIsNewWave) {\n return {otaProgress: {...progress, progress: prev.progress}, otaInProgress}\n }\n }\n\n return {otaProgress: progress, otaInProgress}\n }),\n\n setOtaInProgress: (inProgress: boolean) => set({otaInProgress: inProgress}),\n\n setMtkUpdatedThisSession: (updated: boolean) => set({mtkUpdatedThisSession: updated}),\n\n clearOtaState: () =>\n set({\n otaUpdateAvailable: null,\n otaProgress: null,\n otaInProgress: false,\n // Note: mtkUpdatedThisSession is NOT cleared here - it stays true until glasses disconnect/reboot\n }),\n\n reset: () => set(initialState),\n })),\n)\n\nexport function getGlassesSystemTimeMs(): number {\n return useGlassesStore.getState().systemTimeMs ?? 0\n}\n\nexport const waitForGlassesState = <K extends keyof GlassesState>(\n key: K,\n predicate: (value: GlassesState[K]) => boolean,\n timeoutMs = 1000,\n): Promise<boolean> => {\n return new Promise((resolve) => {\n const state = useGlassesStore.getState()\n if (predicate(state[key])) {\n resolve(true)\n return\n }\n\n const unsubscribe = useGlassesStore.subscribe(\n (s) => s[key],\n (value) => {\n if (predicate(value)) {\n unsubscribe()\n resolve(true)\n }\n },\n )\n\n setTimeout(() => {\n unsubscribe()\n resolve(predicate(useGlassesStore.getState()[key]))\n }, timeoutMs)\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"glasses.js","sourceRoot":"","sources":["../../src/stores/glasses.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n GlassesConnectionStatus,\n HotspotStatus,\n OtaProgress,\n OtaStatus,\n OtaUpdateInfo,\n PublicGlassesStatus,\n WifiStatus,\n} from \"@glassly/bluetooth-sdk\"\nimport {isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady} from \"../services/GlassesReadiness\"\nimport {create} from \"zustand\"\nimport {subscribeWithSelector} from \"zustand/middleware\"\n\n// Re-export the connection predicates (single source of truth lives in\n// GlassesReadiness) so importers of this store keep getting them.\nexport {isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady}\n\nexport const selectGlassesConnected = (state: {connection: GlassesConnectionStatus}) =>\n isGlassesConnected(state.connection)\n\nexport const selectGlassesReady = (state: {connection: GlassesConnectionStatus}) => isGlassesReady(state.connection)\n\ntype EngineGlassesStatus = PublicGlassesStatus & {\n otaUpdateAvailable: OtaUpdateInfo | null\n otaProgress: OtaProgress | null\n otaInProgress: boolean\n otaVersionUrl: string\n}\n\nexport interface GlassesState extends EngineGlassesStatus {\n systemTimeMs: number\n wifiStatusKnown: boolean\n setGlassesInfo: (info: GlassesInfoUpdate) => void\n setBatteryInfo: (batteryLevel: number, charging: boolean, caseBatteryLevel: number, caseCharging: boolean) => void\n setWifiInfo: (connected: boolean, ssid: string) => void\n setHotspotInfo: (enabled: boolean, ssid: string, password: string, ip: string) => void\n // OTA methods\n otaStatus: OtaStatus | null\n setOtaStatus: (status: OtaStatus | null) => void\n setOtaUpdateAvailable: (info: OtaUpdateInfo | null) => void\n setOtaProgress: (progress: OtaProgress | null) => void\n setOtaInProgress: (inProgress: boolean) => void\n setMtkUpdatedThisSession: (updated: boolean) => void\n clearOtaState: () => void\n reset: () => void\n mtkUpdatedThisSession: boolean\n}\n\ntype LegacyWifiFields = {\n wifiConnected?: boolean\n wifiSsid?: string\n wifiLocalIp?: string\n}\n\ntype LegacyHotspotFields = {\n hotspotEnabled?: boolean\n hotspotSsid?: string\n hotspotPassword?: string\n hotspotGatewayIp?: string\n hotspotLocalIp?: string\n}\n\ntype GlassesInfoUpdate = Partial<EngineGlassesStatus> & LegacyWifiFields & LegacyHotspotFields\n\nfunction wifiFromLegacyFields(info: LegacyWifiFields): WifiStatus | null {\n if (info.wifiConnected === true) {\n const ssid = info.wifiSsid?.trim()\n const localIp = info.wifiLocalIp?.trim()\n return ssid ? {state: \"connected\", ssid, ...(localIp ? {localIp} : {})} : null\n }\n if (info.wifiConnected === false) {\n return {state: \"disconnected\"}\n }\n return null\n}\n\nfunction hotspotFromLegacyFields(info: LegacyHotspotFields): HotspotStatus | null {\n if (info.hotspotEnabled === true) {\n const ssid = info.hotspotSsid?.trim()\n const password = info.hotspotPassword?.trim()\n const localIp = (info.hotspotGatewayIp ?? info.hotspotLocalIp)?.trim()\n return ssid && password && localIp ? {state: \"enabled\", ssid, password, localIp} : null\n }\n if (info.hotspotEnabled === false) {\n return {state: \"disabled\"}\n }\n return null\n}\n\nexport const getGlasesInfoPartial = (state: EngineGlassesStatus) => {\n const wifi = state.wifi\n const connected = isGlassesConnected(state.connection)\n return {\n batteryLevel: state.batteryLevel,\n charging: state.charging,\n caseBatteryLevel: state.caseBatteryLevel,\n caseCharging: state.caseCharging,\n connected,\n wifiConnected: wifi.state === \"connected\",\n wifiSsid: wifi.state === \"connected\" ? wifi.ssid : \"\",\n deviceModel: state.deviceModel,\n // Cloud GlassesInfo uses modelName, map from deviceModel so the cloud\n // knows which device is connected when it receives connection state updates\n modelName: state.deviceModel || null,\n }\n}\n\ninterface GlassesStore extends EngineGlassesStatus {\n systemTimeMs: number\n mtkUpdatedThisSession: boolean\n wifiStatusKnown: boolean\n otaStatus: OtaStatus | null\n}\n\nconst initialState: GlassesStore = {\n // state:\n connection: {state: \"disconnected\"},\n micEnabled: false,\n bluetoothClassicConnected: false,\n signalStrength: -1,\n signalStrengthUpdatedAt: 0,\n voiceActivityDetectionEnabled: true,\n // device info\n deviceModel: \"\",\n androidVersion: \"\",\n firmwareVersion: \"\",\n bluetoothMacAddress: \"\",\n wifiMacAddress: \"\",\n leftMacAddress: \"\",\n rightMacAddress: \"\",\n buildNumber: \"\",\n systemTimeMs: 0,\n otaVersionUrl: \"\",\n appVersion: \"\",\n bluetoothName: \"\",\n serialNumber: \"\",\n style: \"\",\n color: \"\",\n mtkFirmwareVersion: \"\",\n besFirmwareVersion: \"\",\n hotspotOtaVersion: 0,\n sceneCanvasWidth: 0,\n sceneCanvasHeight: 0,\n // wifi info\n wifi: {state: \"disconnected\"},\n wifiStatusKnown: false,\n // battery info\n batteryLevel: -1,\n charging: false,\n caseBatteryLevel: -1,\n caseCharging: false,\n caseOpen: false,\n caseRemoved: true,\n // hotspot info\n hotspot: {state: \"disabled\"},\n // OTA update info\n otaStatus: null,\n otaUpdateAvailable: null,\n otaProgress: null,\n otaInProgress: false,\n mtkUpdatedThisSession: false,\n // ring:\n controllerConnected: false,\n controllerFullyBooted: false,\n controllerMacAddress: \"\",\n controllerBatteryLevel: -1,\n controllerSignalStrength: -1,\n // iOS ANCS consent (G2 consumes notifications on-firmware):\n ancsAuthorized: false,\n}\n\nexport const useGlassesStore = create<GlassesState>()(\n subscribeWithSelector((set) => ({\n ...initialState,\n\n setGlassesInfo: (info) =>\n set((state) => {\n const {\n wifiConnected,\n wifiSsid,\n wifiLocalIp,\n hotspotEnabled,\n hotspotSsid,\n hotspotPassword,\n hotspotGatewayIp,\n hotspotLocalIp,\n wifi,\n hotspot,\n ...sdkInfo\n } = info\n const wifiUpdate = wifi ?? wifiFromLegacyFields({wifiConnected, wifiSsid, wifiLocalIp})\n const hotspotUpdate =\n hotspot ??\n hotspotFromLegacyFields({hotspotEnabled, hotspotSsid, hotspotPassword, hotspotGatewayIp, hotspotLocalIp})\n const hasWifiInfoUpdate =\n Object.prototype.hasOwnProperty.call(info, \"wifi\") ||\n Object.prototype.hasOwnProperty.call(info, \"wifiConnected\") ||\n Object.prototype.hasOwnProperty.call(info, \"wifiSsid\") ||\n Object.prototype.hasOwnProperty.call(info, \"wifiLocalIp\")\n const next = {\n ...state,\n ...sdkInfo,\n ...(wifiUpdate ? {wifi: wifiUpdate} : {}),\n ...(hotspotUpdate ? {hotspot: hotspotUpdate} : {}),\n ...(hasWifiInfoUpdate ? {wifiStatusKnown: true} : {}),\n }\n if (!isGlassesConnected(next.connection)) {\n next.wifiStatusKnown = false\n next.hotspotOtaVersion = 0\n }\n return next\n }),\n\n setBatteryInfo: (batteryLevel, charging, caseBatteryLevel, caseCharging) =>\n set({\n batteryLevel,\n charging,\n caseBatteryLevel,\n caseCharging,\n }),\n\n setWifiInfo: (connected, ssid) =>\n set(() => {\n const trimmedSsid = ssid.trim()\n if (connected && !trimmedSsid) {\n return {}\n }\n const wifi: WifiStatus = connected ? {state: \"connected\", ssid: trimmedSsid} : {state: \"disconnected\"}\n return {\n wifi,\n wifiStatusKnown: true,\n }\n }),\n\n setHotspotInfo: (enabled: boolean, ssid: string, password: string, ip: string) =>\n set(() => {\n const hotspot = hotspotFromLegacyFields({\n hotspotEnabled: enabled,\n hotspotSsid: ssid,\n hotspotPassword: password,\n hotspotGatewayIp: ip,\n })\n return hotspot ? {hotspot} : {}\n }),\n\n // OTA methods\n setOtaStatus: (status: OtaStatus | null) => set({otaStatus: status}),\n\n setOtaUpdateAvailable: (info: OtaUpdateInfo | null) => set({otaUpdateAvailable: info}),\n\n setOtaProgress: (progress: OtaProgress | null) =>\n set((state) => {\n const otaInProgress = progress !== null && progress.status !== \"FINISHED\" && progress.status !== \"FAILED\"\n console.log(\"🔍 GLASSES STORE: setOtaProgress called with:\", JSON.stringify(progress))\n console.log(\"🔍 GLASSES STORE: otaInProgress =\", otaInProgress)\n\n // Never allow progress to regress within the same stage+currentUpdate — except a new\n // work wave (STARTED) or the step after FINISHED (multi-hop APK: 27→31→36 re-downloads from 0).\n const prev = state.otaProgress\n const sameWave =\n progress &&\n prev &&\n progress.stage === prev.stage &&\n progress.currentUpdate === prev.currentUpdate &&\n progress.progress < prev.progress\n if (sameWave) {\n const nextIsNewWave = progress.status === \"STARTED\" || prev.status === \"FINISHED\"\n if (!nextIsNewWave) {\n return {otaProgress: {...progress, progress: prev.progress}, otaInProgress}\n }\n }\n\n return {otaProgress: progress, otaInProgress}\n }),\n\n setOtaInProgress: (inProgress: boolean) => set({otaInProgress: inProgress}),\n\n setMtkUpdatedThisSession: (updated: boolean) => set({mtkUpdatedThisSession: updated}),\n\n clearOtaState: () =>\n set({\n otaUpdateAvailable: null,\n otaProgress: null,\n otaInProgress: false,\n // Note: mtkUpdatedThisSession is NOT cleared here - it stays true until glasses disconnect/reboot\n }),\n\n reset: () => set(initialState),\n })),\n)\n\nexport function getGlassesSystemTimeMs(): number {\n return useGlassesStore.getState().systemTimeMs ?? 0\n}\n\nexport const waitForGlassesState = <K extends keyof GlassesState>(\n key: K,\n predicate: (value: GlassesState[K]) => boolean,\n timeoutMs = 1000,\n): Promise<boolean> => {\n return new Promise((resolve) => {\n const state = useGlassesStore.getState()\n if (predicate(state[key])) {\n resolve(true)\n return\n }\n\n const unsubscribe = useGlassesStore.subscribe(\n (s) => s[key],\n (value) => {\n if (predicate(value)) {\n unsubscribe()\n resolve(true)\n }\n },\n )\n\n setTimeout(() => {\n unsubscribe()\n resolve(predicate(useGlassesStore.getState()[key]))\n }, timeoutMs)\n })\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/stores/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAwB,MAAM,aAAa,CAAA;AAS9D,OAAO,EAAC,wBAAwB,EAAE,gCAAgC,EAAC,MAAM,wBAAwB,CAAA;AAEjG,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,EAAE,MAAM,GAAG,CAAA;IACvB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,OAAO,CAAA;IAGrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAEjC,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAA;IAEpB,OAAO,EAAE,OAAO,CAAA;IAQhB,mBAAmB,CAAC,EAAE,IAAI,CAAA;IAC1B;;;;;;;;;;;;;;;OAeG;IACH,qBAAqB,CAAC,EAAE,IAAI,CAAA;CAC7B;AAED,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/stores/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAwB,MAAM,aAAa,CAAA;AAS9D,OAAO,EAAC,wBAAwB,EAAE,gCAAgC,EAAC,MAAM,wBAAwB,CAAA;AAEjG,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,EAAE,MAAM,GAAG,CAAA;IACvB,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,EAAE,OAAO,CAAA;IAGrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAEjC,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAA;IAEpB,OAAO,EAAE,OAAO,CAAA;IAQhB,mBAAmB,CAAC,EAAE,IAAI,CAAA;IAC1B;;;;;;;;;;;;;;;OAeG;IACH,qBAAqB,CAAC,EAAE,IAAI,CAAA;CAC7B;AAED,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CA85BnC,CAAA;AAEV,eAAO,MAAM,eAAe,EAAE,MAAM,EAAuD,CAAA;AAI3F,eAAO,MAAM,sBAAsB,EAAE,MAAM,EAmD1C,CAAA;AAeD,eAAO,MAAM,qBAAqB,EAAE,MAAM,EAEV,CAAA;AAIhC,MAAM,WAAW,aAAa;IAE5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAE7B,aAAa,EAAE,OAAO,CAAA;IAEtB,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,YAAY,CAAC,EAAE,OAAO,KAAK,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACzF,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC3E,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,GAAG,CAAA;IAEhC,eAAe,EAAE,MAAM,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAE/C,oBAAoB,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/C,uBAAuB,EAAE,MAAM,IAAI,CAAA;CACpC;AAuBD,eAAO,MAAM,gBAAgB;;;;;;;;EA+U5B,CAAA;AAED,eAAO,MAAM,UAAU,GAAI,CAAC,GAAG,GAAG,EAAE,KAAK,MAAM,KAAG,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAI3F,CAAA"}
|
package/build/stores/settings.js
CHANGED
|
@@ -98,6 +98,15 @@ export const SETTINGS = {
|
|
|
98
98
|
saveOnServer: true,
|
|
99
99
|
persist: true,
|
|
100
100
|
},
|
|
101
|
+
// Tint the glasses display mirror text with the green chart color instead of
|
|
102
|
+
// the theme foreground. Toggled from Settings > Appearance.
|
|
103
|
+
mirror_green_text: {
|
|
104
|
+
key: "mirror_green_text",
|
|
105
|
+
defaultValue: () => false,
|
|
106
|
+
writable: true,
|
|
107
|
+
saveOnServer: true,
|
|
108
|
+
persist: true,
|
|
109
|
+
},
|
|
101
110
|
debug_navigation_history: {
|
|
102
111
|
key: "debug_navigation_history",
|
|
103
112
|
defaultValue: () => false,
|
|
@@ -857,6 +866,47 @@ export const SETTINGS = {
|
|
|
857
866
|
saveOnServer: true,
|
|
858
867
|
persist: true,
|
|
859
868
|
},
|
|
869
|
+
// iOS: apps observed posting notifications, reported by the glasses' ANCS
|
|
870
|
+
// client ({appId, displayName, lastSeen}[]). Backs the filter UI, since iOS
|
|
871
|
+
// has no installed-apps enumeration. Device-local by design.
|
|
872
|
+
ios_notification_seen_apps: {
|
|
873
|
+
key: "ios_notification_seen_apps",
|
|
874
|
+
defaultValue: () => [],
|
|
875
|
+
writable: true,
|
|
876
|
+
saveOnServer: false,
|
|
877
|
+
persist: true,
|
|
878
|
+
},
|
|
879
|
+
// G2 on-glass notification display behavior (NotificationControl):
|
|
880
|
+
g2_notifications_enabled: {
|
|
881
|
+
key: "g2_notifications_enabled",
|
|
882
|
+
defaultValue: () => true,
|
|
883
|
+
writable: true,
|
|
884
|
+
saveOnServer: true,
|
|
885
|
+
persist: true,
|
|
886
|
+
},
|
|
887
|
+
g2_notification_auto_display: {
|
|
888
|
+
key: "g2_notification_auto_display",
|
|
889
|
+
defaultValue: () => true,
|
|
890
|
+
writable: true,
|
|
891
|
+
saveOnServer: true,
|
|
892
|
+
persist: true,
|
|
893
|
+
},
|
|
894
|
+
// Popup duration in seconds; firmware accepts 0 (default), 5, 7, 10.
|
|
895
|
+
g2_notification_disp_time: {
|
|
896
|
+
key: "g2_notification_disp_time",
|
|
897
|
+
defaultValue: () => 5,
|
|
898
|
+
writable: true,
|
|
899
|
+
saveOnServer: true,
|
|
900
|
+
persist: true,
|
|
901
|
+
},
|
|
902
|
+
// Suppress popups while another on-glass feature (navigation, teleprompter) is active.
|
|
903
|
+
g2_notification_avoid_disturb: {
|
|
904
|
+
key: "g2_notification_avoid_disturb",
|
|
905
|
+
defaultValue: () => true,
|
|
906
|
+
writable: true,
|
|
907
|
+
saveOnServer: true,
|
|
908
|
+
persist: true,
|
|
909
|
+
},
|
|
860
910
|
// Cached required version from server - used to enforce updates even when offline
|
|
861
911
|
cached_required_version: {
|
|
862
912
|
key: "cached_required_version",
|
|
@@ -896,8 +946,8 @@ export const BLUETOOTH_SETTING_KEYS = [
|
|
|
896
946
|
SETTINGS.screen_disabled.key,
|
|
897
947
|
SETTINGS.auth_email.key,
|
|
898
948
|
SETTINGS.core_token.key,
|
|
899
|
-
// glasses settings
|
|
900
|
-
|
|
949
|
+
// glasses settings (contextual_dashboard is phone-side policy now — native
|
|
950
|
+
// no longer reads it):
|
|
901
951
|
SETTINGS.head_up_angle.key,
|
|
902
952
|
SETTINGS.brightness.key,
|
|
903
953
|
SETTINGS.auto_brightness.key,
|
|
@@ -905,6 +955,7 @@ export const BLUETOOTH_SETTING_KEYS = [
|
|
|
905
955
|
SETTINGS.dashboard_depth.key,
|
|
906
956
|
SETTINGS.menu_apps.key,
|
|
907
957
|
SETTINGS.calendar_events.key,
|
|
958
|
+
// G2 native reads this to gate rendering while the ER firmware dashboard is open.
|
|
908
959
|
SETTINGS.use_native_dashboard.key,
|
|
909
960
|
SETTINGS.cfw_scene_renderer.key,
|
|
910
961
|
SETTINGS.twelve_hour_time.key,
|