@mentra/engine 3.1.0-dev.17 → 3.1.0-dev.21
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 +19 -5
- 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/facades/ota.d.ts.map +1 -1
- package/build/facades/ota.js +1 -2
- package/build/facades/ota.js.map +1 -1
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/react/MentraLiveOtaFlow.d.ts +3 -2
- package/build/react/MentraLiveOtaFlow.d.ts.map +1 -1
- package/build/react/MentraLiveOtaFlow.js +68 -345
- 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 +69 -0
- package/build/react/useMentraLiveOta.d.ts.map +1 -0
- package/build/react/useMentraLiveOta.js +485 -0
- package/build/react/useMentraLiveOta.js.map +1 -0
- 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/OtaInstallCoordinator.d.ts +22 -1
- package/build/services/OtaInstallCoordinator.d.ts.map +1 -1
- package/build/services/OtaInstallCoordinator.js +8 -8
- 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 +1 -1
- package/build/services/OtaUpdateCheckService.d.ts.map +1 -1
- package/build/services/OtaUpdateCheckService.js +6 -2
- package/build/services/OtaUpdateCheckService.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.js +1 -1
- package/build/services/glassesClockSync.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/package.json +12 -6
- package/src/bluetooth-sdk/ota-transport.ts +1 -0
- package/src/facades/ota.ts +1 -2
- package/src/generated/releaseMetadata.ts +5 -5
- package/src/react/MentraLiveOtaFlow.tsx +116 -466
- package/src/react/index.ts +13 -0
- package/src/react/useMentraLiveOta.ts +619 -0
- package/src/services/GlassesStatusProjection.ts +7 -6
- package/src/services/HotspotOtaTransport.ts +8 -7
- package/src/services/OtaInstallCoordinator.ts +10 -9
- package/src/services/OtaService.ts +1 -2
- package/src/services/OtaUpdateCheckService.ts +8 -5
- package/src/services/asg/localNetworkTransport.ts +20 -19
- package/src/services/glassesClockSync.ts +1 -1
- package/src/stores/core.ts +4 -4
- package/src/stores/glasses.ts +13 -6
|
@@ -1,27 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable react-native/no-raw-text -- BodyText and PercentText are local Text wrappers. */
|
|
2
|
+
import React, {useMemo} from "react"
|
|
2
3
|
import {ActivityIndicator, Pressable, StyleSheet, Text, View, type StyleProp, type ViewStyle} from "react-native"
|
|
3
4
|
import {SafeAreaView} from "react-native-safe-area-context"
|
|
4
5
|
import Svg, {Path, Rect} from "react-native-svg"
|
|
5
6
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
clearOtaAutoChainReconnectWait,
|
|
10
|
-
isOtaAutoChainActive,
|
|
11
|
-
otaAutoChainFingerprint,
|
|
12
|
-
otaAutoChainReconnectWaitRemaining,
|
|
13
|
-
stopOtaAutoChain,
|
|
14
|
-
tryAdvanceOtaAutoChain,
|
|
15
|
-
} from "../services/OtaAutoChain"
|
|
16
|
-
import {
|
|
17
|
-
BES_INSTALL_RESTART_MESSAGE,
|
|
18
|
-
getOtaErrorMessage,
|
|
19
|
-
shouldRequireGlassesRebootForBesFailure,
|
|
20
|
-
shouldShowChangeWifiForOtaDownloadFailure,
|
|
21
|
-
} from "../services/OtaErrorMapping"
|
|
22
|
-
import {useEngineSnapshot} from "./useEngineSnapshot"
|
|
23
|
-
|
|
24
|
-
export type MentraLiveOtaFlowPage = "check" | "progress"
|
|
7
|
+
import {useMentraLiveOta, type MentraLiveOtaController, type MentraLiveOtaFlowPage} from "./useMentraLiveOta"
|
|
8
|
+
|
|
9
|
+
export type {MentraLiveOtaFlowPage} from "./useMentraLiveOta"
|
|
25
10
|
|
|
26
11
|
export type MentraLiveOtaFlowTheme = {
|
|
27
12
|
background: string
|
|
@@ -40,7 +25,7 @@ export type MentraLiveOtaFlowProps = {
|
|
|
40
25
|
deviceName?: string
|
|
41
26
|
/** Entry page. `progress` exists for recovery/deep-link compatibility. */
|
|
42
27
|
initialPage?: MentraLiveOtaFlowPage
|
|
43
|
-
/** Start the OTA-only projections. Full
|
|
28
|
+
/** Start the OTA-only projections. Full Engine hosts should pass false. */
|
|
44
29
|
initializeRuntime?: boolean
|
|
45
30
|
/** Called after the final check or when the user leaves an optional update. */
|
|
46
31
|
onFinished: () => void
|
|
@@ -59,11 +44,6 @@ export type MentraLiveOtaFlowProps = {
|
|
|
59
44
|
style?: StyleProp<ViewStyle>
|
|
60
45
|
}
|
|
61
46
|
|
|
62
|
-
type CheckState = "checking" | "update_available" | "no_update" | "dev_build" | "error"
|
|
63
|
-
|
|
64
|
-
const AUTO_CHAIN_NETWORK_RETRY_DELAY_MS = 5000
|
|
65
|
-
const AUTO_CHAIN_COMPLETE_DELAY_MS = 750
|
|
66
|
-
|
|
67
47
|
const DEFAULT_THEME: MentraLiveOtaFlowTheme = {
|
|
68
48
|
background: "#FFFFFF",
|
|
69
49
|
border: "#D7DFDA",
|
|
@@ -133,29 +113,13 @@ export function MentraLiveOtaFlow({
|
|
|
133
113
|
translate = defaultTranslate,
|
|
134
114
|
}: MentraLiveOtaFlowProps) {
|
|
135
115
|
const colors = useMemo(() => ({...DEFAULT_THEME, ...theme}), [theme])
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return
|
|
144
|
-
}
|
|
145
|
-
let cancelled = false
|
|
146
|
-
setRuntimeReady(false)
|
|
147
|
-
void ota.initialize().finally(() => {
|
|
148
|
-
if (!cancelled) setRuntimeReady(true)
|
|
149
|
-
})
|
|
150
|
-
return () => {
|
|
151
|
-
cancelled = true
|
|
152
|
-
}
|
|
153
|
-
}, [initializeRuntime])
|
|
154
|
-
|
|
155
|
-
const showCheck = useCallback(() => {
|
|
156
|
-
setPage("check")
|
|
157
|
-
setCheckGeneration((generation) => generation + 1)
|
|
158
|
-
}, [])
|
|
116
|
+
const controller = useMentraLiveOta({
|
|
117
|
+
initialPage,
|
|
118
|
+
initializeRuntime,
|
|
119
|
+
onFinished,
|
|
120
|
+
onFirmwareRestartingChange,
|
|
121
|
+
onOpenWifiSetup,
|
|
122
|
+
})
|
|
159
123
|
|
|
160
124
|
return (
|
|
161
125
|
<SafeAreaView style={[styles.safeArea, {backgroundColor: colors.background}, style]}>
|
|
@@ -163,257 +127,44 @@ export function MentraLiveOtaFlow({
|
|
|
163
127
|
<View />
|
|
164
128
|
<MentraMark color={colors.primary} />
|
|
165
129
|
</View>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
deviceName={deviceName}
|
|
175
|
-
generation={checkGeneration}
|
|
176
|
-
onFinished={onFinished}
|
|
177
|
-
onOpenWifiSetup={onOpenWifiSetup}
|
|
178
|
-
onStartProgress={() => setPage("progress")}
|
|
179
|
-
translate={translate}
|
|
180
|
-
/>
|
|
181
|
-
) : (
|
|
182
|
-
<OtaProgressPage
|
|
183
|
-
colors={colors}
|
|
184
|
-
onFirmwareRestartingChange={onFirmwareRestartingChange}
|
|
185
|
-
onOpenWifiSetup={onOpenWifiSetup}
|
|
186
|
-
onReturnToCheck={showCheck}
|
|
187
|
-
superMode={superMode}
|
|
188
|
-
translate={translate}
|
|
189
|
-
/>
|
|
190
|
-
)}
|
|
130
|
+
<OtaFlowContent
|
|
131
|
+
allowDevSkip={allowDevSkip}
|
|
132
|
+
colors={colors}
|
|
133
|
+
controller={controller}
|
|
134
|
+
deviceName={deviceName}
|
|
135
|
+
superMode={superMode}
|
|
136
|
+
translate={translate}
|
|
137
|
+
/>
|
|
191
138
|
</SafeAreaView>
|
|
192
139
|
)
|
|
193
140
|
}
|
|
194
141
|
|
|
195
|
-
|
|
196
|
-
allowDevSkip: boolean
|
|
197
|
-
colors: MentraLiveOtaFlowTheme
|
|
198
|
-
deviceName: string
|
|
199
|
-
generation: number
|
|
200
|
-
onFinished: () => void
|
|
201
|
-
onOpenWifiSetup: () => void
|
|
202
|
-
onStartProgress: () => void
|
|
203
|
-
translate: MentraLiveOtaFlowTranslate
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function OtaCheckPage({
|
|
142
|
+
function OtaFlowContent({
|
|
207
143
|
allowDevSkip,
|
|
208
144
|
colors,
|
|
145
|
+
controller,
|
|
209
146
|
deviceName,
|
|
210
|
-
|
|
211
|
-
onFinished,
|
|
212
|
-
onOpenWifiSetup,
|
|
213
|
-
onStartProgress,
|
|
147
|
+
superMode,
|
|
214
148
|
translate,
|
|
215
|
-
}:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
const activeCheckKeyRef = useRef<string | null>(null)
|
|
225
|
-
const checkStartedRef = useRef(false)
|
|
226
|
-
const checkCompletedRef = useRef(false)
|
|
227
|
-
const selectedCheckResultRef = useRef<Awaited<ReturnType<typeof ota.checkForUpdates>> | null>(null)
|
|
228
|
-
const onFinishedRef = useRef(onFinished)
|
|
229
|
-
const onStartProgressRef = useRef(onStartProgress)
|
|
230
|
-
onFinishedRef.current = onFinished
|
|
231
|
-
onStartProgressRef.current = onStartProgress
|
|
232
|
-
|
|
233
|
-
const glassesWifiConnected = otaSnapshot.wifiConnected
|
|
234
|
-
const glassesWifiStatusKnown = otaSnapshot.wifiStatusKnown
|
|
235
|
-
const hotspotOtaSupported = otaSnapshot.hotspotOtaVersion === 1
|
|
236
|
-
const canInstallUpdate = glassesWifiStatusKnown && (glassesWifiConnected || hotspotOtaSupported)
|
|
237
|
-
const checkKey = `${generation}:${retryGeneration}`
|
|
238
|
-
|
|
239
|
-
const navigateToProgress = useCallback(() => {
|
|
240
|
-
ota.clearProgress()
|
|
241
|
-
onStartProgressRef.current()
|
|
242
|
-
}, [])
|
|
243
|
-
|
|
244
|
-
useEffect(() => {
|
|
245
|
-
const MIN_DISPLAY_TIME_MS = 1100
|
|
246
|
-
const MAX_WAIT_FOR_VERSION_INFO_MS = 10_000
|
|
247
|
-
if (activeCheckKeyRef.current !== checkKey) {
|
|
248
|
-
activeCheckKeyRef.current = checkKey
|
|
249
|
-
checkStartedRef.current = false
|
|
250
|
-
checkCompletedRef.current = false
|
|
251
|
-
setCheckState("checking")
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const myGeneration = ++performCheckGenerationRef.current
|
|
255
|
-
let cancelled = false
|
|
256
|
-
let reconnectTimeout: ReturnType<typeof setTimeout> | null = null
|
|
257
|
-
|
|
258
|
-
const performCheck = async () => {
|
|
259
|
-
if (checkCompletedRef.current) return
|
|
260
|
-
if (!otaSnapshot.connected) {
|
|
261
|
-
if (isOtaAutoChainActive()) {
|
|
262
|
-
const remainingMs = otaAutoChainReconnectWaitRemaining()
|
|
263
|
-
if (remainingMs === null) return
|
|
264
|
-
reconnectTimeout = setTimeout(() => {
|
|
265
|
-
if (cancelled || myGeneration !== performCheckGenerationRef.current || ota.snapshot().connected) return
|
|
266
|
-
stopOtaAutoChain()
|
|
267
|
-
checkCompletedRef.current = true
|
|
268
|
-
setCheckState("error")
|
|
269
|
-
}, remainingMs)
|
|
270
|
-
return
|
|
271
|
-
}
|
|
272
|
-
if (checkStartedRef.current) {
|
|
273
|
-
stopOtaAutoChain()
|
|
274
|
-
checkCompletedRef.current = true
|
|
275
|
-
setCheckState("error")
|
|
276
|
-
return
|
|
277
|
-
}
|
|
278
|
-
checkCompletedRef.current = true
|
|
279
|
-
onFinishedRef.current()
|
|
280
|
-
return
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
clearOtaAutoChainReconnectWait()
|
|
284
|
-
checkStartedRef.current = true
|
|
285
|
-
const startTime = Date.now()
|
|
286
|
-
try {
|
|
287
|
-
let result = await ota.checkForUpdates({
|
|
288
|
-
waitForBuildNumberMs: MAX_WAIT_FOR_VERSION_INFO_MS,
|
|
289
|
-
waitForBesVersionMs: 5000,
|
|
290
|
-
waitForMtkVersionMs: 2000,
|
|
291
|
-
refreshVersionInfo: true,
|
|
292
|
-
fixClockBeforeCheck: false,
|
|
293
|
-
})
|
|
294
|
-
if (cancelled || myGeneration !== performCheckGenerationRef.current) return
|
|
295
|
-
if (!result.hasCheckCompleted && result.checkFailureReason === "network" && isOtaAutoChainActive()) {
|
|
296
|
-
await new Promise((resolve) => setTimeout(resolve, AUTO_CHAIN_NETWORK_RETRY_DELAY_MS))
|
|
297
|
-
if (cancelled || myGeneration !== performCheckGenerationRef.current) return
|
|
298
|
-
result = await ota.checkForUpdates({
|
|
299
|
-
waitForBuildNumberMs: MAX_WAIT_FOR_VERSION_INFO_MS,
|
|
300
|
-
waitForBesVersionMs: 5000,
|
|
301
|
-
waitForMtkVersionMs: 2000,
|
|
302
|
-
refreshVersionInfo: true,
|
|
303
|
-
fixClockBeforeCheck: false,
|
|
304
|
-
})
|
|
305
|
-
}
|
|
306
|
-
if (cancelled || myGeneration !== performCheckGenerationRef.current) return
|
|
307
|
-
selectedCheckResultRef.current = result
|
|
308
|
-
await new Promise((resolve) => setTimeout(resolve, Math.max(0, MIN_DISPLAY_TIME_MS - (Date.now() - startTime))))
|
|
309
|
-
if (cancelled || myGeneration !== performCheckGenerationRef.current) return
|
|
310
|
-
|
|
311
|
-
if (result.skippedReason === "disconnected") {
|
|
312
|
-
stopOtaAutoChain()
|
|
313
|
-
checkCompletedRef.current = true
|
|
314
|
-
setCheckState("error")
|
|
315
|
-
return
|
|
316
|
-
}
|
|
317
|
-
if (result.skippedReason === "missing_build") {
|
|
318
|
-
checkCompletedRef.current = true
|
|
319
|
-
if (isOtaAutoChainActive()) {
|
|
320
|
-
stopOtaAutoChain()
|
|
321
|
-
setCheckState("error")
|
|
322
|
-
} else {
|
|
323
|
-
onFinishedRef.current()
|
|
324
|
-
}
|
|
325
|
-
return
|
|
326
|
-
}
|
|
327
|
-
if (result.skippedReason === "dev_build") {
|
|
328
|
-
stopOtaAutoChain()
|
|
329
|
-
checkCompletedRef.current = true
|
|
330
|
-
ota.clearUpdateAvailable()
|
|
331
|
-
setCheckState("dev_build")
|
|
332
|
-
return
|
|
333
|
-
}
|
|
334
|
-
if (!result.hasCheckCompleted) {
|
|
335
|
-
stopOtaAutoChain()
|
|
336
|
-
checkCompletedRef.current = true
|
|
337
|
-
setErrorKind(result.checkFailureReason === "pin_unavailable" ? "pin_unavailable" : "network")
|
|
338
|
-
setCheckState("error")
|
|
339
|
-
return
|
|
340
|
-
}
|
|
341
|
-
if (result.updateAvailable && result.updateInfo) {
|
|
342
|
-
setIsUpdateRequired(result.isRequired)
|
|
343
|
-
setIsDowngradeUpdate(result.updateInfo.isDowngrade === true)
|
|
344
|
-
const fingerprint = otaAutoChainFingerprint(result)
|
|
345
|
-
setUpdateFingerprint(fingerprint)
|
|
346
|
-
if (isOtaAutoChainActive()) {
|
|
347
|
-
const snapshot = ota.snapshot()
|
|
348
|
-
if (!snapshot.wifiStatusKnown) return
|
|
349
|
-
if (!snapshot.wifiConnected && snapshot.hotspotOtaVersion !== 1) {
|
|
350
|
-
stopOtaAutoChain()
|
|
351
|
-
} else {
|
|
352
|
-
const admission = tryAdvanceOtaAutoChain(fingerprint, result.updateInfo.isDowngrade === true)
|
|
353
|
-
if (admission.advance) {
|
|
354
|
-
checkCompletedRef.current = true
|
|
355
|
-
ota.installSession.prepare(result)
|
|
356
|
-
navigateToProgress()
|
|
357
|
-
return
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
checkCompletedRef.current = true
|
|
362
|
-
setCheckState("update_available")
|
|
363
|
-
return
|
|
364
|
-
}
|
|
365
|
-
stopOtaAutoChain()
|
|
366
|
-
checkCompletedRef.current = true
|
|
367
|
-
ota.clearUpdateAvailable()
|
|
368
|
-
setCheckState("no_update")
|
|
369
|
-
} catch (error) {
|
|
370
|
-
console.error("OTA check failed:", error)
|
|
371
|
-
await new Promise((resolve) => setTimeout(resolve, Math.max(0, MIN_DISPLAY_TIME_MS - (Date.now() - startTime))))
|
|
372
|
-
if (cancelled || myGeneration !== performCheckGenerationRef.current) return
|
|
373
|
-
stopOtaAutoChain()
|
|
374
|
-
checkCompletedRef.current = true
|
|
375
|
-
setCheckState("error")
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
void performCheck()
|
|
380
|
-
return () => {
|
|
381
|
-
cancelled = true
|
|
382
|
-
if (reconnectTimeout) clearTimeout(reconnectTimeout)
|
|
383
|
-
}
|
|
384
|
-
}, [
|
|
385
|
-
checkKey,
|
|
386
|
-
otaSnapshot.connected,
|
|
387
|
-
otaSnapshot.wifiStatusKnown,
|
|
388
|
-
navigateToProgress,
|
|
389
|
-
])
|
|
390
|
-
|
|
391
|
-
const retry = () => {
|
|
392
|
-
setCheckState("checking")
|
|
393
|
-
setRetryGeneration((value) => value + 1)
|
|
394
|
-
}
|
|
149
|
+
}: {
|
|
150
|
+
allowDevSkip: boolean
|
|
151
|
+
colors: MentraLiveOtaFlowTheme
|
|
152
|
+
controller: MentraLiveOtaController
|
|
153
|
+
deviceName: string
|
|
154
|
+
superMode: boolean
|
|
155
|
+
translate: MentraLiveOtaFlowTranslate
|
|
156
|
+
}) {
|
|
157
|
+
const {state} = controller
|
|
395
158
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
const snapshot = ota.snapshot()
|
|
403
|
-
if (!snapshot.wifiStatusKnown) {
|
|
404
|
-
retry()
|
|
405
|
-
return
|
|
406
|
-
}
|
|
407
|
-
if (!snapshot.wifiConnected && snapshot.hotspotOtaVersion !== 1) {
|
|
408
|
-
onOpenWifiSetup()
|
|
409
|
-
return
|
|
410
|
-
}
|
|
411
|
-
ota.installSession.prepare(result)
|
|
412
|
-
if (updateFingerprint) beginOtaAutoChain(updateFingerprint, isDowngradeUpdate)
|
|
413
|
-
navigateToProgress()
|
|
159
|
+
if (state.screen === "initializing") {
|
|
160
|
+
return (
|
|
161
|
+
<FlowPage colors={colors} icon="download" title={translate("ota:checkingForUpdates")}>
|
|
162
|
+
<ActivityIndicator size="large" color={colors.foreground} />
|
|
163
|
+
</FlowPage>
|
|
164
|
+
)
|
|
414
165
|
}
|
|
415
166
|
|
|
416
|
-
if (
|
|
167
|
+
if (state.screen === "checking") {
|
|
417
168
|
return (
|
|
418
169
|
<FlowPage colors={colors} icon="download" title={translate("ota:checkingForUpdates")}>
|
|
419
170
|
<BodyText colors={colors}>{translate("ota:checkingForUpdatesMessage")}</BodyText>
|
|
@@ -422,41 +173,41 @@ function OtaCheckPage({
|
|
|
422
173
|
)
|
|
423
174
|
}
|
|
424
175
|
|
|
425
|
-
if (
|
|
176
|
+
if (state.screen === "update_available" || state.screen === "wifi_required") {
|
|
426
177
|
return (
|
|
427
178
|
<FlowPage
|
|
428
179
|
colors={colors}
|
|
429
180
|
icon="download"
|
|
430
|
-
title={translate(
|
|
181
|
+
title={translate(state.versionChange ? "ota:downgradeAvailable" : "ota:updateAvailable", {deviceName})}
|
|
431
182
|
actions={
|
|
432
183
|
<>
|
|
433
184
|
<FlowButton
|
|
434
185
|
colors={colors}
|
|
435
|
-
disabled={!
|
|
436
|
-
label={translate(
|
|
437
|
-
onPress={
|
|
186
|
+
disabled={!state.wifiStatusKnown}
|
|
187
|
+
label={translate(state.screen === "wifi_required" ? "ota:setupWifi" : "ota:updateNow")}
|
|
188
|
+
onPress={state.screen === "wifi_required" ? controller.openWifiSetup : controller.install}
|
|
438
189
|
/>
|
|
439
|
-
{
|
|
440
|
-
<FlowButton colors={colors} label={translate("ota:updateLater")} onPress={
|
|
190
|
+
{state.canDismiss ? (
|
|
191
|
+
<FlowButton colors={colors} label={translate("ota:updateLater")} onPress={controller.finish} secondary />
|
|
441
192
|
) : null}
|
|
442
|
-
{allowDevSkip &&
|
|
443
|
-
<FlowButton colors={colors} label="Skip (dev only)" onPress={
|
|
193
|
+
{allowDevSkip && state.updateRequired ? (
|
|
194
|
+
<FlowButton colors={colors} label="Skip (dev only)" onPress={controller.finish} secondary />
|
|
444
195
|
) : null}
|
|
445
196
|
</>
|
|
446
197
|
}>
|
|
447
198
|
<BodyText colors={colors}>
|
|
448
|
-
{
|
|
449
|
-
? translate(
|
|
450
|
-
: translate("ota:
|
|
199
|
+
{state.screen === "wifi_required"
|
|
200
|
+
? translate("ota:updateConnectWifi", {deviceName})
|
|
201
|
+
: translate(state.versionChange ? "ota:downgradeDescription" : "ota:updateDescription")}
|
|
451
202
|
</BodyText>
|
|
452
203
|
</FlowPage>
|
|
453
204
|
)
|
|
454
205
|
}
|
|
455
206
|
|
|
456
|
-
if (
|
|
207
|
+
if (state.screen === "dev_build") {
|
|
457
208
|
return (
|
|
458
209
|
<FlowPage
|
|
459
|
-
actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={
|
|
210
|
+
actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={controller.finish} />}
|
|
460
211
|
colors={colors}
|
|
461
212
|
icon="settings"
|
|
462
213
|
title={translate("ota:devBuild")}>
|
|
@@ -465,10 +216,10 @@ function OtaCheckPage({
|
|
|
465
216
|
)
|
|
466
217
|
}
|
|
467
218
|
|
|
468
|
-
if (
|
|
219
|
+
if (state.screen === "up_to_date") {
|
|
469
220
|
return (
|
|
470
221
|
<FlowPage
|
|
471
|
-
actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={
|
|
222
|
+
actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={controller.finish} />}
|
|
472
223
|
colors={colors}
|
|
473
224
|
icon="check"
|
|
474
225
|
title={translate("ota:upToDate")}>
|
|
@@ -477,10 +228,10 @@ function OtaCheckPage({
|
|
|
477
228
|
)
|
|
478
229
|
}
|
|
479
230
|
|
|
480
|
-
if (
|
|
231
|
+
if (state.screen === "update_info_unavailable") {
|
|
481
232
|
return (
|
|
482
233
|
<FlowPage
|
|
483
|
-
actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={
|
|
234
|
+
actions={<FlowButton colors={colors} label={translate("common:continue")} onPress={controller.finish} />}
|
|
484
235
|
colors={colors}
|
|
485
236
|
icon="alert"
|
|
486
237
|
title={translate("ota:updateInfoUnavailable")}>
|
|
@@ -489,104 +240,32 @@ function OtaCheckPage({
|
|
|
489
240
|
)
|
|
490
241
|
}
|
|
491
242
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
colors: MentraLiveOtaFlowTheme
|
|
510
|
-
onFirmwareRestartingChange?: (restarting: boolean, progressActive: boolean) => void
|
|
511
|
-
onOpenWifiSetup: () => void
|
|
512
|
-
onReturnToCheck: () => void
|
|
513
|
-
superMode: boolean
|
|
514
|
-
translate: MentraLiveOtaFlowTranslate
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
function OtaProgressPage({
|
|
518
|
-
colors,
|
|
519
|
-
onFirmwareRestartingChange,
|
|
520
|
-
onOpenWifiSetup,
|
|
521
|
-
onReturnToCheck,
|
|
522
|
-
superMode,
|
|
523
|
-
translate,
|
|
524
|
-
}: ProgressPageProps) {
|
|
525
|
-
const install = useEngineSnapshot(ota.installSession.snapshot, ota.installSession.onSnapshot)
|
|
526
|
-
const autoChainAdvancedRef = useRef(false)
|
|
527
|
-
const {
|
|
528
|
-
connected,
|
|
529
|
-
continueButtonDisabled,
|
|
530
|
-
displayState,
|
|
531
|
-
errorMsg,
|
|
532
|
-
hotspotArtifactPercent,
|
|
533
|
-
hotspotPhase,
|
|
534
|
-
isVersionChange,
|
|
535
|
-
mtkInstallStallSimulatedPercent,
|
|
536
|
-
otaProgress,
|
|
537
|
-
otaStatus,
|
|
538
|
-
versionChangeConverged,
|
|
539
|
-
versionChangePhase,
|
|
540
|
-
} = install
|
|
541
|
-
const firmwareRestarting = (!connected && displayState === "restarting") || versionChangePhase === "restarting"
|
|
542
|
-
|
|
543
|
-
useEffect(() => {
|
|
544
|
-
onFirmwareRestartingChange?.(firmwareRestarting, true)
|
|
545
|
-
}, [firmwareRestarting, onFirmwareRestartingChange])
|
|
546
|
-
|
|
547
|
-
useEffect(
|
|
548
|
-
() => () => {
|
|
549
|
-
onFirmwareRestartingChange?.(false, false)
|
|
550
|
-
},
|
|
551
|
-
[onFirmwareRestartingChange],
|
|
552
|
-
)
|
|
553
|
-
|
|
554
|
-
useEffect(() => {
|
|
555
|
-
ota.installSession.attach()
|
|
556
|
-
return () => ota.installSession.detach()
|
|
557
|
-
}, [])
|
|
558
|
-
|
|
559
|
-
useEffect(() => {
|
|
560
|
-
if (displayState !== "complete" || !connected || !isOtaAutoChainActive() || autoChainAdvancedRef.current) return
|
|
561
|
-
const timeout = setTimeout(() => {
|
|
562
|
-
if (!isOtaAutoChainActive()) return
|
|
563
|
-
autoChainAdvancedRef.current = true
|
|
564
|
-
ota.installSession.finish()
|
|
565
|
-
onReturnToCheck()
|
|
566
|
-
}, AUTO_CHAIN_COMPLETE_DELAY_MS)
|
|
567
|
-
return () => clearTimeout(timeout)
|
|
568
|
-
}, [connected, displayState, onReturnToCheck])
|
|
569
|
-
|
|
570
|
-
const finishAndCheck = () => {
|
|
571
|
-
ota.installSession.finish()
|
|
572
|
-
onReturnToCheck()
|
|
573
|
-
}
|
|
574
|
-
const stopAndCheck = () => {
|
|
575
|
-
stopOtaAutoChain()
|
|
576
|
-
finishAndCheck()
|
|
577
|
-
}
|
|
578
|
-
const retryInstall = () => {
|
|
579
|
-
onFirmwareRestartingChange?.(false, true)
|
|
580
|
-
ota.installSession.retry()
|
|
243
|
+
if (state.screen === "check_failed") {
|
|
244
|
+
return (
|
|
245
|
+
<FlowPage
|
|
246
|
+
actions={
|
|
247
|
+
<>
|
|
248
|
+
<FlowButton colors={colors} label="Retry" onPress={controller.retryCheck} />
|
|
249
|
+
{allowDevSkip ? (
|
|
250
|
+
<FlowButton colors={colors} label="Skip (dev only)" onPress={controller.finish} secondary />
|
|
251
|
+
) : null}
|
|
252
|
+
</>
|
|
253
|
+
}
|
|
254
|
+
colors={colors}
|
|
255
|
+
icon="alert"
|
|
256
|
+
title={translate("ota:checkFailed")}>
|
|
257
|
+
<BodyText colors={colors}>{translate("ota:checkFailedMessage")}</BodyText>
|
|
258
|
+
</FlowPage>
|
|
259
|
+
)
|
|
581
260
|
}
|
|
582
261
|
|
|
583
|
-
if (versionChangePhase === "restarting" || versionChangePhase === "verifying") {
|
|
262
|
+
if (state.versionChangePhase === "restarting" || state.versionChangePhase === "verifying") {
|
|
584
263
|
return (
|
|
585
264
|
<FlowPage
|
|
586
265
|
colors={colors}
|
|
587
266
|
icon="download"
|
|
588
267
|
title={translate(
|
|
589
|
-
versionChangePhase === "verifying" ? "ota:versionChangeVerifying" : "ota:versionChangeRestarting",
|
|
268
|
+
state.versionChangePhase === "verifying" ? "ota:versionChangeVerifying" : "ota:versionChangeRestarting",
|
|
590
269
|
)}>
|
|
591
270
|
<ActivityIndicator size="large" color={colors.foreground} />
|
|
592
271
|
<BodyText colors={colors}>{translate("ota:versionChangeKeepNearby")}</BodyText>
|
|
@@ -595,19 +274,19 @@ function OtaProgressPage({
|
|
|
595
274
|
)
|
|
596
275
|
}
|
|
597
276
|
|
|
598
|
-
if (
|
|
599
|
-
const
|
|
600
|
-
hotspotPhase === "downloading"
|
|
277
|
+
if (state.screen === "starting" || state.screen === "preparing_hotspot") {
|
|
278
|
+
const title =
|
|
279
|
+
state.hotspotPhase === "downloading"
|
|
601
280
|
? "Downloading update to phone..."
|
|
602
|
-
: hotspotPhase === "starting_hotspot"
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
281
|
+
: state.hotspotPhase === "starting_hotspot"
|
|
282
|
+
? "Starting glasses hotspot..."
|
|
283
|
+
: state.hotspotPhase === "joining_hotspot"
|
|
284
|
+
? "Connecting phone to glasses..."
|
|
285
|
+
: "Starting update..."
|
|
607
286
|
return (
|
|
608
|
-
<FlowPage colors={colors} icon="download" title={
|
|
609
|
-
{hotspotPhase === "downloading" && hotspotArtifactPercent !== null ? (
|
|
610
|
-
<PercentText colors={colors} percent={hotspotArtifactPercent} />
|
|
287
|
+
<FlowPage colors={colors} icon="download" title={title}>
|
|
288
|
+
{state.hotspotPhase === "downloading" && state.hotspotArtifactPercent !== null ? (
|
|
289
|
+
<PercentText colors={colors} percent={state.hotspotArtifactPercent} />
|
|
611
290
|
) : null}
|
|
612
291
|
<ActivityIndicator size="large" color={colors.foreground} />
|
|
613
292
|
<BodyText colors={colors}>Do not disconnect your glasses</BodyText>
|
|
@@ -615,41 +294,34 @@ function OtaProgressPage({
|
|
|
615
294
|
)
|
|
616
295
|
}
|
|
617
296
|
|
|
618
|
-
if (
|
|
619
|
-
const isDownload = otaStatus?.phase === "download"
|
|
620
|
-
const totalSteps = otaStatus?.totalSteps ?? 1
|
|
621
|
-
const isApkOnlyInstalling = otaStatus?.stepType === "apk" && otaStatus.phase === "install" && totalSteps === 1
|
|
622
|
-
const rawPercent = isDownload
|
|
623
|
-
? otaStatus?.stepPercent ?? 0
|
|
624
|
-
: totalSteps >= 2
|
|
625
|
-
? otaStatus?.overallPercent ?? 0
|
|
626
|
-
: otaStatus?.stepPercent ?? 0
|
|
627
|
-
const percent = Math.min(Math.max(rawPercent, mtkInstallStallSimulatedPercent ?? 0, 0), 100)
|
|
297
|
+
if (state.screen === "updating") {
|
|
628
298
|
return (
|
|
629
|
-
<FlowPage colors={colors} icon="download" title={
|
|
630
|
-
{
|
|
299
|
+
<FlowPage colors={colors} icon="download" title={state.phase === "download" ? "Downloading..." : "Installing..."}>
|
|
300
|
+
{state.installingApkOnly ? (
|
|
631
301
|
<ActivityIndicator size="large" color={colors.foreground} />
|
|
632
302
|
) : (
|
|
633
303
|
<>
|
|
634
|
-
<PercentText colors={colors} percent={
|
|
304
|
+
<PercentText colors={colors} percent={state.progress ?? 0} />
|
|
635
305
|
<View style={[styles.progressTrack, {backgroundColor: colors.border}]}>
|
|
636
|
-
<View
|
|
306
|
+
<View
|
|
307
|
+
style={[styles.progressFill, {backgroundColor: colors.primary, width: `${state.progress ?? 0}%`}]}
|
|
308
|
+
/>
|
|
637
309
|
</View>
|
|
638
310
|
</>
|
|
639
311
|
)}
|
|
640
312
|
<BodyText colors={colors}>Do not disconnect your glasses</BodyText>
|
|
641
|
-
{
|
|
313
|
+
{state.versionChange && state.phase === "install" ? (
|
|
642
314
|
<BodyText colors={colors}>{translate("ota:downgradeDuration")}</BodyText>
|
|
643
315
|
) : null}
|
|
644
316
|
</FlowPage>
|
|
645
317
|
)
|
|
646
318
|
}
|
|
647
319
|
|
|
648
|
-
if (
|
|
320
|
+
if (state.screen === "restarting") {
|
|
649
321
|
return (
|
|
650
322
|
<FlowPage
|
|
651
323
|
actions={
|
|
652
|
-
<FlowButton colors={colors} disabled={
|
|
324
|
+
<FlowButton colors={colors} disabled={state.continueDisabled} label="Continue" onPress={controller.finish} />
|
|
653
325
|
}
|
|
654
326
|
colors={colors}
|
|
655
327
|
icon="check"
|
|
@@ -658,24 +330,24 @@ function OtaProgressPage({
|
|
|
658
330
|
)
|
|
659
331
|
}
|
|
660
332
|
|
|
661
|
-
if (
|
|
662
|
-
const title = versionChangeConverged
|
|
333
|
+
if (state.screen === "complete") {
|
|
334
|
+
const title = state.versionChangeConverged
|
|
663
335
|
? translate("ota:versionChangeComplete")
|
|
664
|
-
:
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
const message = versionChangeConverged
|
|
336
|
+
: state.versionChange
|
|
337
|
+
? translate("ota:versionChangeFirmwarePassComplete")
|
|
338
|
+
: "Update complete!"
|
|
339
|
+
const message = state.versionChangeConverged
|
|
668
340
|
? translate("ota:versionChangeCompleteMessage")
|
|
669
|
-
:
|
|
670
|
-
|
|
671
|
-
|
|
341
|
+
: state.versionChange
|
|
342
|
+
? translate("ota:versionChangeFirmwarePassCompleteMessage")
|
|
343
|
+
: "Your glasses are up to date."
|
|
672
344
|
return (
|
|
673
345
|
<FlowPage
|
|
674
346
|
actions={
|
|
675
347
|
<FlowButton
|
|
676
348
|
colors={colors}
|
|
677
|
-
label={
|
|
678
|
-
onPress={
|
|
349
|
+
label={state.versionChange && !state.versionChangeConverged ? "Continue" : "Done"}
|
|
350
|
+
onPress={controller.finish}
|
|
679
351
|
/>
|
|
680
352
|
}
|
|
681
353
|
colors={colors}
|
|
@@ -686,38 +358,25 @@ function OtaProgressPage({
|
|
|
686
358
|
)
|
|
687
359
|
}
|
|
688
360
|
|
|
689
|
-
if (
|
|
690
|
-
const requiresGlassesReboot = shouldRequireGlassesRebootForBesFailure(otaStatus, otaProgress, errorMsg)
|
|
691
|
-
const displayedError = requiresGlassesReboot
|
|
692
|
-
? BES_INSTALL_RESTART_MESSAGE
|
|
693
|
-
: errorMsg || getOtaErrorMessage(otaStatus?.error)
|
|
694
|
-
const showChangeWifi = shouldShowChangeWifiForOtaDownloadFailure(otaStatus, otaProgress, errorMsg)
|
|
361
|
+
if (state.screen === "failed") {
|
|
695
362
|
return (
|
|
696
363
|
<FlowPage
|
|
697
364
|
actions={
|
|
698
365
|
<>
|
|
699
366
|
<FlowButton
|
|
700
367
|
colors={colors}
|
|
701
|
-
label={
|
|
702
|
-
onPress={
|
|
368
|
+
label={state.canRetry ? "Retry" : "Done"}
|
|
369
|
+
onPress={state.canRetry ? controller.retryInstall : controller.finish}
|
|
703
370
|
/>
|
|
704
|
-
{
|
|
705
|
-
<FlowButton
|
|
706
|
-
colors={colors}
|
|
707
|
-
label="Change WiFi"
|
|
708
|
-
onPress={() => {
|
|
709
|
-
stopOtaAutoChain()
|
|
710
|
-
onOpenWifiSetup()
|
|
711
|
-
}}
|
|
712
|
-
secondary
|
|
713
|
-
/>
|
|
371
|
+
{state.canOpenWifiSetup ? (
|
|
372
|
+
<FlowButton colors={colors} label="Change WiFi" onPress={controller.openWifiSetup} secondary />
|
|
714
373
|
) : null}
|
|
715
374
|
</>
|
|
716
375
|
}
|
|
717
376
|
colors={colors}
|
|
718
377
|
icon="alert"
|
|
719
378
|
title="Update Failed">
|
|
720
|
-
<BodyText colors={colors}>{
|
|
379
|
+
<BodyText colors={colors}>{state.error?.message}</BodyText>
|
|
721
380
|
</FlowPage>
|
|
722
381
|
)
|
|
723
382
|
}
|
|
@@ -726,16 +385,7 @@ function OtaProgressPage({
|
|
|
726
385
|
<FlowPage
|
|
727
386
|
actions={
|
|
728
387
|
superMode ? (
|
|
729
|
-
<FlowButton
|
|
730
|
-
colors={colors}
|
|
731
|
-
label="Skip (super)"
|
|
732
|
-
onPress={() => {
|
|
733
|
-
stopOtaAutoChain()
|
|
734
|
-
ota.installSession.discard()
|
|
735
|
-
onReturnToCheck()
|
|
736
|
-
}}
|
|
737
|
-
secondary
|
|
738
|
-
/>
|
|
388
|
+
<FlowButton colors={colors} label="Skip (super)" onPress={controller.discard} secondary />
|
|
739
389
|
) : undefined
|
|
740
390
|
}
|
|
741
391
|
colors={colors}
|