@mentra/bluetooth-sdk 0.1.2 → 0.1.4
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 +75 -19
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +13 -13
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +42 -18
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +19 -21
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +4 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +118 -103
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +110 -38
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +4 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +2 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +6 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +18 -18
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +4 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +2 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +6 -6
- package/app.plugin.js +3 -1
- package/build/BluetoothSdk.types.d.ts +126 -27
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_internal.d.ts +12 -0
- package/build/_internal.d.ts.map +1 -0
- package/build/_internal.js +11 -0
- package/build/_internal.js.map +1 -0
- package/build/{BluetoothSdkModule.d.ts → _private/BluetoothSdkModule.d.ts} +19 -8
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
- package/build/{BluetoothSdkModule.js → _private/BluetoothSdkModule.js} +41 -26
- package/build/_private/BluetoothSdkModule.js.map +1 -0
- package/build/index.d.ts +4 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -4
- package/build/index.js.map +1 -1
- package/build/react/index.d.ts +5 -0
- package/build/react/index.d.ts.map +1 -0
- package/build/react/index.js +5 -0
- package/build/react/index.js.map +1 -0
- package/build/react/useBluetoothEvent.d.ts +6 -0
- package/build/react/useBluetoothEvent.d.ts.map +1 -0
- package/build/react/useBluetoothEvent.js +21 -0
- package/build/react/useBluetoothEvent.js.map +1 -0
- package/build/react/useBluetoothScan.d.ts +22 -0
- package/build/react/useBluetoothScan.d.ts.map +1 -0
- package/build/react/useBluetoothScan.js +135 -0
- package/build/react/useBluetoothScan.js.map +1 -0
- package/build/react/useBluetoothStatus.d.ts +16 -0
- package/build/react/useBluetoothStatus.d.ts.map +1 -0
- package/build/react/useBluetoothStatus.js +137 -0
- package/build/react/useBluetoothStatus.js.map +1 -0
- package/build/react/useGlassesConnection.d.ts +29 -0
- package/build/react/useGlassesConnection.d.ts.map +1 -0
- package/build/react/useGlassesConnection.js +140 -0
- package/build/react/useGlassesConnection.js.map +1 -0
- package/ios/BluetoothSdkModule.swift +14 -9
- package/ios/Source/Bridge.swift +44 -12
- package/ios/Source/DeviceManager.swift +27 -26
- package/ios/Source/DeviceStore.swift +4 -4
- package/ios/Source/MentraBluetoothSDK.swift +250 -132
- package/ios/Source/controllers/ControllerManager.swift +5 -5
- package/ios/Source/controllers/R1.swift +3 -3
- package/ios/Source/services/PhoneMic.swift +5 -5
- package/ios/Source/sgcs/Frame.swift +1 -1
- package/ios/Source/sgcs/G1.swift +1 -1
- package/ios/Source/sgcs/G2.swift +3 -3
- package/ios/Source/sgcs/Mach1.swift +1 -1
- package/ios/Source/sgcs/MentraLive.swift +31 -33
- package/ios/Source/sgcs/MentraNex.swift +2 -2
- package/ios/Source/sgcs/SGCManager.swift +5 -5
- package/ios/Source/sgcs/Simulated.swift +3 -3
- package/ios/Source/utils/Constants.swift +6 -6
- package/ios/Source/utils/JSCExperiment.swift +8 -8
- package/ios/Source/utils/TarBz2Extractor.swift +2 -2
- package/package.json +19 -1
- package/src/BluetoothSdk.types.ts +186 -28
- package/src/_internal.ts +11 -0
- package/src/{BluetoothSdkModule.ts → _private/BluetoothSdkModule.ts} +71 -38
- package/src/index.ts +80 -4
- package/src/react/index.ts +22 -0
- package/src/react/useBluetoothEvent.ts +38 -0
- package/src/react/useBluetoothScan.ts +173 -0
- package/src/react/useBluetoothStatus.ts +180 -0
- package/src/react/useGlassesConnection.ts +194 -0
- package/build/BluetoothSdkModule.d.ts.map +0 -1
- 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(
|
|
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
|
-
|
|
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, "
|
|
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,
|
|
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",
|
|
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,
|
|
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, "
|
|
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.
|
|
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.
|
|
372
|
-
request.
|
|
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.
|
|
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["
|
|
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
|
-
|
|
61
|
-
|
|
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
|
|
121
|
-
get() = DeviceStore.get("glasses", "
|
|
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", "
|
|
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
|
-
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
2613
|
-
|
|
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", "
|
|
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
|
|
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", "
|
|
700
|
-
DeviceStore.INSTANCE.apply("glasses", "
|
|
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("
|
|
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", "
|
|
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", "
|
|
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", "
|
|
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", "
|
|
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", "
|
|
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", "
|
|
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("
|
|
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("
|
|
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
|
|
5827
|
-
int
|
|
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",
|
|
5853
|
-
command.put("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
|
|
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("
|
|
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 + ",
|
|
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?,
|
|
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
|
-
|
|
80
|
-
|
|
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
|
|
144
|
-
get() = DeviceStore.get("glasses", "
|
|
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
|
-
|
|
144
|
-
|
|
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
|
|
32
|
-
const val
|
|
33
|
-
val ALL = arrayOf(PHONE_INTERNAL, GLASSES_CUSTOM,
|
|
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.
|
|
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.
|
|
42
|
+
"bluetooth" to listOf(MicTypes.BLUETOOTH, MicTypes.BLUETOOTH_CLASSIC, MicTypes.PHONE_INTERNAL, MicTypes.GLASSES_CUSTOM),
|
|
43
43
|
)
|
|
44
|
-
}
|
|
44
|
+
}
|
package/app.plugin.js
CHANGED