@mentra/bluetooth-sdk 0.1.2 → 0.1.3

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 (59) hide show
  1. package/README.md +33 -19
  2. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +13 -13
  3. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +42 -18
  4. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +19 -21
  5. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +4 -4
  6. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +118 -103
  7. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +110 -38
  8. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -4
  9. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -2
  10. package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +6 -6
  11. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
  12. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3 -3
  13. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
  14. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +18 -18
  15. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
  16. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +4 -4
  17. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +2 -2
  18. package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +6 -6
  19. package/build/BluetoothSdk.types.d.ts +126 -27
  20. package/build/BluetoothSdk.types.d.ts.map +1 -1
  21. package/build/BluetoothSdk.types.js.map +1 -1
  22. package/build/_internal.d.ts +12 -0
  23. package/build/_internal.d.ts.map +1 -0
  24. package/build/_internal.js +11 -0
  25. package/build/_internal.js.map +1 -0
  26. package/build/{BluetoothSdkModule.d.ts → _private/BluetoothSdkModule.d.ts} +19 -8
  27. package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
  28. package/build/{BluetoothSdkModule.js → _private/BluetoothSdkModule.js} +41 -26
  29. package/build/_private/BluetoothSdkModule.js.map +1 -0
  30. package/build/index.d.ts +4 -2
  31. package/build/index.d.ts.map +1 -1
  32. package/build/index.js +3 -4
  33. package/build/index.js.map +1 -1
  34. package/ios/BluetoothSdkModule.swift +14 -9
  35. package/ios/Source/Bridge.swift +44 -12
  36. package/ios/Source/DeviceManager.swift +27 -26
  37. package/ios/Source/DeviceStore.swift +4 -4
  38. package/ios/Source/MentraBluetoothSDK.swift +250 -132
  39. package/ios/Source/controllers/ControllerManager.swift +5 -5
  40. package/ios/Source/controllers/R1.swift +3 -3
  41. package/ios/Source/services/PhoneMic.swift +5 -5
  42. package/ios/Source/sgcs/Frame.swift +1 -1
  43. package/ios/Source/sgcs/G1.swift +1 -1
  44. package/ios/Source/sgcs/G2.swift +3 -3
  45. package/ios/Source/sgcs/Mach1.swift +1 -1
  46. package/ios/Source/sgcs/MentraLive.swift +31 -33
  47. package/ios/Source/sgcs/MentraNex.swift +2 -2
  48. package/ios/Source/sgcs/SGCManager.swift +5 -5
  49. package/ios/Source/sgcs/Simulated.swift +3 -3
  50. package/ios/Source/utils/Constants.swift +6 -6
  51. package/ios/Source/utils/JSCExperiment.swift +8 -8
  52. package/ios/Source/utils/TarBz2Extractor.swift +2 -2
  53. package/package.json +13 -1
  54. package/src/BluetoothSdk.types.ts +186 -28
  55. package/src/_internal.ts +11 -0
  56. package/src/{BluetoothSdkModule.ts → _private/BluetoothSdkModule.ts} +71 -38
  57. package/src/index.ts +80 -4
  58. package/build/BluetoothSdkModule.d.ts.map +0 -1
  59. package/build/BluetoothSdkModule.js.map +0 -1
@@ -34,6 +34,7 @@ class MentraBluetoothSdk private constructor(
34
34
 
35
35
  companion object {
36
36
  private val DEFAULT_DEVICE_KEYS = setOf("default_wearable", "device_name", "device_address")
37
+ private const val DEFAULT_SCAN_TIMEOUT_MS = 15_000L
37
38
 
38
39
  @JvmStatic
39
40
  fun create(
@@ -103,9 +104,90 @@ class MentraBluetoothSdk private constructor(
103
104
  }
104
105
 
105
106
  fun stopScan() {
107
+ stopScan(ScanStopReason.CANCELLED)
108
+ }
109
+
110
+ private fun stopScan(reason: ScanStopReason) {
106
111
  deviceManager.stopScan()
107
112
  DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "searching", false)
108
- dispatchToListeners { it.onScanStopped(ScanStopReason.CANCELLED) }
113
+ dispatchToListeners { it.onScanStopped(reason) }
114
+ }
115
+
116
+ fun scan(
117
+ model: DeviceModel,
118
+ onResults: (List<Device>) -> Unit,
119
+ ): ScanSession = scan(model, DEFAULT_SCAN_TIMEOUT_MS, onResults)
120
+
121
+ fun scan(
122
+ model: DeviceModel,
123
+ timeoutMs: Long,
124
+ onResults: (List<Device>) -> Unit,
125
+ ): ScanSession =
126
+ scan(
127
+ model = model,
128
+ callback =
129
+ object : MentraBluetoothScanCallback() {
130
+ override fun onResults(devices: List<Device>) {
131
+ onResults(devices)
132
+ }
133
+ },
134
+ timeoutMs = timeoutMs,
135
+ )
136
+
137
+ @JvmOverloads
138
+ fun scan(
139
+ model: DeviceModel,
140
+ callback: ScanCallback,
141
+ timeoutMs: Long = DEFAULT_SCAN_TIMEOUT_MS,
142
+ ): ScanSession {
143
+ val normalizedTimeoutMs = if (timeoutMs > 0) timeoutMs else DEFAULT_SCAN_TIMEOUT_MS
144
+ val latestResults = mutableListOf<Device>()
145
+ lateinit var timeoutRunnable: Runnable
146
+ lateinit var session: ScanSession
147
+ var finished = false
148
+
149
+ fun emitResults(devices: List<Device>) {
150
+ latestResults.clear()
151
+ latestResults.addAll(devices)
152
+ callback.onResults(latestResults.toList())
153
+ }
154
+
155
+ val scanListener =
156
+ object : MentraBluetoothSdkCallback() {
157
+ override fun onBluetoothStatusChanged(status: BluetoothStatusUpdate) {
158
+ status.searchResults?.let { results ->
159
+ emitResults(results.filter { it.model == model })
160
+ }
161
+ }
162
+ }
163
+
164
+ fun finish(reason: ScanStopReason) {
165
+ if (finished) return
166
+ finished = true
167
+ removeListener(scanListener)
168
+ mainHandler.removeCallbacks(timeoutRunnable)
169
+ session.markStopped()
170
+ stopScan(reason)
171
+ callback.onComplete(latestResults.toList())
172
+ }
173
+
174
+ timeoutRunnable = Runnable { finish(ScanStopReason.COMPLETED) }
175
+ session = ScanSession { finish(ScanStopReason.CANCELLED) }
176
+ addListener(scanListener)
177
+
178
+ try {
179
+ emitResults(emptyList())
180
+ startScan(model)
181
+ emitResults(getBluetoothStatus().searchResults.filter { it.model == model })
182
+ mainHandler.postDelayed(timeoutRunnable, normalizedTimeoutMs)
183
+ return session
184
+ } catch (error: Throwable) {
185
+ removeListener(scanListener)
186
+ mainHandler.removeCallbacks(timeoutRunnable)
187
+ session.markStopped()
188
+ callback.onError(error.toBluetoothError("scan_failed"))
189
+ throw error
190
+ }
109
191
  }
110
192
 
111
193
  @JvmOverloads
@@ -149,7 +231,7 @@ class MentraBluetoothSdk private constructor(
149
231
  deviceManager.disconnect()
150
232
  }
151
233
 
152
- fun connectSimulated() {
234
+ internal fun connectSimulated() {
153
235
  deviceManager.connectSimulated()
154
236
  }
155
237
 
@@ -170,7 +252,7 @@ class MentraBluetoothSdk private constructor(
170
252
  deviceManager.displayText(request.toMap())
171
253
  }
172
254
 
173
- fun displayEvent(request: DisplayEventRequest) {
255
+ internal fun displayEvent(request: DisplayEventRequest) {
174
256
  deviceManager.displayEvent(request.toMap())
175
257
  }
176
258
 
@@ -182,13 +264,12 @@ class MentraBluetoothSdk private constructor(
182
264
  deviceManager.showDashboard()
183
265
  }
184
266
 
185
- @JvmOverloads
186
- fun setBrightness(level: Int, autoMode: Boolean? = null) {
267
+ internal fun setBrightness(level: Int, autoMode: Boolean? = null) {
187
268
  autoMode?.let { DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "auto_brightness", it) }
188
269
  DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "brightness", level)
189
270
  }
190
271
 
191
- fun setAutoBrightness(enabled: Boolean) {
272
+ internal fun setAutoBrightness(enabled: Boolean) {
192
273
  DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "auto_brightness", enabled)
193
274
  }
194
275
 
@@ -201,7 +282,7 @@ class MentraBluetoothSdk private constructor(
201
282
  setDashboardPosition(height = request.height, depth = request.depth)
202
283
  }
203
284
 
204
- fun setDashboardMenu(items: List<DashboardMenuItem>) {
285
+ internal fun setDashboardMenu(items: List<DashboardMenuItem>) {
205
286
  DeviceStore.apply(
206
287
  ObservableStore.BLUETOOTH_CATEGORY,
207
288
  "menu_apps",
@@ -218,7 +299,7 @@ class MentraBluetoothSdk private constructor(
218
299
  }
219
300
 
220
301
  fun setGalleryMode(mode: GalleryMode) {
221
- DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "gallery_mode", mode == GalleryMode.AUTO)
302
+ DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "galleryModeAuto", mode == GalleryMode.AUTO)
222
303
  }
223
304
 
224
305
  fun setButtonPhotoSettings(size: ButtonPhotoSize) {
@@ -229,14 +310,14 @@ class MentraBluetoothSdk private constructor(
229
310
  setButtonPhotoSettings(size = settings.size)
230
311
  }
231
312
 
232
- fun setButtonVideoRecordingSettings(width: Int, height: Int, fps: Int) {
313
+ fun setButtonVideoRecordingSettings(width: Int, height: Int, frameRate: Int) {
233
314
  DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "button_video_width", width)
234
315
  DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "button_video_height", height)
235
- DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "button_video_fps", fps)
316
+ DeviceStore.apply(ObservableStore.BLUETOOTH_CATEGORY, "button_video_fps", frameRate)
236
317
  }
237
318
 
238
319
  fun setButtonVideoRecordingSettings(settings: ButtonVideoRecordingSettings) {
239
- setButtonVideoRecordingSettings(width = settings.width, height = settings.height, fps = settings.fps)
320
+ setButtonVideoRecordingSettings(width = settings.width, height = settings.height, frameRate = settings.frameRate)
240
321
  }
241
322
 
242
323
  fun setButtonCameraLed(enabled: Boolean) {
@@ -251,7 +332,7 @@ class MentraBluetoothSdk private constructor(
251
332
  DeviceStore.apply(
252
333
  ObservableStore.BLUETOOTH_CATEGORY,
253
334
  "camera_fov",
254
- mapOf("fov" to fov.fov, "roi_position" to fov.roiPosition),
335
+ mapOf("fov" to fov.fov, "roiPosition" to fov.roiPosition),
255
336
  )
256
337
  }
257
338
 
@@ -277,21 +358,6 @@ class MentraBluetoothSdk private constructor(
277
358
  )
278
359
  }
279
360
 
280
- @Deprecated(
281
- "Use setMicState(enabled = ..., useGlassesMic = ..., bypassVad = ...) instead.",
282
- ReplaceWith(
283
- "setMicState(enabled = config.sendPcmData, bypassVad = config.bypassVad, sendTranscript = config.sendTranscript, sendLc3Data = config.sendLc3Data)"
284
- ),
285
- )
286
- fun setMicState(config: MicConfig) {
287
- applyMicState(
288
- sendPcmData = config.sendPcmData,
289
- sendTranscript = config.sendTranscript,
290
- bypassVad = config.bypassVad,
291
- sendLc3Data = config.sendLc3Data,
292
- )
293
- }
294
-
295
361
  private fun applyMicState(
296
362
  sendPcmData: Boolean,
297
363
  sendTranscript: Boolean,
@@ -338,14 +404,13 @@ class MentraBluetoothSdk private constructor(
338
404
  }
339
405
 
340
406
  fun requestPhoto(request: PhotoRequest) {
341
- deviceManager.photoRequest(
407
+ deviceManager.requestPhoto(
342
408
  request.requestId,
343
409
  request.appId,
344
410
  request.size.value,
345
411
  request.webhookUrl,
346
412
  request.authToken,
347
413
  request.compress.value,
348
- request.flash,
349
414
  request.sound,
350
415
  )
351
416
  }
@@ -368,8 +433,8 @@ class MentraBluetoothSdk private constructor(
368
433
  request.packageName,
369
434
  request.action.value,
370
435
  request.color?.value,
371
- request.ontime,
372
- request.offtime,
436
+ request.onDurationMs,
437
+ request.offDurationMs,
373
438
  request.count,
374
439
  )
375
440
  }
@@ -379,7 +444,7 @@ class MentraBluetoothSdk private constructor(
379
444
  }
380
445
 
381
446
  fun startVideoRecording(request: VideoRecordingRequest) {
382
- deviceManager.startVideoRecording(request.requestId, request.save, request.flash, request.sound)
447
+ deviceManager.startVideoRecording(request.requestId, request.save, request.sound)
383
448
  }
384
449
 
385
450
  fun stopVideoRecording(requestId: String) {
@@ -390,23 +455,23 @@ class MentraBluetoothSdk private constructor(
390
455
  deviceManager.requestVersionInfo()
391
456
  }
392
457
 
393
- fun sendOtaStart() {
458
+ internal fun sendOtaStart() {
394
459
  deviceManager.sendOtaStart()
395
460
  }
396
461
 
397
- fun sendOtaQueryStatus() {
462
+ internal fun sendOtaQueryStatus() {
398
463
  deviceManager.sendOtaQueryStatus()
399
464
  }
400
465
 
401
- fun sendShutdown() {
466
+ internal fun sendShutdown() {
402
467
  deviceManager.sendShutdown()
403
468
  }
404
469
 
405
- fun sendReboot() {
470
+ internal fun sendReboot() {
406
471
  deviceManager.sendReboot()
407
472
  }
408
473
 
409
- fun sendIncidentId(incidentId: String, apiBaseUrl: String? = null) {
474
+ internal fun sendIncidentId(incidentId: String, apiBaseUrl: String? = null) {
410
475
  deviceManager.sendIncidentId(incidentId, apiBaseUrl)
411
476
  }
412
477
 
@@ -509,11 +574,18 @@ class MentraBluetoothSdk private constructor(
509
574
  }
510
575
  }
511
576
 
577
+ private fun Throwable.toBluetoothError(defaultCode: String): BluetoothError =
578
+ if (this is BluetoothException) {
579
+ BluetoothError(code, message ?: code, this)
580
+ } else {
581
+ BluetoothError(defaultCode, message ?: toString(), this)
582
+ }
583
+
512
584
  private fun dispatchDiscoveredDevices(rawSearchResults: Any?) {
513
585
  val results = rawSearchResults as? List<*> ?: return
514
586
  results.forEach { rawResult ->
515
587
  val result = rawResult as? Map<*, *> ?: return@forEach
516
- val name = result["deviceName"] as? String ?: result["name"] as? String ?: return@forEach
588
+ val name = result["name"] as? String ?: return@forEach
517
589
  if (!discoveredDeviceNames.add(name)) return@forEach
518
590
  val values =
519
591
  result.entries.mapNotNull { (key, value) ->
@@ -57,8 +57,8 @@ abstract class ControllerManager {
57
57
  packageName: String?,
58
58
  action: String,
59
59
  color: String?,
60
- ontime: Int,
61
- offtime: Int,
60
+ onDurationMs: Int,
61
+ offDurationMs: Int,
62
62
  count: Int
63
63
  )
64
64
 
@@ -117,8 +117,8 @@ abstract class ControllerManager {
117
117
  val firmwareVersion: String
118
118
  get() = DeviceStore.get("glasses", "firmwareVersion") as? String ?: ""
119
119
 
120
- val btMacAddress: String
121
- get() = DeviceStore.get("glasses", "btMacAddress") as? String ?: ""
120
+ val bluetoothMacAddress: String
121
+ get() = DeviceStore.get("glasses", "bluetoothMacAddress") as? String ?: ""
122
122
 
123
123
  val serialNumber: String
124
124
  get() = DeviceStore.get("glasses", "serialNumber") as? String ?: ""
@@ -454,7 +454,7 @@ class R1 : ControllerManager() {
454
454
  */
455
455
  private fun connectToGlasses() {
456
456
  // Try DeviceStore first; fall back to cached value in SharedPreferences.
457
- val glassesMac = (DeviceStore.get("glasses", "btMacAddress") as? String)
457
+ val glassesMac = (DeviceStore.get("glasses", "bluetoothMacAddress") as? String)
458
458
  ?: prefs.getString("glasses_btMacAddress", null)
459
459
  if (glassesMac == null) {
460
460
  Bridge.log("R1: connectToGlasses: no glasses MAC")
@@ -888,7 +888,7 @@ class R1 : ControllerManager() {
888
888
  override fun sendReboot() {}
889
889
  override fun sendRgbLedControl(
890
890
  requestId: String, packageName: String?, action: String, color: String?,
891
- ontime: Int, offtime: Int, count: Int
891
+ onDurationMs: Int, offDurationMs: Int, count: Int
892
892
  ) {}
893
893
  override fun requestWifiScan() {}
894
894
  override fun sendWifiCredentials(ssid: String, password: String) {}
@@ -190,7 +190,7 @@ class PhoneMic private constructor(private val context: Context) {
190
190
 
191
191
  /**
192
192
  * Start recording from a specific microphone type
193
- * @param mode One of MicTypes constants (PHONE_INTERNAL, BT_CLASSIC, BT)
193
+ * @param mode One of MicTypes constants (PHONE_INTERNAL, BLUETOOTH_CLASSIC, BLUETOOTH)
194
194
  * @return true if successfully started recording, false otherwise
195
195
  */
196
196
  fun startMode(mode: String): Boolean {
@@ -253,7 +253,7 @@ class PhoneMic private constructor(private val context: Context) {
253
253
  Bridge.log("MIC: Starting phone internal mic")
254
254
  return startRecordingPhoneInternal()
255
255
  }
256
- MicTypes.BT_CLASSIC -> {
256
+ MicTypes.BLUETOOTH_CLASSIC -> {
257
257
  Bridge.log("MIC: Starting Bluetooth Classic (SCO)")
258
258
  if (!audioManager.isBluetoothScoAvailableOffCall) {
259
259
  Bridge.log("MIC: Bluetooth SCO not available")
@@ -262,7 +262,7 @@ class PhoneMic private constructor(private val context: Context) {
262
262
  }
263
263
  return startRecordingBtClassic()
264
264
  }
265
- MicTypes.BT -> {
265
+ MicTypes.BLUETOOTH -> {
266
266
  Bridge.log("MIC: Starting high-quality Bluetooth mic")
267
267
  if (!isHighQualityBluetoothAvailable()) {
268
268
  Bridge.log("MIC: High-quality Bluetooth not available")
@@ -346,7 +346,7 @@ class PhoneMic private constructor(private val context: Context) {
346
346
 
347
347
  val success = createAndStartAudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
348
348
  if (success) {
349
- currentMicMode = MicTypes.BT_CLASSIC
349
+ currentMicMode = MicTypes.BLUETOOTH_CLASSIC
350
350
  }
351
351
  return success
352
352
  } catch (e: Exception) {
@@ -383,7 +383,7 @@ class PhoneMic private constructor(private val context: Context) {
383
383
 
384
384
  val success = createAndStartAudioRecord(audioSource)
385
385
  if (success) {
386
- currentMicMode = MicTypes.BT
386
+ currentMicMode = MicTypes.BLUETOOTH
387
387
  }
388
388
  return success
389
389
  } catch (e: Exception) {
@@ -1106,4 +1106,4 @@ class PhoneMic private constructor(private val context: Context) {
1106
1106
 
1107
1107
  Bridge.log("MIC: Cleaned up")
1108
1108
  }
1109
- }
1109
+ }
@@ -1682,7 +1682,7 @@ public class G1 extends SGCManager {
1682
1682
  }
1683
1683
 
1684
1684
  @Override
1685
- public void sendRgbLedControl(String requestId, String packageName, String action, String color, int ontime, int offtime, int count) {
1685
+ public void sendRgbLedControl(String requestId, String packageName, String action, String color, int onDurationMs, int offDurationMs, int count) {
1686
1686
  Bridge.log("sendRgbLedControl - not supported on G1");
1687
1687
  Bridge.sendRgbLedControlResponse(requestId, false, "device_not_supported");
1688
1688
  }
@@ -2609,8 +2609,8 @@ class G2 : SGCManager() {
2609
2609
  packageName: String?,
2610
2610
  action: String,
2611
2611
  color: String?,
2612
- ontime: Int,
2613
- offtime: Int,
2612
+ onDurationMs: Int,
2613
+ offDurationMs: Int,
2614
2614
  count: Int
2615
2615
  ) {
2616
2616
  // G2 doesn't have RGB LEDs
@@ -2711,7 +2711,7 @@ class G2 : SGCManager() {
2711
2711
  if (mac != null) {
2712
2712
  if (name.contains("_L_")) {
2713
2713
  DeviceStore.apply("glasses", "leftMacAddress", mac)
2714
- DeviceStore.apply("glasses", "btMacAddress", mac)
2714
+ DeviceStore.apply("glasses", "bluetoothMacAddress", mac)
2715
2715
  } else if (name.contains("_R_")) {
2716
2716
  DeviceStore.apply("glasses", "rightMacAddress", mac)
2717
2717
  }
@@ -290,7 +290,7 @@ public class Mach1 extends SGCManager {
290
290
  }
291
291
 
292
292
  @Override
293
- public void sendRgbLedControl(String requestId, String packageName, String action, String color, int ontime, int offtime, int count) {
293
+ public void sendRgbLedControl(String requestId, String packageName, String action, String color, int onDurationMs, int offDurationMs, int count) {
294
294
  Bridge.log("sendRgbLedControl - not supported on Mach1");
295
295
  Bridge.sendRgbLedControlResponse(requestId, false, "device_not_supported");
296
296
  }
@@ -696,8 +696,8 @@ public class MentraLive extends SGCManager {
696
696
  // and the phone-side OTA check will disagree with glasses' PackageManager + ota_update_available.
697
697
  DeviceStore.INSTANCE.apply("glasses", "buildNumber", "");
698
698
  DeviceStore.INSTANCE.apply("glasses", "appVersion", "");
699
- DeviceStore.INSTANCE.apply("glasses", "besFwVersion", "");
700
- DeviceStore.INSTANCE.apply("glasses", "mtkFwVersion", "");
699
+ DeviceStore.INSTANCE.apply("glasses", "besFirmwareVersion", "");
700
+ DeviceStore.INSTANCE.apply("glasses", "mtkFirmwareVersion", "");
701
701
  Bridge.log("LIVE: Cleared cached version_info fields for fresh session");
702
702
  }
703
703
 
@@ -841,7 +841,7 @@ public class MentraLive extends SGCManager {
841
841
 
842
842
  private void emitStopScanEvent() {
843
843
  Map<String, Object> body = new HashMap<>();
844
- body.put("device_model", DeviceTypes.LIVE);
844
+ body.put("deviceModel", DeviceTypes.LIVE);
845
845
  Bridge.sendTypedMessage("compatible_glasses_search_stop", body);
846
846
  }
847
847
 
@@ -2776,7 +2776,7 @@ public class MentraLive extends SGCManager {
2776
2776
  DeviceStore.INSTANCE.apply("glasses", "androidVersion", androidVersionLegacy);
2777
2777
  DeviceStore.INSTANCE.apply("glasses", "otaVersionUrl", otaVersionUrlLegacy != null ? otaVersionUrlLegacy : "");
2778
2778
  DeviceStore.INSTANCE.apply("glasses", "firmwareVersion", firmwareVersionLegacy);
2779
- DeviceStore.INSTANCE.apply("glasses", "btMacAddress", btMacAddressLegacy);
2779
+ DeviceStore.INSTANCE.apply("glasses", "bluetoothMacAddress", btMacAddressLegacy);
2780
2780
 
2781
2781
  // Parse build number as integer for version checks (local field)
2782
2782
  try {
@@ -2958,16 +2958,16 @@ public class MentraLive extends SGCManager {
2958
2958
  DeviceStore.INSTANCE.apply("glasses", "otaVersionUrl", (String) fields.get("ota_version_url"));
2959
2959
  }
2960
2960
  if (fields.containsKey("firmware_version")) {
2961
- DeviceStore.INSTANCE.apply("glasses", "fwVersion", (String) fields.get("firmware_version"));
2961
+ DeviceStore.INSTANCE.apply("glasses", "firmwareVersion", (String) fields.get("firmware_version"));
2962
2962
  }
2963
2963
  if (fields.containsKey("bes_fw_version")) {
2964
- DeviceStore.INSTANCE.apply("glasses", "besFwVersion", (String) fields.get("bes_fw_version"));
2964
+ DeviceStore.INSTANCE.apply("glasses", "besFirmwareVersion", (String) fields.get("bes_fw_version"));
2965
2965
  }
2966
2966
  if (fields.containsKey("mtk_fw_version")) {
2967
- DeviceStore.INSTANCE.apply("glasses", "mtkFwVersion", (String) fields.get("mtk_fw_version"));
2967
+ DeviceStore.INSTANCE.apply("glasses", "mtkFirmwareVersion", (String) fields.get("mtk_fw_version"));
2968
2968
  }
2969
2969
  if (fields.containsKey("bt_mac_address")) {
2970
- DeviceStore.INSTANCE.apply("glasses", "btMacAddress", (String) fields.get("bt_mac_address"));
2970
+ DeviceStore.INSTANCE.apply("glasses", "bluetoothMacAddress", (String) fields.get("bt_mac_address"));
2971
2971
  }
2972
2972
 
2973
2973
 
@@ -3625,7 +3625,7 @@ public class MentraLive extends SGCManager {
3625
3625
 
3626
3626
  @Override
3627
3627
  public void sendGalleryMode() {
3628
- boolean active = (Boolean) DeviceStore.INSTANCE.get("bluetooth", "gallery_mode");
3628
+ boolean active = (Boolean) DeviceStore.INSTANCE.get("bluetooth", "galleryModeAuto");
3629
3629
  Bridge.log("LIVE: 📸 Sending gallery mode active to glasses: " + active);
3630
3630
  try {
3631
3631
  JSONObject json = new JSONObject();
@@ -4759,7 +4759,7 @@ public class MentraLive extends SGCManager {
4759
4759
  Map<String, Object> videoSettings = (Map<String, Object>) videoSettingsObj;
4760
4760
  videoWidth = ((Number) videoSettings.getOrDefault("width", videoWidth)).intValue();
4761
4761
  videoHeight = ((Number) videoSettings.getOrDefault("height", videoHeight)).intValue();
4762
- videoFps = ((Number) videoSettings.getOrDefault("fps", videoFps)).intValue();
4762
+ videoFps = ((Number) videoSettings.getOrDefault("frameRate", videoFps)).intValue();
4763
4763
  } else {
4764
4764
  Object width = DeviceStore.INSTANCE.get("bluetooth", "button_video_width");
4765
4765
  Object height = DeviceStore.INSTANCE.get("bluetooth", "button_video_height");
@@ -5249,7 +5249,7 @@ public class MentraLive extends SGCManager {
5249
5249
  }
5250
5250
 
5251
5251
  HashMap<String, Object> map = new HashMap<>();
5252
- map.put("vol", vol);
5252
+ map.put("level", vol);
5253
5253
  map.put("statusCode", status);
5254
5254
  Bridge.log("LIVE: sr_getvol received vol=" + vol + " (0-15), statusCode=" + status);
5255
5255
  if (ok != null) {
@@ -5823,8 +5823,8 @@ public class MentraLive extends SGCManager {
5823
5823
  String packageName,
5824
5824
  String action,
5825
5825
  String color,
5826
- int ontime,
5827
- int offtime,
5826
+ int onDurationMs,
5827
+ int offDurationMs,
5828
5828
  int count) {
5829
5829
  if (!isConnected || !glassesReady) {
5830
5830
  Bridge.log("LIVE: Cannot handle RGB LED control - glasses not connected");
@@ -5849,8 +5849,8 @@ public class MentraLive extends SGCManager {
5849
5849
  int ledIndex = ledIndexForColor(color);
5850
5850
  command.put("type", "rgb_led_control_on");
5851
5851
  command.put("led", ledIndex);
5852
- command.put("ontime", ontime);
5853
- command.put("offtime", offtime);
5852
+ command.put("ontime", onDurationMs);
5853
+ command.put("offtime", offDurationMs);
5854
5854
  command.put("count", count);
5855
5855
  break;
5856
5856
  case "off":
@@ -6487,7 +6487,7 @@ public class MentraLive extends SGCManager {
6487
6487
  }
6488
6488
 
6489
6489
  /**
6490
- * Send camera FOV setting to glasses (K900 / Mentra Live). Reads fov and roi_position from store.
6490
+ * Send camera FOV setting to glasses (K900 / Mentra Live). Reads fov and roiPosition from store.
6491
6491
  */
6492
6492
  @Override
6493
6493
  public void sendCameraFovSetting() {
@@ -6499,7 +6499,7 @@ public class MentraLive extends SGCManager {
6499
6499
  @SuppressWarnings("unchecked")
6500
6500
  java.util.Map<String, Object> map = (java.util.Map<String, Object>) raw;
6501
6501
  Object f = map.get("fov");
6502
- Object r = map.get("roi_position");
6502
+ Object r = map.get("roiPosition");
6503
6503
  if (f instanceof Number) fov = ((Number) f).intValue();
6504
6504
  if (r instanceof Number) roiPosition = ((Number) r).intValue();
6505
6505
  }
@@ -6507,7 +6507,7 @@ public class MentraLive extends SGCManager {
6507
6507
  Log.w(TAG, "Could not read camera_fov from store, using defaults", e);
6508
6508
  }
6509
6509
 
6510
- Bridge.log("LIVE: Sending camera FOV setting: fov=" + fov + ", roi_position=" + roiPosition);
6510
+ Bridge.log("LIVE: Sending camera FOV setting: fov=" + fov + ", roiPosition=" + roiPosition);
6511
6511
 
6512
6512
  if (!isConnected) {
6513
6513
  Log.w(TAG, "Cannot send camera FOV setting - not connected");
@@ -431,7 +431,7 @@ class MentraNex : SGCManager() {
431
431
  Bridge.log("sendReboot - not supported on Nex")
432
432
  }
433
433
 
434
- override fun sendRgbLedControl(requestId: String, packageName: String?, action: String, color: String?, ontime: Int, offtime: Int, count: Int) {
434
+ override fun sendRgbLedControl(requestId: String, packageName: String?, action: String, color: String?, onDurationMs: Int, offDurationMs: Int, count: Int) {
435
435
  Bridge.log("sendRgbLedControl - not supported on Nex");
436
436
  Bridge.sendRgbLedControlResponse(requestId, false, "device_not_supported");
437
437
  }
@@ -76,8 +76,8 @@ abstract class SGCManager {
76
76
  packageName: String?,
77
77
  action: String,
78
78
  color: String?,
79
- ontime: Int,
80
- offtime: Int,
79
+ onDurationMs: Int,
80
+ offDurationMs: Int,
81
81
  count: Int
82
82
  )
83
83
 
@@ -140,8 +140,8 @@ abstract class SGCManager {
140
140
  val firmwareVersion: String
141
141
  get() = DeviceStore.get("glasses", "firmwareVersion") as? String ?: ""
142
142
 
143
- val btMacAddress: String
144
- get() = DeviceStore.get("glasses", "btMacAddress") as? String ?: ""
143
+ val bluetoothMacAddress: String
144
+ get() = DeviceStore.get("glasses", "bluetoothMacAddress") as? String ?: ""
145
145
 
146
146
  val serialNumber: String
147
147
  get() = DeviceStore.get("glasses", "serialNumber") as? String ?: ""
@@ -140,8 +140,8 @@ class Simulated : SGCManager() {
140
140
  packageName: String?,
141
141
  action: String,
142
142
  color: String?,
143
- ontime: Int,
144
- offtime: Int,
143
+ onDurationMs: Int,
144
+ offDurationMs: Int,
145
145
  count: Int
146
146
  ) {
147
147
  Bridge.log("sendRgbLedControl - not supported on Simulated")
@@ -28,17 +28,17 @@ object ConnTypes {
28
28
  object MicTypes {
29
29
  const val PHONE_INTERNAL = "phone"
30
30
  const val GLASSES_CUSTOM = "glasses"
31
- const val BT_CLASSIC = "btclassic"
32
- const val BT = "bt"
33
- val ALL = arrayOf(PHONE_INTERNAL, GLASSES_CUSTOM, BT_CLASSIC, BT)
31
+ const val BLUETOOTH_CLASSIC = "bluetoothClassic"
32
+ const val BLUETOOTH = "bluetooth"
33
+ val ALL = arrayOf(PHONE_INTERNAL, GLASSES_CUSTOM, BLUETOOTH_CLASSIC, BLUETOOTH)
34
34
  }
35
35
 
36
36
  // convert to kotlin:
37
37
  object MicMap {
38
38
  val map: Map<String, List<String>> = mapOf(
39
- "auto" to listOf(MicTypes.GLASSES_CUSTOM, MicTypes.PHONE_INTERNAL, MicTypes.BT, MicTypes.BT_CLASSIC),
39
+ "auto" to listOf(MicTypes.GLASSES_CUSTOM, MicTypes.PHONE_INTERNAL, MicTypes.BLUETOOTH, MicTypes.BLUETOOTH_CLASSIC),
40
40
  "glasses" to listOf(MicTypes.GLASSES_CUSTOM),
41
41
  "phone" to listOf(MicTypes.PHONE_INTERNAL, MicTypes.GLASSES_CUSTOM),
42
- "bluetooth" to listOf(MicTypes.BT, MicTypes.BT_CLASSIC, MicTypes.PHONE_INTERNAL, MicTypes.GLASSES_CUSTOM),
42
+ "bluetooth" to listOf(MicTypes.BLUETOOTH, MicTypes.BLUETOOTH_CLASSIC, MicTypes.PHONE_INTERNAL, MicTypes.GLASSES_CUSTOM),
43
43
  )
44
- }
44
+ }