@mentra/bluetooth-sdk 0.1.0

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 (278) hide show
  1. package/README.md +278 -0
  2. package/android/build.gradle +167 -0
  3. package/android/lc3Lib/CMakeLists.txt +6 -0
  4. package/android/lc3Lib/build.gradle +109 -0
  5. package/android/lc3Lib/proguard-rules.pro +33 -0
  6. package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
  7. package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
  8. package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
  9. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
  10. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
  11. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
  12. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
  13. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
  14. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
  15. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
  16. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
  17. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
  18. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
  19. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
  20. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
  21. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
  22. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
  23. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
  24. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
  25. package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
  26. package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
  27. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
  28. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
  29. package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
  30. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
  31. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
  32. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
  33. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
  34. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
  35. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
  36. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
  37. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
  38. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
  39. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
  40. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
  41. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
  42. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
  43. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
  44. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
  45. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
  46. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
  47. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
  48. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
  49. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
  50. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
  51. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
  52. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
  53. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
  54. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
  55. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
  56. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
  57. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
  58. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
  59. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
  60. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
  61. package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
  62. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
  63. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
  64. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
  65. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
  66. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
  67. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
  68. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
  69. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
  70. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
  71. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
  72. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
  73. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
  74. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
  75. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
  76. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
  77. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
  78. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
  79. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
  80. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
  81. package/android/lc3Lib/src/main/java/com/mentra/lc3Lib/Lc3Cpp.java +38 -0
  82. package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
  83. package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
  84. package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
  85. package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
  86. package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
  87. package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
  88. package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
  89. package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
  90. package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
  91. package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
  92. package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
  93. package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
  94. package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
  95. package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
  96. package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
  97. package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
  98. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
  99. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
  100. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
  101. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
  102. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
  103. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
  104. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
  105. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
  106. package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
  107. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
  108. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
  109. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
  110. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
  111. package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
  112. package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
  113. package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
  114. package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
  115. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
  116. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
  117. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
  118. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
  119. package/android/settings.gradle +1 -0
  120. package/android/src/main/AndroidManifest.xml +40 -0
  121. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +528 -0
  122. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +610 -0
  123. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +1616 -0
  124. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +314 -0
  125. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +1710 -0
  126. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +554 -0
  127. package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +68 -0
  128. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +158 -0
  129. package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +934 -0
  130. package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +175 -0
  131. package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +1109 -0
  132. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +3974 -0
  133. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3551 -0
  134. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1327 -0
  135. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +6959 -0
  136. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1655 -0
  137. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +53675 -0
  138. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +202 -0
  139. package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +224 -0
  140. package/android/src/main/java/com/mentra/bluetoothsdk/stt/STTTools.kt +340 -0
  141. package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +465 -0
  142. package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +221 -0
  143. package/android/src/main/java/com/mentra/bluetoothsdk/utils/AES.java +106 -0
  144. package/android/src/main/java/com/mentra/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
  145. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
  146. package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +179 -0
  147. package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +44 -0
  148. package/android/src/main/java/com/mentra/bluetoothsdk/utils/G1Text.kt +436 -0
  149. package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
  150. package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleUploadService.java +76 -0
  151. package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +791 -0
  152. package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +186 -0
  153. package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +589 -0
  154. package/android/src/main/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitor.kt +303 -0
  155. package/android/src/main/java/com/mentra/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
  156. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
  157. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
  158. package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
  159. package/android/src/main/res/values/strings.xml +4 -0
  160. package/app.plugin.js +1 -0
  161. package/build/BluetoothSdk.types.d.ts +498 -0
  162. package/build/BluetoothSdk.types.d.ts.map +1 -0
  163. package/build/BluetoothSdk.types.js +23 -0
  164. package/build/BluetoothSdk.types.js.map +1 -0
  165. package/build/BluetoothSdkModule.d.ts +71 -0
  166. package/build/BluetoothSdkModule.d.ts.map +1 -0
  167. package/build/BluetoothSdkModule.js +106 -0
  168. package/build/BluetoothSdkModule.js.map +1 -0
  169. package/build/index.d.ts +3 -0
  170. package/build/index.d.ts.map +1 -0
  171. package/build/index.js +5 -0
  172. package/build/index.js.map +1 -0
  173. package/expo-module.config.json +9 -0
  174. package/ios/BluetoothSdkModule.swift +665 -0
  175. package/ios/MentraBluetoothSDK.podspec +77 -0
  176. package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
  177. package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
  178. package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
  179. package/ios/Packages/CoreObjC/attdet.c +92 -0
  180. package/ios/Packages/CoreObjC/attdet.h +44 -0
  181. package/ios/Packages/CoreObjC/bits.c +375 -0
  182. package/ios/Packages/CoreObjC/bits.h +315 -0
  183. package/ios/Packages/CoreObjC/bwdet.c +129 -0
  184. package/ios/Packages/CoreObjC/bwdet.h +69 -0
  185. package/ios/Packages/CoreObjC/common.h +151 -0
  186. package/ios/Packages/CoreObjC/energy.c +70 -0
  187. package/ios/Packages/CoreObjC/energy.h +43 -0
  188. package/ios/Packages/CoreObjC/fastmath.h +158 -0
  189. package/ios/Packages/CoreObjC/lc3.c +704 -0
  190. package/ios/Packages/CoreObjC/lc3.h +313 -0
  191. package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
  192. package/ios/Packages/CoreObjC/lc3_private.h +163 -0
  193. package/ios/Packages/CoreObjC/ltpf.c +905 -0
  194. package/ios/Packages/CoreObjC/ltpf.h +111 -0
  195. package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
  196. package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
  197. package/ios/Packages/CoreObjC/makefile.mk +35 -0
  198. package/ios/Packages/CoreObjC/mdct.c +469 -0
  199. package/ios/Packages/CoreObjC/mdct.h +57 -0
  200. package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
  201. package/ios/Packages/CoreObjC/meson.build +61 -0
  202. package/ios/Packages/CoreObjC/plc.c +61 -0
  203. package/ios/Packages/CoreObjC/plc.h +57 -0
  204. package/ios/Packages/CoreObjC/rnnoise.h +114 -0
  205. package/ios/Packages/CoreObjC/sns.c +880 -0
  206. package/ios/Packages/CoreObjC/sns.h +103 -0
  207. package/ios/Packages/CoreObjC/spec.c +907 -0
  208. package/ios/Packages/CoreObjC/spec.h +119 -0
  209. package/ios/Packages/CoreObjC/tables.c +3457 -0
  210. package/ios/Packages/CoreObjC/tables.h +94 -0
  211. package/ios/Packages/CoreObjC/tns.c +457 -0
  212. package/ios/Packages/CoreObjC/tns.h +99 -0
  213. package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
  214. package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
  215. package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +1659 -0
  216. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/cargs.h +162 -0
  217. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/c-api.h +1852 -0
  218. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/cxx-api.h +674 -0
  219. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +44 -0
  220. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
  221. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/sherpa-onnx.a +0 -0
  222. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
  223. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a +0 -0
  224. package/ios/Packages/VAD/Common/VAD/VADQuality.swift +41 -0
  225. package/ios/Packages/VAD/Common/VAD/VADState.swift +26 -0
  226. package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +29 -0
  227. package/ios/Packages/VAD/Common/VAD/VADType.swift +14 -0
  228. package/ios/Packages/VAD/Data/Configuration.swift +68 -0
  229. package/ios/Packages/VAD/Data/FrameSize.swift +39 -0
  230. package/ios/Packages/VAD/Data/Record.swift +13 -0
  231. package/ios/Packages/VAD/Data/Result.swift +22 -0
  232. package/ios/Packages/VAD/Data/SampleRate.swift +48 -0
  233. package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
  234. package/ios/Packages/VAD/Silero/SileroVAD.swift +284 -0
  235. package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +64 -0
  236. package/ios/Packages/libbz2/module.modulemap +5 -0
  237. package/ios/Packages/libbz2/shim.h +1 -0
  238. package/ios/Source/Bridge.swift +353 -0
  239. package/ios/Source/Bridging-Header.h +16 -0
  240. package/ios/Source/DeviceManager.swift +1478 -0
  241. package/ios/Source/DeviceStore.swift +295 -0
  242. package/ios/Source/MentraBluetoothSDK.swift +2439 -0
  243. package/ios/Source/ObservableStore.swift +88 -0
  244. package/ios/Source/PrivacyInfo.xcprivacy +23 -0
  245. package/ios/Source/controllers/ControllerManager.swift +187 -0
  246. package/ios/Source/controllers/R1.swift +827 -0
  247. package/ios/Source/services/PhoneMic.swift +662 -0
  248. package/ios/Source/sgcs/Frame.swift +651 -0
  249. package/ios/Source/sgcs/G1.swift +2505 -0
  250. package/ios/Source/sgcs/G2.swift +3730 -0
  251. package/ios/Source/sgcs/Mach1.swift +543 -0
  252. package/ios/Source/sgcs/MentraLive.swift +4708 -0
  253. package/ios/Source/sgcs/MentraNex.swift +2479 -0
  254. package/ios/Source/sgcs/SGCManager.swift +243 -0
  255. package/ios/Source/sgcs/Simulated.swift +270 -0
  256. package/ios/Source/sgcs/mentraos_ble.pb.swift +3811 -0
  257. package/ios/Source/stt/STTTools.swift +154 -0
  258. package/ios/Source/stt/SherpaOnnxTranscriber.swift +401 -0
  259. package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
  260. package/ios/Source/utils/Constants.swift +74 -0
  261. package/ios/Source/utils/Enums.swift +95 -0
  262. package/ios/Source/utils/G1Text.swift +2067 -0
  263. package/ios/Source/utils/JSCExperiment.swift +241 -0
  264. package/ios/Source/utils/MemoryMonitor.swift +44 -0
  265. package/ios/Source/utils/MessageChunker.swift +164 -0
  266. package/ios/Source/utils/Models.swift +135 -0
  267. package/ios/Source/utils/PhoneAudioMonitor.swift +226 -0
  268. package/ios/Source/utils/TarBz2Extractor.swift +206 -0
  269. package/package.json +78 -0
  270. package/plugin/build/index.d.ts +6 -0
  271. package/plugin/build/index.js +12 -0
  272. package/plugin/build/withAndroid.d.ts +4 -0
  273. package/plugin/build/withAndroid.js +80 -0
  274. package/plugin/build/withIos.d.ts +4 -0
  275. package/plugin/build/withIos.js +64 -0
  276. package/src/BluetoothSdk.types.ts +581 -0
  277. package/src/BluetoothSdkModule.ts +259 -0
  278. package/src/index.ts +4 -0
@@ -0,0 +1,106 @@
1
+ package com.mentra.bluetoothsdk.utils;
2
+
3
+ import android.util.Base64;
4
+
5
+ import java.io.UnsupportedEncodingException;
6
+ import java.security.MessageDigest;
7
+ import java.security.NoSuchAlgorithmException;
8
+ import java.util.Arrays;
9
+
10
+ import javax.crypto.Cipher;
11
+ import javax.crypto.spec.SecretKeySpec;
12
+
13
+ import android.util.Log;
14
+
15
+ public class AES {
16
+ private static final String TAG = "WearableIntelligenceSystem_AES";
17
+
18
+ private static SecretKeySpec secretKey;
19
+ private static byte[] key;
20
+
21
+ public static void setKey(String myKey)
22
+ {
23
+ MessageDigest sha = null;
24
+ try {
25
+ key = myKey.getBytes("UTF-8");
26
+ sha = MessageDigest.getInstance("SHA-1");
27
+ key = sha.digest(key);
28
+ key = Arrays.copyOf(key, 16);
29
+ secretKey = new SecretKeySpec(key, "AES");
30
+ }
31
+ catch (NoSuchAlgorithmException e) {
32
+ e.printStackTrace();
33
+ }
34
+ catch (UnsupportedEncodingException e) {
35
+ e.printStackTrace();
36
+ }
37
+ }
38
+
39
+ public static String encrypt(String strToEncrypt, String secret)
40
+ {
41
+ try
42
+ {
43
+ setKey(secret);
44
+ Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
45
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
46
+ return Base64.encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")), Base64.DEFAULT);
47
+ }
48
+ catch (Exception e)
49
+ {
50
+ Log.d(TAG, "Error while encrypting: " + e.toString());
51
+ }
52
+ return null;
53
+ }
54
+
55
+ //bytes version
56
+ public static byte [] encrypt(byte [ ] bytesToEncrypt, String secret)
57
+ {
58
+ try
59
+ {
60
+ setKey(secret);
61
+ Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
62
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
63
+ return cipher.doFinal(bytesToEncrypt);
64
+ }
65
+ catch (Exception e)
66
+ {
67
+ Log.d(TAG, "Error while encrypting: " + e.toString());
68
+ }
69
+ return null;
70
+ }
71
+
72
+ //String version
73
+ public static String decrypt(String strToDecrypt, String secret)
74
+ {
75
+ try
76
+ {
77
+ Log.d(TAG, "Secret key is: " + secret);
78
+ setKey(secret);
79
+ Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7PADDING");
80
+ cipher.init(Cipher.DECRYPT_MODE, secretKey);
81
+ return new String(cipher.doFinal(Base64.decode(strToDecrypt, Base64.DEFAULT)));
82
+ }
83
+ catch (Exception e)
84
+ {
85
+ Log.d(TAG, "Error while decrypting: " + e.toString());
86
+ }
87
+ return null;
88
+ }
89
+
90
+ //bytes version
91
+ public static byte [] decrypt(byte [] bytesToDecrypt, String secret)
92
+ {
93
+ try
94
+ {
95
+ setKey(secret);
96
+ Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7PADDING");
97
+ cipher.init(Cipher.DECRYPT_MODE, secretKey);
98
+ return cipher.doFinal(bytesToDecrypt);
99
+ }
100
+ catch (Exception e)
101
+ {
102
+ Log.d(TAG, "Error while decrypting: " + e.toString());
103
+ }
104
+ return null;
105
+ }
106
+ }
@@ -0,0 +1,189 @@
1
+ package com.mentra.bluetoothsdk.utils
2
+
3
+ import android.bluetooth.BluetoothAdapter
4
+ import android.bluetooth.BluetoothDevice
5
+ import android.content.BroadcastReceiver
6
+ import android.content.Context
7
+ import android.content.Intent
8
+ import android.content.IntentFilter
9
+ import android.media.AudioManager
10
+ import com.mentra.bluetoothsdk.Bridge
11
+
12
+ /**
13
+ * Android AudioSessionMonitor - maintains API parity with iOS implementation
14
+ *
15
+ * On Android, CTKD automatically handles BT Classic bonding including audio.
16
+ * This class provides a consistent API surface across platforms while being
17
+ * simpler than the iOS version since Android handles most of this automatically.
18
+ */
19
+ class AudioSessionMonitor private constructor(private val context: Context) {
20
+
21
+ companion object {
22
+ @Volatile
23
+ private var instance: AudioSessionMonitor? = null
24
+
25
+ fun getInstance(context: Context): AudioSessionMonitor {
26
+ return instance ?: synchronized(this) {
27
+ instance ?: AudioSessionMonitor(context.applicationContext).also {
28
+ instance = it
29
+ }
30
+ }
31
+ }
32
+ }
33
+
34
+ private val audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
35
+ private var isMonitoring = false
36
+ private var devicePattern: String? = null
37
+ private var callback: ((Boolean, String?) -> Unit)? = null
38
+
39
+ private val audioDeviceReceiver = object : BroadcastReceiver() {
40
+ override fun onReceive(context: Context?, intent: Intent?) {
41
+ when (intent?.action) {
42
+ AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED -> {
43
+ val state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1)
44
+ handleScoStateChange(state)
45
+ }
46
+ BluetoothDevice.ACTION_ACL_CONNECTED -> {
47
+ val device: BluetoothDevice? = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
48
+ device?.let { handleDeviceConnected(it) }
49
+ }
50
+ BluetoothDevice.ACTION_ACL_DISCONNECTED -> {
51
+ val device: BluetoothDevice? = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
52
+ device?.let { handleDeviceDisconnected(it) }
53
+ }
54
+ }
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Configure audio session for Bluetooth
60
+ * On Android, this is largely handled by the system, so this is mostly a no-op
61
+ * Returns true for API consistency with iOS
62
+ */
63
+ fun configureAudioSession(): Boolean {
64
+ Bridge.log("AudioMonitor: Audio session configured (Android auto-handles)")
65
+ return true
66
+ }
67
+
68
+ /**
69
+ * Check if a Bluetooth audio device matching the pattern is connected
70
+ * On Android, we check if SCO (Synchronous Connection-Oriented) audio is active
71
+ */
72
+ fun isAudioDeviceConnected(devicePattern: String): Boolean {
73
+ val isBluetoothA2dpOn = audioManager.isBluetoothA2dpOn
74
+ val isBluetoothScoOn = audioManager.isBluetoothScoOn
75
+
76
+ if (isBluetoothA2dpOn || isBluetoothScoOn) {
77
+ // Check if any connected device matches pattern
78
+ val adapter = BluetoothAdapter.getDefaultAdapter()
79
+ adapter?.bondedDevices?.forEach { device ->
80
+ if (device.name?.contains(devicePattern, ignoreCase = true) == true) {
81
+ Bridge.log("AudioMonitor: Found active audio device: ${device.name}")
82
+ return true
83
+ }
84
+ }
85
+ }
86
+
87
+ Bridge.log("AudioMonitor: No active audio device matching '$devicePattern'")
88
+ return false
89
+ }
90
+
91
+ /**
92
+ * Set Bluetooth device as preferred audio device
93
+ * On Android, this is handled automatically by CTKD bonding
94
+ * This method is a no-op for API parity with iOS
95
+ * Returns true if device is bonded (meaning audio will be available)
96
+ */
97
+ fun setAsPreferredAudioOutputDevice(devicePattern: String): Boolean {
98
+ val adapter = BluetoothAdapter.getDefaultAdapter() ?: return false
99
+
100
+ adapter.bondedDevices?.forEach { device ->
101
+ if (device.name?.contains(devicePattern, ignoreCase = true) == true) {
102
+ Bridge.log("AudioMonitor: Device '$devicePattern' is bonded, audio routing handled by system")
103
+ return true
104
+ }
105
+ }
106
+
107
+ Bridge.log("AudioMonitor: Device '$devicePattern' not bonded")
108
+ return false
109
+ }
110
+
111
+ /**
112
+ * Start monitoring for audio device connections/disconnections
113
+ */
114
+ fun startMonitoring(devicePattern: String, callback: (Boolean, String?) -> Unit) {
115
+ if (isMonitoring) {
116
+ Bridge.log("AudioMonitor: Already monitoring")
117
+ return
118
+ }
119
+
120
+ this.devicePattern = devicePattern
121
+ this.callback = callback
122
+
123
+ val filter = IntentFilter().apply {
124
+ addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)
125
+ addAction(BluetoothDevice.ACTION_ACL_CONNECTED)
126
+ addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED)
127
+ }
128
+
129
+ context.registerReceiver(audioDeviceReceiver, filter)
130
+ isMonitoring = true
131
+ Bridge.log("AudioMonitor: Started monitoring for '$devicePattern'")
132
+ }
133
+
134
+ /**
135
+ * Stop monitoring for audio device changes
136
+ */
137
+ fun stopMonitoring() {
138
+ if (!isMonitoring) {
139
+ Bridge.log("AudioMonitor: Not currently monitoring")
140
+ return
141
+ }
142
+
143
+ try {
144
+ context.unregisterReceiver(audioDeviceReceiver)
145
+ } catch (e: IllegalArgumentException) {
146
+ Bridge.log("AudioMonitor: Receiver was not registered")
147
+ }
148
+
149
+ isMonitoring = false
150
+ devicePattern = null
151
+ callback = null
152
+ Bridge.log("AudioMonitor: Stopped monitoring")
153
+ }
154
+
155
+ private fun handleScoStateChange(state: Int) {
156
+ val pattern = devicePattern ?: return
157
+
158
+ when (state) {
159
+ AudioManager.SCO_AUDIO_STATE_CONNECTED -> {
160
+ Bridge.log("AudioMonitor: SCO audio connected")
161
+ if (isAudioDeviceConnected(pattern)) {
162
+ callback?.invoke(true, pattern)
163
+ }
164
+ }
165
+ AudioManager.SCO_AUDIO_STATE_DISCONNECTED -> {
166
+ Bridge.log("AudioMonitor: SCO audio disconnected")
167
+ callback?.invoke(false, null)
168
+ }
169
+ }
170
+ }
171
+
172
+ private fun handleDeviceConnected(device: BluetoothDevice) {
173
+ val pattern = devicePattern ?: return
174
+
175
+ if (device.name?.contains(pattern, ignoreCase = true) == true) {
176
+ Bridge.log("AudioMonitor: Device '${device.name}' connected")
177
+ callback?.invoke(true, device.name)
178
+ }
179
+ }
180
+
181
+ private fun handleDeviceDisconnected(device: BluetoothDevice) {
182
+ val pattern = devicePattern ?: return
183
+
184
+ if (device.name?.contains(pattern, ignoreCase = true) == true) {
185
+ Bridge.log("AudioMonitor: Device '${device.name}' disconnected")
186
+ callback?.invoke(false, null)
187
+ }
188
+ }
189
+ }
@@ -0,0 +1,169 @@
1
+ package com.mentra.bluetoothsdk.utils;
2
+
3
+ import java.io.File;
4
+ import android.graphics.Bitmap;
5
+ import android.graphics.BitmapFactory;
6
+ import android.util.Log;
7
+ import android.graphics.Bitmap;
8
+ import java.io.ByteArrayOutputStream;
9
+ import java.io.IOException;
10
+ import java.io.OutputStream;
11
+
12
+ public class BitmapJavaUtils {
13
+ private static final String TAG = "WearableAi_BitmapJavaUtils";
14
+
15
+ public static Bitmap loadImageFromStorage(String path){
16
+ File imgFile = new File(path);
17
+ if(imgFile.exists()){
18
+ Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
19
+ return myBitmap;
20
+ } else {
21
+ Log.d(TAG, "Image doesn't exist");
22
+ return null;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Converts a standard Android ARGB Bitmap into a 1-bit-per-pixel (monochrome) BMP file in memory.
28
+ *
29
+ * <p>This method:
30
+ * <ul>
31
+ * <li>Thresholds each pixel to black or white (simple average-based threshold).
32
+ * <li>Packs the bits: leftmost pixel in the most significant bit.
33
+ * <li>Writes a BITMAPFILEHEADER + BITMAPINFOHEADER + 2-entry palette + raw 1-bpp data.
34
+ * </ul>
35
+ *
36
+ * @param bitmap the Android Bitmap to convert. Its alpha channel is ignored.
37
+ * @param invert if {@code false}, bits of 0 map to white, bits of 1 map to black;
38
+ * if {@code true}, the palette is reversed so 0 maps to black, 1 to white.
39
+ * @return A byte[] containing a valid 1-bpp BMP file.
40
+ * @throws IOException if an I/O error occurs writing to the buffer (unlikely in memory).
41
+ */
42
+ public static byte[] convertBitmapTo1BitBmpBytes(Bitmap bitmap, boolean invert) throws IOException {
43
+ int width = bitmap.getWidth();
44
+ int height = bitmap.getHeight();
45
+
46
+ // Each row is padded to a multiple of 4 bytes (32 bits).
47
+ int rowSizeBytes = ((width + 31) / 32) * 4;
48
+ int imageSize = rowSizeBytes * height;
49
+
50
+ // BMP header sizes for 1-bpp:
51
+ // - File header: 14 bytes
52
+ // - DIB header (BITMAPINFOHEADER): 40 bytes
53
+ // - Color table: 2 entries × 4 bytes each = 8 bytes
54
+ // => Pixel data offset = 14 + 40 + 8 = 62
55
+ int dataOffset = 62;
56
+ int fileSize = dataOffset + imageSize;
57
+
58
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(fileSize);
59
+
60
+ // ================== BMP FILE HEADER (14 bytes) ==================
61
+ // Signature: "BM"
62
+ baos.write('B');
63
+ baos.write('M');
64
+ // File size (4 bytes, LE)
65
+ writeIntLE(baos, fileSize);
66
+ // Reserved (4 bytes)
67
+ writeShortLE(baos, 0);
68
+ writeShortLE(baos, 0);
69
+ // Offset to pixel data
70
+ writeIntLE(baos, dataOffset);
71
+
72
+ // ================== DIB HEADER: BITMAPINFOHEADER (40 bytes) ==================
73
+ writeIntLE(baos, 40); // DIB header size
74
+ writeIntLE(baos, width); // Width
75
+ writeIntLE(baos, height); // Height (positive => bottom-to-top)
76
+ writeShortLE(baos, 1); // Planes = 1
77
+ writeShortLE(baos, 1); // Bits per pixel = 1
78
+ writeIntLE(baos, 0); // Compression = BI_RGB (uncompressed)
79
+ writeIntLE(baos, imageSize); // Image size
80
+ writeIntLE(baos, 2835); // X pixels per meter (72 DPI)
81
+ writeIntLE(baos, 2835); // Y pixels per meter (72 DPI)
82
+ writeIntLE(baos, 2); // # of colors in palette
83
+ writeIntLE(baos, 0); // # of important colors
84
+
85
+ // ================== COLOR TABLE (8 bytes: 2 entries × 4 bytes each) ==================
86
+ // Each color entry: (Blue, Green, Red, Reserved)
87
+ // If invert=false, then 0 => White, 1 => Black. Otherwise, 0 => Black, 1 => White.
88
+ if (!invert) {
89
+ // color index 0 => white
90
+ baos.write(0xFF); baos.write(0xFF); baos.write(0xFF); baos.write(0x00);
91
+ // color index 1 => black
92
+ baos.write(0x00); baos.write(0x00); baos.write(0x00); baos.write(0x00);
93
+ } else {
94
+ // color index 0 => black
95
+ baos.write(0x00); baos.write(0x00); baos.write(0x00); baos.write(0x00);
96
+ // color index 1 => white
97
+ baos.write(0xFF); baos.write(0xFF); baos.write(0xFF); baos.write(0x00);
98
+ }
99
+
100
+ // ================== PIXEL DATA (1-bpp, bottom-to-top) ==================
101
+ // We'll iterate from top row to bottom row in the Android sense,
102
+ // but actually output from bottom row to top row in BMP format.
103
+ int[] rowPixels = new int[width];
104
+
105
+ for (int y = 0; y < height; y++) {
106
+ int py = height - 1 - y; // "py" is the actual row index in the source
107
+ bitmap.getPixels(rowPixels, 0, width, 0, py, width, 1);
108
+
109
+ byte[] packedRow = new byte[rowSizeBytes];
110
+ int bitIndex = 0; // which bit within the current byte [0..7]
111
+ int byteIndex = 0; // which byte in packedRow
112
+
113
+ for (int x = 0; x < width; x++) {
114
+ int color = rowPixels[x];
115
+ int r = (color >> 16) & 0xFF;
116
+ int g = (color >> 8) & 0xFF;
117
+ int b = (color) & 0xFF;
118
+
119
+ // Simple threshold (tweak if you want better dithering)
120
+ int gray = (r + g + b) / 3;
121
+ // int pixelVal = (gray < 128) ? 1 : 0; // 0=white or 1=black depending on palette
122
+ int pixelVal = 0;
123
+ if (!invert) {
124
+ pixelVal = (gray < 128) ? 1 : 0; // Dark → 1 (black), Light → 0 (white)
125
+ } else {
126
+ pixelVal = (gray < 128) ? 0 : 1; // Dark → 0 (black), Light → 1 (white)
127
+ }
128
+
129
+ // The leftmost pixel goes in the MSB of the byte => bit position = 7 - bitIndex
130
+ packedRow[byteIndex] |= (pixelVal << (7 - bitIndex));
131
+
132
+ bitIndex++;
133
+ if (bitIndex == 8) {
134
+ bitIndex = 0;
135
+ byteIndex++;
136
+ }
137
+ }
138
+
139
+ baos.write(packedRow, 0, rowSizeBytes);
140
+ }
141
+
142
+ return baos.toByteArray();
143
+ }
144
+
145
+ /**
146
+ * Writes an integer as 4 little-endian bytes.
147
+ */
148
+ private static void writeIntLE(OutputStream out, int value) throws IOException {
149
+ out.write(value & 0xFF);
150
+ out.write((value >> 8) & 0xFF);
151
+ out.write((value >> 16) & 0xFF);
152
+ out.write((value >> 24) & 0xFF);
153
+ }
154
+
155
+ /**
156
+ * Writes a short as 2 little-endian bytes.
157
+ */
158
+ private static void writeShortLE(OutputStream out, int value) throws IOException {
159
+ out.write(value & 0xFF);
160
+ out.write((value >> 8) & 0xFF);
161
+ }
162
+
163
+ public static Bitmap bytesToBitmap(byte[] imageData) {
164
+ if (imageData == null || imageData.length == 0) {
165
+ return null;
166
+ }
167
+ return BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
168
+ }
169
+ }
@@ -0,0 +1,179 @@
1
+ package com.mentra.bluetoothsdk.utils;
2
+
3
+ import android.graphics.Bitmap;
4
+ import android.graphics.BitmapFactory;
5
+ import android.os.Build;
6
+ import android.util.Log;
7
+
8
+ import androidx.annotation.Nullable;
9
+
10
+ import java.io.ByteArrayOutputStream;
11
+ import java.io.IOException;
12
+ import java.util.concurrent.TimeUnit;
13
+
14
+ import okhttp3.MediaType;
15
+ import okhttp3.MultipartBody;
16
+ import okhttp3.OkHttpClient;
17
+ import okhttp3.Request;
18
+ import okhttp3.RequestBody;
19
+ import okhttp3.Response;
20
+
21
+ /**
22
+ * Service to handle BLE photo uploads including AVIF decoding and webhook posting
23
+ */
24
+ public class BlePhotoUploadService {
25
+ private static final String TAG = "BlePhotoUploadService";
26
+
27
+ public interface UploadCallback {
28
+ void onSuccess(String requestId);
29
+ void onError(String requestId, String error);
30
+ }
31
+
32
+ /**
33
+ * Process image data and upload to webhook
34
+ * @param imageData Raw image data (AVIF or JPEG)
35
+ * @param requestId Original request ID for tracking
36
+ * @param webhookUrl Destination webhook URL
37
+ * @param authToken Optional authentication token for upload
38
+ * @param callback Callback for success/error
39
+ */
40
+ public static void processAndUploadPhoto(byte[] imageData, String requestId,
41
+ String webhookUrl, @Nullable String authToken,
42
+ UploadCallback callback) {
43
+ new Thread(() -> {
44
+ try {
45
+ Log.d(TAG, "Processing BLE photo for upload. Image size: " + imageData.length + " bytes");
46
+
47
+ // 1. Decode image (AVIF or JPEG) to Bitmap
48
+ Bitmap bitmap = decodeImage(imageData);
49
+ if (bitmap == null) {
50
+ throw new Exception("Failed to decode image data");
51
+ }
52
+
53
+ Log.d(TAG, "Decoded image to bitmap: " + bitmap.getWidth() + "x" + bitmap.getHeight());
54
+
55
+ // 2. Convert to JPEG for upload (in case it was AVIF)
56
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
57
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 90, baos);
58
+ byte[] jpegData = baos.toByteArray();
59
+ bitmap.recycle();
60
+
61
+ Log.d(TAG, "Converted to JPEG for upload. Size: " + jpegData.length + " bytes");
62
+
63
+ // 3. Upload to webhook
64
+ uploadToWebhook(jpegData, requestId, webhookUrl, authToken);
65
+
66
+ Log.d(TAG, "Photo uploaded successfully for requestId: " + requestId);
67
+ callback.onSuccess(requestId);
68
+
69
+ } catch (Exception e) {
70
+ Log.e(TAG, "Error processing BLE photo for requestId: " + requestId, e);
71
+ callback.onError(requestId, e.getMessage());
72
+ }
73
+ }).start();
74
+ }
75
+
76
+ /**
77
+ * Decode image data (AVIF or JPEG) to Bitmap
78
+ * @param imageData Raw image bytes
79
+ * @return Decoded bitmap or null if failed
80
+ */
81
+ private static Bitmap decodeImage(byte[] imageData) {
82
+ try {
83
+ // Check if this is AVIF by looking for "ftyp" box
84
+ boolean isAvif = imageData.length > 12 &&
85
+ imageData[4] == 'f' && imageData[5] == 't' &&
86
+ imageData[6] == 'y' && imageData[7] == 'p' &&
87
+ (imageData[8] == 'a' && imageData[9] == 'v' && imageData[10] == 'i' && imageData[11] == 'f');
88
+
89
+ if (isAvif) {
90
+ Log.d(TAG, "Detected AVIF image format");
91
+ // AVIF decoding - requires Android API 31+ for native support
92
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
93
+ // Android 12+ has native AVIF support
94
+ BitmapFactory.Options options = new BitmapFactory.Options();
95
+ options.inPreferredConfig = Bitmap.Config.ARGB_8888;
96
+ return BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
97
+ } else {
98
+ // For older Android versions, we could add a library or convert on glasses side
99
+ Log.e(TAG, "AVIF decoding requires Android 12+ (API 31+). Current API: " + Build.VERSION.SDK_INT);
100
+ throw new UnsupportedOperationException("AVIF not supported on Android " + Build.VERSION.SDK_INT);
101
+ }
102
+ } else {
103
+ Log.d(TAG, "Detected JPEG image format");
104
+ // Standard JPEG decoding
105
+ return BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
106
+ }
107
+ } catch (Exception e) {
108
+ Log.e(TAG, "Failed to decode image", e);
109
+ return null;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Upload JPEG data to webhook
115
+ * @param jpegData JPEG image bytes
116
+ * @param requestId Request ID for tracking
117
+ * @param webhookUrl Destination URL
118
+ * @param authToken Optional bearer token for auth
119
+ * @throws IOException If upload fails
120
+ */
121
+ private static void uploadToWebhook(byte[] jpegData, String requestId,
122
+ String webhookUrl, @Nullable String authToken) throws IOException {
123
+ OkHttpClient client = new OkHttpClient.Builder()
124
+ .connectTimeout(30, TimeUnit.SECONDS)
125
+ .writeTimeout(30, TimeUnit.SECONDS)
126
+ .readTimeout(30, TimeUnit.SECONDS)
127
+ .build();
128
+
129
+ // Build multipart request
130
+ RequestBody requestBody = new MultipartBody.Builder()
131
+ .setType(MultipartBody.FORM)
132
+ .addFormDataPart("requestId", requestId)
133
+ .addFormDataPart("source", "ble_transfer")
134
+ .addFormDataPart("photo", requestId + ".jpg",
135
+ RequestBody.create(MediaType.parse("image/jpeg"), jpegData))
136
+ .build();
137
+
138
+ // Build request with auth header
139
+ Request.Builder requestBuilder = new Request.Builder()
140
+ .url(webhookUrl)
141
+ .post(requestBody);
142
+
143
+ if (authToken != null && !authToken.isEmpty()) {
144
+ requestBuilder.addHeader("Authorization", "Bearer " + authToken);
145
+ }
146
+
147
+ Request request = requestBuilder.build();
148
+
149
+ Log.d(TAG, "Uploading photo to webhook: " + webhookUrl);
150
+
151
+ try (Response response = client.newCall(request).execute()) {
152
+ if (!response.isSuccessful()) {
153
+ String errorBody = response.body() != null ? response.body().string() : "No response body";
154
+ throw new IOException("Upload failed with code " + response.code() + ": " + errorBody);
155
+ }
156
+
157
+ Log.d(TAG, "Upload successful. Response code: " + response.code());
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Alternative method for platforms without AVIF support
163
+ * Expects already-decoded JPEG data instead of AVIF
164
+ */
165
+ public static void uploadJpegPhoto(byte[] jpegData, String requestId,
166
+ String webhookUrl, @Nullable String authToken,
167
+ UploadCallback callback) {
168
+ new Thread(() -> {
169
+ try {
170
+ Log.d(TAG, "Uploading pre-decoded JPEG. Size: " + jpegData.length + " bytes");
171
+ uploadToWebhook(jpegData, requestId, webhookUrl, authToken);
172
+ callback.onSuccess(requestId);
173
+ } catch (Exception e) {
174
+ Log.e(TAG, "Error uploading JPEG photo", e);
175
+ callback.onError(requestId, e.getMessage());
176
+ }
177
+ }).start();
178
+ }
179
+ }
@@ -0,0 +1,44 @@
1
+ package com.mentra.bluetoothsdk.utils
2
+
3
+ object DeviceTypes {
4
+ const val SIMULATED = "Simulated Glasses"
5
+ const val G1 = "Even Realities G1"
6
+ const val NEX = "Mentra Display"
7
+ const val MACH1 = "Mentra Mach1"
8
+ const val LIVE = "Mentra Live"
9
+ const val Z100 = "Vuzix Z100"
10
+ const val FRAME = "Brilliant Frame"
11
+ const val G2 = "Even Realities G2"
12
+ val ALL = arrayOf(SIMULATED, G1, G2, MACH1, LIVE, Z100, FRAME, NEX)
13
+ }
14
+
15
+ object ControllerTypes {
16
+ const val R1 = "Even Realities R1"
17
+ val ALL = arrayOf(R1)
18
+ }
19
+
20
+ object ConnTypes {
21
+ const val CONNECTING = "CONNECTING"
22
+ const val CONNECTED = "CONNECTED"
23
+ const val DISCONNECTED = "DISCONNECTED"
24
+ const val SCANNING = "SCANNING"
25
+ const val BONDING = "BONDING"
26
+ }
27
+
28
+ object MicTypes {
29
+ const val PHONE_INTERNAL = "phone"
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)
34
+ }
35
+
36
+ // convert to kotlin:
37
+ object MicMap {
38
+ val map: Map<String, List<String>> = mapOf(
39
+ "auto" to listOf(MicTypes.GLASSES_CUSTOM, MicTypes.PHONE_INTERNAL, MicTypes.BT, MicTypes.BT_CLASSIC),
40
+ "glasses" to listOf(MicTypes.GLASSES_CUSTOM),
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),
43
+ )
44
+ }