@glassly/engine 0.1.0-dev.61 → 0.1.0-dev.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/build/facades/ota.d.ts +3 -1
- package/build/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +4 -2
- package/build/facades/ota.js.map +1 -1
- package/build/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +2 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -2
- package/build/index.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.d.ts +6 -1
- package/build/react/MentraLiveOtaFlow.d.ts.map +1 -1
- package/build/react/MentraLiveOtaFlow.js +136 -14
- package/build/react/MentraLiveOtaFlow.js.map +1 -1
- package/build/react/useMentraLiveOta.d.ts +5 -1
- package/build/react/useMentraLiveOta.d.ts.map +1 -1
- package/build/react/useMentraLiveOta.js +135 -58
- package/build/react/useMentraLiveOta.js.map +1 -1
- package/build/services/DisplayProcessor.d.ts +3 -3
- package/build/services/DisplayProcessor.js +3 -3
- package/build/services/DisplayProcessor.js.map +1 -1
- package/build/services/LocalDisplayManager.d.ts +2 -2
- package/build/services/LocalDisplayManager.js +2 -2
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/OtaInstallCoordinator.d.ts +2 -0
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +21 -1
- package/build/services/OtaInstallCoordinator.js.map +1 -1
- package/build/services/PhonePhotoCoordinator.js +1 -1
- package/build/services/PhonePhotoCoordinator.js.map +1 -1
- package/build/services/StreamLifecycleController.d.ts +4 -0
- package/build/services/StreamLifecycleController.d.ts.map +1 -1
- package/build/services/StreamLifecycleController.js +4 -0
- package/build/services/StreamLifecycleController.js.map +1 -1
- package/build/services/otaInstallPolicy.d.ts +4 -0
- package/build/services/otaInstallPolicy.d.ts.map +1 -1
- package/build/services/otaInstallPolicy.js +4 -0
- package/build/services/otaInstallPolicy.js.map +1 -1
- package/build/types/applet.d.ts +1 -1
- package/build/types/applet.js.map +1 -1
- package/build/types/capabilities/even-realities-g2.d.ts.map +1 -1
- package/build/types/capabilities/even-realities-g2.js +2 -2
- package/build/types/capabilities/even-realities-g2.js.map +1 -1
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +1 -0
- package/build/types/hardware.js.map +1 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js +1 -1
- package/build/types/index.js.map +1 -1
- package/build/utils/display/composer/ColumnComposer.d.ts +1 -1
- package/build/utils/display/composer/ColumnComposer.js +1 -1
- package/build/utils/display/composer/ColumnComposer.js.map +1 -1
- package/package.json +8 -7
- package/src/facades/ota.ts +4 -2
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/index.ts +2 -1
- package/src/react/MentraLiveOtaFlow.tsx +226 -41
- package/src/react/useMentraLiveOta.ts +146 -60
- package/src/services/DisplayProcessor.ts +3 -3
- package/src/services/LocalDisplayManager.ts +2 -2
- package/src/services/OtaInstallCoordinator.ts +21 -0
- package/src/services/PhonePhotoCoordinator.ts +1 -1
- package/src/services/StreamLifecycleController.ts +4 -0
- package/src/services/otaInstallPolicy.ts +4 -0
- package/src/types/applet.ts +1 -1
- package/src/types/capabilities/even-realities-g2.ts +3 -2
- package/src/types/hardware.ts +1 -0
- package/src/types/index.ts +1 -1
- package/src/utils/display/composer/ColumnComposer.ts +1 -1
|
@@ -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). Mirrors the user-facing behavior of the cloud\n * DisplayManager 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 per plan\n * (agents/local-display-manager-plan.md).\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 from \"./SceneRenderer\"\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 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\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 /** 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 (see LocalMiniappRuntime.foregroundClaimsGesture). 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 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 /** 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 // 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 // Dashboard view: pass straight through (no throttle/arbitration). Local\n // dashboard rendering is currently a stub on the phone anyway.\n if (payload.view === \"dashboard\") {\n this.sendNow(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 resolve?.({status: \"displayed\", degraded: result.degraded, dropped: result.dropped})\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 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 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 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.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 per plan\n * (agents/local-display-manager-plan.md).\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 from \"./SceneRenderer\"\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 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\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 /** 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 (see LocalMiniappRuntime.foregroundClaimsGesture). 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 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 /** 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 // 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 // Dashboard view: pass straight through (no throttle/arbitration). Local\n // dashboard rendering is currently a stub on the phone anyway.\n if (payload.view === \"dashboard\") {\n this.sendNow(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 resolve?.({status: \"displayed\", degraded: result.degraded, dropped: result.dropped})\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 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 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 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.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"]}
|
|
@@ -86,6 +86,7 @@ declare class OtaInstallCoordinator {
|
|
|
86
86
|
private pingInterval;
|
|
87
87
|
private queryReplyTimeout;
|
|
88
88
|
private continueLockoutTimer;
|
|
89
|
+
private restartRecoveryTimeout;
|
|
89
90
|
private legacyApkSettleTimer;
|
|
90
91
|
private mtkStallDetectTimer;
|
|
91
92
|
private mtkSimTickTimer;
|
|
@@ -278,6 +279,7 @@ declare class OtaInstallCoordinator {
|
|
|
278
279
|
private clearPingInterval;
|
|
279
280
|
private clearQueryReplyTimeout;
|
|
280
281
|
private clearContinueLockoutTimer;
|
|
282
|
+
private clearRestartRecoveryTimeout;
|
|
281
283
|
private clearLegacyApkSettleTimer;
|
|
282
284
|
private clearMtkSimulationTimers;
|
|
283
285
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OtaInstallCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/OtaInstallCoordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAqB,EAAC,KAAK,WAAW,EAAE,KAAK,SAAS,EAAC,MAAM,wBAAwB,CAAA;AAIrF,OAAO,EAAsB,KAAK,eAAe,EAAC,MAAM,uBAAuB,CAAA;AAC/E,OAAO,KAAK,EAAC,4BAA4B,EAAC,MAAM,yBAAyB,CAAA;AACzE,OAAO,EAAqB,KAAK,YAAY,EAAC,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"OtaInstallCoordinator.d.ts","sourceRoot":"","sources":["../../src/services/OtaInstallCoordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,7 +23,7 @@ import { isGlassesConnected, useGlassesStore } from "../stores/glasses";
|
|
|
23
23
|
import { resolveOtaManifestUrl } from "./otaManifestUrl";
|
|
24
24
|
import { hotspotOtaTransport } from "./HotspotOtaTransport";
|
|
25
25
|
import { deriveDisplayState } from "./otaDisplayState";
|
|
26
|
-
import { BES_CONTINUE_LOCKOUT_MS, DOWNLOAD_STUCK_TIMEOUT_MS, GLOBAL_OTA_TIMEOUT_MS, LEGACY_APK_COMPLETION_SETTLE_MS, LEGACY_BES_CONTINUE_LOCKOUT_MS, LEGACY_DOWNLOAD_STUCK_TIMEOUT_MS, LEGACY_GLOBAL_OTA_TIMEOUT_MS, LEGACY_MTK_INSTALL_TIMEOUT_MS, LEGACY_MTK_SIM_CAP_PERCENT, LEGACY_MTK_SIM_FLOOR_PERCENT, LEGACY_MTK_SIM_TICK_MS, LEGACY_MTK_STALL_DETECT_MS, LEGACY_MTK_STALL_ZONE_MAX_PERCENT, LEGACY_MTK_STALL_ZONE_MIN_PERCENT, LEGACY_PING_INTERVAL_MS, LEGACY_PROGRESS_TIMEOUT_MS, LEGACY_RETRY_INTERVAL_MS, MAX_RETRIES, MTK_INSTALL_TIMEOUT_MS, OtaProgressMessages, PING_INTERVAL_MS, PROGRESS_TIMEOUT_MS, QUERY_REPLY_TIMEOUT_MS, RETRY_INTERVAL_MS, isLegacyShapedOtaSession, isLegacyShapedOtaStatus, selectOtaProtocolProfile, } from "./otaInstallPolicy";
|
|
26
|
+
import { BES_CONTINUE_LOCKOUT_MS, BES_RESTART_TIMEOUT_MS, DOWNLOAD_STUCK_TIMEOUT_MS, GLOBAL_OTA_TIMEOUT_MS, LEGACY_APK_COMPLETION_SETTLE_MS, LEGACY_BES_CONTINUE_LOCKOUT_MS, LEGACY_BES_RESTART_TIMEOUT_MS, LEGACY_DOWNLOAD_STUCK_TIMEOUT_MS, LEGACY_GLOBAL_OTA_TIMEOUT_MS, LEGACY_MTK_INSTALL_TIMEOUT_MS, LEGACY_MTK_SIM_CAP_PERCENT, LEGACY_MTK_SIM_FLOOR_PERCENT, LEGACY_MTK_SIM_TICK_MS, LEGACY_MTK_STALL_DETECT_MS, LEGACY_MTK_STALL_ZONE_MAX_PERCENT, LEGACY_MTK_STALL_ZONE_MIN_PERCENT, LEGACY_PING_INTERVAL_MS, LEGACY_PROGRESS_TIMEOUT_MS, LEGACY_RETRY_INTERVAL_MS, MAX_RETRIES, MTK_INSTALL_TIMEOUT_MS, OtaProgressMessages, PING_INTERVAL_MS, PROGRESS_TIMEOUT_MS, QUERY_REPLY_TIMEOUT_MS, RETRY_INTERVAL_MS, isLegacyShapedOtaSession, isLegacyShapedOtaStatus, selectOtaProtocolProfile, } from "./otaInstallPolicy";
|
|
27
27
|
function isTerminalForWatchdog(d) {
|
|
28
28
|
return d === "complete" || d === "failed" || d === "restarting";
|
|
29
29
|
}
|
|
@@ -156,6 +156,7 @@ class OtaInstallCoordinator {
|
|
|
156
156
|
pingInterval = null;
|
|
157
157
|
queryReplyTimeout = null;
|
|
158
158
|
continueLockoutTimer = null;
|
|
159
|
+
restartRecoveryTimeout = null;
|
|
159
160
|
legacyApkSettleTimer = null;
|
|
160
161
|
mtkStallDetectTimer = null;
|
|
161
162
|
mtkSimTickTimer = null;
|
|
@@ -850,12 +851,24 @@ class OtaInstallCoordinator {
|
|
|
850
851
|
// (15s unified, 35s for legacy-shaped sessions — WP 8C-f).
|
|
851
852
|
if (displayStateChanged && displayState === "restarting") {
|
|
852
853
|
this.clearContinueLockoutTimer();
|
|
854
|
+
this.clearRestartRecoveryTimeout();
|
|
853
855
|
const lockoutMs = legacySession ? LEGACY_BES_CONTINUE_LOCKOUT_MS : BES_CONTINUE_LOCKOUT_MS;
|
|
856
|
+
const restartTimeoutMs = legacySession ? LEGACY_BES_RESTART_TIMEOUT_MS : BES_RESTART_TIMEOUT_MS;
|
|
854
857
|
this.setContinueButtonDisabled(true);
|
|
855
858
|
this.continueLockoutTimer = setTimeout(() => {
|
|
856
859
|
this.continueLockoutTimer = null;
|
|
857
860
|
this.setContinueButtonDisabled(false);
|
|
858
861
|
}, lockoutMs);
|
|
862
|
+
this.restartRecoveryTimeout = setTimeout(() => {
|
|
863
|
+
this.restartRecoveryTimeout = null;
|
|
864
|
+
if (this.computeDisplayStateNow() !== "restarting")
|
|
865
|
+
return;
|
|
866
|
+
console.log(`[OTA_PROGRESS] watchdog: glasses did not finish restarting in ${restartTimeoutMs}ms`);
|
|
867
|
+
this.setErrorMsg(OtaProgressMessages.restartTimeout);
|
|
868
|
+
}, restartTimeoutMs);
|
|
869
|
+
}
|
|
870
|
+
else if (displayStateChanged) {
|
|
871
|
+
this.clearRestartRecoveryTimeout();
|
|
859
872
|
}
|
|
860
873
|
// Legacy MTK install stall simulation (WP 8C-e): display-only. The simulation
|
|
861
874
|
// timers only ever touch the projected snapshot percent — they never feed back
|
|
@@ -1454,6 +1467,12 @@ class OtaInstallCoordinator {
|
|
|
1454
1467
|
this.continueLockoutTimer = null;
|
|
1455
1468
|
}
|
|
1456
1469
|
}
|
|
1470
|
+
clearRestartRecoveryTimeout() {
|
|
1471
|
+
if (this.restartRecoveryTimeout) {
|
|
1472
|
+
clearTimeout(this.restartRecoveryTimeout);
|
|
1473
|
+
this.restartRecoveryTimeout = null;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1457
1476
|
clearLegacyApkSettleTimer() {
|
|
1458
1477
|
if (this.legacyApkSettleTimer) {
|
|
1459
1478
|
clearTimeout(this.legacyApkSettleTimer);
|
|
@@ -1489,6 +1508,7 @@ class OtaInstallCoordinator {
|
|
|
1489
1508
|
this.clearPingInterval();
|
|
1490
1509
|
this.clearLegacyApkSettleTimer();
|
|
1491
1510
|
this.clearMtkSimulationTimers();
|
|
1511
|
+
this.clearRestartRecoveryTimeout();
|
|
1492
1512
|
}
|
|
1493
1513
|
}
|
|
1494
1514
|
/** Singleton — one install session machine per app process (matches the single progress screen). */
|