@mentra/bluetooth-sdk 3.2.0-dev.200 → 3.2.0-dev.203
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 +46 -45
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +5 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +63 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +5 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedChangelogCatalog.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedReleaseMetadata.kt +5 -5
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +285 -29
- package/android/src/main/java/com/mentra/bluetoothsdk/MessageAckPolicy.kt +4 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/WifiRequestResolution.kt +246 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/ClassicAudioConnectionTracker.kt +104 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +312 -45
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +2 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +14 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/GlassesStatusClassicAudioTest.kt +14 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/MessageAckPolicyTest.kt +16 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/WifiRequestResolutionTest.kt +271 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/ClassicAudioConnectionTrackerTest.kt +131 -0
- package/build/BluetoothSdk.types.d.ts +62 -1
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +3 -2
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/generated/changelogCatalog.d.ts +1 -1
- package/build/generated/changelogCatalog.js +1 -1
- package/build/generated/changelogCatalog.js.map +1 -1
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -0
- package/build/index.js.map +1 -1
- package/ios/BluetoothSdkModule.swift +8 -2
- package/ios/Source/BluetoothSdkDefaults.swift +1 -1
- package/ios/Source/Bridge.swift +63 -0
- package/ios/Source/DeviceManager.swift +6 -3
- package/ios/Source/GeneratedChangelogCatalog.swift +1 -1
- package/ios/Source/GeneratedReleaseMetadata.swift +5 -5
- package/ios/Source/MentraBluetoothSDK.swift +365 -93
- package/ios/Source/WifiRequestResolution.swift +251 -0
- package/ios/Source/sgcs/MentraLive.swift +170 -35
- package/ios/Source/sgcs/SGCManager.swift +13 -1
- package/ios/Source/status/DeviceStatus.swift +28 -0
- package/ios/Tests/WifiRequestResolutionTests.swift +320 -0
- package/package.json +1 -1
- package/src/BluetoothSdk.types.ts +76 -1
- package/src/_private/BluetoothSdkModule.ts +4 -1
- package/src/generated/changelogCatalog.ts +1 -1
- package/src/generated/releaseMetadata.ts +5 -5
- package/src/index.ts +11 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
package com.mentra.bluetoothsdk.sgcs
|
|
2
|
+
|
|
3
|
+
internal enum class ClassicAudioProfile {
|
|
4
|
+
A2DP,
|
|
5
|
+
HEADSET,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** A confirmed connection is sufficient; declaring disconnection requires both profile reads. */
|
|
9
|
+
internal fun readyClassicAudioSnapshot(states: Map<ClassicAudioProfile, Boolean>): Set<ClassicAudioProfile>? {
|
|
10
|
+
val connected = states.filterValues { it }.keys
|
|
11
|
+
return if (connected.isNotEmpty() || states.size == ClassicAudioProfile.entries.size) connected else null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Tracks the Android Classic audio profiles for one dual-mode glasses device.
|
|
16
|
+
*
|
|
17
|
+
* Android reports A2DP and HFP independently. Keeping both states prevents an A2DP disconnect from
|
|
18
|
+
* publishing a false negative while HFP is still connected. Snapshot tickets reject obsolete
|
|
19
|
+
* queries, including a previous session with the same MAC address. Broadcast payloads are not truth.
|
|
20
|
+
*/
|
|
21
|
+
internal class ClassicAudioConnectionTracker(
|
|
22
|
+
private val onConnectedChanged: (Boolean) -> Unit,
|
|
23
|
+
) {
|
|
24
|
+
private var targetAddress: String? = null
|
|
25
|
+
private var revision = 0L
|
|
26
|
+
private val connectedProfiles = mutableSetOf<ClassicAudioProfile>()
|
|
27
|
+
|
|
28
|
+
@get:Synchronized
|
|
29
|
+
val connected: Boolean
|
|
30
|
+
get() = connectedProfiles.isNotEmpty()
|
|
31
|
+
|
|
32
|
+
@Synchronized
|
|
33
|
+
fun setTarget(address: String) {
|
|
34
|
+
val normalizedAddress = address.normalizedBluetoothAddress()
|
|
35
|
+
revision++
|
|
36
|
+
if (targetAddress == normalizedAddress) return
|
|
37
|
+
|
|
38
|
+
targetAddress = normalizedAddress
|
|
39
|
+
clearConnectedProfiles()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Synchronized
|
|
43
|
+
fun beginSnapshot(address: String): Long? {
|
|
44
|
+
if (targetAddress != address.normalizedBluetoothAddress()) return null
|
|
45
|
+
return ++revision
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Both profile queries must belong to the newest request for this session. */
|
|
49
|
+
@Synchronized
|
|
50
|
+
fun applySnapshot(
|
|
51
|
+
ticket: Long,
|
|
52
|
+
address: String,
|
|
53
|
+
profiles: Set<ClassicAudioProfile>,
|
|
54
|
+
onAccepted: () -> Unit = {},
|
|
55
|
+
): Boolean {
|
|
56
|
+
if (ticket != revision || targetAddress != address.normalizedBluetoothAddress()) return false
|
|
57
|
+
val wasConnected = this.connected
|
|
58
|
+
connectedProfiles.clear()
|
|
59
|
+
connectedProfiles.addAll(profiles)
|
|
60
|
+
publishIfChanged(wasConnected)
|
|
61
|
+
// Audio routing notifications must not race a target invalidation after validation.
|
|
62
|
+
onAccepted()
|
|
63
|
+
return true
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@Synchronized
|
|
67
|
+
fun clear(address: String): Boolean {
|
|
68
|
+
if (targetAddress != address.normalizedBluetoothAddress()) return false
|
|
69
|
+
revision++
|
|
70
|
+
clearConnectedProfiles()
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@Synchronized
|
|
75
|
+
fun invalidate(address: String): Boolean {
|
|
76
|
+
if (targetAddress != address.normalizedBluetoothAddress()) return false
|
|
77
|
+
|
|
78
|
+
targetAddress = null
|
|
79
|
+
revision++
|
|
80
|
+
clearConnectedProfiles()
|
|
81
|
+
return true
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Synchronized
|
|
85
|
+
fun reset() {
|
|
86
|
+
targetAddress = null
|
|
87
|
+
revision++
|
|
88
|
+
clearConnectedProfiles()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private fun clearConnectedProfiles() {
|
|
92
|
+
val wasConnected = connected
|
|
93
|
+
connectedProfiles.clear()
|
|
94
|
+
publishIfChanged(wasConnected)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private fun publishIfChanged(wasConnected: Boolean) {
|
|
98
|
+
if (wasConnected != connected) {
|
|
99
|
+
onConnectedChanged(connected)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private fun String.normalizedBluetoothAddress(): String = trim().uppercase()
|