@glassly/engine 0.1.0-dev.62 → 0.1.0-dev.90
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 +1 -1
- 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/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/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/LocalDisplayManager.d.ts +10 -0
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +66 -12
- package/build/services/LocalDisplayManager.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/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/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/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/package.json +7 -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/phoneNotifications.ts +32 -10
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/services/CustomDashboardService.ts +67 -66
- package/src/services/DashboardCoordinator.ts +121 -0
- package/src/services/DeviceEventRouter.ts +5 -7
- package/src/services/LocalDisplayManager.ts +66 -14
- package/src/services/PhoneNotificationsSync.ts +125 -9
- package/src/services/PhoneStreamCoordinator.ts +10 -6
- package/src/services/SceneRenderer.ts +4 -0
- package/src/services/effectiveCapabilities.ts +9 -4
- package/src/services/iosNotificationAppCatalog.ts +39 -0
- package/src/stores/display.ts +16 -48
- package/src/stores/glasses.ts +2 -0
- package/src/stores/settings.ts +53 -2
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phone-side dashboard switching. Native retains a single display state; this
|
|
3
|
+
* service decides when the dashboard covers the main content (head-up,
|
|
4
|
+
* double-tap) and which renderer draws it: the CFW custom dashboard, or the
|
|
5
|
+
* legacy time/battery wall for stock devices.
|
|
6
|
+
*/
|
|
7
|
+
import { useGlassesStore } from "../stores/glasses";
|
|
8
|
+
import { SETTINGS, useSettingsStore } from "../stores/settings";
|
|
9
|
+
import { BgTimer } from "../utils/timers";
|
|
10
|
+
import customDashboardService from "./CustomDashboardService";
|
|
11
|
+
import { isGlassesConnected } from "./GlassesReadiness";
|
|
12
|
+
import localDisplayManager from "./LocalDisplayManager";
|
|
13
|
+
const LEGACY_CLOCK_REFRESH_MS = 30_000;
|
|
14
|
+
const LEGACY_DASHBOARD_PKG = "system.dashboard";
|
|
15
|
+
class DashboardCoordinator {
|
|
16
|
+
opened = false;
|
|
17
|
+
renderer = null;
|
|
18
|
+
legacyTimer = null;
|
|
19
|
+
start() {
|
|
20
|
+
customDashboardService.onRequestClose = () => this.close();
|
|
21
|
+
}
|
|
22
|
+
stop() {
|
|
23
|
+
this.close();
|
|
24
|
+
customDashboardService.onRequestClose = null;
|
|
25
|
+
}
|
|
26
|
+
get isOpen() {
|
|
27
|
+
return this.opened;
|
|
28
|
+
}
|
|
29
|
+
/** Head position (real or simulated). Opening respects contextual_dashboard. */
|
|
30
|
+
setHeadUp(up) {
|
|
31
|
+
if (up === this.opened)
|
|
32
|
+
return;
|
|
33
|
+
if (up) {
|
|
34
|
+
if (useSettingsStore.getState().getSetting(SETTINGS.contextual_dashboard.key) === false)
|
|
35
|
+
return;
|
|
36
|
+
this.open();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.close();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Double-tap on a CFW-eligible device. False when not eligible. */
|
|
43
|
+
toggleCustom() {
|
|
44
|
+
if (!customDashboardService.isEligible())
|
|
45
|
+
return false;
|
|
46
|
+
if (this.opened)
|
|
47
|
+
this.close();
|
|
48
|
+
else
|
|
49
|
+
this.open();
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
/** Double-tap fallback for devices without a firmware dashboard. */
|
|
53
|
+
toggleLegacy() {
|
|
54
|
+
if (this.opened)
|
|
55
|
+
this.close();
|
|
56
|
+
else
|
|
57
|
+
this.open();
|
|
58
|
+
}
|
|
59
|
+
/** True when an open dashboard consumed the gesture. */
|
|
60
|
+
handleGesture(gestureName) {
|
|
61
|
+
if (!this.opened)
|
|
62
|
+
return false;
|
|
63
|
+
if (this.renderer === "custom")
|
|
64
|
+
return customDashboardService.handleGesture(gestureName);
|
|
65
|
+
if (gestureName === "double_tap") {
|
|
66
|
+
this.close();
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
/** Show the dashboard over the main content (ignores contextual_dashboard). */
|
|
72
|
+
open() {
|
|
73
|
+
if (this.opened)
|
|
74
|
+
return;
|
|
75
|
+
if (!isGlassesConnected(useGlassesStore.getState().connection))
|
|
76
|
+
return;
|
|
77
|
+
this.opened = true;
|
|
78
|
+
localDisplayManager.setDashboardActive(true);
|
|
79
|
+
if (customDashboardService.isEligible()) {
|
|
80
|
+
this.renderer = "custom";
|
|
81
|
+
customDashboardService.show();
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
this.renderer = "legacy";
|
|
85
|
+
this.renderLegacy();
|
|
86
|
+
this.legacyTimer = BgTimer.setInterval(() => this.renderLegacy(), LEGACY_CLOCK_REFRESH_MS);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Close and restore the retained main content. */
|
|
90
|
+
close() {
|
|
91
|
+
if (!this.opened)
|
|
92
|
+
return;
|
|
93
|
+
this.opened = false;
|
|
94
|
+
if (this.legacyTimer !== null) {
|
|
95
|
+
BgTimer.clearInterval(this.legacyTimer);
|
|
96
|
+
this.legacyTimer = null;
|
|
97
|
+
}
|
|
98
|
+
if (this.renderer === "custom")
|
|
99
|
+
customDashboardService.hide();
|
|
100
|
+
this.renderer = null;
|
|
101
|
+
localDisplayManager.setDashboardActive(false);
|
|
102
|
+
}
|
|
103
|
+
/** Parity with the retired native head-up wall: time, date, battery. */
|
|
104
|
+
renderLegacy() {
|
|
105
|
+
if (!this.opened)
|
|
106
|
+
return;
|
|
107
|
+
const now = new Date();
|
|
108
|
+
const time = new Intl.DateTimeFormat(undefined, {
|
|
109
|
+
hour: "2-digit",
|
|
110
|
+
minute: "2-digit",
|
|
111
|
+
hour12: useSettingsStore.getState().getSetting(SETTINGS.twelve_hour_time.key) === true,
|
|
112
|
+
}).format(now);
|
|
113
|
+
const date = `${String(now.getMonth() + 1).padStart(2, "0")}/${String(now.getDate()).padStart(2, "0")}`;
|
|
114
|
+
const level = useGlassesStore.getState().batteryLevel;
|
|
115
|
+
const batt = typeof level === "number" && level >= 0 ? ` ${level}%` : "";
|
|
116
|
+
localDisplayManager.renderDashboard(LEGACY_DASHBOARD_PKG, {
|
|
117
|
+
view: "dashboard",
|
|
118
|
+
layout: { layoutType: "text_wall", text: `${time} ${date}${batt} Connected` },
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const dashboardCoordinator = new DashboardCoordinator();
|
|
123
|
+
export default dashboardCoordinator;
|
|
124
|
+
export { DashboardCoordinator };
|
|
125
|
+
//# sourceMappingURL=DashboardCoordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardCoordinator.js","sourceRoot":"","sources":["../../src/services/DashboardCoordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Phone-side dashboard switching. Native retains a single display state; this\n * service decides when the dashboard covers the main content (head-up,\n * double-tap) and which renderer draws it: the CFW custom dashboard, or the\n * legacy time/battery wall for stock devices.\n */\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\nimport {BgTimer} from \"../utils/timers\"\nimport customDashboardService from \"./CustomDashboardService\"\nimport {isGlassesConnected} from \"./GlassesReadiness\"\nimport localDisplayManager from \"./LocalDisplayManager\"\n\nconst LEGACY_CLOCK_REFRESH_MS = 30_000\nconst LEGACY_DASHBOARD_PKG = \"system.dashboard\"\n\nclass DashboardCoordinator {\n private opened = false\n private renderer: \"custom\" | \"legacy\" | null = null\n private legacyTimer: number | null = null\n\n start(): void {\n customDashboardService.onRequestClose = () => this.close()\n }\n\n stop(): void {\n this.close()\n customDashboardService.onRequestClose = null\n }\n\n get isOpen(): boolean {\n return this.opened\n }\n\n /** Head position (real or simulated). Opening respects contextual_dashboard. */\n setHeadUp(up: boolean): void {\n if (up === this.opened) return\n if (up) {\n if (useSettingsStore.getState().getSetting(SETTINGS.contextual_dashboard.key) === false) return\n this.open()\n } else {\n this.close()\n }\n }\n\n /** Double-tap on a CFW-eligible device. False when not eligible. */\n toggleCustom(): boolean {\n if (!customDashboardService.isEligible()) return false\n if (this.opened) this.close()\n else this.open()\n return true\n }\n\n /** Double-tap fallback for devices without a firmware dashboard. */\n toggleLegacy(): void {\n if (this.opened) this.close()\n else this.open()\n }\n\n /** True when an open dashboard consumed the gesture. */\n handleGesture(gestureName: string): boolean {\n if (!this.opened) return false\n if (this.renderer === \"custom\") return customDashboardService.handleGesture(gestureName)\n if (gestureName === \"double_tap\") {\n this.close()\n return true\n }\n return false\n }\n\n /** Show the dashboard over the main content (ignores contextual_dashboard). */\n open(): void {\n if (this.opened) return\n if (!isGlassesConnected(useGlassesStore.getState().connection)) return\n this.opened = true\n localDisplayManager.setDashboardActive(true)\n if (customDashboardService.isEligible()) {\n this.renderer = \"custom\"\n customDashboardService.show()\n } else {\n this.renderer = \"legacy\"\n this.renderLegacy()\n this.legacyTimer = BgTimer.setInterval(() => this.renderLegacy(), LEGACY_CLOCK_REFRESH_MS)\n }\n }\n\n /** Close and restore the retained main content. */\n close(): void {\n if (!this.opened) return\n this.opened = false\n if (this.legacyTimer !== null) {\n BgTimer.clearInterval(this.legacyTimer)\n this.legacyTimer = null\n }\n if (this.renderer === \"custom\") customDashboardService.hide()\n this.renderer = null\n localDisplayManager.setDashboardActive(false)\n }\n\n /** Parity with the retired native head-up wall: time, date, battery. */\n private renderLegacy(): void {\n if (!this.opened) return\n const now = new Date()\n const time = new Intl.DateTimeFormat(undefined, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: useSettingsStore.getState().getSetting(SETTINGS.twelve_hour_time.key) === true,\n }).format(now)\n const date = `${String(now.getMonth() + 1).padStart(2, \"0\")}/${String(now.getDate()).padStart(2, \"0\")}`\n const level = useGlassesStore.getState().batteryLevel\n const batt = typeof level === \"number\" && level >= 0 ? ` ${level}%` : \"\"\n localDisplayManager.renderDashboard(LEGACY_DASHBOARD_PKG, {\n view: \"dashboard\",\n layout: {layoutType: \"text_wall\", text: `${time} ${date}${batt} Connected`},\n })\n }\n}\n\nconst dashboardCoordinator = new DashboardCoordinator()\nexport default dashboardCoordinator\nexport {DashboardCoordinator}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceEventRouter.d.ts","sourceRoot":"","sources":["../../src/services/DeviceEventRouter.ts"],"names":[],"mappings":"AAoDA,wBAAgB,sBAAsB,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"DeviceEventRouter.d.ts","sourceRoot":"","sources":["../../src/services/DeviceEventRouter.ts"],"names":[],"mappings":"AAoDA,wBAAgB,sBAAsB,IAAI,IAAI,CAuP7C;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C"}
|
|
@@ -34,7 +34,7 @@ import { retirePendingSelectionOnPromotion } from "./PairingIdentity";
|
|
|
34
34
|
import GlobalEventEmitter from "../utils/GlobalEventEmitter";
|
|
35
35
|
import { BgTimer } from "../utils/timers";
|
|
36
36
|
import { asgCameraApi } from "./asg/asgCameraApi";
|
|
37
|
-
import
|
|
37
|
+
import dashboardCoordinator from "./DashboardCoordinator";
|
|
38
38
|
import gestureDotsService from "./GestureDotsService";
|
|
39
39
|
let subs = [];
|
|
40
40
|
const miniappExitGesture = new MiniappExitGesture({
|
|
@@ -156,7 +156,7 @@ export function startDeviceEventRouter() {
|
|
|
156
156
|
subs.push(BluetoothSdk.addListener("touch_event", (event) => {
|
|
157
157
|
// While the custom dashboard is visible it owns its focus/navigation
|
|
158
158
|
// gestures; do not leak those into a miniapp running underneath it.
|
|
159
|
-
if (
|
|
159
|
+
if (dashboardCoordinator.handleGesture(event.gestureName))
|
|
160
160
|
return;
|
|
161
161
|
// Gesture-dots debug indicator (any device, gated by its setting). It
|
|
162
162
|
// only paints while the screen is otherwise empty; the gesture still
|
|
@@ -182,7 +182,7 @@ export function startDeviceEventRouter() {
|
|
|
182
182
|
if (miniappExitGesture.tryExitVisibleMiniapp())
|
|
183
183
|
return;
|
|
184
184
|
// Eligible G2 custom firmware replaces the native dashboard.
|
|
185
|
-
if (
|
|
185
|
+
if (dashboardCoordinator.toggleCustom())
|
|
186
186
|
return;
|
|
187
187
|
const useNativeDashboard = useSettingsStore.getState().getSetting(SETTINGS.use_native_dashboard.key) !== false;
|
|
188
188
|
if (useNativeDashboard) {
|
|
@@ -194,9 +194,7 @@ export function startDeviceEventRouter() {
|
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
else {
|
|
197
|
-
|
|
198
|
-
console.error("DeviceEventRouter: toggleHeadUp failed:", err);
|
|
199
|
-
});
|
|
197
|
+
dashboardCoordinator.toggleLegacy();
|
|
200
198
|
}
|
|
201
199
|
}
|
|
202
200
|
}));
|
|
@@ -211,7 +209,7 @@ export function startDeviceEventRouter() {
|
|
|
211
209
|
}));
|
|
212
210
|
// Head position — translate native {up:boolean} → SDK {position:"up"|"down"}.
|
|
213
211
|
subs.push(BluetoothSdk.addListener("head_up", (event) => {
|
|
214
|
-
|
|
212
|
+
dashboardCoordinator.setHeadUp(event.up);
|
|
215
213
|
localMiniappRuntime.forwardEvent("head_up", { position: event.up ? "up" : "down", timestamp: Date.now() });
|
|
216
214
|
}));
|
|
217
215
|
// On-device STT transcripts → local miniapps only while the local engine is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceEventRouter.js","sourceRoot":"","sources":["../../src/services/DeviceEventRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,YAAY,MAAM,iCAAiC,CAAA;AAC1D,OAAO,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAA;AAEvC,OAAO,mBAAmB,MAAM,uBAAuB,CAAA;AACvD,OAAO,mBAAmB,MAAM,uBAAuB,CAAA;AACvD,OAAO,2BAA2B,MAAM,+BAA+B,CAAA;AACvE,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AACvD,OAAO,uBAAuB,MAAM,2BAA2B,CAAA;AAC/D,OAAO,oBAAoB,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAC,qBAAqB,EAAC,MAAM,yBAAyB,CAAA;AAC7D,OAAO,EAAC,sBAAsB,EAAC,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAC,QAAQ,EAAE,gBAAgB,EAAC,MAAM,oBAAoB,CAAA;AAC7D,OAAO,EAAC,iBAAiB,EAAC,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAC,iCAAiC,EAAC,MAAM,mBAAmB,CAAA;AACnE,OAAO,kBAAkB,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAA;AAC/C,OAAO,sBAAsB,MAAM,0BAA0B,CAAA;AAC7D,OAAO,kBAAkB,MAAM,sBAAsB,CAAA;AAErD,IAAI,IAAI,GAAgC,EAAE,CAAA;AAE1C,MAAM,kBAAkB,GAAG,IAAI,kBAAkB,CAAC;IAChD,QAAQ,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE;IAC5C,qBAAqB,EAAE,GAAG,EAAE,CAAC,mBAAmB,CAAC,4BAA4B,EAAE;IAC/E,eAAe,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC;IAC/F,gBAAgB,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,WAAW,CAAC;IACrF,gBAAgB,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,WAAW,CAAC;IACrF,UAAU,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC;IACpE,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC;CACzD,CAAC,CAAA;AAEF,MAAM,UAAU,sBAAsB;IACpC,IAAI,IAAI,CAAC,MAAM;QAAE,OAAM;IAEvB,uCAAuC;IAEvC,0CAA0C;IAC1C,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,oBAAoB,EAAE,CAAC,KAAK,EAAE,EAAE;QACvD,MAAM,EAAC,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,EAAC,GAAG,KAAK,CAAA;QACpC,eAAe,CAAC,QAAQ,EAAE,CAAC,cAAc,CAAC,EAAC,IAAI,EAAC,CAAC,CAAA;IACnD,CAAC,CAAC,CACH,CAAA;IAED,kFAAkF;IAClF,6EAA6E;IAC7E,mFAAmF;IACnF,mFAAmF;IACnF,IAAI,CAAC,IAAI,CAAC;QACR,MAAM,EAAE,eAAe,CAAC,SAAS,CAC/B,CAAC,CAAC,EAAE,EAAE;YACJ,MAAM,SAAS,GAAG,kBAAkB,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,WAAW,CAAA;YAClF,OAAO;gBACL,SAAS;gBACT,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;gBAC5D,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;aACnE,CAAA;QACH,CAAC,EACD,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,YAAY,CAAC,cAAc,EAAE,IAAI,CAAC,EAChE,EAAC,UAAU,EAAE,OAAO,EAAC,CACtB;KACF,CAAC,CAAA;IAEF,+DAA+D;IAC/D,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE;QACnD,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,EAAE,CAAA;QACxC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,YAAY,CAAC,CAAA;QAC7F,mBAAmB,CAAC,YAAY,CAAC,wBAAwB,EAAE;YACzD,IAAI,EAAE,wBAAwB;YAC9B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE;SACzC,CAAC,CAAA;IACJ,CAAC,CAAC,CACH,CAAA;IAED,sFAAsF;IACtF,8EAA8E;IAC9E,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,uBAAuB,EAAE,CAAC,KAAK,EAAE,EAAE;QAC1D,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,KAAK,SAAS,CAAA;QACzC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;QACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;QAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;QAC5C,eAAe,CAAC,QAAQ,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;QAC3E,yEAAyE;QACzE,0EAA0E;QAC1E,sDAAsD;QACtD,YAAY,CAAC,SAAS,CAAC,OAAO,IAAI,WAAW,EAAE,IAAI,CAAC,CAAA;QACpD,kBAAkB,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAC,CAAC,CAAA;IAChG,CAAC,CAAC,CACH,CAAA;IACD,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE;QAClD,kBAAkB,CAAC,IAAI,CAAC,eAAe,EAAE,EAAC,aAAa,EAAE,KAAK,CAAC,YAAY,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAC,CAAC,CAAA;IAC3G,CAAC,CAAC,CACH,CAAA;IAED,+EAA+E;IAC/E,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE;QACnD,kBAAkB,CAAC,IAAI,CAAC,gBAAgB,EAAE;YACxC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,WAAW,EAAE,KAAK,CAAC,UAAU;YAC7B,WAAW,EAAE,KAAK,CAAC,UAAU;SAC9B,CAAC,CAAA;IACJ,CAAC,CAAC,CACH,CAAA;IAED,uFAAuF;IACvF,kFAAkF;IAClF,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QACvD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,EAAE,CAAA;QAC5C,uEAAuE;QACvE,qEAAqE;QACrE,yEAAyE;QACzE,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC;YACnD,MAAM,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;QACnD,CAAC;QACD,uEAAuE;QACvE,wEAAwE;QACxE,MAAM,iCAAiC,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IACjE,CAAC,CAAC,CACH,CAAA;IAED,sCAAsC;IAEtC,8EAA8E;IAC9E,+EAA+E;IAC/E,iFAAiF;IACjF,6EAA6E;IAC7E,uEAAuE;IACvE,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE;QACnD,MAAM,cAAc,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAC1G,IAAI,cAAc,IAAI,qBAAqB,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;YACjE,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;gBAC5B,qBAAqB,CAAC,gBAAgB,CACpC,KAAK,CAAC,SAAS,IAAI,cAAc,EACjC,KAAK,CAAC,SAAS,IAAI,eAAe,EAClC,KAAK,CAAC,YAAY,IAAI,2BAA2B,CAClD,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CACH,CAAA;IAED,sFAAsF;IACtF,mEAAmE;IACnE,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE;QAClD,IAAI,KAAK,CAAC,QAAQ,IAAI,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClE,sBAAsB,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAA;QACnD,CAAC;IACH,CAAC,CAAC,CACH,CAAA;IACD,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE;QACnD,IAAI,KAAK,CAAC,QAAQ,IAAI,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClE,sBAAsB,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAA;QAClD,CAAC;IACH,CAAC,CAAC,CACH,CAAA;IAED,oFAAoF;IACpF,iFAAiF;IACjF,2BAA2B;IAE3B,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE;QACjD,mBAAmB,CAAC,YAAY,CAAC,cAAc,EAAE,KAAK,CAAC,CAAA;IACzD,CAAC,CAAC,CACH,CAAA;IACD,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;QAChD,qEAAqE;QACrE,oEAAoE;QACpE,IAAI,sBAAsB,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC;YAAE,OAAM;QAEnE,sEAAsE;QACtE,qEAAqE;QACrE,2BAA2B;QAC3B,kBAAkB,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;QAEjD,mBAAmB,CAAC,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;QACtD,yEAAyE;QACzE,qEAAqE;QACrE,uCAAuC;QACvC,IAAI,KAAK,CAAC,WAAW,KAAK,YAAY,EAAE,CAAC;YACvC,mEAAmE;YACnE,qEAAqE;YACrE,kEAAkE;YAClE,IAAI,mBAAmB,CAAC,uBAAuB,CAAC,YAAY,CAAC;gBAAE,OAAM;YAErE,wEAAwE;YACxE,oEAAoE;YACpE,uEAAuE;YACvE,uEAAuE;YACvE,qEAAqE;YACrE,qEAAqE;YACrE,gCAAgC;YAChC,IAAI,kBAAkB,CAAC,qBAAqB,EAAE;gBAAE,OAAM;YAEtD,6DAA6D;YAC7D,IAAI,sBAAsB,CAAC,MAAM,EAAE;gBAAE,OAAM;YAE3C,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,KAAK,CAAA;YAC9G,IAAI,kBAAkB,EAAE,CAAC;gBACvB,kEAAkE;gBAClE,IAAI,CAAC,uBAAuB,CAAC,QAAQ,EAAE,CAAC;oBACtC,KAAK,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;wBAC/D,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,GAAG,CAAC,CAAA;oBAChE,CAAC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,KAAK,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC9D,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAA;gBAC/D,CAAC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CACH,CAAA;IACD,8EAA8E;IAC9E,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;QAChD,mBAAmB,CAAC,YAAY,CAAC,aAAa,EAAE;YAC9C,CAAC,EAAE,KAAK,CAAC,CAAC;YACV,CAAC,EAAE,KAAK,CAAC,CAAC;YACV,CAAC,EAAE,KAAK,CAAC,CAAC;YACV,SAAS,EAAE,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;SAC9E,CAAC,CAAA;IACJ,CAAC,CAAC,CACH,CAAA;IACD,8EAA8E;IAC9E,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;QAC5C,sBAAsB,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC1C,mBAAmB,CAAC,YAAY,CAAC,SAAS,EAAE,EAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAC,CAAC,CAAA;IAC1G,CAAC,CAAC,CACH,CAAA;IACD,4EAA4E;IAC5E,8EAA8E;IAC9E,2EAA2E;IAC3E,sEAAsE;IACtE,qFAAqF;IACrF,gDAAgD;IAChD,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,qBAAqB,EAAE,CAAC,KAAK,EAAE,EAAE;QACxD,IAAI,CAAC,2BAA2B,CAAC,QAAQ,EAAE;YAAE,OAAM;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,kBAAkB,IAAI,2BAA2B,CAAC,iBAAiB,EAAE,IAAI,OAAO,CAAA;QACnG,sEAAsE;QACtE,4DAA4D;QAC5D,2DAA2D;QAC3D,mBAAmB,CAAC,YAAY,CAC9B,iBAAiB,IAAI,EAAE,EACvB,oBAAoB,CAAC,uBAAuB,CAAC,KAAK,CAAC,EACnD,OAAO,CACR,CAAA;IACH,CAAC,CAAC,CACH,CAAA;IAED,+CAA+C;IAC/C,IAAI,CAAC,IAAI,CACP,YAAY,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE;QACrD,MAAM,WAAW,GAAG,KAAK,CAAC,WAAqB,CAAA;QAC/C,IAAI,CAAC,WAAW;YAAE,OAAM;QACxB,MAAM,GAAG,GAAG,iBAAiB,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,WAAW,CAAC,CAAA;QACxF,IAAI,CAAC,GAAG;YAAE,OAAM;QAChB,uCAAuC;QACvC,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YAChB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QAChD,CAAC;aAAM,CAAC;YACN,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAC,cAAc,EAAE,IAAI,EAAC,CAAC,CAAA;QACjE,CAAC;IACH,CAAC,CAAC,CACH,CAAA;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,GAAG,CAAC,MAAM,EAAE,CAAA;IACpC,IAAI,GAAG,EAAE,CAAA;IACT,kBAAkB,CAAC,KAAK,EAAE,CAAA;AAC5B,CAAC","sourcesContent":["/**\n * Device-event router — engine-owned. Subscribes to the inbound native BLE/device\n * events and routes them into the engine runtime: device stores, the process event\n * bus, the photo/stream coordinators, and local miniapps (via forwardEvent).\n *\n * Why this exists: engine owns the stores, coordinators, miniapp runtime, and facades,\n * but it never *subscribed to the device* for most events — the host MantleManager was\n * still the event router the whole runtime secretly depended on. So a bare OEM that\n * imported engine + called engine.start() got a connected runtime with almost no device\n * data flowing in (no miniapp input, dead gallery sync, starved coordinators). This\n * service moves those inbound bridges into engine so ANY host gets them.\n *\n * Scope: the engine legs only. The Cloud V1 relays that used to live beside them in\n * MantleManager (touch→cloud, the cloud-SDK stream/photo legs, etc.) were deleted with\n * Cloud V1 app end-of-life.\n *\n * Started by `engine.start()`. Idempotent.\n */\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\nimport {shallow} from \"zustand/shallow\"\n\nimport localMiniappRuntime from \"./LocalMiniappRuntime\"\nimport localDisplayManager from \"./LocalDisplayManager\"\nimport localSttFallbackCoordinator from \"./LocalSttFallbackCoordinator\"\nimport {MiniappExitGesture} from \"./MiniappExitGesture\"\nimport nativeNavigationService from \"./NativeNavigationService\"\nimport speakerLabelResolver from \"./SpeakerLabelResolver\"\nimport {phonePhotoCoordinator} from \"./PhonePhotoCoordinator\"\nimport {phoneStreamCoordinator} from \"./PhoneStreamCoordinator\"\nimport {isGlassesConnected} from \"./GlassesReadiness\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\nimport {useAppStatusStore} from \"../stores/apps\"\nimport {retirePendingSelectionOnPromotion} from \"./PairingIdentity\"\nimport GlobalEventEmitter from \"../utils/GlobalEventEmitter\"\nimport {BgTimer} from \"../utils/timers\"\nimport {asgCameraApi} from \"./asg/asgCameraApi\"\nimport customDashboardService from \"./CustomDashboardService\"\nimport gestureDotsService from \"./GestureDotsService\"\n\nlet subs: Array<{remove: () => void}> = []\n\nconst miniappExitGesture = new MiniappExitGesture({\n getState: () => useAppStatusStore.getState(),\n getVisiblePackageName: () => localDisplayManager.getVisibleMiniappPackageName(),\n beginExitNotice: (packageName, text) => localDisplayManager.beginMiniappExit(packageName, text),\n finishExitNotice: (packageName) => localDisplayManager.finishMiniappExit(packageName),\n cancelExitNotice: (packageName) => localDisplayManager.cancelMiniappExit(packageName),\n setTimeout: (callback, delay) => BgTimer.setTimeout(callback, delay),\n clearTimeout: (timerId) => BgTimer.clearTimeout(timerId),\n})\n\nexport function startDeviceEventRouter(): void {\n if (subs.length) return\n\n // --- device state → engine stores ---\n\n // Standalone WiFi status → glasses store.\n subs.push(\n BluetoothSdk.addListener(\"wifi_status_change\", (event) => {\n const {type: _type, ...wifi} = event\n useGlassesStore.getState().setGlassesInfo({wifi})\n }),\n )\n\n // Forward glasses Wi-Fi to miniapps (session.glasses.onWifi) from the STORE — the\n // single source of truth — so every path converges here: wifi_status_change,\n // onGlassesStatus, and BLE disconnect. Effective connectivity requires the glasses\n // to be connected AND on Wi-Fi, so a disconnect correctly flips `connected` false.\n subs.push({\n remove: useGlassesStore.subscribe(\n (s) => {\n const connected = isGlassesConnected(s.connection) && s.wifi.state === \"connected\"\n return {\n connected,\n ssid: s.wifi.state === \"connected\" ? s.wifi.ssid : undefined,\n localIp: s.wifi.state === \"connected\" ? s.wifi.localIp : undefined,\n }\n },\n (wifi) => localMiniappRuntime.forwardEvent(\"glasses_wifi\", wifi),\n {equalityFn: shallow},\n ),\n })\n\n // Incremental battery status → glasses store + local miniapps.\n subs.push(\n BluetoothSdk.addListener(\"battery_status\", (event) => {\n const state = useGlassesStore.getState()\n state.setBatteryInfo(event.level, event.charging, state.caseBatteryLevel, state.caseCharging)\n localMiniappRuntime.forwardEvent(\"glasses_battery_update\", {\n type: \"glasses_battery_update\",\n level: event.level,\n charging: event.charging,\n timestamp: event.timestamp ?? Date.now(),\n })\n }),\n )\n\n // Hotspot status → glasses store + event bus. engine's own gallerySyncService listens\n // on the bus for these, so without this bridge engine's gallery sync is dead.\n subs.push(\n BluetoothSdk.addListener(\"hotspot_status_change\", (event) => {\n const enabled = event.state === \"enabled\"\n const ssid = enabled ? event.ssid : \"\"\n const password = enabled ? event.password : \"\"\n const localIp = enabled ? event.localIp : \"\"\n useGlassesStore.getState().setHotspotInfo(enabled, ssid, password, localIp)\n // Always retarget the ASG camera client: on disable (or an event with no\n // IP) fall back to the localhost default so later calls fail fast instead\n // of hitting the previous network's stale glasses IP.\n asgCameraApi.setServer(localIp || \"localhost\", 8089)\n GlobalEventEmitter.emit(\"hotspot_status_change\", {enabled, ssid, password, local_ip: localIp})\n }),\n )\n subs.push(\n BluetoothSdk.addListener(\"hotspot_error\", (event) => {\n GlobalEventEmitter.emit(\"hotspot_error\", {error_message: event.errorMessage, timestamp: event.timestamp})\n }),\n )\n\n // Glasses gallery content counts → event bus (consumed by gallerySyncService).\n subs.push(\n BluetoothSdk.addListener(\"gallery_status\", (event) => {\n GlobalEventEmitter.emit(\"gallery_status\", {\n photos: event.photos,\n videos: event.videos,\n total: event.total,\n has_content: event.hasContent,\n camera_busy: event.cameraBusy,\n })\n }),\n )\n\n // Hardware-originated setting changes (user changes a setting ON the glasses) → store.\n // The inbound complement to GlassesSettingsSync (which only pushes store→device).\n subs.push(\n BluetoothSdk.addListener(\"save_setting\", async (event) => {\n const settings = useSettingsStore.getState()\n // Damp the relay: native re-echoes some settings unconditionally (e.g.\n // the identity block at every handleDeviceReady) — a same-value echo\n // must not become a store write (persistence churn + change-push noise).\n if (settings.getSetting(event.key) !== event.value) {\n await settings.setSetting(event.key, event.value)\n }\n // Two-phase identity: a promoted default retires the pending selection\n // marker. The rule lives with PairingIdentity (a no-op for other keys).\n await retirePendingSelectionOnPromotion(event.key, event.value)\n }),\n )\n\n // --- coordinators (owns()-gated) ---\n\n // Phone-owned photo errors settle the in-flight long-poll fast (vs. timeout).\n // Non-owned photo responses used to forward to the Cloud V1 photo pipeline via\n // restComms; that relay was removed with Cloud V1 app end-of-life, so they drop.\n // Wire v2 sends a short 4-hex BLE requestId; the coordinator maps it back to\n // the cloud requestId (resolveCloudRequestId) before ownership checks.\n subs.push(\n BluetoothSdk.addListener(\"photo_response\", (event) => {\n const cloudRequestId = event.requestId ? phonePhotoCoordinator.resolveCloudRequestId(event.requestId) : \"\"\n if (cloudRequestId && phonePhotoCoordinator.owns(cloudRequestId)) {\n if (event.state === \"error\") {\n phonePhotoCoordinator.handlePhotoError(\n event.requestId ?? cloudRequestId,\n event.errorCode ?? \"GLASSES_ERROR\",\n event.errorMessage ?? \"Glasses reported an error\",\n )\n }\n }\n }),\n )\n\n // Phone-owned stream status / keep-alive → the stream coordinator. The Cloud V1 relay\n // for non-owned streams was removed with Cloud V1 app end-of-life.\n subs.push(\n BluetoothSdk.addListener(\"stream_status\", (event) => {\n if (event.streamId && phoneStreamCoordinator.owns(event.streamId)) {\n phoneStreamCoordinator.handleGlassesStatus(event)\n }\n }),\n )\n subs.push(\n BluetoothSdk.addListener(\"keep_alive_ack\", (event) => {\n if (event.streamId && phoneStreamCoordinator.owns(event.streamId)) {\n phoneStreamCoordinator.handleKeepAliveAck(event)\n }\n }),\n )\n\n // --- device input → local miniapps (forwardEvent is subscriber-gated; a no-op when\n // no miniapp listens). The v1 SocketComms cloud legs for these were removed with\n // the Cloud V1 ripout. ---\n\n subs.push(\n BluetoothSdk.addListener(\"button_press\", (event) => {\n localMiniappRuntime.forwardEvent(\"button_press\", event)\n }),\n )\n subs.push(\n BluetoothSdk.addListener(\"touch_event\", (event) => {\n // While the custom dashboard is visible it owns its focus/navigation\n // gestures; do not leak those into a miniapp running underneath it.\n if (customDashboardService.handleGesture(event.gestureName)) return\n\n // Gesture-dots debug indicator (any device, gated by its setting). It\n // only paints while the screen is otherwise empty; the gesture still\n // flows to miniapps below.\n gestureDotsService.noteGesture(event.gestureName)\n\n localMiniappRuntime.forwardEvent(\"touch_event\", event)\n // Double-tap policy, moved out of the native G2 handlers: exit a visible\n // unclaimed miniapp; otherwise open the dashboard or toggle head-up.\n // Native only reports the gesture now.\n if (event.gestureName === \"double_tap\") {\n // A foreground miniapp that claimed double_tap (CLAIM_GESTURES) is\n // using it as an in-app gesture (e.g. the terminal's back-to-menu) —\n // the event was already forwarded above; skip the system default.\n if (localMiniappRuntime.foregroundClaimsGesture(\"double_tap\")) return\n\n // An unclaimed double tap exits only the miniapp whose frame is visibly\n // on the glasses. The controller shows the bounded OS notice first,\n // then uses the normal store stop path (and closes its phone overlay).\n // Checked before the dashboard toggle: while an app owns the screen an\n // unclaimed double-tap always means \"leave the app\" — the (custom or\n // native) dashboard is for the empty screen, and head-up still opens\n // the custom dashboard mid-app.\n if (miniappExitGesture.tryExitVisibleMiniapp()) return\n\n // Eligible G2 custom firmware replaces the native dashboard.\n if (customDashboardService.toggle()) return\n\n const useNativeDashboard = useSettingsStore.getState().getSetting(SETTINGS.use_native_dashboard.key) !== false\n if (useNativeDashboard) {\n // The modal nav UI owns the screen; showDashboard would fight it.\n if (!nativeNavigationService.isActive) {\n void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {\n console.error(\"DeviceEventRouter: showDashboard failed:\", err)\n })\n }\n } else {\n void Promise.resolve(BluetoothSdk.toggleHeadUp()).catch((err) => {\n console.error(\"DeviceEventRouter: toggleHeadUp failed:\", err)\n })\n }\n }\n }),\n )\n // G2 IMU accelerometer — payload already matches the miniapp AccelData shape.\n subs.push(\n BluetoothSdk.addListener(\"accel_event\", (event) => {\n localMiniappRuntime.forwardEvent(\"accel_event\", {\n x: event.x,\n y: event.y,\n z: event.z,\n timestamp: typeof event.timestamp === \"number\" ? event.timestamp : Date.now(),\n })\n }),\n )\n // Head position — translate native {up:boolean} → SDK {position:\"up\"|\"down\"}.\n subs.push(\n BluetoothSdk.addListener(\"head_up\", (event) => {\n customDashboardService.setHeadUp(event.up)\n localMiniappRuntime.forwardEvent(\"head_up\", {position: event.up ? \"up\" : \"down\", timestamp: Date.now()})\n }),\n )\n // On-device STT transcripts → local miniapps only while the local engine is\n // active (cloud fallback or an explicit forceLocal subscription). The runtime\n // filters mixed local/cloud delivery per miniapp to avoid double-delivery.\n // forwardEvent is subscriber-gated — a no-op when no miniapp listens.\n // (Was MantleManager.handle_local_transcription; its offline-captions display branch\n // went away with the pseudo captions renderer.)\n subs.push(\n BluetoothSdk.addListener(\"local_transcription\", (event) => {\n if (!localSttFallbackCoordinator.isActive()) return\n const lang = event.transcribeLanguage ?? localSttFallbackCoordinator.getActiveLanguage() ?? \"en-US\"\n // Native stamps resolvedSpeakerId when the voice matched the enrolled\n // profile; surface that as `isUser` (the native join has no\n // confident-other signal, so unmatched stays unannotated).\n localMiniappRuntime.forwardEvent(\n `transcription:${lang}`,\n speakerLabelResolver.annotateLocalTranscript(event),\n \"local\",\n )\n }),\n )\n\n // --- glasses swipe-menu app launcher (G2) ---\n subs.push(\n BluetoothSdk.addListener(\"miniapp_selected\", (event) => {\n const packageName = event.packageName as string\n if (!packageName) return\n const app = useAppStatusStore.getState().apps.find((a) => a.packageName === packageName)\n if (!app) return\n // Toggle: stop if running, else start.\n if (app.running) {\n useAppStatusStore.getState().stop(packageName)\n } else {\n useAppStatusStore.getState().start(app, {skipNavigation: true})\n }\n }),\n )\n}\n\nexport function stopDeviceEventRouter(): void {\n for (const sub of subs) sub.remove()\n subs = []\n miniappExitGesture.reset()\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DeviceEventRouter.js","sourceRoot":"","sources":["../../src/services/DeviceEventRouter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Device-event router — engine-owned. Subscribes to the inbound native BLE/device\n * events and routes them into the engine runtime: device stores, the process event\n * bus, the photo/stream coordinators, and local miniapps (via forwardEvent).\n *\n * Why this exists: engine owns the stores, coordinators, miniapp runtime, and facades,\n * but it never *subscribed to the device* for most events — the host MantleManager was\n * still the event router the whole runtime secretly depended on. So a bare OEM that\n * imported engine + called engine.start() got a connected runtime with almost no device\n * data flowing in (no miniapp input, dead gallery sync, starved coordinators). This\n * service moves those inbound bridges into engine so ANY host gets them.\n *\n * Scope: the engine legs only. The Cloud V1 relays that used to live beside them in\n * MantleManager (touch→cloud, the cloud-SDK stream/photo legs, etc.) were deleted with\n * Cloud V1 app end-of-life.\n *\n * Started by `engine.start()`. Idempotent.\n */\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\nimport {shallow} from \"zustand/shallow\"\n\nimport localMiniappRuntime from \"./LocalMiniappRuntime\"\nimport localDisplayManager from \"./LocalDisplayManager\"\nimport localSttFallbackCoordinator from \"./LocalSttFallbackCoordinator\"\nimport {MiniappExitGesture} from \"./MiniappExitGesture\"\nimport nativeNavigationService from \"./NativeNavigationService\"\nimport speakerLabelResolver from \"./SpeakerLabelResolver\"\nimport {phonePhotoCoordinator} from \"./PhonePhotoCoordinator\"\nimport {phoneStreamCoordinator} from \"./PhoneStreamCoordinator\"\nimport {isGlassesConnected} from \"./GlassesReadiness\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport {SETTINGS, useSettingsStore} from \"../stores/settings\"\nimport {useAppStatusStore} from \"../stores/apps\"\nimport {retirePendingSelectionOnPromotion} from \"./PairingIdentity\"\nimport GlobalEventEmitter from \"../utils/GlobalEventEmitter\"\nimport {BgTimer} from \"../utils/timers\"\nimport {asgCameraApi} from \"./asg/asgCameraApi\"\nimport dashboardCoordinator from \"./DashboardCoordinator\"\nimport gestureDotsService from \"./GestureDotsService\"\n\nlet subs: Array<{remove: () => void}> = []\n\nconst miniappExitGesture = new MiniappExitGesture({\n getState: () => useAppStatusStore.getState(),\n getVisiblePackageName: () => localDisplayManager.getVisibleMiniappPackageName(),\n beginExitNotice: (packageName, text) => localDisplayManager.beginMiniappExit(packageName, text),\n finishExitNotice: (packageName) => localDisplayManager.finishMiniappExit(packageName),\n cancelExitNotice: (packageName) => localDisplayManager.cancelMiniappExit(packageName),\n setTimeout: (callback, delay) => BgTimer.setTimeout(callback, delay),\n clearTimeout: (timerId) => BgTimer.clearTimeout(timerId),\n})\n\nexport function startDeviceEventRouter(): void {\n if (subs.length) return\n\n // --- device state → engine stores ---\n\n // Standalone WiFi status → glasses store.\n subs.push(\n BluetoothSdk.addListener(\"wifi_status_change\", (event) => {\n const {type: _type, ...wifi} = event\n useGlassesStore.getState().setGlassesInfo({wifi})\n }),\n )\n\n // Forward glasses Wi-Fi to miniapps (session.glasses.onWifi) from the STORE — the\n // single source of truth — so every path converges here: wifi_status_change,\n // onGlassesStatus, and BLE disconnect. Effective connectivity requires the glasses\n // to be connected AND on Wi-Fi, so a disconnect correctly flips `connected` false.\n subs.push({\n remove: useGlassesStore.subscribe(\n (s) => {\n const connected = isGlassesConnected(s.connection) && s.wifi.state === \"connected\"\n return {\n connected,\n ssid: s.wifi.state === \"connected\" ? s.wifi.ssid : undefined,\n localIp: s.wifi.state === \"connected\" ? s.wifi.localIp : undefined,\n }\n },\n (wifi) => localMiniappRuntime.forwardEvent(\"glasses_wifi\", wifi),\n {equalityFn: shallow},\n ),\n })\n\n // Incremental battery status → glasses store + local miniapps.\n subs.push(\n BluetoothSdk.addListener(\"battery_status\", (event) => {\n const state = useGlassesStore.getState()\n state.setBatteryInfo(event.level, event.charging, state.caseBatteryLevel, state.caseCharging)\n localMiniappRuntime.forwardEvent(\"glasses_battery_update\", {\n type: \"glasses_battery_update\",\n level: event.level,\n charging: event.charging,\n timestamp: event.timestamp ?? Date.now(),\n })\n }),\n )\n\n // Hotspot status → glasses store + event bus. engine's own gallerySyncService listens\n // on the bus for these, so without this bridge engine's gallery sync is dead.\n subs.push(\n BluetoothSdk.addListener(\"hotspot_status_change\", (event) => {\n const enabled = event.state === \"enabled\"\n const ssid = enabled ? event.ssid : \"\"\n const password = enabled ? event.password : \"\"\n const localIp = enabled ? event.localIp : \"\"\n useGlassesStore.getState().setHotspotInfo(enabled, ssid, password, localIp)\n // Always retarget the ASG camera client: on disable (or an event with no\n // IP) fall back to the localhost default so later calls fail fast instead\n // of hitting the previous network's stale glasses IP.\n asgCameraApi.setServer(localIp || \"localhost\", 8089)\n GlobalEventEmitter.emit(\"hotspot_status_change\", {enabled, ssid, password, local_ip: localIp})\n }),\n )\n subs.push(\n BluetoothSdk.addListener(\"hotspot_error\", (event) => {\n GlobalEventEmitter.emit(\"hotspot_error\", {error_message: event.errorMessage, timestamp: event.timestamp})\n }),\n )\n\n // Glasses gallery content counts → event bus (consumed by gallerySyncService).\n subs.push(\n BluetoothSdk.addListener(\"gallery_status\", (event) => {\n GlobalEventEmitter.emit(\"gallery_status\", {\n photos: event.photos,\n videos: event.videos,\n total: event.total,\n has_content: event.hasContent,\n camera_busy: event.cameraBusy,\n })\n }),\n )\n\n // Hardware-originated setting changes (user changes a setting ON the glasses) → store.\n // The inbound complement to GlassesSettingsSync (which only pushes store→device).\n subs.push(\n BluetoothSdk.addListener(\"save_setting\", async (event) => {\n const settings = useSettingsStore.getState()\n // Damp the relay: native re-echoes some settings unconditionally (e.g.\n // the identity block at every handleDeviceReady) — a same-value echo\n // must not become a store write (persistence churn + change-push noise).\n if (settings.getSetting(event.key) !== event.value) {\n await settings.setSetting(event.key, event.value)\n }\n // Two-phase identity: a promoted default retires the pending selection\n // marker. The rule lives with PairingIdentity (a no-op for other keys).\n await retirePendingSelectionOnPromotion(event.key, event.value)\n }),\n )\n\n // --- coordinators (owns()-gated) ---\n\n // Phone-owned photo errors settle the in-flight long-poll fast (vs. timeout).\n // Non-owned photo responses used to forward to the Cloud V1 photo pipeline via\n // restComms; that relay was removed with Cloud V1 app end-of-life, so they drop.\n // Wire v2 sends a short 4-hex BLE requestId; the coordinator maps it back to\n // the cloud requestId (resolveCloudRequestId) before ownership checks.\n subs.push(\n BluetoothSdk.addListener(\"photo_response\", (event) => {\n const cloudRequestId = event.requestId ? phonePhotoCoordinator.resolveCloudRequestId(event.requestId) : \"\"\n if (cloudRequestId && phonePhotoCoordinator.owns(cloudRequestId)) {\n if (event.state === \"error\") {\n phonePhotoCoordinator.handlePhotoError(\n event.requestId ?? cloudRequestId,\n event.errorCode ?? \"GLASSES_ERROR\",\n event.errorMessage ?? \"Glasses reported an error\",\n )\n }\n }\n }),\n )\n\n // Phone-owned stream status / keep-alive → the stream coordinator. The Cloud V1 relay\n // for non-owned streams was removed with Cloud V1 app end-of-life.\n subs.push(\n BluetoothSdk.addListener(\"stream_status\", (event) => {\n if (event.streamId && phoneStreamCoordinator.owns(event.streamId)) {\n phoneStreamCoordinator.handleGlassesStatus(event)\n }\n }),\n )\n subs.push(\n BluetoothSdk.addListener(\"keep_alive_ack\", (event) => {\n if (event.streamId && phoneStreamCoordinator.owns(event.streamId)) {\n phoneStreamCoordinator.handleKeepAliveAck(event)\n }\n }),\n )\n\n // --- device input → local miniapps (forwardEvent is subscriber-gated; a no-op when\n // no miniapp listens). The v1 SocketComms cloud legs for these were removed with\n // the Cloud V1 ripout. ---\n\n subs.push(\n BluetoothSdk.addListener(\"button_press\", (event) => {\n localMiniappRuntime.forwardEvent(\"button_press\", event)\n }),\n )\n subs.push(\n BluetoothSdk.addListener(\"touch_event\", (event) => {\n // While the custom dashboard is visible it owns its focus/navigation\n // gestures; do not leak those into a miniapp running underneath it.\n if (dashboardCoordinator.handleGesture(event.gestureName)) return\n\n // Gesture-dots debug indicator (any device, gated by its setting). It\n // only paints while the screen is otherwise empty; the gesture still\n // flows to miniapps below.\n gestureDotsService.noteGesture(event.gestureName)\n\n localMiniappRuntime.forwardEvent(\"touch_event\", event)\n // Double-tap policy, moved out of the native G2 handlers: exit a visible\n // unclaimed miniapp; otherwise open the dashboard or toggle head-up.\n // Native only reports the gesture now.\n if (event.gestureName === \"double_tap\") {\n // A foreground miniapp that claimed double_tap (CLAIM_GESTURES) is\n // using it as an in-app gesture (e.g. the terminal's back-to-menu) —\n // the event was already forwarded above; skip the system default.\n if (localMiniappRuntime.foregroundClaimsGesture(\"double_tap\")) return\n\n // An unclaimed double tap exits only the miniapp whose frame is visibly\n // on the glasses. The controller shows the bounded OS notice first,\n // then uses the normal store stop path (and closes its phone overlay).\n // Checked before the dashboard toggle: while an app owns the screen an\n // unclaimed double-tap always means \"leave the app\" — the (custom or\n // native) dashboard is for the empty screen, and head-up still opens\n // the custom dashboard mid-app.\n if (miniappExitGesture.tryExitVisibleMiniapp()) return\n\n // Eligible G2 custom firmware replaces the native dashboard.\n if (dashboardCoordinator.toggleCustom()) return\n\n const useNativeDashboard = useSettingsStore.getState().getSetting(SETTINGS.use_native_dashboard.key) !== false\n if (useNativeDashboard) {\n // The modal nav UI owns the screen; showDashboard would fight it.\n if (!nativeNavigationService.isActive) {\n void Promise.resolve(BluetoothSdk.showDashboard()).catch((err) => {\n console.error(\"DeviceEventRouter: showDashboard failed:\", err)\n })\n }\n } else {\n dashboardCoordinator.toggleLegacy()\n }\n }\n }),\n )\n // G2 IMU accelerometer — payload already matches the miniapp AccelData shape.\n subs.push(\n BluetoothSdk.addListener(\"accel_event\", (event) => {\n localMiniappRuntime.forwardEvent(\"accel_event\", {\n x: event.x,\n y: event.y,\n z: event.z,\n timestamp: typeof event.timestamp === \"number\" ? event.timestamp : Date.now(),\n })\n }),\n )\n // Head position — translate native {up:boolean} → SDK {position:\"up\"|\"down\"}.\n subs.push(\n BluetoothSdk.addListener(\"head_up\", (event) => {\n dashboardCoordinator.setHeadUp(event.up)\n localMiniappRuntime.forwardEvent(\"head_up\", {position: event.up ? \"up\" : \"down\", timestamp: Date.now()})\n }),\n )\n // On-device STT transcripts → local miniapps only while the local engine is\n // active (cloud fallback or an explicit forceLocal subscription). The runtime\n // filters mixed local/cloud delivery per miniapp to avoid double-delivery.\n // forwardEvent is subscriber-gated — a no-op when no miniapp listens.\n // (Was MantleManager.handle_local_transcription; its offline-captions display branch\n // went away with the pseudo captions renderer.)\n subs.push(\n BluetoothSdk.addListener(\"local_transcription\", (event) => {\n if (!localSttFallbackCoordinator.isActive()) return\n const lang = event.transcribeLanguage ?? localSttFallbackCoordinator.getActiveLanguage() ?? \"en-US\"\n // Native stamps resolvedSpeakerId when the voice matched the enrolled\n // profile; surface that as `isUser` (the native join has no\n // confident-other signal, so unmatched stays unannotated).\n localMiniappRuntime.forwardEvent(\n `transcription:${lang}`,\n speakerLabelResolver.annotateLocalTranscript(event),\n \"local\",\n )\n }),\n )\n\n // --- glasses swipe-menu app launcher (G2) ---\n subs.push(\n BluetoothSdk.addListener(\"miniapp_selected\", (event) => {\n const packageName = event.packageName as string\n if (!packageName) return\n const app = useAppStatusStore.getState().apps.find((a) => a.packageName === packageName)\n if (!app) return\n // Toggle: stop if running, else start.\n if (app.running) {\n useAppStatusStore.getState().stop(packageName)\n } else {\n useAppStatusStore.getState().start(app, {skipNavigation: true})\n }\n }),\n )\n}\n\nexport function stopDeviceEventRouter(): void {\n for (const sub of subs) sub.remove()\n subs = []\n miniappExitGesture.reset()\n}\n"]}
|
|
@@ -61,6 +61,8 @@ declare class LocalDisplayManager {
|
|
|
61
61
|
onActiveDisplayChange(listener: (active: boolean) => void): () => void;
|
|
62
62
|
private bootingApp;
|
|
63
63
|
private bootQueue;
|
|
64
|
+
/** While true the dashboard owns the glasses: main frames are retained but not sent. */
|
|
65
|
+
private dashboardActive;
|
|
64
66
|
/** Miniapp whose visible frame is temporarily covered by an OS exit notice. */
|
|
65
67
|
private exitingApp;
|
|
66
68
|
private expiryTimerId;
|
|
@@ -130,6 +132,13 @@ declare class LocalDisplayManager {
|
|
|
130
132
|
* A local miniapp is going away. Clean up all state associated with it.
|
|
131
133
|
*/
|
|
132
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;
|
|
133
142
|
/**
|
|
134
143
|
* A miniapp requested a display. Routes through boot queue, arbitration,
|
|
135
144
|
* and throttle. This is the only public entry point for miniapp display
|
|
@@ -162,6 +171,7 @@ declare class LocalDisplayManager {
|
|
|
162
171
|
*/
|
|
163
172
|
private sendScene;
|
|
164
173
|
private sendToNative;
|
|
174
|
+
private pushToNative;
|
|
165
175
|
private handleExpiry;
|
|
166
176
|
private tryRestoreCoreDisplay;
|
|
167
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,eAAe,CAA6B;IACpD,OAAO,CAAC,cAAc,CAA8B;IAEpD,4GAA4G;IAC5G,OAAO,CAAC,sBAAsB,CAAuC;IAErE,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,cAAc,QAYzB;IAED,gFAAgF;IACzE,gBAAgB,IAAI,OAAO;IAIlC,+EAA+E;IACxE,qBAAqB,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAK7E,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,SAAS,CAAsF;IAEvG,+EAA+E;IAC/E,OAAO,CAAC,UAAU,CAAoE;IAEtF,OAAO,CAAC,aAAa,CAAsB;IAE3C,6DAA6D;IAC7D,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,mBAAmB,CAAQ;IACnC,OAAO,CAAC,wBAAwB,CAA4B;IAE5D,4BAA4B;IAC5B,OAAO,CAAC,GAAG,CAAiC;IAE5C,OAAO;WAEO,WAAW,IAAI,mBAAmB;IAWhD;;;;OAIG;IACI,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAyC9D;;;;;;;OAOG;IACI,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAkC,GAAG,IAAI;IAW3F;;;OAGG;IACI,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAexD;;;;;;;;;;OAUG;IACI,eAAe,IAAI,MAAM,GAAG,IAAI;IAQvC;;;;;;OAMG;IACI,4BAA4B,IAAI,MAAM,GAAG,IAAI;IAMpD;;;;;;OAMG;IACI,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAenE,4FAA4F;IACrF,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAWnD,yEAAyE;IAClE,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAenD,+DAA+D;IACxD,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAUvD;;OAEG;IACI,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAgE3C;;;;;;;;OAQG;IACI,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"LocalDisplayManager.d.ts","sourceRoot":"","sources":["../../src/services/LocalDisplayManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -92,6 +92,8 @@ class LocalDisplayManager {
|
|
|
92
92
|
}
|
|
93
93
|
bootingApp = null;
|
|
94
94
|
bootQueue = new Map();
|
|
95
|
+
/** While true the dashboard owns the glasses: main frames are retained but not sent. */
|
|
96
|
+
dashboardActive = false;
|
|
95
97
|
/** Miniapp whose visible frame is temporarily covered by an OS exit notice. */
|
|
96
98
|
exitingApp = null;
|
|
97
99
|
expiryTimerId = null;
|
|
@@ -342,6 +344,50 @@ class LocalDisplayManager {
|
|
|
342
344
|
this.finishMiniappExit(packageName);
|
|
343
345
|
}
|
|
344
346
|
// ===========================================================================
|
|
347
|
+
// Dashboard switching (called from DashboardCoordinator)
|
|
348
|
+
// ===========================================================================
|
|
349
|
+
/**
|
|
350
|
+
* Dashboard cover state. On deactivate the retained main frame repaints
|
|
351
|
+
* (scenes replay create-based; legacy re-sends), or the glasses clear.
|
|
352
|
+
*/
|
|
353
|
+
setDashboardActive(active) {
|
|
354
|
+
if (this.dashboardActive === active)
|
|
355
|
+
return;
|
|
356
|
+
this.dashboardActive = active;
|
|
357
|
+
useDisplayStore.getState().setDashboardActive(active);
|
|
358
|
+
if (active)
|
|
359
|
+
return;
|
|
360
|
+
sceneRenderer.markViewStale("dashboard");
|
|
361
|
+
const current = this.currentDisplay;
|
|
362
|
+
if (current && (current.expiresAt === null || this.now() < current.expiresAt)) {
|
|
363
|
+
this.replayCurrent();
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
this.sendClear();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
/** Dashboard renderers only; bypasses arbitration and main ownership state. */
|
|
370
|
+
renderDashboard(packageName, payload) {
|
|
371
|
+
if (!this.dashboardActive)
|
|
372
|
+
return;
|
|
373
|
+
if (payload.scene) {
|
|
374
|
+
sceneRenderer.emitScene(packageName, "dashboard", payload.scene);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (!payload.layout)
|
|
378
|
+
return;
|
|
379
|
+
const rawEvent = { view: "dashboard", layout: payload.layout };
|
|
380
|
+
let processedEvent;
|
|
381
|
+
try {
|
|
382
|
+
processedEvent = displayProcessor.processDisplayEvent(rawEvent);
|
|
383
|
+
}
|
|
384
|
+
catch (err) {
|
|
385
|
+
console.error(`${LOG_TAG}: DisplayProcessor error, using raw event:`, err);
|
|
386
|
+
processedEvent = rawEvent;
|
|
387
|
+
}
|
|
388
|
+
this.pushToNative(processedEvent);
|
|
389
|
+
}
|
|
390
|
+
// ===========================================================================
|
|
345
391
|
// Display request API (called from LocalMiniappRuntime.handleDisplay)
|
|
346
392
|
// ===========================================================================
|
|
347
393
|
/**
|
|
@@ -360,10 +406,11 @@ class LocalDisplayManager {
|
|
|
360
406
|
resolve?.({ status: "blocked", reason: "a miniapp exit notice is active" });
|
|
361
407
|
return;
|
|
362
408
|
}
|
|
363
|
-
// Dashboard view:
|
|
364
|
-
// dashboard
|
|
409
|
+
// Dashboard view: only visible while the dashboard covers the glasses.
|
|
410
|
+
// Local miniapp dashboard content remains a stub.
|
|
365
411
|
if (payload.view === "dashboard") {
|
|
366
|
-
this.
|
|
412
|
+
this.renderDashboard(packageName, payload);
|
|
413
|
+
resolve?.({ status: "displayed" });
|
|
367
414
|
return;
|
|
368
415
|
}
|
|
369
416
|
// During boot, any app's requests go into the queue. If the booting app
|
|
@@ -573,6 +620,21 @@ class LocalDisplayManager {
|
|
|
573
620
|
console.error(`${LOG_TAG}: DisplayProcessor error, using raw event:`, err);
|
|
574
621
|
processedEvent = rawEvent;
|
|
575
622
|
}
|
|
623
|
+
// While the dashboard covers the glasses, main frames only update the
|
|
624
|
+
// retained state; setDashboardActive(false) replays the latest.
|
|
625
|
+
if (!this.dashboardActive)
|
|
626
|
+
this.pushToNative(processedEvent);
|
|
627
|
+
this.currentDisplay = { packageName, processedEvent, expiresAt };
|
|
628
|
+
this.clearExpiryTimer();
|
|
629
|
+
if (expiresAt !== null) {
|
|
630
|
+
const delay = Math.max(0, expiresAt - this.now());
|
|
631
|
+
this.expiryTimerId = BgTimer.setTimeout(() => {
|
|
632
|
+
this.expiryTimerId = null;
|
|
633
|
+
this.handleExpiry(packageName);
|
|
634
|
+
}, delay);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
pushToNative(processedEvent) {
|
|
576
638
|
try {
|
|
577
639
|
// The display output path is a direct btsdk call now (was a host sendDisplayEvent
|
|
578
640
|
// hook) so a bare OEM renders to the glasses without wiring it.
|
|
@@ -586,15 +648,6 @@ class LocalDisplayManager {
|
|
|
586
648
|
catch (err) {
|
|
587
649
|
console.error(`${LOG_TAG}: native display failed:`, err);
|
|
588
650
|
}
|
|
589
|
-
this.currentDisplay = { packageName, processedEvent, expiresAt };
|
|
590
|
-
this.clearExpiryTimer();
|
|
591
|
-
if (expiresAt !== null) {
|
|
592
|
-
const delay = Math.max(0, expiresAt - this.now());
|
|
593
|
-
this.expiryTimerId = BgTimer.setTimeout(() => {
|
|
594
|
-
this.expiryTimerId = null;
|
|
595
|
-
this.handleExpiry(packageName);
|
|
596
|
-
}, delay);
|
|
597
|
-
}
|
|
598
651
|
}
|
|
599
652
|
handleExpiry(packageName) {
|
|
600
653
|
// Someone else is on the glasses now — ignore.
|
|
@@ -789,6 +842,7 @@ class LocalDisplayManager {
|
|
|
789
842
|
this.currentDisplay = null;
|
|
790
843
|
this.backgroundLock = null;
|
|
791
844
|
this.exitingApp = null;
|
|
845
|
+
this.dashboardActive = false;
|
|
792
846
|
this.bootQueue.clear();
|
|
793
847
|
this.now = () => Date.now();
|
|
794
848
|
this.unsubscribeGlassesStatus?.();
|