@mentra/bluetooth-sdk 3.3.0-dev.421 → 3.3.0-dev.422
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/BluetoothSdkModule.kt +0 -7
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +3 -17
- package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedReleaseMetadata.kt +5 -5
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +0 -11
- package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +0 -21
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +31 -213
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SerializedGattCallback.kt +2 -13
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunkReassembler.java +6 -41
- package/build/BluetoothSdk.types.d.ts +0 -10
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +0 -9
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +0 -2
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- 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/package.json +2 -2
- package/src/BluetoothSdk.types.ts +0 -10
- package/src/_private/BluetoothSdkModule.ts +0 -13
- package/src/generated/releaseMetadata.ts +5 -5
- package/android/src/main/java/com/mentra/bluetoothsdk/debug/BleEvidenceLog.kt +0 -454
- package/android/src/test/java/com/mentra/bluetoothsdk/WifiScanEvidenceTest.kt +0 -117
- package/android/src/test/java/com/mentra/bluetoothsdk/debug/BleEvidenceLogTest.kt +0 -282
- package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/MentraLiveEvidenceTest.kt +0 -603
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/MessageChunkReassemblerOriginTest.kt +0 -51
- package/build/_private/diagnosticRender.d.ts +0 -12
- package/build/_private/diagnosticRender.d.ts.map +0 -1
- package/build/_private/diagnosticRender.js +0 -27
- package/build/_private/diagnosticRender.js.map +0 -1
- package/src/_private/diagnosticRender.ts +0 -35
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
package com.mentra.bluetoothsdk.debug
|
|
2
|
-
|
|
3
|
-
import android.os.Handler
|
|
4
|
-
import android.os.HandlerThread
|
|
5
|
-
import android.os.Looper
|
|
6
|
-
import org.json.JSONObject
|
|
7
|
-
import org.junit.Assert.assertEquals
|
|
8
|
-
import org.junit.Assert.assertFalse
|
|
9
|
-
import org.junit.Assert.assertNotEquals
|
|
10
|
-
import org.junit.Assert.assertNull
|
|
11
|
-
import org.junit.Assert.assertTrue
|
|
12
|
-
import org.junit.Before
|
|
13
|
-
import org.junit.Test
|
|
14
|
-
import org.junit.runner.RunWith
|
|
15
|
-
import org.robolectric.RobolectricTestRunner
|
|
16
|
-
import org.robolectric.annotation.Config
|
|
17
|
-
|
|
18
|
-
@RunWith(RobolectricTestRunner::class)
|
|
19
|
-
@Config(sdk = [33])
|
|
20
|
-
class BleEvidenceLogTest {
|
|
21
|
-
@Before fun reset() = BleEvidenceLog.resetForTest()
|
|
22
|
-
|
|
23
|
-
private fun records(snapshot: JSONObject) =
|
|
24
|
-
snapshot.getJSONArray("records").let { array -> (0 until array.length()).map { array.getJSONObject(it) } }
|
|
25
|
-
|
|
26
|
-
@Test
|
|
27
|
-
fun `ids derive from one stream and a strict sequence`() {
|
|
28
|
-
val origin = BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01")
|
|
29
|
-
val first = BleEvidenceLog.battery(origin, 57, "battery_status", null)
|
|
30
|
-
val second = BleEvidenceLog.battery(origin, 57, "battery_status", null)
|
|
31
|
-
|
|
32
|
-
assertEquals("${BleEvidenceLog.streamId}:2", first)
|
|
33
|
-
assertEquals("${BleEvidenceLog.streamId}:3", second)
|
|
34
|
-
val snapshot = BleEvidenceLog.snapshot(0, null)
|
|
35
|
-
assertEquals("ok", snapshot.getString("outcome"))
|
|
36
|
-
assertEquals(listOf(1L, 2L, 3L), records(snapshot).map { it.getLong("seq") })
|
|
37
|
-
assertEquals(3L, snapshot.getLong("fenceSeq"))
|
|
38
|
-
// Percent-only sources never claim PMU charging.
|
|
39
|
-
assertFalse(records(snapshot)[1].has("pmuCharging"))
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@Test
|
|
43
|
-
fun `eviction is an explicit gap, never a clean interval`() {
|
|
44
|
-
repeat(BleEvidenceLog.CAPACITY + 88) { BleEvidenceLog.receiveRejected("stale_gatt", null) }
|
|
45
|
-
|
|
46
|
-
val gap = BleEvidenceLog.snapshot(0, null)
|
|
47
|
-
assertEquals("gap", gap.getString("outcome"))
|
|
48
|
-
assertEquals(88L, gap.getLong("droppedCount"))
|
|
49
|
-
assertEquals(89L, gap.getLong("firstRetainedSeq"))
|
|
50
|
-
assertEquals("ok", BleEvidenceLog.snapshot(88, null).getString("outcome"))
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@Test
|
|
54
|
-
fun `cursor from another process or the future is stale`() {
|
|
55
|
-
BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01")
|
|
56
|
-
val oldStream = BleEvidenceLog.streamId
|
|
57
|
-
BleEvidenceLog.resetForTest()
|
|
58
|
-
|
|
59
|
-
val stale = BleEvidenceLog.snapshot(1, null)
|
|
60
|
-
assertEquals("stale_cursor", stale.getString("outcome"))
|
|
61
|
-
assertNotEquals(oldStream, stale.getString("streamId"))
|
|
62
|
-
assertEquals(0, stale.getJSONArray("records").length())
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@Test
|
|
66
|
-
fun `malformed requests are refused`() {
|
|
67
|
-
assertEquals("invalid_request", BleEvidenceLog.snapshot(null, null).getString("outcome"))
|
|
68
|
-
assertEquals("invalid_request", BleEvidenceLog.snapshot(0, "LabAP").getString("outcome"))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@Test
|
|
72
|
-
fun `scan snapshot reports only the requested target and never an SSID`() {
|
|
73
|
-
val origin = BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01")
|
|
74
|
-
BleEvidenceLog.scanChunk(
|
|
75
|
-
origin,
|
|
76
|
-
"scan-1",
|
|
77
|
-
listOf(
|
|
78
|
-
mapOf("ssid" to "LabAP", "requiresPassword" to true),
|
|
79
|
-
mapOf("ssid" to "Neighbor", "requiresPassword" to false),
|
|
80
|
-
mapOf("ssid" to "Stringly", "requiresPassword" to "true"),
|
|
81
|
-
),
|
|
82
|
-
complete = true,
|
|
83
|
-
entriesParsed = true,
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
val targeted = BleEvidenceLog.snapshot(0, BleEvidenceLog.sha256Hex("LabAP"))
|
|
87
|
-
val chunk = records(targeted).single { it.getString("kind") == "scan_chunk" }
|
|
88
|
-
assertTrue(chunk.getBoolean("targetSeen"))
|
|
89
|
-
assertTrue(chunk.getBoolean("targetRequiresPassword"))
|
|
90
|
-
assertEquals(3, chunk.getInt("networks"))
|
|
91
|
-
assertFalse(targeted.toString().contains("LabAP"))
|
|
92
|
-
assertFalse(targeted.toString().contains("Neighbor"))
|
|
93
|
-
|
|
94
|
-
val absent = records(BleEvidenceLog.snapshot(0, BleEvidenceLog.sha256Hex("Other"))).last()
|
|
95
|
-
assertFalse(absent.getBoolean("targetSeen"))
|
|
96
|
-
assertFalse(absent.has("targetRequiresPassword"))
|
|
97
|
-
|
|
98
|
-
// Only an exact boolean counts as the security value.
|
|
99
|
-
val nonBoolean = records(BleEvidenceLog.snapshot(0, BleEvidenceLog.sha256Hex("Stringly"))).last()
|
|
100
|
-
assertTrue(nonBoolean.getBoolean("targetSeen"))
|
|
101
|
-
assertTrue(nonBoolean.isNull("targetRequiresPassword"))
|
|
102
|
-
|
|
103
|
-
assertFalse(records(BleEvidenceLog.snapshot(0, null)).last().has("targetSeen"))
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private fun chunkRecord(target: String) =
|
|
107
|
-
records(BleEvidenceLog.snapshot(0, BleEvidenceLog.sha256Hex(target))).last { it.getString("kind") == "scan_chunk" }
|
|
108
|
-
|
|
109
|
-
@Test
|
|
110
|
-
fun `a target beyond retained digests is unknown, never absent`() {
|
|
111
|
-
val origin = BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01")
|
|
112
|
-
// 70 unique networks: only the first 64 digests are retained.
|
|
113
|
-
val networks = (1..70).map { mapOf("ssid" to "Net$it", "requiresPassword" to (it % 2 == 0)) }
|
|
114
|
-
BleEvidenceLog.scanChunk(origin, "scan-many", networks, complete = true, entriesParsed = true)
|
|
115
|
-
|
|
116
|
-
val beyond = chunkRecord("Net70")
|
|
117
|
-
assertTrue("target at index 70 must not be reported absent", beyond.isNull("targetSeen"))
|
|
118
|
-
assertEquals("incomplete", beyond.getString("targetCoverage"))
|
|
119
|
-
assertFalse(beyond.has("targetRequiresPassword"))
|
|
120
|
-
assertEquals(70, beyond.getInt("networks"))
|
|
121
|
-
|
|
122
|
-
// A retained target is still exact even when the chunk is truncated.
|
|
123
|
-
val covered = chunkRecord("Net2")
|
|
124
|
-
assertTrue(covered.getBoolean("targetSeen"))
|
|
125
|
-
assertTrue(covered.getBoolean("targetRequiresPassword"))
|
|
126
|
-
assertEquals("incomplete", covered.getString("targetCoverage"))
|
|
127
|
-
|
|
128
|
-
// Neither SSIDs nor unrelated digests are serialized.
|
|
129
|
-
val serialized = BleEvidenceLog.snapshot(0, BleEvidenceLog.sha256Hex("Net70")).toString()
|
|
130
|
-
assertFalse(serialized.contains("Net"))
|
|
131
|
-
assertFalse(serialized.contains(BleEvidenceLog.sha256Hex("Net1")))
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
@Test
|
|
135
|
-
fun `absence is reported only with complete coverage`() {
|
|
136
|
-
val origin = BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01")
|
|
137
|
-
val networks = (1..64).map { mapOf("ssid" to "Net$it", "requiresPassword" to true) }
|
|
138
|
-
BleEvidenceLog.scanChunk(origin, "scan-full", networks, complete = true, entriesParsed = true)
|
|
139
|
-
|
|
140
|
-
val absent = chunkRecord("LabAP")
|
|
141
|
-
assertEquals("complete", absent.getString("targetCoverage"))
|
|
142
|
-
assertFalse(absent.getBoolean("targetSeen"))
|
|
143
|
-
val present = chunkRecord("Net64")
|
|
144
|
-
assertTrue(present.getBoolean("targetSeen"))
|
|
145
|
-
assertEquals("complete", present.getString("targetCoverage"))
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
@Test
|
|
149
|
-
fun `entries without an SSID or with conflicting duplicates are not certified`() {
|
|
150
|
-
val origin = BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01")
|
|
151
|
-
BleEvidenceLog.scanChunk(
|
|
152
|
-
origin,
|
|
153
|
-
"scan-odd",
|
|
154
|
-
listOf(
|
|
155
|
-
mapOf("requiresPassword" to true),
|
|
156
|
-
mapOf("ssid" to "Dup", "requiresPassword" to true),
|
|
157
|
-
mapOf("ssid" to "Dup", "requiresPassword" to false),
|
|
158
|
-
),
|
|
159
|
-
complete = true,
|
|
160
|
-
entriesParsed = true,
|
|
161
|
-
)
|
|
162
|
-
val missing = chunkRecord("LabAP")
|
|
163
|
-
assertEquals("incomplete", missing.getString("targetCoverage"))
|
|
164
|
-
assertTrue(missing.isNull("targetSeen"))
|
|
165
|
-
val duplicate = chunkRecord("Dup")
|
|
166
|
-
assertTrue(duplicate.getBoolean("targetSeen"))
|
|
167
|
-
assertTrue(duplicate.isNull("targetRequiresPassword"))
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
@Test
|
|
171
|
-
fun `a partially parsed chunk certifies neither absence nor security`() {
|
|
172
|
-
val origin = BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01")
|
|
173
|
-
BleEvidenceLog.scanChunk(
|
|
174
|
-
origin,
|
|
175
|
-
"scan-partial",
|
|
176
|
-
listOf(mapOf("ssid" to "Other", "requiresPassword" to false)),
|
|
177
|
-
complete = true,
|
|
178
|
-
entriesParsed = false,
|
|
179
|
-
)
|
|
180
|
-
val absent = chunkRecord("LabAP")
|
|
181
|
-
assertTrue(absent.isNull("targetSeen"))
|
|
182
|
-
assertEquals("incomplete", absent.getString("targetCoverage"))
|
|
183
|
-
assertFalse(absent.getBoolean("entriesParsed"))
|
|
184
|
-
val seen = chunkRecord("Other")
|
|
185
|
-
assertTrue(seen.getBoolean("targetSeen"))
|
|
186
|
-
assertTrue(seen.isNull("targetRequiresPassword"))
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
@Test
|
|
190
|
-
fun `send-queue generations are ordered boundaries`() {
|
|
191
|
-
val first = BleEvidenceLog.bleGeneration(0, 0)
|
|
192
|
-
val origin = BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01")
|
|
193
|
-
BleEvidenceLog.scanSend("scan-1", "queued", 0, 1, origin.connection, first)
|
|
194
|
-
BleEvidenceLog.connectionClosed(origin.connection, "remote_disconnect")
|
|
195
|
-
val second = BleEvidenceLog.bleGeneration(0, 1)
|
|
196
|
-
|
|
197
|
-
val snapshot = BleEvidenceLog.snapshot(0, null)
|
|
198
|
-
assertEquals(second, snapshot.getJSONObject("current").getLong("writeGeneration"))
|
|
199
|
-
val send = records(snapshot).single { it.getString("kind") == "scan_send" }
|
|
200
|
-
assertEquals(first, send.getLong("writeGeneration"))
|
|
201
|
-
assertEquals(listOf(0L, 1L), records(snapshot).filter { it.getString("kind") == "ble_generation" }.map { it.getLong("generation") })
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
@Test
|
|
205
|
-
fun `render markers accept only allowlisted surfaces, bounded values and ids of this stream`() {
|
|
206
|
-
val id = BleEvidenceLog.battery(BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01"), 57, "battery_status", null)
|
|
207
|
-
|
|
208
|
-
assertFalse(BleEvidenceLog.uiRender("debug_panel", listOf(id), 1))
|
|
209
|
-
assertFalse(BleEvidenceLog.uiRender(BleEvidenceLog.SURFACE_BATTERY, listOf(id), 101))
|
|
210
|
-
assertTrue(
|
|
211
|
-
BleEvidenceLog.uiRender(
|
|
212
|
-
BleEvidenceLog.SURFACE_BATTERY,
|
|
213
|
-
listOf(id, "other-stream:2", "${BleEvidenceLog.streamId}:999"),
|
|
214
|
-
57,
|
|
215
|
-
)
|
|
216
|
-
)
|
|
217
|
-
val render = records(BleEvidenceLog.snapshot(0, null)).last()
|
|
218
|
-
assertEquals("ui_render", render.getString("kind"))
|
|
219
|
-
assertEquals(listOf(id), (0 until render.getJSONArray("eventIds").length()).map { render.getJSONArray("eventIds").getString(it) })
|
|
220
|
-
assertEquals(2, render.getInt("rejectedEventIds"))
|
|
221
|
-
assertEquals(57, render.getInt("value"))
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
@Test
|
|
225
|
-
fun `an out-of-range render value withdraws the surface without storing the value`() {
|
|
226
|
-
val id = BleEvidenceLog.battery(BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01"), 57, "battery_status", null)
|
|
227
|
-
assertTrue(BleEvidenceLog.uiRender(BleEvidenceLog.SURFACE_BATTERY, listOf(id), 57))
|
|
228
|
-
|
|
229
|
-
for ((surface, value) in listOf(
|
|
230
|
-
BleEvidenceLog.SURFACE_BATTERY to 150,
|
|
231
|
-
BleEvidenceLog.SURFACE_BATTERY to -1,
|
|
232
|
-
BleEvidenceLog.SURFACE_WIFI_SCAN to 501,
|
|
233
|
-
BleEvidenceLog.SURFACE_WIFI_SCAN to Int.MAX_VALUE,
|
|
234
|
-
)) {
|
|
235
|
-
// The value is not accepted, but the surface's earlier marker must not stay current.
|
|
236
|
-
assertFalse(BleEvidenceLog.uiRender(surface, listOf(id), value))
|
|
237
|
-
val withdrawal = records(BleEvidenceLog.snapshot(0, null)).last()
|
|
238
|
-
assertEquals("ui_render", withdrawal.getString("kind"))
|
|
239
|
-
assertEquals(surface, withdrawal.getString("surface"))
|
|
240
|
-
assertEquals(0, withdrawal.getJSONArray("eventIds").length())
|
|
241
|
-
assertTrue(withdrawal.isNull("value"))
|
|
242
|
-
assertFalse(withdrawal.toString().contains(value.toString()))
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Boundary values stay qualifying markers; the next valid reading restores provenance.
|
|
246
|
-
assertTrue(BleEvidenceLog.uiRender(BleEvidenceLog.SURFACE_BATTERY, listOf(id), 100))
|
|
247
|
-
assertTrue(BleEvidenceLog.uiRender(BleEvidenceLog.SURFACE_WIFI_SCAN, emptyList(), 500))
|
|
248
|
-
val restored = records(BleEvidenceLog.snapshot(0, null)).last { it.getString("surface") == BleEvidenceLog.SURFACE_BATTERY }
|
|
249
|
-
assertEquals(100, restored.getInt("value"))
|
|
250
|
-
assertEquals(1, restored.getJSONArray("eventIds").length())
|
|
251
|
-
|
|
252
|
-
// An unknown surface has nothing to withdraw and is still refused without a record.
|
|
253
|
-
val before = BleEvidenceLog.snapshot(0, null).getLong("fenceSeq")
|
|
254
|
-
assertFalse(BleEvidenceLog.uiRender("debug_panel", listOf(id), 1))
|
|
255
|
-
assertEquals(before, BleEvidenceLog.snapshot(0, null).getLong("fenceSeq"))
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
@Test
|
|
259
|
-
fun `dump answers only its command and reports an unavailable owner`() {
|
|
260
|
-
BleEvidenceLog.connectionAccepted("AA:BB:CC:DD:EE:01")
|
|
261
|
-
val main = Handler(Looper.getMainLooper())
|
|
262
|
-
|
|
263
|
-
assertNull(BleEvidenceLog.dump(arrayOf("--other"), main))
|
|
264
|
-
assertNull(BleEvidenceLog.dump(null, main))
|
|
265
|
-
|
|
266
|
-
val line = BleEvidenceLog.dump(arrayOf(BleEvidenceLog.DUMP_COMMAND, "afterSeq=0"), main)!!
|
|
267
|
-
assertTrue(line.startsWith(BleEvidenceLog.OUTPUT_PREFIX))
|
|
268
|
-
val json = JSONObject(line.removePrefix(BleEvidenceLog.OUTPUT_PREFIX))
|
|
269
|
-
assertEquals("ok", json.getString("outcome"))
|
|
270
|
-
assertEquals("AA:BB:CC:DD:EE:01", json.getJSONObject("current").getString("peerMac"))
|
|
271
|
-
|
|
272
|
-
val unknownArg = BleEvidenceLog.dump(arrayOf(BleEvidenceLog.DUMP_COMMAND, "afterSeq=0", "eval=1"), main)!!
|
|
273
|
-
assertEquals("invalid_request", JSONObject(unknownArg.removePrefix(BleEvidenceLog.OUTPUT_PREFIX)).getString("outcome"))
|
|
274
|
-
|
|
275
|
-
val dead = HandlerThread("dead-owner").apply { start() }
|
|
276
|
-
val deadHandler = Handler(dead.looper)
|
|
277
|
-
dead.quitSafely()
|
|
278
|
-
dead.join()
|
|
279
|
-
val unavailable = BleEvidenceLog.dump(arrayOf(BleEvidenceLog.DUMP_COMMAND, "afterSeq=0"), deadHandler, 50)!!
|
|
280
|
-
assertEquals("unavailable", JSONObject(unavailable.removePrefix(BleEvidenceLog.OUTPUT_PREFIX)).getString("outcome"))
|
|
281
|
-
}
|
|
282
|
-
}
|