@mentra/bluetooth-sdk 3.3.0-dev.421 → 3.3.0-dev.423

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.
Files changed (33) hide show
  1. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +0 -7
  2. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +3 -17
  3. package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedReleaseMetadata.kt +5 -5
  4. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +0 -11
  5. package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +0 -21
  6. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +31 -213
  7. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SerializedGattCallback.kt +2 -13
  8. package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunkReassembler.java +6 -41
  9. package/build/BluetoothSdk.types.d.ts +0 -10
  10. package/build/BluetoothSdk.types.d.ts.map +1 -1
  11. package/build/BluetoothSdk.types.js.map +1 -1
  12. package/build/_private/BluetoothSdkModule.d.ts +0 -9
  13. package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
  14. package/build/_private/BluetoothSdkModule.js +0 -2
  15. package/build/_private/BluetoothSdkModule.js.map +1 -1
  16. package/build/generated/releaseMetadata.js +5 -5
  17. package/build/generated/releaseMetadata.js.map +1 -1
  18. package/ios/Source/BluetoothSdkDefaults.swift +1 -1
  19. package/ios/Source/GeneratedReleaseMetadata.swift +5 -5
  20. package/package.json +2 -2
  21. package/src/BluetoothSdk.types.ts +0 -10
  22. package/src/_private/BluetoothSdkModule.ts +0 -13
  23. package/src/generated/releaseMetadata.ts +5 -5
  24. package/android/src/main/java/com/mentra/bluetoothsdk/debug/BleEvidenceLog.kt +0 -454
  25. package/android/src/test/java/com/mentra/bluetoothsdk/WifiScanEvidenceTest.kt +0 -117
  26. package/android/src/test/java/com/mentra/bluetoothsdk/debug/BleEvidenceLogTest.kt +0 -282
  27. package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/MentraLiveEvidenceTest.kt +0 -603
  28. package/android/src/test/java/com/mentra/bluetoothsdk/utils/MessageChunkReassemblerOriginTest.kt +0 -51
  29. package/build/_private/diagnosticRender.d.ts +0 -12
  30. package/build/_private/diagnosticRender.d.ts.map +0 -1
  31. package/build/_private/diagnosticRender.js +0 -27
  32. package/build/_private/diagnosticRender.js.map +0 -1
  33. 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
- }