@mentra/engine 0.1.0-dev.1 → 3.1.0-beta.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -29
- package/build/bluetooth-sdk/debug.d.ts +2 -0
- package/build/bluetooth-sdk/debug.d.ts.map +1 -0
- package/build/bluetooth-sdk/debug.js +2 -0
- package/build/bluetooth-sdk/debug.js.map +1 -0
- package/build/bluetooth-sdk/index.d.ts +3 -0
- package/build/bluetooth-sdk/index.d.ts.map +1 -0
- package/build/bluetooth-sdk/index.js +3 -0
- package/build/bluetooth-sdk/index.js.map +1 -0
- package/build/bluetooth-sdk/ota-transport.d.ts +2 -0
- package/build/bluetooth-sdk/ota-transport.d.ts.map +1 -0
- package/build/bluetooth-sdk/ota-transport.js +2 -0
- package/build/bluetooth-sdk/ota-transport.js.map +1 -0
- package/build/bluetooth-sdk/photo-receiver.d.ts +3 -0
- package/build/bluetooth-sdk/photo-receiver.d.ts.map +1 -0
- package/build/bluetooth-sdk/photo-receiver.js +3 -0
- package/build/bluetooth-sdk/photo-receiver.js.map +1 -0
- package/build/bluetooth-sdk/react.d.ts +2 -0
- package/build/bluetooth-sdk/react.d.ts.map +1 -0
- package/build/bluetooth-sdk/react.js +2 -0
- package/build/bluetooth-sdk/react.js.map +1 -0
- package/build/bluetooth-sdk/types.d.ts +2 -0
- package/build/bluetooth-sdk/types.d.ts.map +1 -0
- package/build/bluetooth-sdk/types.js +2 -0
- package/build/bluetooth-sdk/types.js.map +1 -0
- package/build/engine.d.ts +18 -15
- package/build/engine.d.ts.map +1 -1
- package/build/engine.js +2 -2
- package/build/engine.js.map +1 -1
- package/build/facades/display.d.ts +1 -1
- package/build/facades/display.d.ts.map +1 -1
- package/build/facades/display.js +1 -1
- package/build/facades/display.js.map +1 -1
- package/build/facades/glasses.d.ts +3 -13
- package/build/facades/glasses.d.ts.map +1 -1
- package/build/facades/glasses.js +3 -3
- package/build/facades/glasses.js.map +1 -1
- package/build/facades/ota.d.ts +16 -22
- package/build/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +13 -9
- package/build/facades/ota.js.map +1 -1
- package/build/facades/pairing.d.ts +8 -5
- package/build/facades/pairing.d.ts.map +1 -1
- package/build/facades/pairing.js +83 -9
- package/build/facades/pairing.js.map +1 -1
- package/build/facades/speech.d.ts +7 -6
- package/build/facades/speech.d.ts.map +1 -1
- package/build/facades/speech.js +1 -1
- package/build/facades/speech.js.map +1 -1
- package/build/generated/releaseMetadata.d.ts +12 -0
- package/build/generated/releaseMetadata.d.ts.map +1 -0
- package/build/generated/releaseMetadata.js +10 -0
- package/build/generated/releaseMetadata.js.map +1 -0
- package/build/index.d.ts +7 -8
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -5
- package/build/index.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.d.ts +8 -2
- package/build/react/MentraLiveOtaFlow.d.ts.map +1 -1
- package/build/react/MentraLiveOtaFlow.js +256 -354
- package/build/react/MentraLiveOtaFlow.js.map +1 -1
- package/build/react/index.d.ts +1 -0
- package/build/react/index.d.ts.map +1 -1
- package/build/react/index.js +1 -0
- package/build/react/index.js.map +1 -1
- package/build/react/useMentraLiveOta.d.ts +84 -0
- package/build/react/useMentraLiveOta.d.ts.map +1 -0
- package/build/react/useMentraLiveOta.js +627 -0
- package/build/react/useMentraLiveOta.js.map +1 -0
- package/build/services/AppRegistry.d.ts +8 -0
- package/build/services/AppRegistry.d.ts.map +1 -1
- package/build/services/AppRegistry.js +15 -0
- package/build/services/AppRegistry.js.map +1 -1
- package/build/services/BlobStore.d.ts +2 -0
- package/build/services/BlobStore.d.ts.map +1 -1
- package/build/services/BlobStore.js +63 -10
- package/build/services/BlobStore.js.map +1 -1
- package/build/services/DisplayProcessor.d.ts +3 -3
- package/build/services/DisplayProcessor.js +3 -3
- package/build/services/DisplayProcessor.js.map +1 -1
- package/build/services/GlassesStatusProjection.d.ts +15 -2
- package/build/services/GlassesStatusProjection.d.ts.map +1 -1
- package/build/services/GlassesStatusProjection.js +3 -3
- package/build/services/GlassesStatusProjection.js.map +1 -1
- package/build/services/HotspotOtaTransport.d.ts.map +1 -1
- package/build/services/HotspotOtaTransport.js +8 -7
- package/build/services/HotspotOtaTransport.js.map +1 -1
- package/build/services/LocalDisplayManager.d.ts +2 -3
- package/build/services/LocalDisplayManager.d.ts.map +1 -1
- package/build/services/LocalDisplayManager.js +2 -3
- package/build/services/LocalDisplayManager.js.map +1 -1
- package/build/services/OtaAutoChain.d.ts +9 -2
- package/build/services/OtaAutoChain.d.ts.map +1 -1
- package/build/services/OtaAutoChain.js +10 -2
- package/build/services/OtaAutoChain.js.map +1 -1
- package/build/services/OtaInstallCoordinator.d.ts +26 -3
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +38 -13
- package/build/services/OtaInstallCoordinator.js.map +1 -1
- package/build/services/OtaService.d.ts.map +1 -1
- package/build/services/OtaService.js +1 -1
- package/build/services/OtaService.js.map +1 -1
- package/build/services/OtaUpdateCheckService.d.ts +4 -1
- package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
- package/build/services/OtaUpdateCheckService.js +33 -21
- package/build/services/OtaUpdateCheckService.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 +3 -3
- package/build/services/StreamLifecycleController.js +3 -3
- package/build/services/StreamLifecycleController.js.map +1 -1
- package/build/services/asg/localNetworkTransport.d.ts.map +1 -1
- package/build/services/asg/localNetworkTransport.js +13 -12
- package/build/services/asg/localNetworkTransport.js.map +1 -1
- package/build/services/glassesClockSync.d.ts.map +1 -1
- package/build/services/glassesClockSync.js +5 -1
- package/build/services/glassesClockSync.js.map +1 -1
- package/build/services/otaDisplayState.d.ts +1 -1
- package/build/services/otaDisplayState.d.ts.map +1 -1
- package/build/services/otaDisplayState.js.map +1 -1
- package/build/services/otaInstallPolicy.d.ts +5 -1
- package/build/services/otaInstallPolicy.d.ts.map +1 -1
- package/build/services/otaInstallPolicy.js +4 -0
- package/build/services/otaInstallPolicy.js.map +1 -1
- package/build/services/otaLegacyMapping.d.ts +1 -1
- package/build/services/otaLegacyMapping.d.ts.map +1 -1
- package/build/services/otaLegacyMapping.js.map +1 -1
- package/build/services/otaManifestPolicy.d.ts +14 -0
- package/build/services/otaManifestPolicy.d.ts.map +1 -0
- package/build/services/otaManifestPolicy.js +19 -0
- package/build/services/otaManifestPolicy.js.map +1 -0
- package/build/services/otaManifestUrl.d.ts +2 -1
- package/build/services/otaManifestUrl.d.ts.map +1 -1
- package/build/services/otaManifestUrl.js +24 -32
- package/build/services/otaManifestUrl.js.map +1 -1
- package/build/services/otaReleaseVersion.d.ts +10 -0
- package/build/services/otaReleaseVersion.d.ts.map +1 -0
- package/build/services/otaReleaseVersion.js +14 -0
- package/build/services/otaReleaseVersion.js.map +1 -0
- package/build/stores/appVisibility.d.ts +3 -0
- package/build/stores/appVisibility.d.ts.map +1 -0
- package/build/stores/appVisibility.js +3 -0
- package/build/stores/appVisibility.js.map +1 -0
- package/build/stores/apps.d.ts.map +1 -1
- package/build/stores/apps.js +7 -1
- package/build/stores/apps.js.map +1 -1
- package/build/stores/core.d.ts +3 -3
- package/build/stores/core.d.ts.map +1 -1
- package/build/stores/core.js.map +1 -1
- package/build/stores/glasses.d.ts +10 -4
- package/build/stores/glasses.d.ts.map +1 -1
- package/build/stores/glasses.js.map +1 -1
- package/build/stores/settings.js +3 -3
- package/build/stores/settings.js.map +1 -1
- package/build/types/applet.d.ts +1 -1
- package/build/types/applet.js +1 -1
- package/build/types/applet.js.map +1 -1
- package/build/types/capabilities/even-realities-g1.d.ts.map +1 -1
- package/build/types/capabilities/even-realities-g1.js +2 -0
- package/build/types/capabilities/even-realities-g1.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 -0
- package/build/types/capabilities/even-realities-g2.js.map +1 -1
- package/build/types/capabilities/mentra-display.d.ts.map +1 -1
- package/build/types/capabilities/mentra-display.js +2 -0
- package/build/types/capabilities/mentra-display.js.map +1 -1
- package/build/types/capabilities/mentra-live.d.ts.map +1 -1
- package/build/types/capabilities/mentra-live.js +2 -0
- package/build/types/capabilities/mentra-live.js.map +1 -1
- package/build/types/capabilities/nimo.d.ts +9 -0
- package/build/types/capabilities/nimo.d.ts.map +1 -0
- package/build/types/capabilities/nimo.js +57 -0
- package/build/types/capabilities/nimo.js.map +1 -0
- package/build/types/capabilities/none.d.ts.map +1 -1
- package/build/types/capabilities/none.js +2 -0
- package/build/types/capabilities/none.js.map +1 -1
- package/build/types/capabilities/simulated-glasses.d.ts.map +1 -1
- package/build/types/capabilities/simulated-glasses.js +2 -0
- package/build/types/capabilities/simulated-glasses.js.map +1 -1
- package/build/types/capabilities/vuzix-z100.d.ts.map +1 -1
- package/build/types/capabilities/vuzix-z100.js +2 -0
- package/build/types/capabilities/vuzix-z100.js.map +1 -1
- package/build/types/enums.d.ts +3 -26
- package/build/types/enums.d.ts.map +1 -1
- package/build/types/enums.js +2 -27
- package/build/types/enums.js.map +1 -1
- package/build/types/hardware.d.ts +6 -15
- package/build/types/hardware.d.ts.map +1 -1
- package/build/types/hardware.js +4 -4
- package/build/types/hardware.js.map +1 -1
- package/build/types/index.d.ts +3 -7
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js +3 -7
- package/build/types/index.js.map +1 -1
- package/build/utils/display/composer/ColumnComposer.d.ts +1 -1
- package/build/utils/display/composer/ColumnComposer.js +1 -1
- package/build/utils/display/composer/ColumnComposer.js.map +1 -1
- package/package.json +47 -22
- package/src/bluetooth-sdk/debug.ts +1 -0
- package/src/bluetooth-sdk/index.ts +2 -0
- package/src/bluetooth-sdk/ota-transport.ts +1 -0
- package/src/bluetooth-sdk/photo-receiver.ts +2 -0
- package/src/bluetooth-sdk/react.ts +1 -0
- package/src/bluetooth-sdk/types.ts +1 -0
- package/src/engine.ts +2 -2
- package/src/facades/display.ts +1 -1
- package/src/facades/glasses.ts +4 -4
- package/src/facades/ota.ts +23 -10
- package/src/facades/pairing.ts +92 -16
- package/src/facades/speech.ts +21 -7
- package/src/generated/releaseMetadata.ts +20 -0
- package/src/index.ts +16 -11
- package/src/react/MentraLiveOtaFlow.tsx +378 -480
- package/src/react/index.ts +14 -0
- package/src/react/useMentraLiveOta.ts +793 -0
- package/src/services/AppRegistry.ts +16 -0
- package/src/services/BlobStore.ts +57 -10
- package/src/services/DisplayProcessor.ts +3 -3
- package/src/services/GlassesStatusProjection.ts +7 -6
- package/src/services/HotspotOtaTransport.ts +8 -7
- package/src/services/LocalDisplayManager.ts +2 -3
- package/src/services/OtaAutoChain.ts +26 -2
- package/src/services/OtaInstallCoordinator.ts +40 -13
- package/src/services/OtaService.ts +1 -2
- package/src/services/OtaUpdateCheckService.ts +45 -27
- package/src/services/PhonePhotoCoordinator.ts +1 -1
- package/src/services/StreamLifecycleController.ts +3 -3
- package/src/services/asg/localNetworkTransport.ts +20 -19
- package/src/services/glassesClockSync.ts +5 -1
- package/src/services/otaDisplayState.ts +1 -1
- package/src/services/otaInstallPolicy.ts +5 -1
- package/src/services/otaLegacyMapping.ts +1 -1
- package/src/services/otaManifestPolicy.ts +42 -0
- package/src/services/otaManifestUrl.ts +27 -36
- package/src/services/otaReleaseVersion.ts +22 -0
- package/src/stores/appVisibility.ts +3 -0
- package/src/stores/apps.ts +7 -1
- package/src/stores/core.ts +4 -4
- package/src/stores/glasses.ts +13 -6
- package/src/stores/settings.ts +3 -3
- package/src/types/applet.ts +1 -1
- package/src/types/capabilities/even-realities-g1.ts +3 -0
- package/src/types/capabilities/even-realities-g2.ts +3 -0
- package/src/types/capabilities/mentra-display.ts +3 -0
- package/src/types/capabilities/mentra-live.ts +3 -0
- package/src/types/capabilities/nimo.ts +59 -0
- package/src/types/capabilities/none.ts +3 -0
- package/src/types/capabilities/simulated-glasses.ts +3 -0
- package/src/types/capabilities/vuzix-z100.ts +3 -0
- package/src/types/enums.ts +2 -27
- package/src/types/hardware.ts +7 -15
- package/src/types/index.ts +3 -6
- package/src/utils/display/composer/ColumnComposer.ts +1 -1
- package/build/devtools.d.ts +0 -11
- package/build/devtools.d.ts.map +0 -1
- package/build/devtools.js +0 -13
- package/build/devtools.js.map +0 -1
- package/build/internal.d.ts +0 -67
- package/build/internal.d.ts.map +0 -1
- package/build/internal.js +0 -90
- package/build/internal.js.map +0 -1
- package/src/devtools.ts +0 -13
- package/src/internal.ts +0 -160
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import BluetoothSdk from "@mentra/bluetooth-sdk
|
|
2
|
-
import
|
|
1
|
+
import BluetoothSdk, {type OtaUpdateInfo} from "@mentra/bluetooth-sdk"
|
|
2
|
+
import {ENGINE_RELEASE_METADATA} from "../generated/releaseMetadata"
|
|
3
3
|
import {getGlassesSystemTimeMs, isGlassesConnected, useGlassesStore, waitForGlassesState} from "../stores/glasses"
|
|
4
|
-
import {SETTINGS, useSettingsStore} from "../stores/settings"
|
|
5
4
|
import {maybeFixGlassesClockFromVersionInfo} from "./glassesClockSync"
|
|
6
|
-
import {resolveOtaManifestUrl} from "./otaManifestUrl"
|
|
5
|
+
import {hasConfiguredModernOtaManifestPin, resolveOtaManifestUrl} from "./otaManifestUrl"
|
|
6
|
+
import {resolveOtaReleaseVersion} from "./otaReleaseVersion"
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Phone-side mirror of ASG's `DOWNGRADE_FLOOR_VERSION_CODE`. Set to the versionCode of the first
|
|
@@ -39,6 +39,7 @@ export interface BesFirmware {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export interface VersionJson {
|
|
42
|
+
releaseVersion?: string
|
|
42
43
|
apps?: {
|
|
43
44
|
[packageName: string]: VersionInfo
|
|
44
45
|
}
|
|
@@ -67,6 +68,8 @@ export interface OtaCheckResult {
|
|
|
67
68
|
* instead of racing it with a second fetch of the same URL.
|
|
68
69
|
*/
|
|
69
70
|
manifestBody: string | null
|
|
71
|
+
/** Coordinated release identity for the selected OTA pin. */
|
|
72
|
+
releaseVersion: string | null
|
|
70
73
|
/**
|
|
71
74
|
* Why the check failed, when it did. "network" is retryable (connection/server
|
|
72
75
|
* trouble); "pin_unavailable" is permanent for this app build (manifest 404/gone,
|
|
@@ -107,6 +110,7 @@ function emptyCheckResult(skippedReason?: OtaCheckSkippedReason): OtaCheckCurren
|
|
|
107
110
|
besVersion: null,
|
|
108
111
|
isApkDowngrade: false,
|
|
109
112
|
manifestBody: null,
|
|
113
|
+
releaseVersion: null,
|
|
110
114
|
updateInfo: null,
|
|
111
115
|
isRequired: true,
|
|
112
116
|
skippedReason,
|
|
@@ -123,20 +127,23 @@ async function fetchVersionInfoDetailed(url: string): Promise<ManifestFetchResul
|
|
|
123
127
|
try {
|
|
124
128
|
const response = await fetch(url)
|
|
125
129
|
if (!response.ok) {
|
|
126
|
-
console.
|
|
130
|
+
console.warn("Failed to fetch version info:", response.status)
|
|
127
131
|
// 4xx: the manifest does not exist (or is gone) — permanent for this app
|
|
128
132
|
// build, retrying cannot help. Everything else is transient server/network
|
|
129
133
|
// trouble and retryable.
|
|
130
|
-
return {
|
|
134
|
+
return {
|
|
135
|
+
json: null,
|
|
136
|
+
failureReason: response.status >= 400 && response.status < 500 ? "pin_unavailable" : "network",
|
|
137
|
+
}
|
|
131
138
|
}
|
|
132
139
|
try {
|
|
133
140
|
return {json: await response.json()}
|
|
134
141
|
} catch (parseError) {
|
|
135
|
-
console.
|
|
142
|
+
console.warn("OTA: manifest is not valid JSON:", parseError)
|
|
136
143
|
return {json: null, failureReason: "pin_unavailable"}
|
|
137
144
|
}
|
|
138
145
|
} catch (error) {
|
|
139
|
-
console.
|
|
146
|
+
console.warn("OTA: Error fetching version info:", error)
|
|
140
147
|
return {json: null, failureReason: "network"}
|
|
141
148
|
}
|
|
142
149
|
}
|
|
@@ -194,12 +201,7 @@ export function getApkUpdateDirection(
|
|
|
194
201
|
// Downgrades require an exact pin AND a target at/above the enabled floor. A non-positive floor
|
|
195
202
|
// disables downgrades entirely, matching ASG's fail-closed DowngradeGate — so the phone never
|
|
196
203
|
// offers what the glasses would refuse.
|
|
197
|
-
if (
|
|
198
|
-
serverVersion < currentVersion &&
|
|
199
|
-
exactPin &&
|
|
200
|
-
floorVersionCode > 0 &&
|
|
201
|
-
serverVersion >= floorVersionCode
|
|
202
|
-
) {
|
|
204
|
+
if (serverVersion < currentVersion && exactPin && floorVersionCode > 0 && serverVersion >= floorVersionCode) {
|
|
203
205
|
return "downgrade"
|
|
204
206
|
}
|
|
205
207
|
return null
|
|
@@ -301,6 +303,7 @@ export async function checkForOtaUpdate(
|
|
|
301
303
|
besVersion: null,
|
|
302
304
|
isApkDowngrade: false,
|
|
303
305
|
manifestBody: null,
|
|
306
|
+
releaseVersion: null,
|
|
304
307
|
checkFailureReason: fetched.failureReason ?? "network",
|
|
305
308
|
}
|
|
306
309
|
}
|
|
@@ -332,6 +335,7 @@ export async function checkForOtaUpdate(
|
|
|
332
335
|
besVersion: null,
|
|
333
336
|
isApkDowngrade: false,
|
|
334
337
|
manifestBody: null,
|
|
338
|
+
releaseVersion: null,
|
|
335
339
|
checkFailureReason: "pin_unavailable",
|
|
336
340
|
}
|
|
337
341
|
}
|
|
@@ -370,6 +374,12 @@ export async function checkForOtaUpdate(
|
|
|
370
374
|
besVersion: versionJson?.bes_firmware?.version || null,
|
|
371
375
|
isApkDowngrade: apkDirection === "downgrade",
|
|
372
376
|
manifestBody: versionJson ? JSON.stringify(versionJson) : null,
|
|
377
|
+
releaseVersion: resolveOtaReleaseVersion({
|
|
378
|
+
manifestReleaseVersion: versionJson.releaseVersion,
|
|
379
|
+
manifestUrl: otaVersionUrl,
|
|
380
|
+
packagedManifestUrl: ENGINE_RELEASE_METADATA.otaManifestUrl,
|
|
381
|
+
packagedReleaseIdentity: ENGINE_RELEASE_METADATA.releaseIdentity,
|
|
382
|
+
}),
|
|
373
383
|
}
|
|
374
384
|
} catch (error) {
|
|
375
385
|
console.error("Error checking for OTA update:", error)
|
|
@@ -382,6 +392,7 @@ export async function checkForOtaUpdate(
|
|
|
382
392
|
besVersion: null,
|
|
383
393
|
isApkDowngrade: false,
|
|
384
394
|
manifestBody: null,
|
|
395
|
+
releaseVersion: null,
|
|
385
396
|
checkFailureReason: "network",
|
|
386
397
|
}
|
|
387
398
|
}
|
|
@@ -403,22 +414,19 @@ export async function checkCurrentGlassesForUpdate(
|
|
|
403
414
|
return emptyCheckResult("disconnected")
|
|
404
415
|
}
|
|
405
416
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const overrideUrl = useSettingsStore.getState().getSetting(SETTINGS.ota_version_url.key)
|
|
409
|
-
const overrideActive = superMode && typeof overrideUrl === "string" && overrideUrl.trim() !== ""
|
|
410
|
-
if (!embeddedManifestUrl && !overrideActive) {
|
|
411
|
-
console.log("OTA: check skipped - mobile app has no embedded OTA manifest pin")
|
|
417
|
+
if (!hasConfiguredModernOtaManifestPin()) {
|
|
418
|
+
console.log("OTA: check skipped - this app or Engine package has no embedded OTA manifest pin")
|
|
412
419
|
return emptyCheckResult("dev_build")
|
|
413
420
|
}
|
|
414
|
-
if (!embeddedManifestUrl) {
|
|
415
|
-
console.log("OTA: no embedded manifest pin, but super-mode manifest override is active - checking anyway")
|
|
416
|
-
}
|
|
417
421
|
|
|
418
422
|
if (refreshVersionInfo) {
|
|
419
|
-
void BluetoothSdk.requestVersionInfo()
|
|
420
|
-
|
|
421
|
-
|
|
423
|
+
void BluetoothSdk.requestVersionInfo()
|
|
424
|
+
.then((versionInfo) => {
|
|
425
|
+
useGlassesStore.getState().setGlassesInfo(versionInfo)
|
|
426
|
+
})
|
|
427
|
+
.catch((error) => {
|
|
428
|
+
console.warn("OTA: Failed to request version_info from glasses:", error)
|
|
429
|
+
})
|
|
422
430
|
}
|
|
423
431
|
|
|
424
432
|
let buildNumber = useGlassesStore.getState().buildNumber
|
|
@@ -472,7 +480,17 @@ export async function checkCurrentGlassesForUpdate(
|
|
|
472
480
|
}
|
|
473
481
|
|
|
474
482
|
const manifestUrl = resolveOtaManifestUrl(useGlassesStore.getState().otaVersionUrl, buildNumber)
|
|
475
|
-
|
|
483
|
+
if (!manifestUrl) {
|
|
484
|
+
console.log("OTA: check skipped - no OTA manifest pin resolved")
|
|
485
|
+
return emptyCheckResult("dev_build")
|
|
486
|
+
}
|
|
487
|
+
const result = await checkForOtaUpdate(
|
|
488
|
+
manifestUrl,
|
|
489
|
+
buildNumber,
|
|
490
|
+
mtkFirmwareVersion,
|
|
491
|
+
besFirmwareVersion,
|
|
492
|
+
floorVersionCode,
|
|
493
|
+
)
|
|
476
494
|
|
|
477
495
|
if (!result.hasCheckCompleted) {
|
|
478
496
|
return {
|
|
@@ -166,7 +166,7 @@ export class PhonePhotoCoordinator {
|
|
|
166
166
|
// to time out. Fail fast with a typed error.
|
|
167
167
|
//
|
|
168
168
|
// We DON'T pre-check `hasCamera` here — the canonical capability data
|
|
169
|
-
// lives in `getModelCapabilities(deviceModel)` from @mentra/
|
|
169
|
+
// lives in `getModelCapabilities(deviceModel)` from @mentra/engine and
|
|
170
170
|
// pulling that into this file would add a cross-package import. If a
|
|
171
171
|
// cameraless device receives the BLE photo command, the glasses-side
|
|
172
172
|
// handler will return a photo_response error within ~1s and the gated
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* `setActive(true)` starts the timer; each tick sends a keep-alive with a
|
|
4
4
|
* fresh ackId; `maxMissedAcks` consecutive timeouts fire `onTimeout`.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Phone-owned successor to the retired cloud stream lifecycle controller.
|
|
7
|
+
* It uses the local `LifecycleLogger` interface because pino is not a phone
|
|
8
|
+
* dependency.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export interface LifecycleLogger {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as RNFS from "@dr.pogodin/react-native-fs"
|
|
2
|
-
import {
|
|
2
|
+
import {otaLocalNetwork, type OtaLocalNetworkDownloadProgress} from "@mentra/bluetooth-sdk/ota-transport"
|
|
3
3
|
import {Buffer} from "buffer"
|
|
4
4
|
import {Platform} from "react-native"
|
|
5
5
|
import WifiManager from "react-native-wifi-reborn"
|
|
@@ -17,7 +17,7 @@ export function shouldUseScopedLocalNetwork(os: string, moduleAvailable: boolean
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function supportsScopedConnection(): boolean {
|
|
20
|
-
return shouldUseScopedLocalNetwork(Platform.OS,
|
|
20
|
+
return shouldUseScopedLocalNetwork(Platform.OS, otaLocalNetwork.isAvailable())
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function normalizeHeaders(headers?: HeadersInit): Record<string, string> {
|
|
@@ -48,25 +48,25 @@ export const localNetworkTransport = {
|
|
|
48
48
|
await WifiManager.connectToProtectedSSID(ssid, password, false, false)
|
|
49
49
|
return undefined
|
|
50
50
|
}
|
|
51
|
-
const result = await
|
|
51
|
+
const result = await otaLocalNetwork.connect(ssid, password)
|
|
52
52
|
scopedConnectionActive = true
|
|
53
53
|
return result.localAddress
|
|
54
54
|
},
|
|
55
55
|
|
|
56
56
|
async disconnect(): Promise<void> {
|
|
57
57
|
if (supportsScopedConnection()) {
|
|
58
|
-
await
|
|
58
|
+
await otaLocalNetwork.disconnect().catch(() => {})
|
|
59
59
|
}
|
|
60
60
|
scopedConnectionActive = false
|
|
61
61
|
nativeJobs.clear()
|
|
62
62
|
},
|
|
63
63
|
|
|
64
64
|
async fetch(url: string | URL | Request, init?: RequestInit, timeoutMs = 30_000): Promise<Response> {
|
|
65
|
-
if (!scopedConnectionActive || !
|
|
65
|
+
if (!scopedConnectionActive || !otaLocalNetwork.isAvailable() || typeof url !== "string") {
|
|
66
66
|
return globalThis.fetch(url, init)
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
const nativeModule =
|
|
69
|
+
const nativeModule = otaLocalNetwork
|
|
70
70
|
const id = requestId("request")
|
|
71
71
|
const signal = init?.signal
|
|
72
72
|
const cancel = () => void nativeModule.cancel(id)
|
|
@@ -92,13 +92,13 @@ export const localNetworkTransport = {
|
|
|
92
92
|
},
|
|
93
93
|
|
|
94
94
|
downloadFile(options: DownloadOptions): DownloadHandle {
|
|
95
|
-
if (!scopedConnectionActive || !
|
|
95
|
+
if (!scopedConnectionActive || !otaLocalNetwork.isAvailable()) return RNFS.downloadFile(options)
|
|
96
96
|
|
|
97
97
|
const jobId = nextJobId++
|
|
98
98
|
const id = requestId("download")
|
|
99
99
|
let began = false
|
|
100
100
|
nativeJobs.set(jobId, id)
|
|
101
|
-
const subscription =
|
|
101
|
+
const subscription = otaLocalNetwork.onDownloadProgress((event: OtaLocalNetworkDownloadProgress) => {
|
|
102
102
|
if (event.requestId !== id) return
|
|
103
103
|
if (!began) {
|
|
104
104
|
began = true
|
|
@@ -116,14 +116,15 @@ export const localNetworkTransport = {
|
|
|
116
116
|
})
|
|
117
117
|
})
|
|
118
118
|
|
|
119
|
-
const promise =
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
const promise = otaLocalNetwork
|
|
120
|
+
.download(
|
|
121
|
+
id,
|
|
122
|
+
options.fromUrl,
|
|
123
|
+
options.toFile,
|
|
124
|
+
options.headers || {},
|
|
125
|
+
options.connectionTimeout || 30_000,
|
|
126
|
+
options.readTimeout || 30_000,
|
|
127
|
+
)
|
|
127
128
|
.then((result) => {
|
|
128
129
|
if (!began) {
|
|
129
130
|
options.begin?.({
|
|
@@ -154,16 +155,16 @@ export const localNetworkTransport = {
|
|
|
154
155
|
|
|
155
156
|
stopDownload(jobId: number): void {
|
|
156
157
|
const nativeId = nativeJobs.get(jobId)
|
|
157
|
-
if (nativeId &&
|
|
158
|
+
if (nativeId && otaLocalNetwork.isAvailable()) {
|
|
158
159
|
cancelledNativeJobs.add(jobId)
|
|
159
|
-
void
|
|
160
|
+
void otaLocalNetwork.cancel(nativeId)
|
|
160
161
|
return
|
|
161
162
|
}
|
|
162
163
|
RNFS.stopDownload(jobId)
|
|
163
164
|
},
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
|
|
167
|
+
otaLocalNetwork.onNetworkLost(() => {
|
|
167
168
|
scopedConnectionActive = false
|
|
168
169
|
nativeJobs.clear()
|
|
169
170
|
})
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Push phone time to glasses only when clock skew is detected (gallery sync, OTA, etc.).
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import BluetoothSdk from "@mentra/bluetooth-sdk
|
|
5
|
+
import BluetoothSdk from "@mentra/bluetooth-sdk"
|
|
6
6
|
import {BgTimer} from "../utils/timers"
|
|
7
7
|
import {useGlassesStore} from "../stores/glasses"
|
|
8
8
|
|
|
@@ -87,6 +87,10 @@ export async function handleOtaClockSkewFromGlasses(
|
|
|
87
87
|
lastOtaClockFixAt = Date.now()
|
|
88
88
|
const {buildNumber, otaVersionUrl} = useGlassesStore.getState()
|
|
89
89
|
const manifestUrl = resolveOtaManifestUrl(otaVersionUrl, buildNumber)
|
|
90
|
+
if (!manifestUrl) {
|
|
91
|
+
console.warn("[GlassesClockSync] OTA restart skipped because this build has no manifest pin")
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
90
94
|
console.log("[GlassesClockSync] ⏰ Restarting OTA with ota_start after clock fix")
|
|
91
95
|
await BluetoothSdk.startOtaUpdate(manifestUrl)
|
|
92
96
|
return true
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Shared OTA progress watchdog timings (see progress-legacy.tsx / progress.tsx). */
|
|
2
|
-
import type {OtaProgress, OtaStatus} from "@mentra/bluetooth-sdk
|
|
2
|
+
import type {OtaProgress, OtaStatus} from "@mentra/bluetooth-sdk"
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* First glasses `build_number` (ASG `versionCode`) that uses `progress.tsx` with unified
|
|
@@ -32,6 +32,8 @@ export const PING_INTERVAL_MS = 10_000
|
|
|
32
32
|
export const QUERY_REPLY_TIMEOUT_MS = 6000
|
|
33
33
|
/** 15s lockout on the Continue button after a BES restart, to prevent an accidental tap. */
|
|
34
34
|
export const BES_CONTINUE_LOCKOUT_MS = 15_000
|
|
35
|
+
/** Fail closed if a BES reboot never reconnects; normal restarts complete in a fraction of this window. */
|
|
36
|
+
export const BES_RESTART_TIMEOUT_MS = 120_000
|
|
35
37
|
|
|
36
38
|
// --- Legacy old-build (< MINIMUM_OTA_STATUS_BUILD) OTA policy (WP 8C) ---
|
|
37
39
|
//
|
|
@@ -51,6 +53,7 @@ export const LEGACY_MTK_INSTALL_TIMEOUT_MS = MTK_INSTALL_TIMEOUT_MS + LEGACY_EXT
|
|
|
51
53
|
export const LEGACY_GLOBAL_OTA_TIMEOUT_MS = GLOBAL_OTA_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS
|
|
52
54
|
export const LEGACY_PING_INTERVAL_MS = PING_INTERVAL_MS + LEGACY_EXTRA_TIMEOUT_MS
|
|
53
55
|
export const LEGACY_BES_CONTINUE_LOCKOUT_MS = BES_CONTINUE_LOCKOUT_MS + LEGACY_EXTRA_TIMEOUT_MS
|
|
56
|
+
export const LEGACY_BES_RESTART_TIMEOUT_MS = BES_RESTART_TIMEOUT_MS + LEGACY_EXTRA_TIMEOUT_MS
|
|
54
57
|
/**
|
|
55
58
|
* After a legacy apk `install FINISHED` observed in-flight, the legacy screen held the
|
|
56
59
|
* completed state for 12s (+20s pad) so the ASG process restart settles (and fresh
|
|
@@ -122,6 +125,7 @@ export function selectOtaProtocolProfile(
|
|
|
122
125
|
export const OtaProgressMessages = {
|
|
123
126
|
stalledOrStuck: "Update may have failed. Ensure glasses have internet access and try again.",
|
|
124
127
|
globalTimeout: "Update took too long. Please try again.",
|
|
128
|
+
restartTimeout: "Glasses did not finish restarting. Restart them before trying the update again.",
|
|
125
129
|
sendOtaStartFailed: "Failed to communicate with glasses.",
|
|
126
130
|
hotspotArtifactDownloadFailed: "Could not download the update to your phone. Check phone internet and try again.",
|
|
127
131
|
hotspotArtifactVerifyFailed: "The update package could not be verified. Please try again later.",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {OtaProgress, OtaProgressStatus, OtaStatus} from "@mentra/bluetooth-sdk
|
|
1
|
+
import type {OtaProgress, OtaProgressStatus, OtaStatus} from "@mentra/bluetooth-sdk"
|
|
2
2
|
|
|
3
3
|
/** Normalized ota_status fields (snake_case) after bridging Core/expo (snake or camel). */
|
|
4
4
|
export type NormalizedOtaStatusEvent = {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const OTA_VERSION_URL_LEGACY_PROD = "https://ota.mentraglass.com/prod_live_version.json"
|
|
2
|
+
|
|
3
|
+
function trimmed(value?: string | null): string | null {
|
|
4
|
+
const result = value?.trim()
|
|
5
|
+
return result || null
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function isLegacyAsgOtaStartBuild(glassesBuildNumber?: string | null): boolean {
|
|
9
|
+
const buildNumber = Number.parseInt(glassesBuildNumber ?? "", 10)
|
|
10
|
+
return Number.isFinite(buildNumber) && buildNumber < 39
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function selectModernOtaManifestPin({
|
|
14
|
+
developerOverride,
|
|
15
|
+
hostReleasePin,
|
|
16
|
+
engineReleasePin,
|
|
17
|
+
}: {
|
|
18
|
+
developerOverride?: string | null
|
|
19
|
+
hostReleasePin?: string | null
|
|
20
|
+
engineReleasePin?: string | null
|
|
21
|
+
}): string | null {
|
|
22
|
+
return trimmed(developerOverride) || trimmed(hostReleasePin) || trimmed(engineReleasePin)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function resolveOtaManifestPolicy({
|
|
26
|
+
glassesUrl,
|
|
27
|
+
glassesBuildNumber,
|
|
28
|
+
developerOverride,
|
|
29
|
+
hostReleasePin,
|
|
30
|
+
engineReleasePin,
|
|
31
|
+
}: {
|
|
32
|
+
glassesUrl?: string | null
|
|
33
|
+
glassesBuildNumber?: string | null
|
|
34
|
+
developerOverride?: string | null
|
|
35
|
+
hostReleasePin?: string | null
|
|
36
|
+
engineReleasePin?: string | null
|
|
37
|
+
}): string | null {
|
|
38
|
+
if (isLegacyAsgOtaStartBuild(glassesBuildNumber)) {
|
|
39
|
+
return trimmed(glassesUrl) || OTA_VERSION_URL_LEGACY_PROD
|
|
40
|
+
}
|
|
41
|
+
return selectModernOtaManifestPin({developerOverride, hostReleasePin, engineReleasePin})
|
|
42
|
+
}
|
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {ENGINE_RELEASE_METADATA} from "../generated/releaseMetadata"
|
|
3
2
|
import {SETTINGS, useSettingsStore} from "../stores/settings"
|
|
4
|
-
|
|
5
|
-
// Legacy production manifest — pre-39 glasses install from this (they ignore ota_start's URL).
|
|
6
|
-
const OTA_VERSION_URL_LEGACY_PROD = "https://ota.mentraglass.com/prod_live_version.json"
|
|
7
|
-
// Modern production fleet manifest (v2). Only a last-resort fallback when the SDK-derived pin
|
|
8
|
-
// URL is somehow unavailable; modern glasses honor ota_start's URL, so this must be the v2
|
|
9
|
-
// artifact, not the legacy v1 rescue manifest.
|
|
10
|
-
const OTA_VERSION_URL_PROD = "https://ota.mentraglass.com/prod_live_version_v2.json"
|
|
11
|
-
|
|
12
|
-
function isLegacyAsgOtaStartBuild(glassesBuildNumber?: string | null): boolean {
|
|
13
|
-
const buildNumber = Number.parseInt(glassesBuildNumber ?? "", 10)
|
|
14
|
-
// ASG builds before 39 ignore ota_start.ota_version_url, so compare against
|
|
15
|
-
// the URL they will actually use.
|
|
16
|
-
return Number.isFinite(buildNumber) && buildNumber < 39
|
|
17
|
-
}
|
|
3
|
+
import {resolveOtaManifestPolicy, selectModernOtaManifestPin} from "./otaManifestPolicy"
|
|
18
4
|
|
|
19
5
|
function getOtaVersionUrlDevOverride(): string | null {
|
|
20
6
|
// Super mode only: a wrong OTA manifest can brick glasses, so a saved
|
|
@@ -27,27 +13,32 @@ function getOtaVersionUrlDevOverride(): string | null {
|
|
|
27
13
|
return trimmed || null
|
|
28
14
|
}
|
|
29
15
|
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// compiled default, so the developer override does not apply to them either.
|
|
35
|
-
return deviceUrl || OTA_VERSION_URL_LEGACY_PROD
|
|
36
|
-
}
|
|
16
|
+
function getHostReleasePin(): string | null {
|
|
17
|
+
const value = process.env.EXPO_PUBLIC_ASG_OTA_VERSION_URL?.trim()
|
|
18
|
+
return value || null
|
|
19
|
+
}
|
|
37
20
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
21
|
+
function getEmbeddedEngineReleasePin(): string | null {
|
|
22
|
+
const value = ENGINE_RELEASE_METADATA.otaManifestUrl?.trim()
|
|
23
|
+
return value || null
|
|
24
|
+
}
|
|
42
25
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
26
|
+
export function hasConfiguredModernOtaManifestPin(): boolean {
|
|
27
|
+
return Boolean(
|
|
28
|
+
selectModernOtaManifestPin({
|
|
29
|
+
developerOverride: getOtaVersionUrlDevOverride(),
|
|
30
|
+
hostReleasePin: getHostReleasePin(),
|
|
31
|
+
engineReleasePin: getEmbeddedEngineReleasePin(),
|
|
32
|
+
}),
|
|
33
|
+
)
|
|
34
|
+
}
|
|
47
35
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
export function resolveOtaManifestUrl(glassesUrl?: string | null, glassesBuildNumber?: string | null): string | null {
|
|
37
|
+
return resolveOtaManifestPolicy({
|
|
38
|
+
glassesUrl,
|
|
39
|
+
glassesBuildNumber,
|
|
40
|
+
developerOverride: getOtaVersionUrlDevOverride(),
|
|
41
|
+
hostReleasePin: getHostReleasePin(),
|
|
42
|
+
engineReleasePin: getEmbeddedEngineReleasePin(),
|
|
43
|
+
})
|
|
53
44
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const COORDINATED_RELEASE_VERSION = /^\d+\.\d+\.\d+(?:-(?:dev|beta)\.[1-9]\d*)?$/
|
|
2
|
+
|
|
3
|
+
type OtaReleaseVersionInput = {
|
|
4
|
+
manifestReleaseVersion?: string | null
|
|
5
|
+
manifestUrl: string
|
|
6
|
+
packagedManifestUrl?: string | null
|
|
7
|
+
packagedReleaseIdentity?: string | null
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function validReleaseVersion(version: string | null | undefined): string | null {
|
|
11
|
+
const trimmed = version?.trim()
|
|
12
|
+
return trimmed && COORDINATED_RELEASE_VERSION.test(trimmed) ? trimmed : null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Resolve the label for the selected OTA pin, including stable promotion of exact beta OTA bytes. */
|
|
16
|
+
export function resolveOtaReleaseVersion(input: OtaReleaseVersionInput): string | null {
|
|
17
|
+
const packagedRelease = validReleaseVersion(input.packagedReleaseIdentity)
|
|
18
|
+
if (packagedRelease && input.packagedManifestUrl?.trim() === input.manifestUrl.trim()) {
|
|
19
|
+
return packagedRelease
|
|
20
|
+
}
|
|
21
|
+
return validReleaseVersion(input.manifestReleaseVersion)
|
|
22
|
+
}
|
package/src/stores/apps.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {islandNotifications} from "../services/NotificationsEmitter"
|
|
|
25
25
|
import sttModelManager from "../services/STTModelManager"
|
|
26
26
|
import {miniappLauncher} from "../services/MiniappLauncher"
|
|
27
27
|
import {miniappRunningRegistry} from "../services/MiniappRunningRegistry"
|
|
28
|
+
import {resolveHiddenStatus} from "./appVisibility"
|
|
28
29
|
import {SETTINGS, useSettingsStore} from "./settings"
|
|
29
30
|
import BluetoothSdk from "@mentra/bluetooth-sdk"
|
|
30
31
|
|
|
@@ -221,7 +222,12 @@ function projectApps(previousState: AppStatusState, localApps: ClientApp[]): Cli
|
|
|
221
222
|
...app,
|
|
222
223
|
screenshot: previousByPackage.get(app.packageName)?.screenshot ?? app.screenshot,
|
|
223
224
|
compatibility: HardwareCompatibility.checkCompatibility(app.hardwareRequirements, capabilities),
|
|
224
|
-
|
|
225
|
+
// A registry source can force an app off the primary home screen (for
|
|
226
|
+
// example, Miniapp Developer while its home-screen setting is disabled).
|
|
227
|
+
// Compose that gate with the user's persisted home-screen layout instead
|
|
228
|
+
// of replacing it, otherwise a default-false persisted value makes a
|
|
229
|
+
// source-hidden app visible again during projection.
|
|
230
|
+
hidden: resolveHiddenStatus(app.hidden, previousState.getHiddenStatus(app.packageName)),
|
|
225
231
|
// Derive the foreground flag from the store's single source of truth
|
|
226
232
|
// (`foregroundedPackage`), NOT from the previous snapshot. Carrying it over
|
|
227
233
|
// per-app meant a refresh that momentarily omitted an app (e.g. the
|
package/src/stores/core.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {create} from "zustand"
|
|
2
2
|
import {subscribeWithSelector} from "zustand/middleware"
|
|
3
|
-
import type {
|
|
3
|
+
import type {PublicBluetoothStatus} from "@mentra/bluetooth-sdk"
|
|
4
4
|
|
|
5
|
-
export interface CoreState extends
|
|
6
|
-
setCoreInfo: (info: Partial<
|
|
5
|
+
export interface CoreState extends PublicBluetoothStatus {
|
|
6
|
+
setCoreInfo: (info: Partial<PublicBluetoothStatus>) => void
|
|
7
7
|
reset: () => void
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const initialState:
|
|
10
|
+
const initialState: PublicBluetoothStatus = {
|
|
11
11
|
// state:
|
|
12
12
|
searching: false,
|
|
13
13
|
searchingController: false,
|
package/src/stores/glasses.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
GlassesConnectionStatus,
|
|
3
|
-
GlassesStatus,
|
|
4
3
|
HotspotStatus,
|
|
5
4
|
OtaProgress,
|
|
6
5
|
OtaStatus,
|
|
7
6
|
OtaUpdateInfo,
|
|
7
|
+
PublicGlassesStatus,
|
|
8
8
|
WifiStatus,
|
|
9
|
-
} from "@mentra/bluetooth-sdk
|
|
9
|
+
} from "@mentra/bluetooth-sdk"
|
|
10
10
|
import {isGlassesConnected, isGlassesLinkLayerBusy, isGlassesReady} from "../services/GlassesReadiness"
|
|
11
11
|
import {create} from "zustand"
|
|
12
12
|
import {subscribeWithSelector} from "zustand/middleware"
|
|
@@ -20,7 +20,14 @@ export const selectGlassesConnected = (state: {connection: GlassesConnectionStat
|
|
|
20
20
|
|
|
21
21
|
export const selectGlassesReady = (state: {connection: GlassesConnectionStatus}) => isGlassesReady(state.connection)
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
type EngineGlassesStatus = PublicGlassesStatus & {
|
|
24
|
+
otaUpdateAvailable: OtaUpdateInfo | null
|
|
25
|
+
otaProgress: OtaProgress | null
|
|
26
|
+
otaInProgress: boolean
|
|
27
|
+
otaVersionUrl: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface GlassesState extends EngineGlassesStatus {
|
|
24
31
|
systemTimeMs: number
|
|
25
32
|
wifiStatusKnown: boolean
|
|
26
33
|
setGlassesInfo: (info: GlassesInfoUpdate) => void
|
|
@@ -53,7 +60,7 @@ type LegacyHotspotFields = {
|
|
|
53
60
|
hotspotLocalIp?: string
|
|
54
61
|
}
|
|
55
62
|
|
|
56
|
-
type GlassesInfoUpdate = Partial<
|
|
63
|
+
type GlassesInfoUpdate = Partial<EngineGlassesStatus> & LegacyWifiFields & LegacyHotspotFields
|
|
57
64
|
|
|
58
65
|
function wifiFromLegacyFields(info: LegacyWifiFields): WifiStatus | null {
|
|
59
66
|
if (info.wifiConnected === true) {
|
|
@@ -80,7 +87,7 @@ function hotspotFromLegacyFields(info: LegacyHotspotFields): HotspotStatus | nul
|
|
|
80
87
|
return null
|
|
81
88
|
}
|
|
82
89
|
|
|
83
|
-
export const getGlasesInfoPartial = (state:
|
|
90
|
+
export const getGlasesInfoPartial = (state: EngineGlassesStatus) => {
|
|
84
91
|
const wifi = state.wifi
|
|
85
92
|
const connected = isGlassesConnected(state.connection)
|
|
86
93
|
return {
|
|
@@ -98,7 +105,7 @@ export const getGlasesInfoPartial = (state: GlassesStatus) => {
|
|
|
98
105
|
}
|
|
99
106
|
}
|
|
100
107
|
|
|
101
|
-
interface GlassesStore extends
|
|
108
|
+
interface GlassesStore extends EngineGlassesStatus {
|
|
102
109
|
systemTimeMs: number
|
|
103
110
|
mtkUpdatedThisSession: boolean
|
|
104
111
|
wifiStatusKnown: boolean
|
package/src/stores/settings.ts
CHANGED
|
@@ -994,9 +994,9 @@ export const useSettingsStore = create<SettingsState>()(
|
|
|
994
994
|
// easy to get backwards. TestFlight and the App Store receive the SAME
|
|
995
995
|
// binary, so promotion does not change EXPO_PUBLIC_BUILD_ENV and this
|
|
996
996
|
// reset never fires on it. Promotion is safe for a different reason:
|
|
997
|
-
// the publishing lane bakes
|
|
998
|
-
//
|
|
999
|
-
//
|
|
997
|
+
// the publishing lane bakes the selected release cloud environment, and
|
|
998
|
+
// production promotes the already-tested binary. The same holds for
|
|
999
|
+
// Android beta-track to production.
|
|
1000
1000
|
//
|
|
1001
1001
|
// The residual gap is therefore an override pinned while already on a
|
|
1002
1002
|
// prod-labelled build, which no label comparison can see. That is a
|
package/src/types/applet.ts
CHANGED
|
@@ -82,6 +82,9 @@ export const evenRealitiesG2: Capabilities = {
|
|
|
82
82
|
// WiFi capabilities - G2 does not support WiFi
|
|
83
83
|
hasWifi: false,
|
|
84
84
|
|
|
85
|
+
// OTA capabilities - G2 firmware updates are not driven by the ASG OTA flow
|
|
86
|
+
hasOta: false,
|
|
87
|
+
|
|
85
88
|
// Dashboard - G2 renders Even Realities' native dashboard in firmware, so
|
|
86
89
|
// MentraOS does not manage the dashboard or expose dashboard settings for it
|
|
87
90
|
hasNativeDashboard: true,
|