@mentra/bluetooth-sdk 3.3.0-dev.788 → 3.3.0-dev.789
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/android/src/main/java/com/mentra/bluetoothsdk/GeneratedReleaseMetadata.kt +5 -5
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/ios/Source/BluetoothSdkDefaults.swift +1 -1
- package/ios/Source/GeneratedReleaseMetadata.swift +5 -5
- package/ios/Source/sgcs/MentraLive.swift +25 -8
- package/ios/Tests/MentraLiveSessionReadinessTests.swift +163 -0
- package/package.json +2 -2
- package/src/generated/releaseMetadata.ts +5 -5
|
@@ -3,9 +3,9 @@ package com.mentra.bluetoothsdk
|
|
|
3
3
|
/** Generated by release CI. Do not edit in a release checkout. */
|
|
4
4
|
internal object GeneratedReleaseMetadata {
|
|
5
5
|
const val FAMILY_BASE_VERSION: String = "3.3.0"
|
|
6
|
-
const val RELEASE_IDENTITY: String = "3.3.0-dev.
|
|
7
|
-
const val RELEASE_SET_ID: String = "mentra-3.3.0-dev.
|
|
8
|
-
const val SOURCE_COMMIT: String = "
|
|
9
|
-
const val OTA_MANIFEST_URL: String = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.
|
|
10
|
-
const val OTA_MANIFEST_SHA256: String = "
|
|
6
|
+
const val RELEASE_IDENTITY: String = "3.3.0-dev.789"
|
|
7
|
+
const val RELEASE_SET_ID: String = "mentra-3.3.0-dev.789"
|
|
8
|
+
const val SOURCE_COMMIT: String = "bc626e0ee83b97c82b5801c9011eb9505d5f2d38"
|
|
9
|
+
const val OTA_MANIFEST_URL: String = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.789.json"
|
|
10
|
+
const val OTA_MANIFEST_SHA256: String = "dae48e505e730394ac18761b2d7b5ebf6ac84df978d2b9691d7950c89d1ff95c"
|
|
11
11
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export const BLUETOOTH_SDK_RELEASE_METADATA = Object.freeze({
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"familyBaseVersion": "3.3.0",
|
|
4
|
-
"releaseIdentity": "3.3.0-dev.
|
|
5
|
-
"releaseSetId": "mentra-3.3.0-dev.
|
|
6
|
-
"sourceCommit": "
|
|
7
|
-
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.
|
|
8
|
-
"otaManifestSha256": "
|
|
4
|
+
"releaseIdentity": "3.3.0-dev.789",
|
|
5
|
+
"releaseSetId": "mentra-3.3.0-dev.789",
|
|
6
|
+
"sourceCommit": "bc626e0ee83b97c82b5801c9011eb9505d5f2d38",
|
|
7
|
+
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.789.json",
|
|
8
|
+
"otaManifestSha256": "dae48e505e730394ac18761b2d7b5ebf6ac84df978d2b9691d7950c89d1ff95c"
|
|
9
9
|
});
|
|
10
10
|
//# sourceMappingURL=releaseMetadata.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,sBAAsB;IACtC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,iIAAiI;IACnJ,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.3.0\",\n \"releaseIdentity\": \"3.3.0-dev.
|
|
1
|
+
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,sBAAsB;IACtC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,iIAAiI;IACnJ,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.3.0\",\n \"releaseIdentity\": \"3.3.0-dev.789\",\n \"releaseSetId\": \"mentra-3.3.0-dev.789\",\n \"sourceCommit\": \"bc626e0ee83b97c82b5801c9011eb9505d5f2d38\",\n \"otaManifestUrl\": \"https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.789.json\",\n \"otaManifestSha256\": \"dae48e505e730394ac18761b2d7b5ebf6ac84df978d2b9691d7950c89d1ff95c\"\n})\n"]}
|
|
@@ -16,7 +16,7 @@ enum BluetoothSdkDefaults {
|
|
|
16
16
|
/// silently disable it on every pair the app touches.
|
|
17
17
|
static let autoPowerOffEnabled = false
|
|
18
18
|
private static let infoSdkVersionKey = "MentraBluetoothSdkVersion"
|
|
19
|
-
private static let swiftPackageSdkVersion = "3.3.0-dev.
|
|
19
|
+
private static let swiftPackageSdkVersion = "3.3.0-dev.789"
|
|
20
20
|
private static let swiftPackageSdkVersionPlaceholder = "__MENTRA" + "_BLUETOOTH_SDK_VERSION__"
|
|
21
21
|
|
|
22
22
|
private static func normalizedSdkVersion(_ value: String?) -> String? {
|
|
@@ -3,9 +3,9 @@ import Foundation
|
|
|
3
3
|
/// Generated by release CI. Do not edit in a release checkout.
|
|
4
4
|
enum GeneratedReleaseMetadata {
|
|
5
5
|
static let familyBaseVersion = "3.3.0"
|
|
6
|
-
static let releaseIdentity = "3.3.0-dev.
|
|
7
|
-
static let releaseSetId = "mentra-3.3.0-dev.
|
|
8
|
-
static let sourceCommit = "
|
|
9
|
-
static let otaManifestUrl = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.
|
|
10
|
-
static let otaManifestSha256 = "
|
|
6
|
+
static let releaseIdentity = "3.3.0-dev.789"
|
|
7
|
+
static let releaseSetId = "mentra-3.3.0-dev.789"
|
|
8
|
+
static let sourceCommit = "bc626e0ee83b97c82b5801c9011eb9505d5f2d38"
|
|
9
|
+
static let otaManifestUrl = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.789.json"
|
|
10
|
+
static let otaManifestSha256 = "dae48e505e730394ac18761b2d7b5ebf6ac84df978d2b9691d7950c89d1ff95c"
|
|
11
11
|
}
|
|
@@ -923,7 +923,7 @@ extension MentraLive: CBCentralManagerDelegate {
|
|
|
923
923
|
self.isConnecting = false
|
|
924
924
|
|
|
925
925
|
self.connectedPeripheral = nil
|
|
926
|
-
self.
|
|
926
|
+
self.clearPhysicalReadiness()
|
|
927
927
|
self.connected = false
|
|
928
928
|
self.glassesSessionId = nil // Fresh BLE session starts with no sid known
|
|
929
929
|
self.streamControlVersion = 0
|
|
@@ -1617,6 +1617,16 @@ class MentraLive: NSObject, SGCManager {
|
|
|
1617
1617
|
set { DeviceStore.shared.apply("glasses", "connected", newValue) }
|
|
1618
1618
|
}
|
|
1619
1619
|
|
|
1620
|
+
private func clearPhysicalReadiness() {
|
|
1621
|
+
let readinessWasPending = connected && !fullyBooted
|
|
1622
|
+
fullyBooted = false
|
|
1623
|
+
if readinessWasPending {
|
|
1624
|
+
// Logical ASG readiness already emitted false without disconnecting.
|
|
1625
|
+
// The real disconnect must still perform the cleanup apply deduplicates.
|
|
1626
|
+
DeviceManager.shared.handleDeviceDisconnected()
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1620
1630
|
// Queue Management
|
|
1621
1631
|
private let commandQueue = CommandQueue()
|
|
1622
1632
|
private let bluetoothQueue = DispatchQueue(label: "MentraLiveBluetooth", qos: .userInitiated)
|
|
@@ -1744,8 +1754,8 @@ class MentraLive: NSObject, SGCManager {
|
|
|
1744
1754
|
// Publish disconnect immediately for Phone A UI. didDisconnectPeripheral may lag
|
|
1745
1755
|
// or race with cancelPeripheralConnection; do not wait on it for stand-down.
|
|
1746
1756
|
isConnecting = false
|
|
1757
|
+
clearPhysicalReadiness()
|
|
1747
1758
|
connected = false
|
|
1748
|
-
fullyBooted = false
|
|
1749
1759
|
glassesSessionId = nil
|
|
1750
1760
|
streamControlVersion = 0
|
|
1751
1761
|
readinessCompletedThisBleSession = false
|
|
@@ -2523,8 +2533,8 @@ class MentraLive: NSObject, SGCManager {
|
|
|
2523
2533
|
Bridge.log("LIVE: Maximum reconnection attempts reached (\(MAX_RECONNECT_ATTEMPTS))")
|
|
2524
2534
|
reconnectAttempts = 0
|
|
2525
2535
|
updateConnectionState(ConnTypes.DISCONNECTED)
|
|
2536
|
+
clearPhysicalReadiness()
|
|
2526
2537
|
connected = false
|
|
2527
|
-
fullyBooted = false
|
|
2528
2538
|
glassesSessionId = nil
|
|
2529
2539
|
streamControlVersion = 0
|
|
2530
2540
|
readinessCompletedThisBleSession = false
|
|
@@ -3138,6 +3148,11 @@ class MentraLive: NSObject, SGCManager {
|
|
|
3138
3148
|
if type.hasPrefix("version_info") {
|
|
3139
3149
|
Bridge.log("LIVE: Received \(type)")
|
|
3140
3150
|
|
|
3151
|
+
// A new process can report its build before glasses_ready resets the
|
|
3152
|
+
// wire epoch. Publish its pending readiness before those version fields
|
|
3153
|
+
// can complete OTA and trigger the next request.
|
|
3154
|
+
handleGlassesSessionId(json)
|
|
3155
|
+
|
|
3141
3156
|
// Extract all fields from JSON (except "type")
|
|
3142
3157
|
var fields: [String: Any] = [:]
|
|
3143
3158
|
fields["version_info_type"] = type
|
|
@@ -3210,7 +3225,6 @@ class MentraLive: NSObject, SGCManager {
|
|
|
3210
3225
|
// running them per chunk is safe.
|
|
3211
3226
|
parsePeerWireCaps(json)
|
|
3212
3227
|
maybeSendWireHandshake()
|
|
3213
|
-
handleGlassesSessionId(json)
|
|
3214
3228
|
|
|
3215
3229
|
Bridge.sendVersionInfo(fields, responseChunk: type)
|
|
3216
3230
|
} else {
|
|
@@ -5737,7 +5751,7 @@ class MentraLive: NSObject, SGCManager {
|
|
|
5737
5751
|
stopReadinessCheckLoop()
|
|
5738
5752
|
|
|
5739
5753
|
readinessCheckCounter = 0
|
|
5740
|
-
|
|
5754
|
+
clearPhysicalReadiness()
|
|
5741
5755
|
connected = false
|
|
5742
5756
|
glassesSessionId = nil
|
|
5743
5757
|
streamControlVersion = 0
|
|
@@ -6018,8 +6032,8 @@ class MentraLive: NSObject, SGCManager {
|
|
|
6018
6032
|
centralManager?.cancelPeripheralConnection(peripheral)
|
|
6019
6033
|
}
|
|
6020
6034
|
|
|
6035
|
+
clearPhysicalReadiness()
|
|
6021
6036
|
DeviceStore.shared.apply("glasses", "connected", false)
|
|
6022
|
-
DeviceStore.shared.apply("glasses", "fullyBooted", false)
|
|
6023
6037
|
DeviceStore.shared.apply("glasses", "wifiConnected", false)
|
|
6024
6038
|
DeviceStore.shared.apply("glasses", "wifiSsid", "")
|
|
6025
6039
|
DeviceStore.shared.apply("glasses", "wifiLocalIp", "")
|
|
@@ -6156,8 +6170,8 @@ extension MentraLive {
|
|
|
6156
6170
|
/// pre-sid build) or differing from the recorded one = restart; same sid = no action.
|
|
6157
6171
|
/// A restart is a LOGICAL session reset: send phone_ready immediately (bypassing the
|
|
6158
6172
|
/// sr_hrt heartbeat's stale-readiness suppression); the returning glasses_ready runs
|
|
6159
|
-
/// the full existing remote-wire-reset flow.
|
|
6160
|
-
///
|
|
6173
|
+
/// the full existing remote-wire-reset flow. Keep the physical connection intact,
|
|
6174
|
+
/// but mark readiness pending until that new wire epoch has been established.
|
|
6161
6175
|
private func handleGlassesSessionId(_ json: [String: Any]) {
|
|
6162
6176
|
guard let sid = json["sid"] as? String, !sid.isEmpty else { return }
|
|
6163
6177
|
let previous = glassesSessionId
|
|
@@ -6172,6 +6186,9 @@ extension MentraLive {
|
|
|
6172
6186
|
"LIVE: 🔁 Glasses session changed (\(previous ?? "<pre-sid build>") -> \(sid)) - " +
|
|
6173
6187
|
"asg restarted under a live link, re-running readiness"
|
|
6174
6188
|
)
|
|
6189
|
+
// Emit the existing connected-but-not-ready status without invoking the
|
|
6190
|
+
// physical-disconnect side effects of DeviceStore.apply(fullyBooted: false).
|
|
6191
|
+
DeviceStore.shared.set("glasses", "fullyBooted", false)
|
|
6175
6192
|
sendPhoneReady(reason: "glasses session changed")
|
|
6176
6193
|
Bridge.sendTypedMessage(
|
|
6177
6194
|
"glasses_session_changed",
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
@testable import MentraBluetoothSDK
|
|
2
|
+
import XCTest
|
|
3
|
+
|
|
4
|
+
@MainActor
|
|
5
|
+
private final class SessionReadinessTransport: MentraLive {
|
|
6
|
+
var commands: [[String: Any]] = []
|
|
7
|
+
|
|
8
|
+
override func sendJson(_ jsonOriginal: [String: Any], wakeUp: Bool, requireAck: Bool) {
|
|
9
|
+
commands.append(jsonOriginal)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@MainActor
|
|
14
|
+
final class MentraLiveSessionReadinessTests: XCTestCase {
|
|
15
|
+
func testChangedSessionPublishesPendingReadinessBeforeItsBuildAndRecoversAtGlassesReady() throws {
|
|
16
|
+
let store = DeviceStore.shared.store
|
|
17
|
+
let saved = ["bluetooth", "glasses"].map { ($0, store.getCategory($0)) }
|
|
18
|
+
let previous = DeviceManager.shared.sgc
|
|
19
|
+
let transport = SessionReadinessTransport()
|
|
20
|
+
let sdk = MentraBluetoothSDK()
|
|
21
|
+
DeviceManager.shared.sgc = transport
|
|
22
|
+
var observations: [(key: String, ready: Bool, connected: Bool)] = []
|
|
23
|
+
let listener = store.addListener { category, changed in
|
|
24
|
+
guard category == "glasses" else { return }
|
|
25
|
+
for key in changed.keys where key == "fullyBooted" || key == "buildNumber" {
|
|
26
|
+
observations.append((key, sdk.glassesStatus.fullyBooted, sdk.glassesStatus.connected))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var sessionEvents: [Bool] = []
|
|
30
|
+
let sink = Bridge.addEventSink { event, body in
|
|
31
|
+
if event == "glasses_session_changed" {
|
|
32
|
+
sessionEvents.append(sdk.glassesStatus.fullyBooted)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
defer {
|
|
36
|
+
store.removeListener(listener)
|
|
37
|
+
Bridge.removeEventSink(sink)
|
|
38
|
+
sdk.invalidate()
|
|
39
|
+
transport.cleanup()
|
|
40
|
+
DeviceManager.shared.sgc = previous
|
|
41
|
+
for (category, values) in saved {
|
|
42
|
+
for key in store.getCategory(category).keys where values[key] == nil {
|
|
43
|
+
store.remove(category, key)
|
|
44
|
+
}
|
|
45
|
+
for (key, value) in values { store.set(category, key, value) }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func receive(_ value: [String: Any]) throws {
|
|
50
|
+
try transport.processReceivedData(JSONSerialization.data(withJSONObject: value))
|
|
51
|
+
}
|
|
52
|
+
try receive(["type": "glasses_ready", "sid": "original"])
|
|
53
|
+
observations.removeAll()
|
|
54
|
+
transport.commands.removeAll()
|
|
55
|
+
|
|
56
|
+
// The physical BLE link remains live across APK replacement. Its first
|
|
57
|
+
// version chunk can prove the target build before remote wire readiness.
|
|
58
|
+
try receive(["type": "version_info_1", "sid": "replacement", "build_number": "302010070"])
|
|
59
|
+
XCTAssertEqual(observations.map(\.key), ["fullyBooted", "buildNumber"])
|
|
60
|
+
XCTAssertTrue(observations.allSatisfy { !$0.ready && $0.connected })
|
|
61
|
+
XCTAssertEqual(sessionEvents, [false])
|
|
62
|
+
XCTAssertEqual(transport.commands.compactMap { $0["type"] as? String }, ["phone_ready"])
|
|
63
|
+
|
|
64
|
+
// Another chunk from the same pending process must not restart readiness.
|
|
65
|
+
try receive(["type": "version_info_3", "sid": "replacement"])
|
|
66
|
+
XCTAssertEqual(sessionEvents, [false])
|
|
67
|
+
XCTAssertFalse(sdk.glassesStatus.fullyBooted)
|
|
68
|
+
|
|
69
|
+
try receive(["type": "glasses_ready", "sid": "replacement"])
|
|
70
|
+
XCTAssertTrue(sdk.glassesStatus.connected)
|
|
71
|
+
XCTAssertTrue(sdk.glassesStatus.fullyBooted)
|
|
72
|
+
XCTAssertEqual(observations.last?.key, "fullyBooted")
|
|
73
|
+
XCTAssertEqual(observations.last?.ready, true)
|
|
74
|
+
XCTAssertEqual(transport.commands.filter { $0["type"] as? String == "request_version" }.count, 1)
|
|
75
|
+
|
|
76
|
+
observations.removeAll()
|
|
77
|
+
try receive(["type": "version_info_1", "sid": "replacement", "build_number": "302010070"])
|
|
78
|
+
XCTAssertTrue(sdk.glassesStatus.fullyBooted)
|
|
79
|
+
XCTAssertFalse(observations.contains { $0.key == "fullyBooted" })
|
|
80
|
+
XCTAssertEqual(sessionEvents, [false])
|
|
81
|
+
|
|
82
|
+
// A physical teardown before the next logical restart becomes ready must
|
|
83
|
+
// still run disconnect cleanup, even though readiness is already false.
|
|
84
|
+
try receive(["type": "version_info_1", "sid": "third", "build_number": "303000267"])
|
|
85
|
+
store.set("glasses", "headUp", true)
|
|
86
|
+
store.set("glasses", "voiceActivityDetectionEnabled", !BluetoothSdkDefaults.voiceActivityDetectionEnabled)
|
|
87
|
+
XCTAssertFalse(sdk.glassesStatus.fullyBooted)
|
|
88
|
+
XCTAssertTrue(sdk.glassesStatus.connected)
|
|
89
|
+
transport.cleanup()
|
|
90
|
+
XCTAssertFalse(sdk.glassesStatus.connected)
|
|
91
|
+
XCTAssertEqual(store.get("glasses", "headUp") as? Bool, false)
|
|
92
|
+
XCTAssertEqual(store.get("glasses", "voiceActivityDetectionEnabled") as? Bool,
|
|
93
|
+
BluetoothSdkDefaults.voiceActivityDetectionEnabled)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
func testPairingYieldDuringPendingReadinessCleansUpAndReclaimsAfterItsWindow() async throws {
|
|
97
|
+
let store = DeviceStore.shared.store
|
|
98
|
+
let saved = ["bluetooth", "glasses"].map { ($0, store.getCategory($0)) }
|
|
99
|
+
let previous = DeviceManager.shared.sgc
|
|
100
|
+
let transport = SessionReadinessTransport()
|
|
101
|
+
let sdk = MentraBluetoothSDK()
|
|
102
|
+
DeviceManager.shared.sgc = transport
|
|
103
|
+
defer {
|
|
104
|
+
sdk.invalidate()
|
|
105
|
+
transport.cleanup()
|
|
106
|
+
DeviceManager.shared.sgc = previous
|
|
107
|
+
for (category, values) in saved {
|
|
108
|
+
for key in store.getCategory(category).keys where values[key] == nil {
|
|
109
|
+
store.remove(category, key)
|
|
110
|
+
}
|
|
111
|
+
for (key, value) in values { store.set(category, key, value) }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
func receive(_ value: [String: Any]) throws {
|
|
116
|
+
try transport.processReceivedData(JSONSerialization.data(withJSONObject: value))
|
|
117
|
+
}
|
|
118
|
+
try receive(["type": "glasses_ready", "sid": "original"])
|
|
119
|
+
try receive(["type": "version_info_1", "sid": "replacement", "build_number": "302010070"])
|
|
120
|
+
XCTAssertTrue(sdk.glassesStatus.connected)
|
|
121
|
+
XCTAssertFalse(sdk.glassesStatus.fullyBooted)
|
|
122
|
+
store.set("glasses", "headUp", true)
|
|
123
|
+
store.set("glasses", "voiceActivityDetectionEnabled", !BluetoothSdkDefaults.voiceActivityDetectionEnabled)
|
|
124
|
+
|
|
125
|
+
try receive(["type": "entering_pairing_mode", "window_ms": 5000])
|
|
126
|
+
XCTAssertTrue(transport.isPairingYieldActive())
|
|
127
|
+
XCTAssertFalse(sdk.glassesStatus.connected)
|
|
128
|
+
XCTAssertFalse(sdk.glassesStatus.fullyBooted)
|
|
129
|
+
XCTAssertEqual(store.get("glasses", "headUp") as? Bool, false)
|
|
130
|
+
XCTAssertEqual(store.get("glasses", "voiceActivityDetectionEnabled") as? Bool,
|
|
131
|
+
BluetoothSdkDefaults.voiceActivityDetectionEnabled)
|
|
132
|
+
|
|
133
|
+
// Readiness queued on the relinquished GATT must not close the yield.
|
|
134
|
+
try receive(["type": "glasses_ready", "sid": "replacement"])
|
|
135
|
+
XCTAssertTrue(transport.isPairingYieldActive())
|
|
136
|
+
XCTAssertFalse(sdk.glassesStatus.fullyBooted)
|
|
137
|
+
|
|
138
|
+
// Let the existing minimum yield expire, then accept a fresh readiness.
|
|
139
|
+
try await Task.sleep(nanoseconds: 5_100_000_000)
|
|
140
|
+
XCTAssertFalse(transport.isPairingYieldActive())
|
|
141
|
+
try receive(["type": "glasses_ready", "sid": "reclaimed"])
|
|
142
|
+
XCTAssertTrue(sdk.glassesStatus.connected)
|
|
143
|
+
XCTAssertTrue(sdk.glassesStatus.fullyBooted)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
func testInitialVersionChunkDoesNotStartAnExtraReadinessExchange() throws {
|
|
147
|
+
let store = DeviceStore.shared.store
|
|
148
|
+
let saved = store.getCategory("glasses")
|
|
149
|
+
let transport = SessionReadinessTransport()
|
|
150
|
+
defer {
|
|
151
|
+
transport.cleanup()
|
|
152
|
+
for key in store.getCategory("glasses").keys where saved[key] == nil { store.remove("glasses", key) }
|
|
153
|
+
for (key, value) in saved { store.set("glasses", key, value) }
|
|
154
|
+
}
|
|
155
|
+
store.set("glasses", "fullyBooted", false)
|
|
156
|
+
try transport.processReceivedData(JSONSerialization.data(withJSONObject: [
|
|
157
|
+
"type": "version_info_1", "sid": "initial", "build_number": "303000267",
|
|
158
|
+
]))
|
|
159
|
+
XCTAssertTrue(transport.commands.isEmpty)
|
|
160
|
+
XCTAssertEqual(store.get("glasses", "buildNumber") as? String, "303000267")
|
|
161
|
+
XCTAssertEqual(store.get("glasses", "fullyBooted") as? Bool, false)
|
|
162
|
+
}
|
|
163
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/bluetooth-sdk",
|
|
3
|
-
"version": "3.3.0-dev.
|
|
3
|
+
"version": "3.3.0-dev.789",
|
|
4
4
|
"description": "SDK for communicating with smart glasses",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"registry": "https://registry.npmjs.org/"
|
|
115
115
|
},
|
|
116
116
|
"dependencies": {
|
|
117
|
-
"@mentra/cloud-protocol": "3.3.0-dev.
|
|
117
|
+
"@mentra/cloud-protocol": "3.3.0-dev.789"
|
|
118
118
|
},
|
|
119
119
|
"devDependencies": {
|
|
120
120
|
"@types/node": "^25.9.3",
|
|
@@ -12,9 +12,9 @@ export interface BluetoothSdkReleaseMetadata {
|
|
|
12
12
|
export const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({
|
|
13
13
|
"schemaVersion": 1,
|
|
14
14
|
"familyBaseVersion": "3.3.0",
|
|
15
|
-
"releaseIdentity": "3.3.0-dev.
|
|
16
|
-
"releaseSetId": "mentra-3.3.0-dev.
|
|
17
|
-
"sourceCommit": "
|
|
18
|
-
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.
|
|
19
|
-
"otaManifestSha256": "
|
|
15
|
+
"releaseIdentity": "3.3.0-dev.789",
|
|
16
|
+
"releaseSetId": "mentra-3.3.0-dev.789",
|
|
17
|
+
"sourceCommit": "bc626e0ee83b97c82b5801c9011eb9505d5f2d38",
|
|
18
|
+
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.789.json",
|
|
19
|
+
"otaManifestSha256": "dae48e505e730394ac18761b2d7b5ebf6ac84df978d2b9691d7950c89d1ff95c"
|
|
20
20
|
})
|