@mentra/bluetooth-sdk 0.1.11 → 0.1.13

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 (80) hide show
  1. package/README.md +67 -11
  2. package/android/build.gradle +1 -0
  3. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkAnalytics.kt +182 -0
  4. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +73 -6
  5. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +10 -0
  6. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +83 -26
  7. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +1 -1
  8. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +266 -31
  9. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdkDebug.kt +14 -0
  10. package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +20 -0
  11. package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +153 -0
  12. package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +93 -10
  13. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +3 -14
  14. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +3 -6
  15. package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +1 -0
  16. package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +90 -4
  17. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.kt +3835 -0
  18. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +20 -23
  19. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/{Mach1.java → Mach1.kt} +517 -560
  20. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +8712 -0
  21. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +11 -1
  22. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +15 -13
  23. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +7 -14
  24. package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +2 -1
  25. package/build/BluetoothSdk.types.d.ts +72 -10
  26. package/build/BluetoothSdk.types.d.ts.map +1 -1
  27. package/build/BluetoothSdk.types.js.map +1 -1
  28. package/build/_private/BluetoothSdkModule.d.ts +9 -7
  29. package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
  30. package/build/_private/BluetoothSdkModule.js +0 -2
  31. package/build/_private/BluetoothSdkModule.js.map +1 -1
  32. package/build/_private/photoRequestPayload.d.ts +3 -1
  33. package/build/_private/photoRequestPayload.d.ts.map +1 -1
  34. package/build/_private/photoRequestPayload.js +43 -1
  35. package/build/_private/photoRequestPayload.js.map +1 -1
  36. package/build/debug.d.ts +3 -0
  37. package/build/debug.d.ts.map +1 -0
  38. package/build/debug.js +8 -0
  39. package/build/debug.js.map +1 -0
  40. package/build/index.d.ts +1 -1
  41. package/build/index.d.ts.map +1 -1
  42. package/build/index.js +16 -5
  43. package/build/index.js.map +1 -1
  44. package/ios/BluetoothSdkModule.swift +59 -64
  45. package/ios/Source/BluetoothSdkDefaults.swift +47 -0
  46. package/ios/Source/Bridge.swift +6 -0
  47. package/ios/Source/DeviceManager.swift +46 -32
  48. package/ios/Source/DeviceStore.swift +5 -1
  49. package/ios/Source/MentraBluetoothSDK.swift +357 -34
  50. package/ios/Source/MentraBluetoothSDKDebug.swift +12 -0
  51. package/ios/Source/ObservableStore.swift +11 -0
  52. package/ios/Source/OtaManifest.swift +170 -0
  53. package/ios/Source/camera/CameraModels.swift +267 -9
  54. package/ios/Source/controllers/ControllerManager.swift +2 -5
  55. package/ios/Source/controllers/R1.swift +2 -5
  56. package/ios/Source/events/BluetoothEvents.swift +3 -0
  57. package/ios/Source/internal/BluetoothAvailability.swift +20 -0
  58. package/ios/Source/internal/BluetoothSdkAnalytics.swift +160 -0
  59. package/ios/Source/sgcs/G1.swift +6 -5
  60. package/ios/Source/sgcs/G2.swift +20 -18
  61. package/ios/Source/sgcs/Mach1.swift +6 -5
  62. package/ios/Source/sgcs/MentraLive.swift +158 -38
  63. package/ios/Source/sgcs/MentraNex.swift +6 -5
  64. package/ios/Source/sgcs/SGCManager.swift +16 -7
  65. package/ios/Source/sgcs/Simulated.swift +7 -3
  66. package/ios/Source/status/DeviceStatus.swift +1 -1
  67. package/ios/Source/types/DeviceModels.swift +5 -1
  68. package/package.json +6 -1
  69. package/plugin/build/index.d.ts +4 -0
  70. package/plugin/build/withAndroid.d.ts +2 -3
  71. package/plugin/build/withAndroid.js +46 -0
  72. package/plugin/build/withIos.d.ts +2 -3
  73. package/plugin/build/withIos.js +32 -0
  74. package/src/BluetoothSdk.types.ts +80 -10
  75. package/src/_private/BluetoothSdkModule.ts +13 -10
  76. package/src/_private/photoRequestPayload.ts +45 -2
  77. package/src/debug.ts +9 -0
  78. package/src/index.ts +25 -6
  79. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +0 -3974
  80. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +0 -7405
package/build/index.js CHANGED
@@ -19,6 +19,8 @@ const PUBLIC_EVENT_NAMES = new Set([
19
19
  "photo_response",
20
20
  "photo_status",
21
21
  "video_recording_status",
22
+ "media_success",
23
+ "media_error",
22
24
  "gallery_status",
23
25
  "compatible_glasses_search_stop",
24
26
  "swipe_volume_status",
@@ -32,7 +34,6 @@ const PUBLIC_EVENT_NAMES = new Set([
32
34
  "mic_pcm",
33
35
  "mic_lc3",
34
36
  "stream_status",
35
- "ota_update_available",
36
37
  "ota_start_ack",
37
38
  "ota_status",
38
39
  "version_info",
@@ -44,6 +45,9 @@ const addListener = (eventName, listener) => {
44
45
  }
45
46
  return PrivateBluetoothSdkModule.addListener(eventName, listener);
46
47
  };
48
+ const startOtaUpdate = () => {
49
+ return PrivateBluetoothSdkModule.startOtaUpdate();
50
+ };
47
51
  export const BluetoothSdk = Object.freeze({
48
52
  addListener,
49
53
  getDefaultDevice: PrivateBluetoothSdkModule.getDefaultDevice.bind(PrivateBluetoothSdkModule),
@@ -70,7 +74,15 @@ export const BluetoothSdk = Object.freeze({
70
74
  setHotspotState: PrivateBluetoothSdkModule.setHotspotState.bind(PrivateBluetoothSdkModule),
71
75
  setGalleryModeEnabled: PrivateBluetoothSdkModule.setGalleryModeEnabled.bind(PrivateBluetoothSdkModule),
72
76
  setVoiceActivityDetectionEnabled: PrivateBluetoothSdkModule.setVoiceActivityDetectionEnabled.bind(PrivateBluetoothSdkModule),
73
- setButtonPhotoSettings: PrivateBluetoothSdkModule.setButtonPhotoSettings.bind(PrivateBluetoothSdkModule),
77
+ setButtonPhotoSettings: (settings) => {
78
+ // setButtonPhotoCaptureSettings is available in SDK 0.1.13+. Guard for OTA version-skew
79
+ // where a new JS bundle runs against an older native module that only has the string form.
80
+ if (typeof PrivateBluetoothSdkModule.setButtonPhotoCaptureSettings === "function") {
81
+ return PrivateBluetoothSdkModule.setButtonPhotoCaptureSettings(settings);
82
+ }
83
+ // Legacy fallback: old native bridge only accepts a size string
84
+ return PrivateBluetoothSdkModule.setButtonPhotoSettings({ size: settings.size ?? "max" });
85
+ },
74
86
  setButtonVideoRecordingSettings: PrivateBluetoothSdkModule.setButtonVideoRecordingSettings.bind(PrivateBluetoothSdkModule),
75
87
  setButtonCameraLed: PrivateBluetoothSdkModule.setButtonCameraLed.bind(PrivateBluetoothSdkModule),
76
88
  setButtonMaxRecordingTime: PrivateBluetoothSdkModule.setButtonMaxRecordingTime.bind(PrivateBluetoothSdkModule),
@@ -88,9 +100,8 @@ export const BluetoothSdk = Object.freeze({
88
100
  setGlassesMediaVolume: PrivateBluetoothSdkModule.setGlassesMediaVolume.bind(PrivateBluetoothSdkModule),
89
101
  rgbLedControl: PrivateBluetoothSdkModule.rgbLedControl.bind(PrivateBluetoothSdkModule),
90
102
  requestVersionInfo: PrivateBluetoothSdkModule.requestVersionInfo.bind(PrivateBluetoothSdkModule),
91
- checkForOtaUpdate: PrivateBluetoothSdkModule.sendOtaQueryStatus.bind(PrivateBluetoothSdkModule),
92
- startOtaUpdate: PrivateBluetoothSdkModule.sendOtaStart.bind(PrivateBluetoothSdkModule),
93
- retryOtaVersionCheck: PrivateBluetoothSdkModule.retryOtaVersionCheck.bind(PrivateBluetoothSdkModule),
103
+ checkForOtaUpdate: PrivateBluetoothSdkModule.checkForOtaUpdate.bind(PrivateBluetoothSdkModule),
104
+ startOtaUpdate,
94
105
  setSttModelDetails: PrivateBluetoothSdkModule.setSttModelDetails.bind(PrivateBluetoothSdkModule),
95
106
  getSttModelPath: PrivateBluetoothSdkModule.getSttModelPath.bind(PrivateBluetoothSdkModule),
96
107
  checkSttModelAvailable: PrivateBluetoothSdkModule.checkSttModelAvailable.bind(PrivateBluetoothSdkModule),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import PrivateBluetoothSdkModule from \"./_private/BluetoothSdkModule\"\nimport type {BluetoothSdkEventListener, BluetoothSdkEventName, BluetoothSdkPublicModule} from \"./BluetoothSdk.types\"\n\nconst PUBLIC_EVENT_NAMES = new Set<BluetoothSdkEventName>([\n \"log\",\n \"device_discovered\",\n \"default_device_changed\",\n \"glasses_not_ready\",\n \"button_press\",\n \"touch_event\",\n \"accel_event\",\n \"head_up\",\n \"voice_activity_detection_status\",\n \"speaking_status\",\n \"battery_status\",\n \"local_transcription\",\n \"wifi_status_change\",\n \"wifi_scan_result\",\n \"hotspot_status_change\",\n \"hotspot_error\",\n \"photo_response\",\n \"photo_status\",\n \"video_recording_status\",\n \"gallery_status\",\n \"compatible_glasses_search_stop\",\n \"swipe_volume_status\",\n \"switch_status\",\n \"rgb_led_control_response\",\n \"settings_ack\",\n \"pair_failure\",\n \"audio_pairing_needed\",\n \"audio_connected\",\n \"audio_disconnected\",\n \"mic_pcm\",\n \"mic_lc3\",\n \"stream_status\",\n \"ota_update_available\",\n \"ota_start_ack\",\n \"ota_status\",\n \"version_info\",\n \"extraction_progress\",\n])\n\nconst addListener: BluetoothSdkPublicModule[\"addListener\"] = (eventName, listener) => {\n if (!PUBLIC_EVENT_NAMES.has(eventName)) {\n throw new Error(`Unsupported BluetoothSdk event \"${eventName}\". Use @mentra/bluetooth-sdk/react for status state.`)\n }\n return PrivateBluetoothSdkModule.addListener(eventName, listener as BluetoothSdkEventListener<BluetoothSdkEventName>)\n}\n\nexport const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({\n addListener,\n getDefaultDevice: PrivateBluetoothSdkModule.getDefaultDevice.bind(PrivateBluetoothSdkModule),\n setDefaultDevice: PrivateBluetoothSdkModule.setDefaultDevice.bind(PrivateBluetoothSdkModule),\n clearDefaultDevice: PrivateBluetoothSdkModule.clearDefaultDevice.bind(PrivateBluetoothSdkModule),\n startScan: PrivateBluetoothSdkModule.startScan.bind(PrivateBluetoothSdkModule),\n stopScan: PrivateBluetoothSdkModule.stopScan.bind(PrivateBluetoothSdkModule),\n scan: PrivateBluetoothSdkModule.scan.bind(PrivateBluetoothSdkModule) as BluetoothSdkPublicModule[\"scan\"],\n connect: PrivateBluetoothSdkModule.connect.bind(PrivateBluetoothSdkModule),\n connectDefault: PrivateBluetoothSdkModule.connectDefault.bind(PrivateBluetoothSdkModule),\n cancelConnectionAttempt: PrivateBluetoothSdkModule.cancelConnectionAttempt.bind(PrivateBluetoothSdkModule),\n disconnect: PrivateBluetoothSdkModule.disconnect.bind(PrivateBluetoothSdkModule),\n forget: PrivateBluetoothSdkModule.forget.bind(PrivateBluetoothSdkModule),\n displayText: PrivateBluetoothSdkModule.displayText.bind(PrivateBluetoothSdkModule),\n clearDisplay: PrivateBluetoothSdkModule.clearDisplay.bind(PrivateBluetoothSdkModule),\n showDashboard: PrivateBluetoothSdkModule.showDashboard.bind(PrivateBluetoothSdkModule),\n setDashboardPosition: PrivateBluetoothSdkModule.setDashboardPosition.bind(PrivateBluetoothSdkModule),\n setHeadUpAngle: PrivateBluetoothSdkModule.setHeadUpAngle.bind(PrivateBluetoothSdkModule),\n setImuEnabled: PrivateBluetoothSdkModule.setImuEnabled.bind(PrivateBluetoothSdkModule),\n setScreenDisabled: PrivateBluetoothSdkModule.setScreenDisabled.bind(PrivateBluetoothSdkModule),\n requestWifiScan: PrivateBluetoothSdkModule.requestWifiScan.bind(PrivateBluetoothSdkModule),\n sendWifiCredentials: PrivateBluetoothSdkModule.sendWifiCredentials.bind(PrivateBluetoothSdkModule),\n forgetWifiNetwork: PrivateBluetoothSdkModule.forgetWifiNetwork.bind(PrivateBluetoothSdkModule),\n setHotspotState: PrivateBluetoothSdkModule.setHotspotState.bind(PrivateBluetoothSdkModule),\n setGalleryModeEnabled: PrivateBluetoothSdkModule.setGalleryModeEnabled.bind(PrivateBluetoothSdkModule),\n setVoiceActivityDetectionEnabled:\n PrivateBluetoothSdkModule.setVoiceActivityDetectionEnabled.bind(PrivateBluetoothSdkModule),\n setButtonPhotoSettings: PrivateBluetoothSdkModule.setButtonPhotoSettings.bind(PrivateBluetoothSdkModule),\n setButtonVideoRecordingSettings:\n PrivateBluetoothSdkModule.setButtonVideoRecordingSettings.bind(PrivateBluetoothSdkModule),\n setButtonCameraLed: PrivateBluetoothSdkModule.setButtonCameraLed.bind(PrivateBluetoothSdkModule),\n setButtonMaxRecordingTime: PrivateBluetoothSdkModule.setButtonMaxRecordingTime.bind(PrivateBluetoothSdkModule),\n setCameraFov: PrivateBluetoothSdkModule.setCameraFov.bind(PrivateBluetoothSdkModule),\n queryGalleryStatus: PrivateBluetoothSdkModule.queryGalleryStatus.bind(PrivateBluetoothSdkModule),\n requestPhoto: PrivateBluetoothSdkModule.requestPhoto.bind(PrivateBluetoothSdkModule),\n startVideoRecording: PrivateBluetoothSdkModule.startVideoRecording.bind(PrivateBluetoothSdkModule),\n stopVideoRecording: PrivateBluetoothSdkModule.stopVideoRecording.bind(PrivateBluetoothSdkModule),\n startStream: PrivateBluetoothSdkModule.startStream.bind(PrivateBluetoothSdkModule),\n stopStream: PrivateBluetoothSdkModule.stopStream.bind(PrivateBluetoothSdkModule),\n setMicState: PrivateBluetoothSdkModule.setMicState.bind(PrivateBluetoothSdkModule),\n setPreferredMic: PrivateBluetoothSdkModule.setPreferredMic.bind(PrivateBluetoothSdkModule),\n setOwnAppAudioPlaying: PrivateBluetoothSdkModule.setOwnAppAudioPlaying.bind(PrivateBluetoothSdkModule),\n getGlassesMediaVolume: PrivateBluetoothSdkModule.getGlassesMediaVolume.bind(PrivateBluetoothSdkModule),\n setGlassesMediaVolume: PrivateBluetoothSdkModule.setGlassesMediaVolume.bind(PrivateBluetoothSdkModule),\n rgbLedControl: PrivateBluetoothSdkModule.rgbLedControl.bind(PrivateBluetoothSdkModule),\n requestVersionInfo: PrivateBluetoothSdkModule.requestVersionInfo.bind(PrivateBluetoothSdkModule),\n checkForOtaUpdate: PrivateBluetoothSdkModule.sendOtaQueryStatus.bind(PrivateBluetoothSdkModule),\n startOtaUpdate: PrivateBluetoothSdkModule.sendOtaStart.bind(PrivateBluetoothSdkModule),\n retryOtaVersionCheck: PrivateBluetoothSdkModule.retryOtaVersionCheck.bind(PrivateBluetoothSdkModule),\n setSttModelDetails: PrivateBluetoothSdkModule.setSttModelDetails.bind(PrivateBluetoothSdkModule),\n getSttModelPath: PrivateBluetoothSdkModule.getSttModelPath.bind(PrivateBluetoothSdkModule),\n checkSttModelAvailable: PrivateBluetoothSdkModule.checkSttModelAvailable.bind(PrivateBluetoothSdkModule),\n validateSttModel: PrivateBluetoothSdkModule.validateSttModel.bind(PrivateBluetoothSdkModule),\n extractTarBz2: PrivateBluetoothSdkModule.extractTarBz2.bind(PrivateBluetoothSdkModule),\n restartTranscriber: PrivateBluetoothSdkModule.restartTranscriber.bind(PrivateBluetoothSdkModule),\n setTtsModelDetails: PrivateBluetoothSdkModule.setTtsModelDetails.bind(PrivateBluetoothSdkModule),\n getTtsModelPath: PrivateBluetoothSdkModule.getTtsModelPath.bind(PrivateBluetoothSdkModule),\n getTtsModelLanguage: PrivateBluetoothSdkModule.getTtsModelLanguage.bind(PrivateBluetoothSdkModule),\n checkTtsModelAvailable: PrivateBluetoothSdkModule.checkTtsModelAvailable.bind(PrivateBluetoothSdkModule),\n validateTtsModel: PrivateBluetoothSdkModule.validateTtsModel.bind(PrivateBluetoothSdkModule),\n generateTtsAudio: PrivateBluetoothSdkModule.generateTtsAudio.bind(PrivateBluetoothSdkModule),\n})\n\nexport default BluetoothSdk\n\nexport {\n CAMERA_FOV_DEFAULT,\n CAMERA_FOV_MAX,\n CAMERA_FOV_MIN,\n DeviceModels,\n isBusyGlassesConnectionStatus,\n isConnectedGlassesConnectionStatus,\n isConnectedWifiStatus,\n isEnabledHotspotStatus,\n isReadyGlassesConnectionStatus,\n} from \"./BluetoothSdk.types\"\n\nexport type {\n AccelEvent,\n AudioConnectedEvent,\n AudioDisconnectedEvent,\n AudioPairingNeededEvent,\n BatteryStatusEvent,\n BluetoothSdkEvent,\n BluetoothSdkEventListener,\n BluetoothSdkEventMap,\n BluetoothSdkEventName,\n BluetoothSdkPublicModule as BluetoothSdkModule,\n BluetoothSdkSubscription,\n ButtonPhotoSize,\n ButtonPressEvent,\n CameraFovPreset,\n CameraFovRequest,\n CameraFovResult,\n CameraRoiPosition,\n CompatibleGlassesSearchStopEvent,\n ConnectOptions,\n ConnectedGlassesConnectionStatus,\n ConnectedWifiStatus,\n Device,\n DeviceModel,\n EnabledHotspotStatus,\n GalleryStatusEvent,\n GlassesConnectionStatus,\n GlassesMediaVolumeGetResult,\n GlassesMediaVolumeSetResult,\n GlassesNotReadyEvent,\n HeadUpEvent,\n HotspotErrorEvent,\n HotspotStatus,\n HotspotStatusChangeEvent,\n LocalTranscriptionEvent,\n LogEvent,\n MicLc3Event,\n MicMode,\n MicPcmEvent,\n MicPreference,\n OtaStartAckEvent,\n OtaStatus,\n OtaStatusEvent,\n OtaQueryResult,\n OtaUpdateAvailableEvent,\n OtaUpdateInfo,\n PairFailureEvent,\n PhotoCaptureMetadata,\n PhotoResolvedConfig,\n PhotoCompression,\n PhotoFpsRange,\n PhotoMeteredPreview,\n PhotoResponseEvent,\n PhotoRequestedCaptureConfig,\n PhotoSize,\n PhotoStatusEvent,\n PhotoStatusState,\n PhotoSuccessResponseEvent,\n RgbLedAction,\n RgbLedColor,\n RgbLedControlResponseEvent,\n RgbLedControlSuccessResponseEvent,\n ScanModelOptions,\n ScanOptions,\n ScanResultsCallback,\n SpeakingStatusEvent,\n SettingsAckEvent,\n SettingsAckSetting,\n SettingsAckSuccessEvent,\n SettingsAckSuccessStatus,\n SettingsAckStatus,\n StreamAudioConfig,\n StreamResolvedConfig,\n StreamStartRequest,\n StreamStatusEvent,\n StreamStatusLifecycleState,\n StreamStatusReconnectState,\n StreamStatusState,\n StreamVideoConfig,\n SwipeVolumeStatusEvent,\n SwitchStatusEvent,\n TouchEvent,\n VideoRecordingStartedStatusEvent,\n VideoRecordingStatusEvent,\n VideoRecordingStatusState,\n VideoRecordingStoppedStatusEvent,\n VideoRecordingSuccessStatusEvent,\n VersionInfoEvent,\n VersionInfoResult,\n WifiScanResultEvent,\n VoiceActivityDetectionStatusEvent,\n WifiSearchResult,\n WifiStatus,\n WifiStatusChangeEvent,\n} from \"./BluetoothSdk.types\"\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import PrivateBluetoothSdkModule from \"./_private/BluetoothSdkModule\"\nimport type {\n BluetoothSdkEventListener,\n BluetoothSdkEventName,\n BluetoothSdkPublicModule,\n ButtonPhotoSettings,\n} from \"./BluetoothSdk.types\"\n\nconst PUBLIC_EVENT_NAMES = new Set<BluetoothSdkEventName>([\n \"log\",\n \"device_discovered\",\n \"default_device_changed\",\n \"glasses_not_ready\",\n \"button_press\",\n \"touch_event\",\n \"accel_event\",\n \"head_up\",\n \"voice_activity_detection_status\",\n \"speaking_status\",\n \"battery_status\",\n \"local_transcription\",\n \"wifi_status_change\",\n \"wifi_scan_result\",\n \"hotspot_status_change\",\n \"hotspot_error\",\n \"photo_response\",\n \"photo_status\",\n \"video_recording_status\",\n \"media_success\",\n \"media_error\",\n \"gallery_status\",\n \"compatible_glasses_search_stop\",\n \"swipe_volume_status\",\n \"switch_status\",\n \"rgb_led_control_response\",\n \"settings_ack\",\n \"pair_failure\",\n \"audio_pairing_needed\",\n \"audio_connected\",\n \"audio_disconnected\",\n \"mic_pcm\",\n \"mic_lc3\",\n \"stream_status\",\n \"ota_start_ack\",\n \"ota_status\",\n \"version_info\",\n \"extraction_progress\",\n])\n\nconst addListener: BluetoothSdkPublicModule[\"addListener\"] = (eventName, listener) => {\n if (!PUBLIC_EVENT_NAMES.has(eventName)) {\n throw new Error(`Unsupported BluetoothSdk event \"${eventName}\". Use @mentra/bluetooth-sdk/react for status state.`)\n }\n return PrivateBluetoothSdkModule.addListener(eventName, listener as BluetoothSdkEventListener<BluetoothSdkEventName>)\n}\n\nconst startOtaUpdate: BluetoothSdkPublicModule[\"startOtaUpdate\"] = () => {\n return PrivateBluetoothSdkModule.startOtaUpdate()\n}\n\nexport const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({\n addListener,\n getDefaultDevice: PrivateBluetoothSdkModule.getDefaultDevice.bind(PrivateBluetoothSdkModule),\n setDefaultDevice: PrivateBluetoothSdkModule.setDefaultDevice.bind(PrivateBluetoothSdkModule),\n clearDefaultDevice: PrivateBluetoothSdkModule.clearDefaultDevice.bind(PrivateBluetoothSdkModule),\n startScan: PrivateBluetoothSdkModule.startScan.bind(PrivateBluetoothSdkModule),\n stopScan: PrivateBluetoothSdkModule.stopScan.bind(PrivateBluetoothSdkModule),\n scan: PrivateBluetoothSdkModule.scan.bind(PrivateBluetoothSdkModule) as BluetoothSdkPublicModule[\"scan\"],\n connect: PrivateBluetoothSdkModule.connect.bind(PrivateBluetoothSdkModule),\n connectDefault: PrivateBluetoothSdkModule.connectDefault.bind(PrivateBluetoothSdkModule),\n cancelConnectionAttempt: PrivateBluetoothSdkModule.cancelConnectionAttempt.bind(PrivateBluetoothSdkModule),\n disconnect: PrivateBluetoothSdkModule.disconnect.bind(PrivateBluetoothSdkModule),\n forget: PrivateBluetoothSdkModule.forget.bind(PrivateBluetoothSdkModule),\n displayText: PrivateBluetoothSdkModule.displayText.bind(PrivateBluetoothSdkModule),\n clearDisplay: PrivateBluetoothSdkModule.clearDisplay.bind(PrivateBluetoothSdkModule),\n showDashboard: PrivateBluetoothSdkModule.showDashboard.bind(PrivateBluetoothSdkModule),\n setDashboardPosition: PrivateBluetoothSdkModule.setDashboardPosition.bind(PrivateBluetoothSdkModule),\n setHeadUpAngle: PrivateBluetoothSdkModule.setHeadUpAngle.bind(PrivateBluetoothSdkModule),\n setImuEnabled: PrivateBluetoothSdkModule.setImuEnabled.bind(PrivateBluetoothSdkModule),\n setScreenDisabled: PrivateBluetoothSdkModule.setScreenDisabled.bind(PrivateBluetoothSdkModule),\n requestWifiScan: PrivateBluetoothSdkModule.requestWifiScan.bind(PrivateBluetoothSdkModule),\n sendWifiCredentials: PrivateBluetoothSdkModule.sendWifiCredentials.bind(PrivateBluetoothSdkModule),\n forgetWifiNetwork: PrivateBluetoothSdkModule.forgetWifiNetwork.bind(PrivateBluetoothSdkModule),\n setHotspotState: PrivateBluetoothSdkModule.setHotspotState.bind(PrivateBluetoothSdkModule),\n setGalleryModeEnabled: PrivateBluetoothSdkModule.setGalleryModeEnabled.bind(PrivateBluetoothSdkModule),\n setVoiceActivityDetectionEnabled:\n PrivateBluetoothSdkModule.setVoiceActivityDetectionEnabled.bind(PrivateBluetoothSdkModule),\n setButtonPhotoSettings: (settings: ButtonPhotoSettings) => {\n // setButtonPhotoCaptureSettings is available in SDK 0.1.13+. Guard for OTA version-skew\n // where a new JS bundle runs against an older native module that only has the string form.\n if (typeof PrivateBluetoothSdkModule.setButtonPhotoCaptureSettings === \"function\") {\n return PrivateBluetoothSdkModule.setButtonPhotoCaptureSettings(settings)\n }\n // Legacy fallback: old native bridge only accepts a size string\n return PrivateBluetoothSdkModule.setButtonPhotoSettings({size: settings.size ?? \"max\"} as any)\n },\n setButtonVideoRecordingSettings:\n PrivateBluetoothSdkModule.setButtonVideoRecordingSettings.bind(PrivateBluetoothSdkModule),\n setButtonCameraLed: PrivateBluetoothSdkModule.setButtonCameraLed.bind(PrivateBluetoothSdkModule),\n setButtonMaxRecordingTime: PrivateBluetoothSdkModule.setButtonMaxRecordingTime.bind(PrivateBluetoothSdkModule),\n setCameraFov: PrivateBluetoothSdkModule.setCameraFov.bind(PrivateBluetoothSdkModule),\n queryGalleryStatus: PrivateBluetoothSdkModule.queryGalleryStatus.bind(PrivateBluetoothSdkModule),\n requestPhoto: PrivateBluetoothSdkModule.requestPhoto.bind(PrivateBluetoothSdkModule),\n startVideoRecording: PrivateBluetoothSdkModule.startVideoRecording.bind(PrivateBluetoothSdkModule),\n stopVideoRecording: PrivateBluetoothSdkModule.stopVideoRecording.bind(PrivateBluetoothSdkModule),\n startStream: PrivateBluetoothSdkModule.startStream.bind(PrivateBluetoothSdkModule),\n stopStream: PrivateBluetoothSdkModule.stopStream.bind(PrivateBluetoothSdkModule),\n setMicState: PrivateBluetoothSdkModule.setMicState.bind(PrivateBluetoothSdkModule),\n setPreferredMic: PrivateBluetoothSdkModule.setPreferredMic.bind(PrivateBluetoothSdkModule),\n setOwnAppAudioPlaying: PrivateBluetoothSdkModule.setOwnAppAudioPlaying.bind(PrivateBluetoothSdkModule),\n getGlassesMediaVolume: PrivateBluetoothSdkModule.getGlassesMediaVolume.bind(PrivateBluetoothSdkModule),\n setGlassesMediaVolume: PrivateBluetoothSdkModule.setGlassesMediaVolume.bind(PrivateBluetoothSdkModule),\n rgbLedControl: PrivateBluetoothSdkModule.rgbLedControl.bind(PrivateBluetoothSdkModule),\n requestVersionInfo: PrivateBluetoothSdkModule.requestVersionInfo.bind(PrivateBluetoothSdkModule),\n checkForOtaUpdate: PrivateBluetoothSdkModule.checkForOtaUpdate.bind(PrivateBluetoothSdkModule),\n startOtaUpdate,\n setSttModelDetails: PrivateBluetoothSdkModule.setSttModelDetails.bind(PrivateBluetoothSdkModule),\n getSttModelPath: PrivateBluetoothSdkModule.getSttModelPath.bind(PrivateBluetoothSdkModule),\n checkSttModelAvailable: PrivateBluetoothSdkModule.checkSttModelAvailable.bind(PrivateBluetoothSdkModule),\n validateSttModel: PrivateBluetoothSdkModule.validateSttModel.bind(PrivateBluetoothSdkModule),\n extractTarBz2: PrivateBluetoothSdkModule.extractTarBz2.bind(PrivateBluetoothSdkModule),\n restartTranscriber: PrivateBluetoothSdkModule.restartTranscriber.bind(PrivateBluetoothSdkModule),\n setTtsModelDetails: PrivateBluetoothSdkModule.setTtsModelDetails.bind(PrivateBluetoothSdkModule),\n getTtsModelPath: PrivateBluetoothSdkModule.getTtsModelPath.bind(PrivateBluetoothSdkModule),\n getTtsModelLanguage: PrivateBluetoothSdkModule.getTtsModelLanguage.bind(PrivateBluetoothSdkModule),\n checkTtsModelAvailable: PrivateBluetoothSdkModule.checkTtsModelAvailable.bind(PrivateBluetoothSdkModule),\n validateTtsModel: PrivateBluetoothSdkModule.validateTtsModel.bind(PrivateBluetoothSdkModule),\n generateTtsAudio: PrivateBluetoothSdkModule.generateTtsAudio.bind(PrivateBluetoothSdkModule),\n})\n\nexport default BluetoothSdk\n\nexport {\n CAMERA_FOV_DEFAULT,\n CAMERA_FOV_MAX,\n CAMERA_FOV_MIN,\n DeviceModels,\n isBusyGlassesConnectionStatus,\n isConnectedGlassesConnectionStatus,\n isConnectedWifiStatus,\n isEnabledHotspotStatus,\n isReadyGlassesConnectionStatus,\n} from \"./BluetoothSdk.types\"\n\nexport type {\n AccelEvent,\n AudioConnectedEvent,\n AudioDisconnectedEvent,\n AudioPairingNeededEvent,\n BatteryStatusEvent,\n BluetoothSdkEvent,\n BluetoothSdkEventListener,\n BluetoothSdkEventMap,\n BluetoothSdkEventName,\n BluetoothSdkPublicModule as BluetoothSdkModule,\n BluetoothSdkSubscription,\n ButtonPhotoSize,\n ButtonPhotoSettings,\n ButtonPressEvent,\n CameraFovPreset,\n CameraFovRequest,\n CameraFovResult,\n CameraRoiPosition,\n CompatibleGlassesSearchStopEvent,\n ConnectOptions,\n ConnectedGlassesConnectionStatus,\n ConnectedWifiStatus,\n Device,\n DeviceModel,\n EnabledHotspotStatus,\n GalleryStatusEvent,\n GlassesConnectionStatus,\n GlassesMediaVolumeGetResult,\n GlassesMediaVolumeSetResult,\n GlassesNotReadyEvent,\n HeadUpEvent,\n HotspotErrorEvent,\n HotspotStatus,\n HotspotStatusChangeEvent,\n LocalTranscriptionEvent,\n LogEvent,\n MicLc3Event,\n MicMode,\n MicPcmEvent,\n MicPreference,\n OtaStartAckEvent,\n OtaStatus,\n OtaStatusEvent,\n OtaQueryResult,\n OtaUpdateAvailableEvent,\n OtaUpdateInfo,\n PairFailureEvent,\n PhotoCaptureMetadata,\n PhotoResolvedConfig,\n PhotoCompression,\n PhotoFpsRange,\n PhotoMeteredPreview,\n PhotoResponseEvent,\n PhotoRequestedCaptureConfig,\n PhotoRequestParams,\n PhotoSize,\n PhotoStatusEvent,\n PhotoStatusState,\n PhotoSuccessResponseEvent,\n RgbLedAction,\n RgbLedColor,\n RgbLedControlResponseEvent,\n RgbLedControlSuccessResponseEvent,\n ScanModelOptions,\n ScanOptions,\n ScanResultsCallback,\n SpeakingStatusEvent,\n SettingsAckEvent,\n SettingsAckSetting,\n SettingsAckSuccessEvent,\n SettingsAckSuccessStatus,\n SettingsAckStatus,\n StreamAudioConfig,\n StreamResolvedConfig,\n StreamStartRequest,\n StreamStatusEvent,\n StreamStatusLifecycleState,\n StreamStatusReconnectState,\n StreamStatusState,\n StreamVideoConfig,\n SwipeVolumeStatusEvent,\n SwitchStatusEvent,\n TouchEvent,\n VideoRecordingStartedStatusEvent,\n VideoRecordingStatusEvent,\n VideoRecordingStatusState,\n VideoRecordingStoppedStatusEvent,\n VideoRecordingSuccessStatusEvent,\n VersionInfoEvent,\n VersionInfoResult,\n WifiScanResultEvent,\n VoiceActivityDetectionStatusEvent,\n WifiSearchResult,\n WifiStatus,\n WifiStatusChangeEvent,\n} from \"./BluetoothSdk.types\"\n"]}
@@ -32,6 +32,8 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
32
32
  "photo_response",
33
33
  "photo_status",
34
34
  "video_recording_status",
35
+ "media_success",
36
+ "media_error",
35
37
  "gallery_status",
36
38
  "compatible_glasses_search_stop",
37
39
  "heartbeat_sent",
@@ -329,6 +331,11 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
329
331
  return try await sdk.setButtonPhotoSettings(size: ButtonPhotoSize(rawValue: size) ?? .medium).values
330
332
  }
331
333
 
334
+ AsyncFunction("setButtonPhotoCaptureSettings") { (params: [String: Any]) in
335
+ let sdk = await MainActor.run { self.bluetoothSdk() }
336
+ return try await sdk.setButtonPhotoSettings(ButtonPhotoSettings.from(params: params)).values
337
+ }
338
+
332
339
  AsyncFunction("setButtonVideoRecordingSettings") { (width: Int, height: Int, fps: Int) in
333
340
  let sdk = await MainActor.run { self.bluetoothSdk() }
334
341
  return try await sdk.setButtonVideoRecordingSettings(width: width, height: height, fps: fps).values
@@ -359,66 +366,42 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
359
366
  }
360
367
 
361
368
  AsyncFunction("requestPhoto") { (params: [String: Any]) in
362
- let requestId = params["requestId"] as? String ?? ""
363
- let appId = params["appId"] as? String ?? ""
369
+ let req = PhotoRequest.from(params: params)
364
370
  Bridge.log(
365
- "NATIVE: PHOTO PIPELINE [3/6] BluetoothSdk.requestPhoto requestId=\(requestId) appId=\(appId)"
371
+ "NATIVE: PHOTO PIPELINE [3/6] BluetoothSdk.requestPhoto requestId=\(req.requestId) appId=\(req.appId) size=\(req.size.rawValue) compress=\(req.compress?.rawValue ?? "none") aeDivisor=\(req.aeExposureDivisor.map { String($0) } ?? "nil")"
366
372
  )
367
- let size = params["size"] as? String ?? "medium"
368
- let webhookUrl = params["webhookUrl"] as? String ?? ""
369
- let authToken = params["authToken"] as? String ?? ""
370
- let compress = params["compress"] as? String ?? "none"
371
- let flash = params["flash"] as? Bool ?? true
372
- let save = params["save"] as? Bool ?? params["saveToGallery"] as? Bool ?? false
373
- let sound = params["sound"] as? Bool ?? true
374
- let exposureTimeNs: Double?
375
- switch params["exposureTimeNs"] {
376
- case let value as Double:
377
- exposureTimeNs = value
378
- case let value as Int:
379
- exposureTimeNs = Double(value)
380
- case let value as NSNumber:
381
- exposureTimeNs = value.doubleValue
382
- default:
383
- exposureTimeNs = nil
384
- }
385
- let iso: Int?
386
- switch params["iso"] {
387
- case let value as Int:
388
- iso = value > 0 ? value : nil
389
- case let value as Double:
390
- // Guard against Int(Double) trapping on out-of-range values.
391
- iso = (value.isFinite && value > 0 && value < Double(Int.max)) ? Int(value) : nil
392
- case let value as NSNumber:
393
- let intValue = value.intValue
394
- iso = intValue > 0 ? intValue : nil
395
- default:
396
- iso = nil
397
- }
398
373
 
399
374
  let sdk = await MainActor.run { self.bluetoothSdk() }
400
- return try await sdk.requestPhoto(
401
- PhotoRequest(
402
- requestId: requestId,
403
- appId: appId,
404
- size: PhotoSize(rawValue: size) ?? .medium,
405
- webhookUrl: webhookUrl,
406
- authToken: authToken,
407
- compress: PhotoCompression(rawValue: compress),
408
- flash: flash,
409
- save: save,
410
- sound: sound,
411
- exposureTimeNs: exposureTimeNs,
412
- iso: iso
413
- )
414
- ).values
375
+ return try await sdk.requestPhoto(req).values
415
376
  }
416
377
 
417
378
  // MARK: - OTA Commands
418
379
 
419
- AsyncFunction("sendOtaStart") {
380
+ Function("setOtaVersionUrl") { (otaVersionUrl: String) in
381
+ try self.readOnMainActor {
382
+ let sdk = self.bluetoothSdk()
383
+ try sdk.setOtaVersionUrl(otaVersionUrl)
384
+ }
385
+ }
386
+
387
+ Function("getOtaVersionUrl") {
388
+ try self.readOnMainActor {
389
+ let sdk = self.bluetoothSdk()
390
+ return try sdk.getOtaVersionUrl()
391
+ }
392
+ }
393
+
394
+ AsyncFunction("checkForOtaUpdate") {
395
+ let sdk = await MainActor.run { self.bluetoothSdk() }
396
+ return try await sdk.checkForOtaUpdate()
397
+ }
398
+
399
+ AsyncFunction("startOtaUpdate") { (otaVersionUrl: String?) in
420
400
  let sdk = await MainActor.run { self.bluetoothSdk() }
421
- return try await sdk.sendOtaStart().values
401
+ if let otaVersionUrl, !otaVersionUrl.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
402
+ return try await sdk.startOtaUpdate(otaVersionUrl: otaVersionUrl).values
403
+ }
404
+ return try await sdk.startOtaUpdate().values
422
405
  }
423
406
 
424
407
  AsyncFunction("sendOtaQueryStatus") {
@@ -456,9 +439,9 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
456
439
 
457
440
  AsyncFunction("startVideoRecording") {
458
441
  (requestId: String, save: Bool, sound: Bool, settings: [String: Any]?) in
459
- // Optional per-recording {width,height,fps}. Absent fields stay 0, which
460
- // the glasses treat as "use the saved button-video default". JS numbers
461
- // arrive as Double across the bridge, so coerce to Int.
442
+ /// Optional per-recording {width,height,fps}. Absent fields stay 0, which
443
+ /// the glasses treat as "use the saved button-video default". JS numbers
444
+ /// arrive as Double across the bridge, so coerce to Int.
462
445
  func dim(_ key: String) -> Int {
463
446
  (settings?[key] as? NSNumber)?.intValue ?? 0
464
447
  }
@@ -466,14 +449,20 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
466
449
  return try await sdk.startVideoRecording(
467
450
  VideoRecordingRequest(
468
451
  requestId: requestId, save: save, sound: sound,
469
- width: dim("width"), height: dim("height"), fps: dim("fps")
452
+ width: dim("width"), height: dim("height"), fps: dim("fps"),
453
+ maxRecordingTimeMinutes: dim("maxRecordingTimeMinutes")
470
454
  )
471
455
  ).values
472
456
  }
473
457
 
474
- AsyncFunction("stopVideoRecording") { (requestId: String) in
458
+ // webhookUrl/authToken are supplied at stop (not start) so the token is
459
+ // fresh when the upload runs. Empty/nil webhook = keep on device.
460
+ AsyncFunction("stopVideoRecording") {
461
+ (requestId: String, webhookUrl: String?, authToken: String?) in
475
462
  let sdk = await MainActor.run { self.bluetoothSdk() }
476
- return try await sdk.stopVideoRecording(requestId: requestId).values
463
+ return try await sdk.stopVideoRecording(
464
+ requestId: requestId, webhookUrl: webhookUrl, authToken: authToken
465
+ ).values
477
466
  }
478
467
 
479
468
  // MARK: - Stream Commands
@@ -624,22 +613,26 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
624
613
  return sdk
625
614
  }
626
615
 
627
- let sdk = MentraBluetoothSDK()
616
+ let sdk = MentraBluetoothSDK(
617
+ configuration: MentraBluetoothSDKConfiguration(
618
+ analytics: BluetoothSdkAnalyticsConfiguration().withSurface("react_native")
619
+ )
620
+ )
628
621
  sdk.delegate = self
629
622
  self.sdk = sdk
630
623
  return sdk
631
624
  }
632
625
 
633
- private func readOnMainActor<T>(_ body: @MainActor () -> T) -> T {
626
+ private func readOnMainActor<T>(_ body: @MainActor () throws -> T) rethrows -> T {
634
627
  if Thread.isMainThread {
635
- return MainActor.assumeIsolated {
636
- body()
628
+ return try MainActor.assumeIsolated {
629
+ try body()
637
630
  }
638
631
  }
639
632
 
640
- return DispatchQueue.main.sync {
641
- MainActor.assumeIsolated {
642
- body()
633
+ return try DispatchQueue.main.sync {
634
+ try MainActor.assumeIsolated {
635
+ try body()
643
636
  }
644
637
  }
645
638
  }
@@ -703,6 +696,8 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
703
696
  sendEvent("photo_status", status.values)
704
697
  case let .videoRecordingStatus(status):
705
698
  sendEvent("video_recording_status", status.values)
699
+ case let .mediaUpload(event):
700
+ sendEvent(event.type, event.values)
706
701
  case let .rgbLedControlResponse(response):
707
702
  sendEvent("rgb_led_control_response", response.values)
708
703
  case let .streamStatus(status):
@@ -2,5 +2,52 @@ import Foundation
2
2
 
3
3
  /// Defaults for the public Bluetooth SDK surface.
4
4
  enum BluetoothSdkDefaults {
5
+ static var sdkVersion: String? {
6
+ #if SWIFT_PACKAGE
7
+ normalizedSdkVersion(swiftPackageSdkVersion)
8
+ #else
9
+ packageVersion(from: sdkBundle)
10
+ #endif
11
+ }
12
+
5
13
  static let voiceActivityDetectionEnabled = false
14
+ private static let swiftPackageSdkVersion = "__MENTRA_BLUETOOTH_SDK_VERSION__"
15
+ private static let swiftPackageSdkVersionPlaceholder = "__MENTRA" + "_BLUETOOTH_SDK_VERSION__"
16
+
17
+ private static var sdkBundle: Bundle {
18
+ #if SWIFT_PACKAGE
19
+ Bundle.module
20
+ #else
21
+ Bundle(for: BluetoothSdkBundleToken.self)
22
+ #endif
23
+ }
24
+
25
+ private static func packageVersion(from bundle: Bundle) -> String? {
26
+ let version = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
27
+ let build = bundle.object(forInfoDictionaryKey: "CFBundleVersion") as? String
28
+
29
+ for candidate in [version, build] {
30
+ if let sdkVersion = normalizedSdkVersion(candidate) {
31
+ return sdkVersion
32
+ }
33
+ }
34
+
35
+ return nil
36
+ }
37
+
38
+ private static func normalizedSdkVersion(_ value: String?) -> String? {
39
+ guard let value else {
40
+ return nil
41
+ }
42
+ let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
43
+ guard !trimmed.isEmpty,
44
+ trimmed != "1.0",
45
+ trimmed != swiftPackageSdkVersionPlaceholder
46
+ else {
47
+ return nil
48
+ }
49
+ return trimmed
50
+ }
6
51
  }
52
+
53
+ private final class BluetoothSdkBundleToken {}
@@ -303,6 +303,12 @@ class Bridge {
303
303
  Bridge.sendTypedMessage("video_recording_status", body: body)
304
304
  }
305
305
 
306
+ static func sendMediaUploadEvent(type: String, values: [String: Any]) {
307
+ var body = values
308
+ body["type"] = type
309
+ Bridge.sendTypedMessage(type, body: body)
310
+ }
311
+
306
312
  static func sendVersionInfo(_ values: [String: Any]) {
307
313
  var body: [String: Any] = [
308
314
  "type": "version_info",
@@ -1169,9 +1169,9 @@ struct ViewState {
1169
1169
  /// Send OTA start command to glasses.
1170
1170
  /// Called when user approves an update (onboarding or background mode).
1171
1171
  /// Triggers glasses to begin download and installation.
1172
- func sendOtaStart() {
1172
+ func sendOtaStart(otaVersionUrl: String? = nil) {
1173
1173
  Bridge.log("MAN: 📱 Sending OTA start command to glasses")
1174
- sgc?.sendOtaStart()
1174
+ sgc?.sendOtaStart(otaVersionUrl: otaVersionUrl)
1175
1175
  }
1176
1176
 
1177
1177
  func sendOtaQueryStatus() {
@@ -1191,7 +1191,14 @@ struct ViewState {
1191
1191
  }
1192
1192
 
1193
1193
  func sendButtonPhotoSettings(requestId: String, size: String) throws {
1194
- try liveSgc().sendButtonPhotoSettings(requestId: requestId, size: size)
1194
+ try sendButtonPhotoSettings(
1195
+ requestId: requestId,
1196
+ settings: ButtonPhotoSettings(size: ButtonPhotoSize(normalizedRawValue: size))
1197
+ )
1198
+ }
1199
+
1200
+ func sendButtonPhotoSettings(requestId: String, settings: ButtonPhotoSettings) throws {
1201
+ try liveSgc().sendButtonPhotoSettings(requestId: requestId, settings: settings)
1195
1202
  }
1196
1203
 
1197
1204
  func sendButtonVideoRecordingSettings(requestId: String, width: Int, height: Int, fps: Int) throws {
@@ -1238,20 +1245,22 @@ struct ViewState {
1238
1245
 
1239
1246
  func startVideoRecording(
1240
1247
  _ requestId: String, _ save: Bool, _ sound: Bool, _ width: Int = 0, _ height: Int = 0,
1241
- _ fps: Int = 0
1248
+ _ fps: Int = 0, _ maxRecordingTimeMinutes: Int = 0
1242
1249
  ) {
1243
1250
  Bridge.log(
1244
- "MAN: onStartVideoRecording: requestId=\(requestId), save=\(save), flash=true, sound=\(sound), resolution=\(width)x\(height)@\(fps)fps"
1251
+ "MAN: onStartVideoRecording: requestId=\(requestId), save=\(save), flash=true, sound=\(sound), resolution=\(width)x\(height)@\(fps)fps, maxRecordingTimeMinutes=\(maxRecordingTimeMinutes)"
1245
1252
  )
1246
1253
  sgc?.startVideoRecording(
1247
1254
  requestId: requestId, save: save, flash: true, sound: sound, width: width, height: height,
1248
- fps: fps
1255
+ fps: fps, maxRecordingTimeMinutes: maxRecordingTimeMinutes
1249
1256
  )
1250
1257
  }
1251
1258
 
1252
- func stopVideoRecording(_ requestId: String) {
1253
- Bridge.log("MAN: onStopVideoRecording: requestId=\(requestId)")
1254
- sgc?.stopVideoRecording(requestId: requestId)
1259
+ func stopVideoRecording(_ requestId: String, _ webhookUrl: String?, _ authToken: String?) {
1260
+ Bridge.log(
1261
+ "MAN: onStopVideoRecording: requestId=\(requestId), webhook=\((webhookUrl?.isEmpty ?? true) ? "none" : "set")"
1262
+ )
1263
+ sgc?.stopVideoRecording(requestId: requestId, webhookUrl: webhookUrl, authToken: authToken)
1255
1264
  }
1256
1265
 
1257
1266
  func setMicState() {
@@ -1315,36 +1324,40 @@ struct ViewState {
1315
1324
  }
1316
1325
  }
1317
1326
 
1318
- func requestPhoto(
1319
- _ requestId: String,
1320
- _ appId: String,
1321
- _ size: String,
1322
- _ webhookUrl: String?,
1323
- _ authToken: String?,
1324
- _ compress: String?,
1325
- _ flash: Bool,
1326
- _ save: Bool,
1327
- _ sound: Bool,
1328
- exposureTimeNs: Double? = nil,
1329
- iso: Int? = nil
1330
- ) {
1331
- // Only honor manual exposure when it is a usable value; manual ISO is a one-shot
1332
- // companion to manual exposure and must be dropped when exposure is invalid.
1333
- let manualExposureNs = exposureTimeNs.flatMap { $0.isFinite && $0 > 0 ? $0 : nil }
1334
- let manualIso = manualExposureNs != nil ? iso.flatMap { $0 > 0 ? $0 : nil } : nil
1327
+ func requestPhoto(_ request: PhotoRequest) {
1328
+ let manualExposureNs = request.exposureTimeNs.flatMap { $0.isFinite && $0 > 0 ? $0 : nil }
1329
+ let manualIso = manualExposureNs != nil ? request.iso.flatMap { $0 > 0 ? $0 : nil } : nil
1330
+ let routed = PhotoRequest(
1331
+ requestId: request.requestId,
1332
+ appId: request.appId,
1333
+ size: request.size,
1334
+ webhookUrl: request.webhookUrl,
1335
+ authToken: request.authToken,
1336
+ compress: request.compress,
1337
+ flash: request.flash,
1338
+ save: request.save,
1339
+ sound: request.sound,
1340
+ exposureTimeNs: manualExposureNs,
1341
+ iso: manualIso,
1342
+ aeExposureDivisor: request.aeExposureDivisor,
1343
+ isoCap: request.isoCap,
1344
+ noiseReduction: request.noiseReduction,
1345
+ edgeEnhancement: request.edgeEnhancement,
1346
+ mfnr: request.mfnr,
1347
+ zsl: request.zsl,
1348
+ ispDigitalGain: request.ispDigitalGain,
1349
+ ispAnalogGain: request.ispAnalogGain
1350
+ )
1335
1351
  Bridge.log(
1336
- "MAN: PHOTO PIPELINE [4/6] DeviceManager.requestPhoto requestId=\(requestId) appId=\(appId) webhookUrl=\(webhookUrl ?? "nil") size=\(size) compress=\(compress ?? "none") flash=\(flash) save=\(save) sound=\(sound) exposureTimeNs=\(manualExposureNs.map { String($0) } ?? "nil") iso=\(manualIso.map { String($0) } ?? "auto") sgc=\(sgc != nil ? String(describing: type(of: sgc!)) : "null")"
1352
+ "MAN: PHOTO PIPELINE [4/6] DeviceManager.requestPhoto requestId=\(routed.requestId) appId=\(routed.appId) webhookUrl=\(routed.webhookUrl ?? "nil") size=\(routed.size.rawValue) compress=\(routed.compress?.rawValue ?? "none") flash=\(routed.flash) save=\(routed.save) sound=\(routed.sound) exposureTimeNs=\(manualExposureNs.map { String($0) } ?? "nil") iso=\(manualIso.map { String($0) } ?? "auto") aeDivisor=\(routed.aeExposureDivisor.map { String($0) } ?? "nil") isoCap=\(routed.isoCap.map { String($0) } ?? "nil") sgc=\(sgc != nil ? String(describing: type(of: sgc!)) : "null")"
1337
1353
  )
1338
1354
  guard let sgc else {
1339
1355
  Bridge.log(
1340
- "MAN: PHOTO PIPELINE — sgc is null (glasses not connected); dropping requestId=\(requestId)"
1356
+ "MAN: PHOTO PIPELINE — sgc is null (glasses not connected); dropping requestId=\(routed.requestId)"
1341
1357
  )
1342
1358
  return
1343
1359
  }
1344
- sgc.requestPhoto(
1345
- requestId, appId: appId, size: size, webhookUrl: webhookUrl, authToken: authToken,
1346
- compress: compress, flash: flash, save: save, sound: sound, exposureTimeNs: manualExposureNs, iso: manualIso
1347
- )
1360
+ sgc.requestPhoto(routed)
1348
1361
  }
1349
1362
 
1350
1363
  func connectDefault() {
@@ -1450,6 +1463,7 @@ struct ViewState {
1450
1463
  DeviceStore.shared.apply("glasses", "deviceModel", "")
1451
1464
  DeviceStore.shared.apply("glasses", "fullyBooted", false)
1452
1465
  DeviceStore.shared.apply("glasses", "connected", false)
1466
+ DeviceStore.shared.apply("glasses", "connectionState", ConnTypes.DISCONNECTED)
1453
1467
  DeviceStore.shared.apply("glasses", "voiceActivityDetectionEnabled", BluetoothSdkDefaults.voiceActivityDetectionEnabled)
1454
1468
  // disconnect the controller as well:
1455
1469
  searchingController = false
@@ -91,7 +91,7 @@ class DeviceStore {
91
91
  // Mentra Nex feature flag (off by default; toggled from Nex Developer Settings):
92
92
  store.set("bluetooth", "nex_chinese_captions", false)
93
93
  store.set("bluetooth", "screen_disabled", false)
94
- store.set("bluetooth", "button_photo_size", "medium")
94
+ store.set("bluetooth", "button_photo_size", "max")
95
95
  store.set("bluetooth", "button_camera_led", true)
96
96
  store.set("bluetooth", "button_max_recording_time", 10)
97
97
  store.set("bluetooth", "camera_fov", ["fov": 118, "roi_position": 0])
@@ -116,6 +116,10 @@ class DeviceStore {
116
116
  store.set(category, key, value)
117
117
  }
118
118
 
119
+ func remove(_ category: String, _ key: String) {
120
+ store.remove(category, key)
121
+ }
122
+
119
123
  private func scheduleDashboardHeightToGlasses() {
120
124
  dashboardHeightDebounceTask?.cancel()
121
125
  dashboardHeightDebounceTask = Task { @MainActor in