@glassly/engine 0.3.5-dev.706 → 0.3.5-dev.720
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/build/engine.d.ts +1 -1
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +1 -1
- package/build/engine.js.map +1 -1
- package/build/facades/ai.d.ts +3 -3
- package/build/facades/ai.d.ts.map +1 -1
- package/build/facades/ai.js +3 -3
- package/build/facades/ai.js.map +1 -1
- package/build/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/services/GlassesTouchInput.d.ts +4 -3
- package/build/services/GlassesTouchInput.d.ts.map +1 -1
- package/build/services/GlassesTouchInput.js +12 -11
- package/build/services/GlassesTouchInput.js.map +1 -1
- package/build/services/LocalDisplayManager.d.ts +12 -4
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +21 -7
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +3 -0
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +31 -6
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/MiniappExitGesture.d.ts +4 -3
- package/build/services/MiniappExitGesture.d.ts.map +1 -1
- package/build/services/MiniappExitGesture.js +3 -3
- package/build/services/MiniappExitGesture.js.map +1 -1
- package/build/services/MiniappWidgetMode.d.ts +2 -1
- package/build/services/MiniappWidgetMode.d.ts.map +1 -1
- package/build/services/MiniappWidgetMode.js +3 -3
- package/build/services/MiniappWidgetMode.js.map +1 -1
- package/package.json +7 -7
- package/src/engine.ts +1 -1
- package/src/facades/ai.ts +3 -3
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/services/GlassesTouchInput.ts +12 -11
- package/src/services/LocalDisplayManager.ts +22 -8
- package/src/services/LocalMiniappRuntime.ts +28 -6
- package/src/services/MiniappExitGesture.ts +5 -4
- package/src/services/MiniappWidgetMode.ts +5 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalDisplayManager.js","sourceRoot":"","sources":["../../src/services/LocalDisplayManager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * LocalDisplayManager\n *\n * Phone-side arbiter for display requests originating from LOCAL miniapps\n * (the @glassly/miniapp SDK). Preserves the retired cloud display manager's\n * user-facing behavior for the features that matter on the phone:\n *\n * - boot message (\"Starting <AppName>…\") with a bounded window\n * - durationMs auto-clear\n * - core-app vs background-app arbitration with a background lock\n *\n * Scope is deliberately local-only. Cloud-originated displays are untouched\n * and may race with local displays during dev; that's acceptable.\n *\n * Display pacing is NOT done here. A JS-side ~300ms throttle used to live in\n * this class, but JS timers (and therefore the throttle's trailing flush) do\n * not fire on schedule while the iOS app is suspended in the background — so\n * under streaming captions, updates accumulated and then flushed in a burst on\n * the next wake. Pacing + last-wins coalescing now live in the native per-device\n * queue (e.g. G2's event-driven EvenHub queue), which drains off the same BLE\n * events that wake the process. This class forwards every request straight\n * through; the native layer collapses redundant frames per display target.\n *\n * The remaining BgTimer use (boot window, durationMs expiry) is timing that\n * does not need sub-second background fidelity.\n */\n\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\nimport displayProcessor from \"./DisplayProcessor\"\nimport {useDisplayStore} from \"../stores/display\"\nimport sceneRenderer, {type SceneEmitResult} from \"./SceneRenderer\"\nimport dashboardOpenTrace from \"./debug/DashboardOpenTrace\"\nimport {isGlassesConnected} from \"./GlassesReadiness\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport type {SceneElementInput} from \"../utils/display/scene\"\nimport {BgTimer} from \"../utils/timers\"\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface DisplayPayload {\n view?: \"main\" | \"dashboard\" | string\n /** Legacy layout (sugar / old bundles / cloud shapes). Either this or `scene`. */\n layout?: {layoutType: string; [key: string]: unknown}\n /** Scene elements from display.render(). Either this or `layout`. */\n scene?: SceneElementInput[]\n durationMs?: number\n}\n\n/** Outcome delivered to an awaiting render() call (REQUEST_RESULT payload). */\nexport interface DisplayRequestResult {\n status: \"displayed\" | \"blocked\"\n degraded?: boolean\n dropped?: string[]\n /** Scene frames: the glasses had the frame (and finished its transitions) before this resolved. */\n presented?: boolean\n /** A newer frame from the same app settled this one. */\n superseded?: boolean\n reason?: string\n}\n\nexport type DisplayRequestResolver = (result: DisplayRequestResult) => void\n\ninterface ActiveDisplay {\n packageName: string\n processedEvent: Record<string, unknown>\n /** Set when this display is a scene — restore goes through SceneRenderer replay. */\n scene?: SceneElementInput[]\n expiresAt: number | null\n}\n\ninterface BootingApp {\n packageName: string\n displayName: string\n startedAt: number\n timerId: number\n /** Whatever was on the glasses when this boot started, so a boot that times\n * out without the app rendering can restore it instead of blanking a frame\n * another (e.g. foreground) app owns. Null if the glasses were empty. */\n preBoot: ActiveDisplay | null\n}\n\ninterface BackgroundLock {\n packageName: string\n acquiredAt: number\n expiresAt: number\n lastActiveTime: number\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst LOG_TAG = \"LOCAL_DISPLAY\"\nconst BOOT_DURATION_MS = 1500\n// Mirrors cloud lease for a bg app holding the display. The bg app has to\n// keep driving the display to hold the lock; if it goes quiet and the core\n// app wants the screen, we release.\nconst BACKGROUND_LOCK_TIMEOUT_MS = 10_000\n// Sentinel package name used as the \"source\" of the system boot message.\nconst SYSTEM_BOOT_PKG = \"system.boot\"\n// Sentinel package for transient OS notices (quota exhausted, etc.).\nconst SYSTEM_NOTICE_PKG = \"system.notice\"\nconst SYSTEM_NOTICE_DURATION_MS = 6_000\n// A scene frame native never reports on (page rebuilding, link stalled)\n// resolves presented:false after this — long enough for a full-frame BLE\n// image transfer with retries, short enough that an awaiting app isn't stuck.\nconst PRESENTATION_TIMEOUT_MS = 3_000\n\n/** \"Render nothing\" — an empty scene or an explicit clear_view layout. */\nfunction isClearPayload(payload: DisplayPayload): boolean {\n if (payload.scene) return payload.scene.length === 0\n return payload.layout?.layoutType === \"clear_view\"\n}\n\n// =============================================================================\n// LocalDisplayManager\n// =============================================================================\n\nclass LocalDisplayManager {\n private static instance: LocalDisplayManager | null = null\n\n private coreApp: string | null = null\n private coreAppDisplay: ActiveDisplay | null = null\n private _currentDisplay: ActiveDisplay | null = null\n private backgroundLock: BackgroundLock | null = null\n\n /** Fired when the display transitions between empty and occupied (any package, system screens included). */\n private activeDisplayListeners = new Set<(active: boolean) => void>()\n\n private get currentDisplay(): ActiveDisplay | null {\n return this._currentDisplay\n }\n\n private set currentDisplay(value: ActiveDisplay | null) {\n const wasActive = this._currentDisplay !== null\n this._currentDisplay = value\n const isActive = value !== null\n if (wasActive === isActive) return\n for (const listener of this.activeDisplayListeners) {\n try {\n listener(isActive)\n } catch (error) {\n console.error(`${LOG_TAG}: onActiveDisplayChange listener failed:`, error)\n }\n }\n }\n\n /** True while anything (miniapp or system screen) is on the glasses display. */\n public hasActiveDisplay(): boolean {\n return this._currentDisplay !== null\n }\n\n /** Subscribe to empty↔occupied display transitions. Returns an unsubscribe. */\n public onActiveDisplayChange(listener: (active: boolean) => void): () => void {\n this.activeDisplayListeners.add(listener)\n return () => this.activeDisplayListeners.delete(listener)\n }\n\n private bootingApp: BootingApp | null = null\n private bootQueue: Map<string, {payload: DisplayPayload; resolve?: DisplayRequestResolver}> = new Map()\n\n /** The page holding the overlay slot; while set, main frames are retained but not sent. */\n private overlayOwner: string | null = null\n\n /** Miniapp whose visible frame is temporarily covered by an OS exit notice. */\n private exitingApp: {packageName: string; coveredDisplay: ActiveDisplay} | null = null\n\n private expiryTimerId: number | null = null\n\n /** Reconnect-replay subscription state (attachToRuntime). */\n private runtimeAttached = false\n private glassesWasConnected = false\n private unsubscribeGlassesStatus: (() => void) | null = null\n\n /** Injectable for tests. */\n private now: () => number = () => Date.now()\n\n private constructor() {}\n\n public static getInstance(): LocalDisplayManager {\n if (!LocalDisplayManager.instance) {\n LocalDisplayManager.instance = new LocalDisplayManager()\n }\n return LocalDisplayManager.instance\n }\n\n // ===========================================================================\n // Lifecycle API (called from MiniappHost)\n // ===========================================================================\n\n /**\n * A new local miniapp just mounted. Start the boot window.\n * Calling this for a different pkg while another is booting cancels the\n * previous boot.\n */\n public onMount(packageName: string, displayName: string): void {\n console.log(`${LOG_TAG}: onMount(${packageName}, \"${displayName}\")`)\n\n // Snapshot whatever's on the glasses BEFORE the boot text overwrites it.\n // registerApp fires onMount for every spawn — including a background app or\n // a crash-respawn while another app is foreground — so a boot that times out\n // without rendering must put the prior frame back rather than blank it.\n // Never snapshot the boot text itself: back-to-back mounts (the autostart\n // restore loop, crash-respawn chains) land while the previous app's\n // \"Starting X…\" is still on the glasses, and endBoot would \"restore\" that\n // stale, expiry-less frame permanently. Across chained boots, inherit the\n // original pre-boot frame instead.\n const inherited = this.bootingApp ? this.bootingApp.preBoot : this.currentDisplay\n const preBoot = inherited?.packageName === SYSTEM_BOOT_PKG ? null : inherited\n\n // Cancel any in-flight boot for a prior app.\n this.cancelBoot()\n\n // Send the boot message directly (bypass arbitration — this is a system\n // display). Goes through sendNow so scene devices render it as a scene:\n // otherwise every app start would be a legacy→scene transition on the\n // glasses (which costs a blanking clear).\n this.sendNow(SYSTEM_BOOT_PKG, {\n view: \"main\",\n layout: {layoutType: \"text_wall\", text: `Starting ${displayName}…`},\n })\n\n const timerId = BgTimer.setTimeout(() => {\n this.endBoot()\n }, BOOT_DURATION_MS)\n\n this.bootingApp = {\n packageName,\n displayName,\n startedAt: this.now(),\n timerId,\n preBoot,\n }\n this.bootQueue.clear()\n }\n\n /**\n * Show a transient system-level text wall on the glasses (quota exhausted,\n * etc.). Bypasses arbitration like the boot message — an OS notice must not\n * lose to a background app's frame — and rides the existing durationMs\n * expiry, which restores the core app's display (or clears) afterwards.\n * Skipped during a boot window: racing the \"Starting X…\" flow would strand\n * whichever frame lost.\n */\n public showSystemNotice(text: string, durationMs: number = SYSTEM_NOTICE_DURATION_MS): void {\n if (!isGlassesConnected(useGlassesStore.getState().connection)) return\n if (this.bootingApp || this.exitingApp) return\n console.log(`${LOG_TAG}: showSystemNotice(\"${text}\")`)\n this.sendNow(SYSTEM_NOTICE_PKG, {\n view: \"main\",\n layout: {layoutType: \"text_wall\", text},\n durationMs,\n })\n }\n\n /**\n * Mark which miniapp is the \"core\" (foreground) app. Pass null when no local\n * miniapp is foreground.\n */\n public onCoreAppChange(packageName: string | null): void {\n if (this.coreApp === packageName) return\n console.log(`${LOG_TAG}: onCoreAppChange(${packageName ?? \"null\"})`)\n\n this.coreApp = packageName\n\n // No core app means no saved frame to restore on the next unmount.\n // Without this, the previous core's last frame can flicker back onto\n // the glasses when the user-initiated clear is followed by an\n // onUnmount that still finds a populated coreAppDisplay.\n if (packageName === null) {\n this.coreAppDisplay = null\n }\n }\n\n /**\n * The package that currently owns the glasses screen, for gesture-claim\n * arbitration (the double-tap exit rule in GlassesTouchInput). This is\n * glasses ownership, not the phone's Compositor foreground: a background\n * miniapp rendering to the glasses with the phone pocketed is the owner.\n *\n * The live frame's owner wins; a background app that holds the display lock\n * but has no frame up right now (between renders) still counts. System\n * frames (boot, notices) own nothing claimable. Returns null when the\n * glasses are idle.\n */\n public getGestureOwner(): string | null {\n const current = this.currentDisplay?.packageName ?? null\n if (current && current !== SYSTEM_BOOT_PKG && current !== SYSTEM_NOTICE_PKG) return current\n const lock = this.backgroundLock\n if (lock && this.now() <= lock.expiresAt) return lock.packageName\n return null\n }\n\n /**\n * The miniapp whose frame is visibly on the glasses right now.\n *\n * Unlike getGestureOwner(), this deliberately does not fall back to a\n * background display lock: a lock holder with no live frame is not visible\n * and therefore must not be closed by the system double-tap gesture.\n */\n public getVisibleMiniappPackageName(): string | null {\n // Main content is retained while an overlay covers it, but is not visible.\n if (this.overlayOwner !== null) return null\n const current = this.currentDisplay?.packageName ?? null\n if (!current || current === SYSTEM_BOOT_PKG || current === SYSTEM_NOTICE_PKG) return null\n return current\n }\n\n /**\n * Cover the currently visible miniapp with a persistent system exit notice.\n * While it is up, miniapp display traffic is held off so a streaming app\n * cannot immediately overwrite the notice. The caller completes the normal\n * stop flow and then calls finishMiniappExit(); onUnmount does the same as a\n * safety net.\n */\n public beginMiniappExit(packageName: string, text: string): boolean {\n if (this.exitingApp !== null) return this.exitingApp.packageName === packageName\n const coveredDisplay = this.currentDisplay\n if (!coveredDisplay || this.getVisibleMiniappPackageName() !== packageName) return false\n\n console.log(`${LOG_TAG}: beginMiniappExit(${packageName})`)\n this.exitingApp = {packageName, coveredDisplay}\n this.clearExpiryTimer()\n this.sendNow(SYSTEM_NOTICE_PKG, {\n view: \"main\",\n layout: {layoutType: \"text_wall\", text},\n })\n return true\n }\n\n /** Remove an exit notice and resume the display state normal app teardown leaves behind. */\n public finishMiniappExit(packageName: string): void {\n if (this.exitingApp?.packageName !== packageName) return\n console.log(`${LOG_TAG}: finishMiniappExit(${packageName})`)\n this.exitingApp = null\n\n if (this.currentDisplay?.packageName !== SYSTEM_NOTICE_PKG) return\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) this.sendClear()\n }\n\n /** Cancel the handoff and put back the frame the exit notice covered. */\n public cancelMiniappExit(packageName: string): void {\n if (this.exitingApp?.packageName !== packageName) return\n const covered = this.exitingApp.coveredDisplay\n this.exitingApp = null\n\n if (this.currentDisplay?.packageName !== SYSTEM_NOTICE_PKG) return\n if (covered.expiresAt === null || covered.expiresAt > this.now()) {\n this.restoreDisplay(covered)\n } else {\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) this.sendClear()\n }\n }\n\n /** The foreground (core) miniapp is drawing on the glasses right now. */\n public foregroundAppOnScreen(): boolean {\n const current = this.currentDisplay\n return current !== null && this.coreApp !== null && current.packageName === this.coreApp\n }\n\n /** Report-safe ownership snapshot for incident diagnostics. */\n public getDiagnosticSnapshot(): Record<string, unknown> {\n return {\n coreAppPackageName: this.coreApp,\n currentDisplayPackageName: this.currentDisplay?.packageName ?? null,\n backgroundLockPackageName: this.backgroundLock?.packageName ?? null,\n bootingPackageName: this.bootingApp?.packageName ?? null,\n exitingPackageName: this.exitingApp?.packageName ?? null,\n }\n }\n\n /**\n * A local miniapp is going away. Clean up all state associated with it.\n */\n public onUnmount(packageName: string): void {\n console.log(`${LOG_TAG}: onUnmount(${packageName})`)\n\n // If this was the booting app, cancel boot — and don't strand its\n // \"Starting X…\" text (a system frame with no expiry): put back what the\n // boot covered, or clear.\n if (this.bootingApp?.packageName === packageName) {\n const preBoot = this.bootingApp.preBoot\n this.cancelBoot()\n if (this.currentDisplay?.packageName === SYSTEM_BOOT_PKG) {\n // The preBoot owner may have forfeited its frame during the boot\n // window (a clear parked in the boot queue) — don't resurrect it.\n const ownerQueued = preBoot ? this.bootQueue.get(preBoot.packageName) : undefined\n const preBootForfeited = ownerQueued !== undefined && isClearPayload(ownerQueued.payload)\n if (preBoot && !preBootForfeited && (preBoot.expiresAt === null || preBoot.expiresAt > this.now())) {\n this.restoreDisplay(preBoot)\n } else {\n this.sendClear()\n }\n }\n }\n this.bootQueue.get(packageName)?.resolve?.({status: \"blocked\", reason: \"app stopped\"})\n this.bootQueue.delete(packageName)\n\n // Forget the app's retained scenes — nothing left to replay for it.\n sceneRenderer.clearApp(packageName)\n\n // Release bg lock if this app held it.\n if (this.backgroundLock?.packageName === packageName) {\n this.backgroundLock = null\n }\n\n // Drop the saved core frame if the core's context is going away — the\n // frame belongs to a dead context and must not be restored later. The\n // coreApp POINTER itself is NOT cleared here: it is derived state owned\n // by the apps-store reconciler. A liveness/crash respawn tears the\n // context down (this path) without any store change — the app is still\n // \"running\" — and clearing the pointer here would leave the respawned\n // foreground app arbitrating as background until an unrelated store\n // write happened to re-run the reconciler. Real stops release the slot\n // via the store (running → false → reconciler → onCoreAppChange(null)).\n if (this.coreApp === packageName) {\n this.coreAppDisplay = null\n }\n\n // If this app owned the current on-glasses display, clear it (and maybe\n // restore the core app's display if it still has time left).\n if (this.currentDisplay?.packageName === packageName) {\n this.clearExpiryTimer()\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) {\n // Nothing to restore → clear the glasses.\n this.sendClear()\n }\n }\n\n this.finishMiniappExit(packageName)\n }\n\n // ===========================================================================\n // Dashboard switching (called from DashboardCoordinator)\n // ===========================================================================\n\n /**\n * Dashboard cover state. On deactivate the retained main frame repaints\n * (scenes replay create-based; legacy re-sends), or the glasses clear.\n */\n /** The page holding the overlay slot, or null while the main content shows. */\n public getOverlayOwner(): string | null {\n return this.overlayOwner\n }\n\n /**\n * Hand the overlay slot to `owner` (a page's scene app id) or release it.\n * A new owner replaces the previous page: its retained scene is dropped so\n * the first frame paints from empty. Releasing replays the retained main\n * content, or clears when it has expired.\n */\n public setOverlayOwner(owner: string | null): void {\n const previous = this.overlayOwner\n if (previous === owner) return\n this.overlayOwner = owner\n useDisplayStore.getState().setOverlayOwner(owner)\n if (previous !== null) {\n sceneRenderer.markViewStale(\"dashboard\")\n sceneRenderer.clearApp(previous)\n }\n if (owner !== null) return\n const current = this.currentDisplay\n if (current && (current.expiresAt === null || this.now() < current.expiresAt)) {\n this.replayCurrent()\n } else {\n this.sendClear()\n }\n }\n\n /**\n * The overlay slot only; bypasses arbitration and main ownership state.\n * Frames from an owner other than the slot's are dropped. Returns the scene\n * frame's seq (0 when nothing went to the glasses). With `resolve` (an\n * awaited render from the designated miniapp) the outcome settles the way\n * a main frame's does: `presented` once the glasses have the frame, or\n * false at once when the slot is not this owner's.\n */\n public renderOverlay(packageName: string, payload: DisplayPayload, resolve?: DisplayRequestResolver): number {\n if (this.overlayOwner !== packageName) {\n resolve?.({status: \"displayed\", presented: false, reason: \"dashboard view not showing\"})\n return 0\n }\n if (payload.scene) {\n const result = sceneRenderer.emitScene(packageName, \"dashboard\", payload.scene)\n if (result.kind === \"no-display\") {\n resolve?.({status: \"blocked\", reason: \"no display connected\"})\n return 0\n }\n if (result.kind === \"legacy\") {\n resolve?.({status: \"displayed\", degraded: result.degraded, dropped: result.dropped})\n return 0\n }\n if (resolve) this.settleScene(packageName, result, resolve)\n if (result.sent) dashboardOpenTrace.frameSent(result.seq)\n return result.sent ? result.seq : 0\n }\n if (!payload.layout) {\n resolve?.({status: \"displayed\", presented: false, reason: \"empty frame\"})\n return 0\n }\n const rawEvent = {view: \"dashboard\", layout: payload.layout}\n let processedEvent: Record<string, unknown>\n try {\n processedEvent = displayProcessor.processDisplayEvent(rawEvent as any)\n } catch (err) {\n console.error(`${LOG_TAG}: DisplayProcessor error, using raw event:`, err)\n processedEvent = rawEvent\n }\n this.pushToNative(processedEvent)\n resolve?.({status: \"displayed\"})\n return 0\n }\n\n // ===========================================================================\n // Display request API (called from LocalMiniappRuntime.handleDisplay)\n // ===========================================================================\n\n /**\n * A miniapp requested a display. Routes through boot queue, arbitration,\n * and throttle. This is the only public entry point for miniapp display\n * traffic on the local path.\n *\n * `resolve`, when provided (render() requests), is guaranteed to be called\n * exactly once with the request's outcome — including for requests parked in\n * the boot queue (resolved when drained or superseded).\n */\n public request(packageName: string, payload: DisplayPayload, resolve?: DisplayRequestResolver): void {\n // Keep the OS exit notice visible for its short handoff window. Without\n // this, streaming captions/terminal frames can replace it immediately.\n if (this.exitingApp !== null) {\n resolve?.({status: \"blocked\", reason: \"a miniapp exit notice is active\"})\n return\n }\n\n // The overlay slot: only its owner (the designated dashboard miniapp,\n // under its package name) draws there; anyone else's frame is dropped.\n if (payload.view === \"dashboard\") {\n this.renderOverlay(packageName, payload, resolve)\n return\n }\n\n // During boot, any app's requests go into the queue. If the booting app\n // itself makes its first display call, end boot early and drain.\n if (this.bootingApp) {\n const superseded = this.bootQueue.get(packageName)\n superseded?.resolve?.({status: \"blocked\", reason: \"superseded by a newer frame\"})\n this.bootQueue.set(packageName, {payload, resolve})\n if (this.bootingApp.packageName === packageName) {\n this.endBoot()\n }\n return\n }\n\n this.arbitrateAndSend(packageName, payload, resolve)\n }\n\n /**\n * End a package's temporary display early. If it currently owns the main\n * view, release its background lock and restore the foreground miniapp's\n * saved frame. A dismissal for a package that is no longer visible is a\n * no-op.\n */\n public dismiss(packageName: string): void {\n this.handleExpiry(packageName)\n }\n\n // ===========================================================================\n // Internals — arbitration\n // ===========================================================================\n\n private arbitrateAndSend(packageName: string, payload: DisplayPayload, resolve?: DisplayRequestResolver): void {\n const now = this.now()\n\n // Expire a stale bg lock before arbitrating.\n if (this.backgroundLock && now > this.backgroundLock.expiresAt) {\n this.backgroundLock = null\n }\n\n // A clear (\"render nothing\") means \"I'm done with the display\" — it is a\n // forfeit, not a frame. A background app releases its lock and the core\n // app's still-valid display comes back; treating it as a render instead\n // would RENEW the lock with an empty frame and blank the glasses while\n // still blocking everyone else.\n if (isClearPayload(payload)) {\n this.handleAppClear(packageName, resolve)\n return\n }\n\n const isCore = packageName === this.coreApp\n\n if (isCore) {\n // Save so we can restore later.\n this.coreAppDisplay = {\n packageName,\n processedEvent: {}, // filled by sendNow\n scene: payload.scene,\n expiresAt: payload.durationMs ? now + payload.durationMs : null,\n }\n\n // If a bg app holds the lock AND is currently on the glasses, core is\n // blocked. The saved coreAppDisplay surfaces when the bg app expires\n // or unmounts.\n const bgHoldsAndDisplays =\n this.backgroundLock &&\n this.currentDisplay &&\n this.currentDisplay.packageName === this.backgroundLock.packageName\n if (bgHoldsAndDisplays) {\n resolve?.({status: \"blocked\", reason: \"a background app holds the display\"})\n return\n }\n\n // Core can display. If a bg lock exists but holder isn't actively on\n // the glasses, release it.\n if (this.backgroundLock && !bgHoldsAndDisplays) {\n this.backgroundLock = null\n }\n\n this.sendNow(packageName, payload, resolve)\n return\n }\n\n // Non-core: this is a background app.\n if (this.backgroundLock && this.backgroundLock.packageName !== packageName) {\n // Another bg app already holds the lock — drop.\n resolve?.({status: \"blocked\", reason: \"another background app holds the display\"})\n return\n }\n\n // Acquire or bump the lock.\n if (!this.backgroundLock) {\n this.backgroundLock = {\n packageName,\n acquiredAt: now,\n expiresAt: now + BACKGROUND_LOCK_TIMEOUT_MS,\n lastActiveTime: now,\n }\n } else {\n this.backgroundLock.lastActiveTime = now\n this.backgroundLock.expiresAt = now + BACKGROUND_LOCK_TIMEOUT_MS\n }\n\n this.sendNow(packageName, payload, resolve)\n }\n\n /**\n * An app cleared its display (\"render nothing\"). Same semantics as its\n * frame expiring: give up ownership, restore the core app's still-valid\n * display if there is one, otherwise clear the glasses.\n */\n private handleAppClear(packageName: string, resolve?: DisplayRequestResolver): void {\n // Forget the app's retained scene state — its next render starts fresh.\n sceneRenderer.clearApp(packageName)\n\n if (this.backgroundLock?.packageName === packageName) {\n this.backgroundLock = null\n }\n if (this.coreApp === packageName) {\n this.coreAppDisplay = null\n }\n\n if (this.currentDisplay?.packageName === packageName) {\n this.clearExpiryTimer()\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) {\n this.sendClear()\n }\n }\n resolve?.({status: \"displayed\"})\n }\n\n // ===========================================================================\n // Internals — send\n // ===========================================================================\n\n private sendNow(packageName: string, payload: DisplayPayload, resolve?: DisplayRequestResolver): void {\n const expiresAt = payload.durationMs ? this.now() + payload.durationMs : null\n const view = (payload.view === \"dashboard\" ? \"dashboard\" : \"main\") as \"main\" | \"dashboard\"\n\n // Scene requests — and legacy layouts a positioning device can render as a\n // scene (sugar, old bundles) — go through the scene pipeline. Everything\n // else stays on the legacy path.\n let sceneElements = payload.scene ?? null\n if (!sceneElements && payload.layout) {\n const caps = sceneRenderer.currentCapabilities()\n if (caps?.canPosition) {\n sceneElements = sceneRenderer.convertLegacyLayout(payload.layout, caps)\n }\n }\n\n if (sceneElements) {\n this.sendScene(packageName, view, sceneElements, expiresAt, resolve)\n } else if (payload.layout) {\n // This layout bypasses the scene pipeline (clear_view, dashboard_card,\n // unknown types, or a non-positioning device). If this (app, view) had a\n // retained scene, the glasses no longer match it — reset the diff\n // baseline so the next render() repaints from empty instead of skipping\n // \"unchanged\" elements.\n sceneRenderer.resetBaseline(packageName, view)\n const rawEvent: Record<string, unknown> = {\n view: payload.view ?? \"main\",\n layout: payload.layout,\n }\n if (payload.durationMs !== undefined) {\n rawEvent.durationMs = payload.durationMs\n }\n this.sendToNative(packageName, rawEvent, expiresAt)\n resolve?.({status: \"displayed\"})\n } else {\n // A scene payload on a device with no display block at all.\n resolve?.({status: \"blocked\", reason: \"no display connected\"})\n return\n }\n\n // If core app fired, refresh the saved snapshot with the actual processed\n // event so restore uses the wrapped text (legacy) / the retained scene.\n if (packageName === this.coreApp && this.currentDisplay) {\n this.coreAppDisplay = {\n packageName,\n processedEvent: this.currentDisplay.processedEvent,\n scene: this.currentDisplay.scene,\n expiresAt: this.currentDisplay.expiresAt,\n }\n }\n }\n\n /**\n * Send a scene through SceneRenderer. On positioning devices this emits a\n * SceneFrame; on degrade devices SceneRenderer hands back a legacy layout\n * that rides the existing (unchanged) DisplayProcessor path.\n */\n private sendScene(\n packageName: string,\n view: \"main\" | \"dashboard\",\n elements: SceneElementInput[],\n expiresAt: number | null,\n resolve?: DisplayRequestResolver,\n ): void {\n const result = sceneRenderer.emitScene(packageName, view, elements)\n\n if (result.kind === \"no-display\") {\n resolve?.({status: \"blocked\", reason: \"no display connected\"})\n return\n }\n\n if (result.kind === \"legacy\") {\n if (result.layout) {\n this.sendToNative(packageName, {view, layout: result.layout}, expiresAt)\n } else {\n // Scene degraded to nothing (e.g. all-image scene on a text-only\n // device). render() replaces the frame, so nothing means clear.\n this.sendClear()\n }\n resolve?.({status: \"displayed\", degraded: result.degraded, dropped: result.dropped})\n return\n }\n\n this.currentDisplay = {packageName, processedEvent: {}, scene: elements, expiresAt}\n this.clearExpiryTimer()\n if (expiresAt !== null) {\n const delay = Math.max(0, expiresAt - this.now())\n this.expiryTimerId = BgTimer.setTimeout(() => {\n this.expiryTimerId = null\n this.handleExpiry(packageName)\n }, delay)\n }\n if (!resolve) return\n this.settleScene(packageName, result, resolve)\n }\n\n /**\n * Settle an awaited render() once the glasses have the frame and its\n * transitions have played out. A frame that stayed phone-side (the other\n * view is showing) settles at once with `presented: false`. The timeout\n * keeps a frame the device never reports on from hanging the app.\n */\n private settleScene(\n packageName: string,\n result: Extract<SceneEmitResult, {kind: \"scene\"}>,\n resolve: DisplayRequestResolver,\n ): void {\n const base = {status: \"displayed\" as const, degraded: result.degraded, dropped: result.dropped}\n if (!result.sent) {\n resolve({...base, presented: false, reason: \"dashboard active\"})\n return\n }\n void sceneRenderer.whenPresented(result.seq, PRESENTATION_TIMEOUT_MS, packageName).then((p) => {\n const finish = () =>\n resolve({\n ...base,\n presented: p.presented,\n ...(p.superseded ? {superseded: true} : {}),\n ...(p.reason !== undefined ? {reason: p.reason} : {}),\n })\n if (p.presented && result.settleMs > 0) BgTimer.setTimeout(finish, result.settleMs)\n else finish()\n })\n }\n\n private sendToNative(packageName: string, rawEvent: Record<string, unknown>, expiresAt: number | null): void {\n let processedEvent: Record<string, unknown>\n try {\n processedEvent = displayProcessor.processDisplayEvent(rawEvent as any)\n } catch (err) {\n console.error(`${LOG_TAG}: DisplayProcessor error, using raw event:`, err)\n processedEvent = rawEvent\n }\n\n // While a page holds the overlay slot, main frames only update the\n // retained state; setOverlayOwner(null) replays the latest.\n if (this.overlayOwner === null) this.pushToNative(processedEvent)\n\n this.currentDisplay = {packageName, processedEvent, expiresAt}\n\n this.clearExpiryTimer()\n if (expiresAt !== null) {\n const delay = Math.max(0, expiresAt - this.now())\n this.expiryTimerId = BgTimer.setTimeout(() => {\n this.expiryTimerId = null\n this.handleExpiry(packageName)\n }, delay)\n }\n }\n\n private pushToNative(processedEvent: Record<string, unknown>): void {\n try {\n // The display output path is a direct btsdk call now (was a host sendDisplayEvent\n // hook) so a bare OEM renders to the glasses without wiring it.\n void Promise.resolve(BluetoothSdk.displayEvent(processedEvent)).catch((err) => {\n console.error(`${LOG_TAG}: native display failed:`, err)\n })\n // The mirror store also lives in engine, so display requests update the\n // phone-side preview without any host hook.\n useDisplayStore.getState().setDisplayEvent(JSON.stringify(processedEvent))\n } catch (err) {\n console.error(`${LOG_TAG}: native display failed:`, err)\n }\n }\n\n private handleExpiry(packageName: string): void {\n // Someone else is on the glasses now — ignore.\n if (!this.currentDisplay || this.currentDisplay.packageName !== packageName) {\n return\n }\n\n // Release the lock if it belonged to this (bg) app.\n if (this.backgroundLock?.packageName === packageName) {\n this.backgroundLock = null\n }\n\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) {\n this.sendClear()\n }\n }\n\n private tryRestoreCoreDisplay(): void {\n if (!this.coreAppDisplay) return\n // If the core snapshot has a duration and it's already elapsed, skip.\n if (this.coreAppDisplay.expiresAt !== null && this.now() >= this.coreAppDisplay.expiresAt) {\n this.coreAppDisplay = null\n return\n }\n // Re-send the core's saved display.\n this.restoreDisplay(this.coreAppDisplay)\n }\n\n private sendClear(): void {\n const clearEvent: Record<string, unknown> = {\n view: \"main\",\n layout: {layoutType: \"clear_view\"},\n }\n this.sendToNative(\"system.clear\", clearEvent, null)\n this.currentDisplay = null\n // The glasses main view is now blank: every app's retained scene is\n // replay-only until it re-renders — diffing against it would skip\n // \"unchanged\" elements onto the blank screen.\n sceneRenderer.markViewStale(\"main\")\n }\n\n // ===========================================================================\n // Internals — boot\n // ===========================================================================\n\n private cancelBoot(): void {\n if (!this.bootingApp) return\n BgTimer.clearTimeout(this.bootingApp.timerId)\n this.bootingApp = null\n }\n\n private endBoot(): void {\n if (!this.bootingApp) return\n const preBoot = this.bootingApp.preBoot\n BgTimer.clearTimeout(this.bootingApp.timerId)\n this.bootingApp = null\n\n // Drain the queue: core first, then everyone else. Per-app last wins\n // because the map holds one payload per packageName.\n const queued = Array.from(this.bootQueue.entries())\n this.bootQueue.clear()\n\n const corePayload = this.coreApp ? queued.find(([pkg]) => pkg === this.coreApp) : undefined\n if (corePayload) {\n this.arbitrateAndSend(corePayload[0], corePayload[1].payload, corePayload[1].resolve)\n }\n for (const [pkg, entry] of queued) {\n if (pkg === this.coreApp) continue\n this.arbitrateAndSend(pkg, entry.payload, entry.resolve)\n }\n\n // If the boot text is still on the glasses — nothing was queued, or every\n // drained request lost arbitration — it must not strand: it's a system\n // frame with no expiry. Restore whatever was on the glasses before the\n // boot, else clear. Two reasons NOT to restore: the frame's duration\n // elapsed during the boot window, or its owner FORFEITED it during the\n // window (its final queued intent — the queue keeps last-wins per app —\n // was a clear, which the drain above processed as a forfeit; restoring\n // would resurrect content the clear removed).\n if (this.currentDisplay?.packageName === SYSTEM_BOOT_PKG) {\n const ownerEntry = preBoot ? queued.find(([pkg]) => pkg === preBoot.packageName) : undefined\n const preBootForfeited = ownerEntry !== undefined && isClearPayload(ownerEntry[1].payload)\n if (preBoot && !preBootForfeited && (preBoot.expiresAt === null || preBoot.expiresAt > this.now())) {\n this.restoreDisplay(preBoot)\n } else {\n this.sendClear()\n }\n }\n }\n\n /**\n * Re-push a previously-captured on-glasses frame (e.g. the display a boot\n * window overwrote). Mirrors tryRestoreCoreDisplay: the saved event is already\n * processed, and any remaining duration is recomputed from its expiry.\n */\n private restoreDisplay(saved: ActiveDisplay): void {\n const remaining = saved.expiresAt !== null ? Math.max(0, saved.expiresAt - this.now()) : undefined\n\n // Scene restores must REPLAY (create-based, epoch-bumped): re-emitting the\n // scene through the normal diff would come back all-\"unchanged\" and the\n // device would skip every element (spec §4 — replay is always create-based).\n if (saved.scene) {\n const expiresAt = remaining !== undefined ? this.now() + remaining : null\n if (sceneRenderer.replayApp(saved.packageName, \"main\")) {\n this.currentDisplay = {packageName: saved.packageName, processedEvent: {}, scene: saved.scene, expiresAt}\n this.clearExpiryTimer()\n if (expiresAt !== null) {\n const delay = Math.max(0, expiresAt - this.now())\n this.expiryTimerId = BgTimer.setTimeout(() => {\n this.expiryTimerId = null\n this.handleExpiry(saved.packageName)\n }, delay)\n }\n } else {\n // Retained state gone (app stopped since) — re-render the saved\n // elements as a fresh scene instead.\n this.sendNow(saved.packageName, {view: \"main\", scene: saved.scene, durationMs: remaining})\n }\n return\n }\n\n this.sendNow(saved.packageName, {\n view: \"main\",\n layout: saved.processedEvent.layout as DisplayPayload[\"layout\"],\n durationMs: remaining,\n })\n }\n\n // ===========================================================================\n // Reconnect replay (design doc §3.4.7 — recovery = replay, host-driven)\n // ===========================================================================\n\n /**\n * Subscribe to glasses connection state so the current owner's frame is\n * replayed after a reconnect. Safe to call repeatedly; attaches once. Wired\n * from MantleManager next to displayProcessor.attachToRuntime().\n */\n public attachToRuntime(): void {\n if (this.runtimeAttached) return\n // dev wired this through the (since-removed) glassesStatus runtime hooks;\n // engine reads its own glasses store directly.\n this.glassesWasConnected = isGlassesConnected(useGlassesStore.getState().connection)\n this.unsubscribeGlassesStatus = useGlassesStore.subscribe(() => {\n const connected = isGlassesConnected(useGlassesStore.getState().connection)\n if (connected === this.glassesWasConnected) return\n this.glassesWasConnected = connected\n if (connected) {\n this.replayCurrent()\n }\n })\n this.runtimeAttached = true\n }\n\n /**\n * Re-push the current on-glasses frame after a device recovery. Scenes replay\n * from SceneRenderer's retained state (create-based, epoch-bumped); legacy\n * frames re-send their processed event. Expired frames don't come back.\n */\n public replayCurrent(): void {\n const current = this.currentDisplay\n if (!current) return\n if (current.expiresAt !== null && this.now() >= current.expiresAt) return\n\n console.log(`${LOG_TAG}: replayCurrent(${current.packageName})`)\n if (current.scene) {\n if (!sceneRenderer.replayApp(current.packageName, \"main\")) {\n // Retained state gone (app stopped between disconnect and reconnect).\n this.sendClear()\n }\n } else if (current.processedEvent.layout) {\n this.sendToNative(current.packageName, current.processedEvent, current.expiresAt)\n }\n }\n\n // ===========================================================================\n // Internals — timer helpers\n // ===========================================================================\n\n private clearExpiryTimer(): void {\n if (this.expiryTimerId !== null) {\n BgTimer.clearTimeout(this.expiryTimerId)\n this.expiryTimerId = null\n }\n }\n\n // ===========================================================================\n // Test hooks\n // ===========================================================================\n\n /** Injected clock — tests only. */\n public _setNowForTest(fn: () => number): void {\n this.now = fn\n }\n\n /** Wipe state — tests only. */\n public _resetForTest(): void {\n this.cancelBoot()\n this.clearExpiryTimer()\n this.coreApp = null\n this.coreAppDisplay = null\n this.currentDisplay = null\n this.backgroundLock = null\n this.exitingApp = null\n this.overlayOwner = null\n this.bootQueue.clear()\n this.now = () => Date.now()\n this.unsubscribeGlassesStatus?.()\n this.unsubscribeGlassesStatus = null\n this.runtimeAttached = false\n this.glassesWasConnected = false\n sceneRenderer._resetForTest()\n }\n\n /** Read-only state snapshot — tests only. */\n public _peekForTest(): {\n coreApp: string | null\n currentDisplayPkg: string | null\n bgLockPkg: string | null\n isBooting: boolean\n } {\n return {\n coreApp: this.coreApp,\n currentDisplayPkg: this.currentDisplay?.packageName ?? null,\n bgLockPkg: this.backgroundLock?.packageName ?? null,\n isBooting: this.bootingApp !== null,\n }\n }\n}\n\nconst localDisplayManager = LocalDisplayManager.getInstance()\nexport default localDisplayManager\nexport {LocalDisplayManager}\n"]}
|
|
1
|
+
{"version":3,"file":"LocalDisplayManager.js","sourceRoot":"","sources":["../../src/services/LocalDisplayManager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * LocalDisplayManager\n *\n * Phone-side arbiter for display requests originating from LOCAL miniapps\n * (the @glassly/miniapp SDK). Preserves the retired cloud display manager's\n * user-facing behavior for the features that matter on the phone:\n *\n * - boot message (\"Starting <AppName>…\") with a bounded window\n * - durationMs auto-clear\n * - core-app vs background-app arbitration with a background lock\n *\n * Scope is deliberately local-only. Cloud-originated displays are untouched\n * and may race with local displays during dev; that's acceptable.\n *\n * Display pacing is NOT done here. A JS-side ~300ms throttle used to live in\n * this class, but JS timers (and therefore the throttle's trailing flush) do\n * not fire on schedule while the iOS app is suspended in the background — so\n * under streaming captions, updates accumulated and then flushed in a burst on\n * the next wake. Pacing + last-wins coalescing now live in the native per-device\n * queue (e.g. G2's event-driven EvenHub queue), which drains off the same BLE\n * events that wake the process. This class forwards every request straight\n * through; the native layer collapses redundant frames per display target.\n *\n * The remaining BgTimer use (boot window, durationMs expiry) is timing that\n * does not need sub-second background fidelity.\n */\n\nimport BluetoothSdk from \"@glassly/bluetooth-sdk/internal\"\nimport displayProcessor from \"./DisplayProcessor\"\nimport {useDisplayStore} from \"../stores/display\"\nimport sceneRenderer, {type SceneEmitResult} from \"./SceneRenderer\"\nimport dashboardOpenTrace from \"./debug/DashboardOpenTrace\"\nimport {isGlassesConnected} from \"./GlassesReadiness\"\nimport {useGlassesStore} from \"../stores/glasses\"\nimport type {SceneElementInput} from \"../utils/display/scene\"\nimport {BgTimer} from \"../utils/timers\"\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface DisplayPayload {\n view?: \"main\" | \"dashboard\" | string\n /** Legacy layout (sugar / old bundles / cloud shapes). Either this or `scene`. */\n layout?: {layoutType: string; [key: string]: unknown}\n /** Scene elements from display.render(). Either this or `layout`. */\n scene?: SceneElementInput[]\n durationMs?: number\n}\n\n/** Outcome delivered to an awaiting render() call (REQUEST_RESULT payload). */\nexport interface DisplayRequestResult {\n status: \"displayed\" | \"blocked\"\n degraded?: boolean\n dropped?: string[]\n /** Scene frames: the glasses had the frame (and finished its transitions) before this resolved. */\n presented?: boolean\n /** A newer frame from the same app settled this one. */\n superseded?: boolean\n reason?: string\n}\n\nexport type DisplayRequestResolver = (result: DisplayRequestResult) => void\n\ninterface ActiveDisplay {\n packageName: string\n processedEvent: Record<string, unknown>\n /** Set when this display is a scene — restore goes through SceneRenderer replay. */\n scene?: SceneElementInput[]\n expiresAt: number | null\n}\n\ninterface BootingApp {\n packageName: string\n displayName: string\n startedAt: number\n timerId: number\n /** Whatever was on the glasses when this boot started, so a boot that times\n * out without the app rendering can restore it instead of blanking a frame\n * another (e.g. foreground) app owns. Null if the glasses were empty. */\n preBoot: ActiveDisplay | null\n}\n\ninterface BackgroundLock {\n packageName: string\n acquiredAt: number\n expiresAt: number\n lastActiveTime: number\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst LOG_TAG = \"LOCAL_DISPLAY\"\nconst BOOT_DURATION_MS = 1500\n// Mirrors cloud lease for a bg app holding the display. The bg app has to\n// keep driving the display to hold the lock; if it goes quiet and the core\n// app wants the screen, we release.\nconst BACKGROUND_LOCK_TIMEOUT_MS = 10_000\n// Sentinel package name used as the \"source\" of the system boot message.\nconst SYSTEM_BOOT_PKG = \"system.boot\"\n// Sentinel package for transient OS notices (quota exhausted, etc.).\nconst SYSTEM_NOTICE_PKG = \"system.notice\"\nconst SYSTEM_NOTICE_DURATION_MS = 6_000\n// A scene frame native never reports on (page rebuilding, link stalled)\n// resolves presented:false after this — long enough for a full-frame BLE\n// image transfer with retries, short enough that an awaiting app isn't stuck.\nconst PRESENTATION_TIMEOUT_MS = 3_000\n\n/** \"Render nothing\" — an empty scene or an explicit clear_view layout. */\nfunction isClearPayload(payload: DisplayPayload): boolean {\n if (payload.scene) return payload.scene.length === 0\n return payload.layout?.layoutType === \"clear_view\"\n}\n\n// =============================================================================\n// LocalDisplayManager\n// =============================================================================\n\nclass LocalDisplayManager {\n private static instance: LocalDisplayManager | null = null\n\n private coreApp: string | null = null\n private coreAppDisplay: ActiveDisplay | null = null\n private _currentDisplay: ActiveDisplay | null = null\n private backgroundLock: BackgroundLock | null = null\n\n /** Fired when the display transitions between empty and occupied (any package, system screens included). */\n private activeDisplayListeners = new Set<(active: boolean) => void>()\n\n private get currentDisplay(): ActiveDisplay | null {\n return this._currentDisplay\n }\n\n private set currentDisplay(value: ActiveDisplay | null) {\n const wasActive = this._currentDisplay !== null\n this._currentDisplay = value\n const isActive = value !== null\n if (wasActive === isActive) return\n for (const listener of this.activeDisplayListeners) {\n try {\n listener(isActive)\n } catch (error) {\n console.error(`${LOG_TAG}: onActiveDisplayChange listener failed:`, error)\n }\n }\n }\n\n /** True while anything (miniapp or system screen) is on the glasses display. */\n public hasActiveDisplay(): boolean {\n return this._currentDisplay !== null\n }\n\n /** Subscribe to empty↔occupied display transitions. Returns an unsubscribe. */\n public onActiveDisplayChange(listener: (active: boolean) => void): () => void {\n this.activeDisplayListeners.add(listener)\n return () => this.activeDisplayListeners.delete(listener)\n }\n\n private bootingApp: BootingApp | null = null\n private bootQueue: Map<string, {payload: DisplayPayload; resolve?: DisplayRequestResolver}> = new Map()\n\n /** The page holding the overlay slot; while set, main frames are retained but not sent. */\n private overlayOwner: string | null = null\n\n /** Miniapp whose visible frame is temporarily covered by an OS exit notice. */\n private exitingApp: {packageName: string; coveredDisplay: ActiveDisplay | null} | null = null\n\n private expiryTimerId: number | null = null\n\n /** Reconnect-replay subscription state (attachToRuntime). */\n private runtimeAttached = false\n private glassesWasConnected = false\n private unsubscribeGlassesStatus: (() => void) | null = null\n\n /** Injectable for tests. */\n private now: () => number = () => Date.now()\n\n private constructor() {}\n\n public static getInstance(): LocalDisplayManager {\n if (!LocalDisplayManager.instance) {\n LocalDisplayManager.instance = new LocalDisplayManager()\n }\n return LocalDisplayManager.instance\n }\n\n // ===========================================================================\n // Lifecycle API (called from MiniappHost)\n // ===========================================================================\n\n /**\n * A new local miniapp just mounted. Start the boot window.\n * Calling this for a different pkg while another is booting cancels the\n * previous boot.\n */\n public onMount(packageName: string, displayName: string): void {\n console.log(`${LOG_TAG}: onMount(${packageName}, \"${displayName}\")`)\n\n // Snapshot whatever's on the glasses BEFORE the boot text overwrites it.\n // registerApp fires onMount for every spawn — including a background app or\n // a crash-respawn while another app is foreground — so a boot that times out\n // without rendering must put the prior frame back rather than blank it.\n // Never snapshot the boot text itself: back-to-back mounts (the autostart\n // restore loop, crash-respawn chains) land while the previous app's\n // \"Starting X…\" is still on the glasses, and endBoot would \"restore\" that\n // stale, expiry-less frame permanently. Across chained boots, inherit the\n // original pre-boot frame instead.\n const inherited = this.bootingApp ? this.bootingApp.preBoot : this.currentDisplay\n const preBoot = inherited?.packageName === SYSTEM_BOOT_PKG ? null : inherited\n\n // Cancel any in-flight boot for a prior app.\n this.cancelBoot()\n\n // Send the boot message directly (bypass arbitration — this is a system\n // display). Goes through sendNow so scene devices render it as a scene:\n // otherwise every app start would be a legacy→scene transition on the\n // glasses (which costs a blanking clear).\n this.sendNow(SYSTEM_BOOT_PKG, {\n view: \"main\",\n layout: {layoutType: \"text_wall\", text: `Starting ${displayName}…`},\n })\n\n const timerId = BgTimer.setTimeout(() => {\n this.endBoot()\n }, BOOT_DURATION_MS)\n\n this.bootingApp = {\n packageName,\n displayName,\n startedAt: this.now(),\n timerId,\n preBoot,\n }\n this.bootQueue.clear()\n }\n\n /**\n * Show a transient system-level text wall on the glasses (quota exhausted,\n * etc.). Bypasses arbitration like the boot message — an OS notice must not\n * lose to a background app's frame — and rides the existing durationMs\n * expiry, which restores the core app's display (or clears) afterwards.\n * Skipped during a boot window: racing the \"Starting X…\" flow would strand\n * whichever frame lost.\n */\n public showSystemNotice(text: string, durationMs: number = SYSTEM_NOTICE_DURATION_MS): void {\n if (!isGlassesConnected(useGlassesStore.getState().connection)) return\n if (this.bootingApp || this.exitingApp) return\n console.log(`${LOG_TAG}: showSystemNotice(\"${text}\")`)\n this.sendNow(SYSTEM_NOTICE_PKG, {\n view: \"main\",\n layout: {layoutType: \"text_wall\", text},\n durationMs,\n })\n }\n\n /**\n * Mark which miniapp is the \"core\" (foreground) app. Pass null when no local\n * miniapp is foreground.\n */\n public onCoreAppChange(packageName: string | null): void {\n if (this.coreApp === packageName) return\n console.log(`${LOG_TAG}: onCoreAppChange(${packageName ?? \"null\"})`)\n\n this.coreApp = packageName\n\n // No core app means no saved frame to restore on the next unmount.\n // Without this, the previous core's last frame can flicker back onto\n // the glasses when the user-initiated clear is followed by an\n // onUnmount that still finds a populated coreAppDisplay.\n if (packageName === null) {\n this.coreAppDisplay = null\n }\n }\n\n /**\n * The package that currently owns the glasses screen, for gesture-claim\n * arbitration (the double-tap exit rule in GlassesTouchInput). This is\n * glasses ownership, not the phone's Compositor foreground: a background\n * miniapp rendering to the glasses with the phone pocketed is the owner.\n *\n * The live frame's owner wins; a background app that holds the display lock\n * but has no frame up right now (between renders) still counts. System\n * frames (boot, notices) own nothing claimable. Returns null when the\n * glasses are idle.\n */\n public getGestureOwner(): string | null {\n const current = this.currentDisplay?.packageName ?? null\n if (current && current !== SYSTEM_BOOT_PKG && current !== SYSTEM_NOTICE_PKG) return current\n const lock = this.backgroundLock\n if (lock && this.now() <= lock.expiresAt) return lock.packageName\n return null\n }\n\n /**\n * The miniapp whose frame is visibly on the glasses right now.\n *\n * Unlike getGestureOwner(), this deliberately does not fall back to a\n * background display lock: a lock holder with no live frame is not visible\n * and therefore must not be closed by the system double-tap gesture.\n */\n public getVisibleMiniappPackageName(): string | null {\n // Main content is retained while an overlay covers it, but is not visible.\n if (this.overlayOwner !== null) return null\n const current = this.currentDisplay?.packageName ?? null\n if (!current || current === SYSTEM_BOOT_PKG || current === SYSTEM_NOTICE_PKG) return null\n return current\n }\n\n /**\n * The miniapp an unclaimed double tap leaves: the one visibly drawing on\n * the main view, else the core (running standard) app on an empty or\n * system-drawn screen — an app that has drawn nothing yet, or whose frame\n * expired, is still the one the wearer is in. Nothing while a page covers\n * the main view: the page's claims own the tap.\n */\n public getMiniappToLeave(): string | null {\n if (this.overlayOwner !== null) return null\n return this.getVisibleMiniappPackageName() ?? this.coreApp\n }\n\n /**\n * Cover the leaving miniapp with a persistent system exit notice. While it\n * is up, miniapp display traffic is held off so a streaming app cannot\n * immediately overwrite the notice. The caller completes the normal stop\n * flow and then calls finishMiniappExit(); onUnmount does the same as a\n * safety net.\n */\n public beginMiniappExit(packageName: string, text: string): boolean {\n if (this.exitingApp !== null) return this.exitingApp.packageName === packageName\n if (this.getMiniappToLeave() !== packageName) return false\n // Only the app's own visible frame comes back on cancel; a system frame\n // or an empty screen does not.\n const coveredDisplay = this.getVisibleMiniappPackageName() === packageName ? this.currentDisplay : null\n\n console.log(`${LOG_TAG}: beginMiniappExit(${packageName})`)\n this.exitingApp = {packageName, coveredDisplay}\n this.clearExpiryTimer()\n this.sendNow(SYSTEM_NOTICE_PKG, {\n view: \"main\",\n layout: {layoutType: \"text_wall\", text},\n })\n return true\n }\n\n /** Remove an exit notice and resume the display state normal app teardown leaves behind. */\n public finishMiniappExit(packageName: string): void {\n if (this.exitingApp?.packageName !== packageName) return\n console.log(`${LOG_TAG}: finishMiniappExit(${packageName})`)\n this.exitingApp = null\n\n if (this.currentDisplay?.packageName !== SYSTEM_NOTICE_PKG) return\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) this.sendClear()\n }\n\n /** Cancel the handoff and put back the frame the exit notice covered. */\n public cancelMiniappExit(packageName: string): void {\n if (this.exitingApp?.packageName !== packageName) return\n const covered = this.exitingApp.coveredDisplay\n this.exitingApp = null\n\n if (this.currentDisplay?.packageName !== SYSTEM_NOTICE_PKG) return\n if (covered && (covered.expiresAt === null || covered.expiresAt > this.now())) {\n this.restoreDisplay(covered)\n } else {\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) this.sendClear()\n }\n }\n\n /** The foreground (core) miniapp is drawing on the glasses right now. */\n public foregroundAppOnScreen(): boolean {\n const current = this.currentDisplay\n return current !== null && this.coreApp !== null && current.packageName === this.coreApp\n }\n\n /** Report-safe ownership snapshot for incident diagnostics. */\n public getDiagnosticSnapshot(): Record<string, unknown> {\n return {\n coreAppPackageName: this.coreApp,\n currentDisplayPackageName: this.currentDisplay?.packageName ?? null,\n backgroundLockPackageName: this.backgroundLock?.packageName ?? null,\n bootingPackageName: this.bootingApp?.packageName ?? null,\n exitingPackageName: this.exitingApp?.packageName ?? null,\n }\n }\n\n /**\n * A local miniapp is going away. Clean up all state associated with it.\n */\n public onUnmount(packageName: string): void {\n console.log(`${LOG_TAG}: onUnmount(${packageName})`)\n\n // If this was the booting app, cancel boot — and don't strand its\n // \"Starting X…\" text (a system frame with no expiry): put back what the\n // boot covered, or clear.\n if (this.bootingApp?.packageName === packageName) {\n const preBoot = this.bootingApp.preBoot\n this.cancelBoot()\n if (this.currentDisplay?.packageName === SYSTEM_BOOT_PKG) {\n // The preBoot owner may have forfeited its frame during the boot\n // window (a clear parked in the boot queue) — don't resurrect it.\n const ownerQueued = preBoot ? this.bootQueue.get(preBoot.packageName) : undefined\n const preBootForfeited = ownerQueued !== undefined && isClearPayload(ownerQueued.payload)\n if (preBoot && !preBootForfeited && (preBoot.expiresAt === null || preBoot.expiresAt > this.now())) {\n this.restoreDisplay(preBoot)\n } else {\n this.sendClear()\n }\n }\n }\n this.bootQueue.get(packageName)?.resolve?.({status: \"blocked\", reason: \"app stopped\"})\n this.bootQueue.delete(packageName)\n\n // Forget the app's retained scenes — nothing left to replay for it.\n sceneRenderer.clearApp(packageName)\n\n // Release bg lock if this app held it.\n if (this.backgroundLock?.packageName === packageName) {\n this.backgroundLock = null\n }\n\n // Drop the saved core frame if the core's context is going away — the\n // frame belongs to a dead context and must not be restored later. The\n // coreApp POINTER itself is NOT cleared here: it is derived state owned\n // by the apps-store reconciler. A liveness/crash respawn tears the\n // context down (this path) without any store change — the app is still\n // \"running\" — and clearing the pointer here would leave the respawned\n // foreground app arbitrating as background until an unrelated store\n // write happened to re-run the reconciler. Real stops release the slot\n // via the store (running → false → reconciler → onCoreAppChange(null)).\n if (this.coreApp === packageName) {\n this.coreAppDisplay = null\n }\n\n // If this app owned the current on-glasses display, clear it (and maybe\n // restore the core app's display if it still has time left).\n if (this.currentDisplay?.packageName === packageName) {\n this.clearExpiryTimer()\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) {\n // Nothing to restore → clear the glasses.\n this.sendClear()\n }\n }\n\n this.finishMiniappExit(packageName)\n }\n\n // ===========================================================================\n // Dashboard switching (called from DashboardCoordinator)\n // ===========================================================================\n\n /**\n * Dashboard cover state. On deactivate the retained main frame repaints\n * (scenes replay create-based; legacy re-sends), or the glasses clear.\n */\n /** The page holding the overlay slot, or null while the main content shows. */\n public getOverlayOwner(): string | null {\n return this.overlayOwner\n }\n\n /**\n * Hand the overlay slot to `owner` (a page's scene app id) or release it.\n * A new owner replaces the previous page: its retained scene is dropped so\n * the first frame paints from empty. Releasing replays the retained main\n * content, or clears when it has expired.\n */\n public setOverlayOwner(owner: string | null): void {\n const previous = this.overlayOwner\n if (previous === owner) return\n this.overlayOwner = owner\n useDisplayStore.getState().setOverlayOwner(owner)\n if (previous !== null) {\n sceneRenderer.markViewStale(\"dashboard\")\n sceneRenderer.clearApp(previous)\n }\n if (owner !== null) return\n const current = this.currentDisplay\n if (current && (current.expiresAt === null || this.now() < current.expiresAt)) {\n this.replayCurrent()\n } else {\n this.sendClear()\n }\n }\n\n /**\n * The overlay slot only; bypasses arbitration and main ownership state.\n * Frames from an owner other than the slot's are dropped. Returns the scene\n * frame's seq (0 when nothing went to the glasses). With `resolve` (an\n * awaited render from the designated miniapp) the outcome settles the way\n * a main frame's does: `presented` once the glasses have the frame, or\n * false at once when the slot is not this owner's.\n */\n public renderOverlay(packageName: string, payload: DisplayPayload, resolve?: DisplayRequestResolver): number {\n if (this.overlayOwner !== packageName) {\n resolve?.({status: \"displayed\", presented: false, reason: \"dashboard view not showing\"})\n return 0\n }\n if (payload.scene) {\n const result = sceneRenderer.emitScene(packageName, \"dashboard\", payload.scene)\n if (result.kind === \"no-display\") {\n resolve?.({status: \"blocked\", reason: \"no display connected\"})\n return 0\n }\n if (result.kind === \"legacy\") {\n resolve?.({status: \"displayed\", degraded: result.degraded, dropped: result.dropped})\n return 0\n }\n if (resolve) this.settleScene(packageName, result, resolve)\n if (result.sent) dashboardOpenTrace.frameSent(result.seq)\n return result.sent ? result.seq : 0\n }\n if (!payload.layout) {\n resolve?.({status: \"displayed\", presented: false, reason: \"empty frame\"})\n return 0\n }\n const rawEvent = {view: \"dashboard\", layout: payload.layout}\n let processedEvent: Record<string, unknown>\n try {\n processedEvent = displayProcessor.processDisplayEvent(rawEvent as any)\n } catch (err) {\n console.error(`${LOG_TAG}: DisplayProcessor error, using raw event:`, err)\n processedEvent = rawEvent\n }\n this.pushToNative(processedEvent)\n resolve?.({status: \"displayed\"})\n return 0\n }\n\n // ===========================================================================\n // Display request API (called from LocalMiniappRuntime.handleDisplay)\n // ===========================================================================\n\n /**\n * A miniapp requested a display. Routes through boot queue, arbitration,\n * and throttle. This is the only public entry point for miniapp display\n * traffic on the local path.\n *\n * `resolve`, when provided (render() requests), is guaranteed to be called\n * exactly once with the request's outcome — including for requests parked in\n * the boot queue (resolved when drained or superseded).\n */\n public request(packageName: string, payload: DisplayPayload, resolve?: DisplayRequestResolver): void {\n // Keep the OS exit notice visible for its short handoff window. Without\n // this, streaming captions/terminal frames can replace it immediately.\n if (this.exitingApp !== null) {\n resolve?.({status: \"blocked\", reason: \"a miniapp exit notice is active\"})\n return\n }\n\n // The overlay slot: only its owner (the designated dashboard miniapp,\n // under its package name) draws there; anyone else's frame is dropped.\n if (payload.view === \"dashboard\") {\n this.renderOverlay(packageName, payload, resolve)\n return\n }\n\n // During boot, any app's requests go into the queue. If the booting app\n // itself makes its first display call, end boot early and drain.\n if (this.bootingApp) {\n const superseded = this.bootQueue.get(packageName)\n superseded?.resolve?.({status: \"blocked\", reason: \"superseded by a newer frame\"})\n this.bootQueue.set(packageName, {payload, resolve})\n if (this.bootingApp.packageName === packageName) {\n this.endBoot()\n }\n return\n }\n\n this.arbitrateAndSend(packageName, payload, resolve)\n }\n\n /**\n * End a package's temporary display early. If it currently owns the main\n * view, release its background lock and restore the foreground miniapp's\n * saved frame. A dismissal for a package that is no longer visible is a\n * no-op.\n */\n public dismiss(packageName: string): void {\n this.handleExpiry(packageName)\n }\n\n // ===========================================================================\n // Internals — arbitration\n // ===========================================================================\n\n private arbitrateAndSend(packageName: string, payload: DisplayPayload, resolve?: DisplayRequestResolver): void {\n const now = this.now()\n\n // Expire a stale bg lock before arbitrating.\n if (this.backgroundLock && now > this.backgroundLock.expiresAt) {\n this.backgroundLock = null\n }\n\n // A clear (\"render nothing\") means \"I'm done with the display\" — it is a\n // forfeit, not a frame. A background app releases its lock and the core\n // app's still-valid display comes back; treating it as a render instead\n // would RENEW the lock with an empty frame and blank the glasses while\n // still blocking everyone else.\n if (isClearPayload(payload)) {\n this.handleAppClear(packageName, resolve)\n return\n }\n\n const isCore = packageName === this.coreApp\n\n if (isCore) {\n // Save so we can restore later.\n this.coreAppDisplay = {\n packageName,\n processedEvent: {}, // filled by sendNow\n scene: payload.scene,\n expiresAt: payload.durationMs ? now + payload.durationMs : null,\n }\n\n // If a bg app holds the lock AND is currently on the glasses, core is\n // blocked. The saved coreAppDisplay surfaces when the bg app expires\n // or unmounts.\n const bgHoldsAndDisplays =\n this.backgroundLock &&\n this.currentDisplay &&\n this.currentDisplay.packageName === this.backgroundLock.packageName\n if (bgHoldsAndDisplays) {\n resolve?.({status: \"blocked\", reason: \"a background app holds the display\"})\n return\n }\n\n // Core can display. If a bg lock exists but holder isn't actively on\n // the glasses, release it.\n if (this.backgroundLock && !bgHoldsAndDisplays) {\n this.backgroundLock = null\n }\n\n this.sendNow(packageName, payload, resolve)\n return\n }\n\n // Non-core: this is a background app.\n if (this.backgroundLock && this.backgroundLock.packageName !== packageName) {\n // Another bg app already holds the lock — drop.\n resolve?.({status: \"blocked\", reason: \"another background app holds the display\"})\n return\n }\n\n // Acquire or bump the lock.\n if (!this.backgroundLock) {\n this.backgroundLock = {\n packageName,\n acquiredAt: now,\n expiresAt: now + BACKGROUND_LOCK_TIMEOUT_MS,\n lastActiveTime: now,\n }\n } else {\n this.backgroundLock.lastActiveTime = now\n this.backgroundLock.expiresAt = now + BACKGROUND_LOCK_TIMEOUT_MS\n }\n\n this.sendNow(packageName, payload, resolve)\n }\n\n /**\n * An app cleared its display (\"render nothing\"). Same semantics as its\n * frame expiring: give up ownership, restore the core app's still-valid\n * display if there is one, otherwise clear the glasses.\n */\n private handleAppClear(packageName: string, resolve?: DisplayRequestResolver): void {\n // Forget the app's retained scene state — its next render starts fresh.\n sceneRenderer.clearApp(packageName)\n\n if (this.backgroundLock?.packageName === packageName) {\n this.backgroundLock = null\n }\n if (this.coreApp === packageName) {\n this.coreAppDisplay = null\n }\n\n if (this.currentDisplay?.packageName === packageName) {\n this.clearExpiryTimer()\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) {\n this.sendClear()\n }\n }\n resolve?.({status: \"displayed\"})\n }\n\n // ===========================================================================\n // Internals — send\n // ===========================================================================\n\n private sendNow(packageName: string, payload: DisplayPayload, resolve?: DisplayRequestResolver): void {\n const expiresAt = payload.durationMs ? this.now() + payload.durationMs : null\n const view = (payload.view === \"dashboard\" ? \"dashboard\" : \"main\") as \"main\" | \"dashboard\"\n\n // Scene requests — and legacy layouts a positioning device can render as a\n // scene (sugar, old bundles) — go through the scene pipeline. Everything\n // else stays on the legacy path.\n let sceneElements = payload.scene ?? null\n if (!sceneElements && payload.layout) {\n const caps = sceneRenderer.currentCapabilities()\n if (caps?.canPosition) {\n sceneElements = sceneRenderer.convertLegacyLayout(payload.layout, caps)\n }\n }\n\n if (sceneElements) {\n this.sendScene(packageName, view, sceneElements, expiresAt, resolve)\n } else if (payload.layout) {\n // This layout bypasses the scene pipeline (clear_view, dashboard_card,\n // unknown types, or a non-positioning device). If this (app, view) had a\n // retained scene, the glasses no longer match it — reset the diff\n // baseline so the next render() repaints from empty instead of skipping\n // \"unchanged\" elements.\n sceneRenderer.resetBaseline(packageName, view)\n const rawEvent: Record<string, unknown> = {\n view: payload.view ?? \"main\",\n layout: payload.layout,\n }\n if (payload.durationMs !== undefined) {\n rawEvent.durationMs = payload.durationMs\n }\n this.sendToNative(packageName, rawEvent, expiresAt)\n resolve?.({status: \"displayed\"})\n } else {\n // A scene payload on a device with no display block at all.\n resolve?.({status: \"blocked\", reason: \"no display connected\"})\n return\n }\n\n // If core app fired, refresh the saved snapshot with the actual processed\n // event so restore uses the wrapped text (legacy) / the retained scene.\n if (packageName === this.coreApp && this.currentDisplay) {\n this.coreAppDisplay = {\n packageName,\n processedEvent: this.currentDisplay.processedEvent,\n scene: this.currentDisplay.scene,\n expiresAt: this.currentDisplay.expiresAt,\n }\n }\n }\n\n /**\n * Send a scene through SceneRenderer. On positioning devices this emits a\n * SceneFrame; on degrade devices SceneRenderer hands back a legacy layout\n * that rides the existing (unchanged) DisplayProcessor path.\n */\n private sendScene(\n packageName: string,\n view: \"main\" | \"dashboard\",\n elements: SceneElementInput[],\n expiresAt: number | null,\n resolve?: DisplayRequestResolver,\n ): void {\n const result = sceneRenderer.emitScene(packageName, view, elements)\n\n if (result.kind === \"no-display\") {\n resolve?.({status: \"blocked\", reason: \"no display connected\"})\n return\n }\n\n if (result.kind === \"legacy\") {\n if (result.layout) {\n this.sendToNative(packageName, {view, layout: result.layout}, expiresAt)\n } else {\n // Scene degraded to nothing (e.g. all-image scene on a text-only\n // device). render() replaces the frame, so nothing means clear.\n this.sendClear()\n }\n resolve?.({status: \"displayed\", degraded: result.degraded, dropped: result.dropped})\n return\n }\n\n this.currentDisplay = {packageName, processedEvent: {}, scene: elements, expiresAt}\n this.clearExpiryTimer()\n if (expiresAt !== null) {\n const delay = Math.max(0, expiresAt - this.now())\n this.expiryTimerId = BgTimer.setTimeout(() => {\n this.expiryTimerId = null\n this.handleExpiry(packageName)\n }, delay)\n }\n if (!resolve) return\n this.settleScene(packageName, result, resolve)\n }\n\n /**\n * Settle an awaited render() once the glasses have the frame and its\n * transitions have played out. A frame that stayed phone-side (the other\n * view is showing) settles at once with `presented: false`. The timeout\n * keeps a frame the device never reports on from hanging the app.\n */\n private settleScene(\n packageName: string,\n result: Extract<SceneEmitResult, {kind: \"scene\"}>,\n resolve: DisplayRequestResolver,\n ): void {\n const base = {status: \"displayed\" as const, degraded: result.degraded, dropped: result.dropped}\n if (!result.sent) {\n resolve({...base, presented: false, reason: \"dashboard active\"})\n return\n }\n void sceneRenderer.whenPresented(result.seq, PRESENTATION_TIMEOUT_MS, packageName).then((p) => {\n const finish = () =>\n resolve({\n ...base,\n presented: p.presented,\n ...(p.superseded ? {superseded: true} : {}),\n ...(p.reason !== undefined ? {reason: p.reason} : {}),\n })\n if (p.presented && result.settleMs > 0) BgTimer.setTimeout(finish, result.settleMs)\n else finish()\n })\n }\n\n private sendToNative(packageName: string, rawEvent: Record<string, unknown>, expiresAt: number | null): void {\n let processedEvent: Record<string, unknown>\n try {\n processedEvent = displayProcessor.processDisplayEvent(rawEvent as any)\n } catch (err) {\n console.error(`${LOG_TAG}: DisplayProcessor error, using raw event:`, err)\n processedEvent = rawEvent\n }\n\n // While a page holds the overlay slot, main frames only update the\n // retained state; setOverlayOwner(null) replays the latest.\n if (this.overlayOwner === null) this.pushToNative(processedEvent)\n\n this.currentDisplay = {packageName, processedEvent, expiresAt}\n\n this.clearExpiryTimer()\n if (expiresAt !== null) {\n const delay = Math.max(0, expiresAt - this.now())\n this.expiryTimerId = BgTimer.setTimeout(() => {\n this.expiryTimerId = null\n this.handleExpiry(packageName)\n }, delay)\n }\n }\n\n private pushToNative(processedEvent: Record<string, unknown>): void {\n try {\n // The display output path is a direct btsdk call now (was a host sendDisplayEvent\n // hook) so a bare OEM renders to the glasses without wiring it.\n void Promise.resolve(BluetoothSdk.displayEvent(processedEvent)).catch((err) => {\n console.error(`${LOG_TAG}: native display failed:`, err)\n })\n // The mirror store also lives in engine, so display requests update the\n // phone-side preview without any host hook.\n useDisplayStore.getState().setDisplayEvent(JSON.stringify(processedEvent))\n } catch (err) {\n console.error(`${LOG_TAG}: native display failed:`, err)\n }\n }\n\n private handleExpiry(packageName: string): void {\n // Someone else is on the glasses now — ignore.\n if (!this.currentDisplay || this.currentDisplay.packageName !== packageName) {\n return\n }\n\n // Release the lock if it belonged to this (bg) app.\n if (this.backgroundLock?.packageName === packageName) {\n this.backgroundLock = null\n }\n\n this.currentDisplay = null\n this.tryRestoreCoreDisplay()\n if (!this.currentDisplay) {\n this.sendClear()\n }\n }\n\n private tryRestoreCoreDisplay(): void {\n if (!this.coreAppDisplay) return\n // If the core snapshot has a duration and it's already elapsed, skip.\n if (this.coreAppDisplay.expiresAt !== null && this.now() >= this.coreAppDisplay.expiresAt) {\n this.coreAppDisplay = null\n return\n }\n // Re-send the core's saved display.\n this.restoreDisplay(this.coreAppDisplay)\n }\n\n private sendClear(): void {\n const clearEvent: Record<string, unknown> = {\n view: \"main\",\n layout: {layoutType: \"clear_view\"},\n }\n this.sendToNative(\"system.clear\", clearEvent, null)\n this.currentDisplay = null\n // The glasses main view is now blank: every app's retained scene is\n // replay-only until it re-renders — diffing against it would skip\n // \"unchanged\" elements onto the blank screen.\n sceneRenderer.markViewStale(\"main\")\n }\n\n // ===========================================================================\n // Internals — boot\n // ===========================================================================\n\n private cancelBoot(): void {\n if (!this.bootingApp) return\n BgTimer.clearTimeout(this.bootingApp.timerId)\n this.bootingApp = null\n }\n\n private endBoot(): void {\n if (!this.bootingApp) return\n const preBoot = this.bootingApp.preBoot\n BgTimer.clearTimeout(this.bootingApp.timerId)\n this.bootingApp = null\n\n // Drain the queue: core first, then everyone else. Per-app last wins\n // because the map holds one payload per packageName.\n const queued = Array.from(this.bootQueue.entries())\n this.bootQueue.clear()\n\n const corePayload = this.coreApp ? queued.find(([pkg]) => pkg === this.coreApp) : undefined\n if (corePayload) {\n this.arbitrateAndSend(corePayload[0], corePayload[1].payload, corePayload[1].resolve)\n }\n for (const [pkg, entry] of queued) {\n if (pkg === this.coreApp) continue\n this.arbitrateAndSend(pkg, entry.payload, entry.resolve)\n }\n\n // If the boot text is still on the glasses — nothing was queued, or every\n // drained request lost arbitration — it must not strand: it's a system\n // frame with no expiry. Restore whatever was on the glasses before the\n // boot, else clear. Two reasons NOT to restore: the frame's duration\n // elapsed during the boot window, or its owner FORFEITED it during the\n // window (its final queued intent — the queue keeps last-wins per app —\n // was a clear, which the drain above processed as a forfeit; restoring\n // would resurrect content the clear removed).\n if (this.currentDisplay?.packageName === SYSTEM_BOOT_PKG) {\n const ownerEntry = preBoot ? queued.find(([pkg]) => pkg === preBoot.packageName) : undefined\n const preBootForfeited = ownerEntry !== undefined && isClearPayload(ownerEntry[1].payload)\n if (preBoot && !preBootForfeited && (preBoot.expiresAt === null || preBoot.expiresAt > this.now())) {\n this.restoreDisplay(preBoot)\n } else {\n this.sendClear()\n }\n }\n }\n\n /**\n * Re-push a previously-captured on-glasses frame (e.g. the display a boot\n * window overwrote). Mirrors tryRestoreCoreDisplay: the saved event is already\n * processed, and any remaining duration is recomputed from its expiry.\n */\n private restoreDisplay(saved: ActiveDisplay): void {\n const remaining = saved.expiresAt !== null ? Math.max(0, saved.expiresAt - this.now()) : undefined\n\n // Scene restores must REPLAY (create-based, epoch-bumped): re-emitting the\n // scene through the normal diff would come back all-\"unchanged\" and the\n // device would skip every element (spec §4 — replay is always create-based).\n if (saved.scene) {\n const expiresAt = remaining !== undefined ? this.now() + remaining : null\n if (sceneRenderer.replayApp(saved.packageName, \"main\")) {\n this.currentDisplay = {packageName: saved.packageName, processedEvent: {}, scene: saved.scene, expiresAt}\n this.clearExpiryTimer()\n if (expiresAt !== null) {\n const delay = Math.max(0, expiresAt - this.now())\n this.expiryTimerId = BgTimer.setTimeout(() => {\n this.expiryTimerId = null\n this.handleExpiry(saved.packageName)\n }, delay)\n }\n } else {\n // Retained state gone (app stopped since) — re-render the saved\n // elements as a fresh scene instead.\n this.sendNow(saved.packageName, {view: \"main\", scene: saved.scene, durationMs: remaining})\n }\n return\n }\n\n this.sendNow(saved.packageName, {\n view: \"main\",\n layout: saved.processedEvent.layout as DisplayPayload[\"layout\"],\n durationMs: remaining,\n })\n }\n\n // ===========================================================================\n // Reconnect replay (design doc §3.4.7 — recovery = replay, host-driven)\n // ===========================================================================\n\n /**\n * Subscribe to glasses connection state so the current owner's frame is\n * replayed after a reconnect. Safe to call repeatedly; attaches once. Wired\n * from MantleManager next to displayProcessor.attachToRuntime().\n */\n public attachToRuntime(): void {\n if (this.runtimeAttached) return\n // dev wired this through the (since-removed) glassesStatus runtime hooks;\n // engine reads its own glasses store directly.\n this.glassesWasConnected = isGlassesConnected(useGlassesStore.getState().connection)\n this.unsubscribeGlassesStatus = useGlassesStore.subscribe(() => {\n const connected = isGlassesConnected(useGlassesStore.getState().connection)\n if (connected === this.glassesWasConnected) return\n this.glassesWasConnected = connected\n if (connected) {\n this.replayCurrent()\n }\n })\n this.runtimeAttached = true\n }\n\n /**\n * Re-push the current on-glasses frame after a device recovery. Scenes replay\n * from SceneRenderer's retained state (create-based, epoch-bumped); legacy\n * frames re-send their processed event. Expired frames don't come back.\n */\n public replayCurrent(): void {\n const current = this.currentDisplay\n if (!current) return\n if (current.expiresAt !== null && this.now() >= current.expiresAt) return\n\n console.log(`${LOG_TAG}: replayCurrent(${current.packageName})`)\n if (current.scene) {\n if (!sceneRenderer.replayApp(current.packageName, \"main\")) {\n // Retained state gone (app stopped between disconnect and reconnect).\n this.sendClear()\n }\n } else if (current.processedEvent.layout) {\n this.sendToNative(current.packageName, current.processedEvent, current.expiresAt)\n }\n }\n\n // ===========================================================================\n // Internals — timer helpers\n // ===========================================================================\n\n private clearExpiryTimer(): void {\n if (this.expiryTimerId !== null) {\n BgTimer.clearTimeout(this.expiryTimerId)\n this.expiryTimerId = null\n }\n }\n\n // ===========================================================================\n // Test hooks\n // ===========================================================================\n\n /** Injected clock — tests only. */\n public _setNowForTest(fn: () => number): void {\n this.now = fn\n }\n\n /** Wipe state — tests only. */\n public _resetForTest(): void {\n this.cancelBoot()\n this.clearExpiryTimer()\n this.coreApp = null\n this.coreAppDisplay = null\n this.currentDisplay = null\n this.backgroundLock = null\n this.exitingApp = null\n this.overlayOwner = null\n this.bootQueue.clear()\n this.now = () => Date.now()\n this.unsubscribeGlassesStatus?.()\n this.unsubscribeGlassesStatus = null\n this.runtimeAttached = false\n this.glassesWasConnected = false\n sceneRenderer._resetForTest()\n }\n\n /** Read-only state snapshot — tests only. */\n public _peekForTest(): {\n coreApp: string | null\n currentDisplayPkg: string | null\n bgLockPkg: string | null\n isBooting: boolean\n } {\n return {\n coreApp: this.coreApp,\n currentDisplayPkg: this.currentDisplay?.packageName ?? null,\n bgLockPkg: this.backgroundLock?.packageName ?? null,\n isBooting: this.bootingApp !== null,\n }\n }\n}\n\nconst localDisplayManager = LocalDisplayManager.getInstance()\nexport default localDisplayManager\nexport {LocalDisplayManager}\n"]}
|
|
@@ -72,6 +72,7 @@ declare class LocalMiniappRuntime {
|
|
|
72
72
|
private connectedApps;
|
|
73
73
|
/** Claimed gestures (CLAIM_GESTURES): a stack per gesture, the most recent claimer holding it. */
|
|
74
74
|
private gestureClaims;
|
|
75
|
+
private retainedRenders;
|
|
75
76
|
/**
|
|
76
77
|
* Packages that have completed their CONNECT handshake (sent
|
|
77
78
|
* `miniapp_connect`, got `CONNECT_ACK`). Distinct from `connectedApps`,
|
|
@@ -284,6 +285,8 @@ declare class LocalMiniappRuntime {
|
|
|
284
285
|
* becomes the REQUEST_RESULT data.
|
|
285
286
|
*/
|
|
286
287
|
private handleRender;
|
|
288
|
+
/** Put a promoted app's last main-view frame on the glasses; widget mode had refused it. */
|
|
289
|
+
private replayRetainedRender;
|
|
287
290
|
/**
|
|
288
291
|
* display.showView: the active dashboard takes or releases the overlay
|
|
289
292
|
* slot. Refused (NOT_PERMITTED) for an app that is not a dashboard;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalMiniappRuntime.d.ts","sourceRoot":"","sources":["../../src/services/LocalMiniappRuntime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsBH,OAAO,KAAK,EAAkB,mBAAmB,EAAqB,MAAM,kBAAkB,CAAA;AAsI9F,OAAO,EAA+B,KAAK,gCAAgC,EAAC,MAAM,6BAA6B,CAAA;AAmB/G,MAAM,WAAW,wBAAwB;IACvC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;4EACwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAC,CAAA;IAC1C,WAAW,CAAC,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAAA;IAC7E,oBAAoB,CAAC,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAAA;IACjF,OAAO,CAAC,EAAE,KAAK,CAAC;QAAC,EAAE,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC,CAAA;IACpG,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAoDD,KAAK,wBAAwB,GAAG,OAAO,GAAG,OAAO,CAAA;AAwWjD,cAAM,mBAAmB;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmC;IAE1D;;;;;;;;OAQG;IACH,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,GAAG,eAAe,EAAE,IAAI,CAAC,EAAE;QAAC,cAAc,EAAE,OAAO,CAAA;KAAC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAO;IAE7G;;;;;OAKG;IACH,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,GAAG,eAAe,KAAK,IAAI,CAAC,GAAG,IAAI,CAAO;IAE3E,+EAA+E;IAC/E,OAAO,CAAC,oBAAoB,CAAI;IAEhC,6EAA6E;IAC7E,OAAO,CAAC,eAAe,CAAQ;IAE/B,+CAA+C;IAC/C,OAAO,CAAC,aAAa,CAA2C;IAChE,kGAAkG;IAClG,OAAO,CAAC,aAAa,CAA0C;
|
|
1
|
+
{"version":3,"file":"LocalMiniappRuntime.d.ts","sourceRoot":"","sources":["../../src/services/LocalMiniappRuntime.ts"],"names":[],"mappings":"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"}
|
|
@@ -438,6 +438,10 @@ class LocalMiniappRuntime {
|
|
|
438
438
|
connectedApps = new Map();
|
|
439
439
|
/** Claimed gestures (CLAIM_GESTURES): a stack per gesture, the most recent claimer holding it. */
|
|
440
440
|
gestureClaims = emptyGestureClaims();
|
|
441
|
+
// The last main-view frame each app asked to render. Widget mode refuses
|
|
442
|
+
// frames and demotion clears them, and an app that has drawn once may not
|
|
443
|
+
// draw again on its own, so promotion replays this.
|
|
444
|
+
retainedRenders = new Map();
|
|
441
445
|
/**
|
|
442
446
|
* Packages that have completed their CONNECT handshake (sent
|
|
443
447
|
* `miniapp_connect`, got `CONNECT_ACK`). Distinct from `connectedApps`,
|
|
@@ -490,7 +494,14 @@ class LocalMiniappRuntime {
|
|
|
490
494
|
// secret never leaves the device.
|
|
491
495
|
localSecret = `miniapp_${Date.now()}_${Math.random().toString(36).slice(2, 14)}`;
|
|
492
496
|
usedTokens = new Set();
|
|
493
|
-
constructor() {
|
|
497
|
+
constructor() {
|
|
498
|
+
miniappWidgetMode.subscribe((packageName, widgetOnly) => {
|
|
499
|
+
// Promotion happens inside the apps store's start(); the core-app slot
|
|
500
|
+
// settles with that store write, so replay once it has.
|
|
501
|
+
if (!widgetOnly)
|
|
502
|
+
queueMicrotask(() => this.replayRetainedRender(packageName));
|
|
503
|
+
});
|
|
504
|
+
}
|
|
494
505
|
/** Snapshot of miniapps actively subscribed to hardware button events. */
|
|
495
506
|
getButtonPressSubscribers() {
|
|
496
507
|
return [...(this.streamSubscribers.get(MiniappStreamType.BUTTON_PRESS) ?? [])].sort();
|
|
@@ -996,6 +1007,7 @@ class LocalMiniappRuntime {
|
|
|
996
1007
|
}
|
|
997
1008
|
// Its gesture claims go back to whoever claimed them before.
|
|
998
1009
|
this.applyGestureClaimChanges(dropGestureClaims(this.gestureClaims, packageName));
|
|
1010
|
+
this.retainedRenders.delete(packageName);
|
|
999
1011
|
// Warm-up is a request-owned camera lease. Cancel it even if the app record was already
|
|
1000
1012
|
// removed so a close racing the camera-open promise cannot leave the sensor running.
|
|
1001
1013
|
// Keep camera teardown ordered: restoring FOV can restart the HAL, so the warm-up lease must
|
|
@@ -2124,11 +2136,6 @@ class LocalMiniappRuntime {
|
|
|
2124
2136
|
this.sendResult(packageName, requestId, true, { status: "blocked", reason: "app stopped" });
|
|
2125
2137
|
return;
|
|
2126
2138
|
}
|
|
2127
|
-
// A widget-only app draws through its widget alone.
|
|
2128
|
-
if (miniappWidgetMode.isWidgetOnly(packageName)) {
|
|
2129
|
-
this.sendResult(packageName, requestId, true, { status: "blocked", reason: "widget mode" });
|
|
2130
|
-
return;
|
|
2131
|
-
}
|
|
2132
2139
|
if (!Array.isArray(payload.elements)) {
|
|
2133
2140
|
this.sendResult(packageName, requestId, false, undefined, {
|
|
2134
2141
|
code: MiniappErrorCode.INTERNAL,
|
|
@@ -2136,6 +2143,17 @@ class LocalMiniappRuntime {
|
|
|
2136
2143
|
});
|
|
2137
2144
|
return;
|
|
2138
2145
|
}
|
|
2146
|
+
if (payload.view !== "dashboard") {
|
|
2147
|
+
if (payload.elements.length === 0)
|
|
2148
|
+
this.retainedRenders.delete(packageName);
|
|
2149
|
+
else
|
|
2150
|
+
this.retainedRenders.set(packageName, payload);
|
|
2151
|
+
}
|
|
2152
|
+
// A widget-only app draws through its widget alone; the frame waits for promotion.
|
|
2153
|
+
if (miniappWidgetMode.isWidgetOnly(packageName)) {
|
|
2154
|
+
this.sendResult(packageName, requestId, true, { status: "blocked", reason: "widget mode" });
|
|
2155
|
+
return;
|
|
2156
|
+
}
|
|
2139
2157
|
// The dashboard view is the overlay app's alone; anyone else's frame
|
|
2140
2158
|
// is dropped, reported rather than silently lost.
|
|
2141
2159
|
if (payload.view === "dashboard" && !isOverlayApp(packageName)) {
|
|
@@ -2160,6 +2178,13 @@ class LocalMiniappRuntime {
|
|
|
2160
2178
|
});
|
|
2161
2179
|
}
|
|
2162
2180
|
}
|
|
2181
|
+
/** Put a promoted app's last main-view frame on the glasses; widget mode had refused it. */
|
|
2182
|
+
replayRetainedRender(packageName) {
|
|
2183
|
+
const payload = this.retainedRenders.get(packageName);
|
|
2184
|
+
if (!payload || !this.connectedApps.has(packageName) || miniappWidgetMode.isWidgetOnly(packageName))
|
|
2185
|
+
return;
|
|
2186
|
+
this.handleRender(packageName, payload);
|
|
2187
|
+
}
|
|
2163
2188
|
/**
|
|
2164
2189
|
* display.showView: the active dashboard takes or releases the overlay
|
|
2165
2190
|
* slot. Refused (NOT_PERMITTED) for an app that is not a dashboard;
|