@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.
- package/README.md +278 -0
- package/android/build.gradle +167 -0
- package/android/lc3Lib/CMakeLists.txt +6 -0
- package/android/lc3Lib/build.gradle +109 -0
- package/android/lc3Lib/proguard-rules.pro +33 -0
- package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
- package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
- package/android/lc3Lib/src/main/java/com/mentra/lc3Lib/Lc3Cpp.java +38 -0
- package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
- package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
- package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
- package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
- package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
- package/android/settings.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +40 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +528 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +610 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +1616 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +314 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +1710 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +554 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/ObservableStore.kt +68 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +158 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +934 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/services/Foreground.kt +175 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/services/PhoneMic.kt +1109 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +3974 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +3551 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +1327 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +6959 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +1655 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +53675 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +202 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +224 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/STTTools.kt +340 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +465 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +221 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/AES.java +106 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +179 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/Constants.kt +44 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/G1Text.kt +436 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleUploadService.java +76 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +791 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +186 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +589 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/PhoneAudioMonitor.kt +303 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
- package/android/src/main/res/values/strings.xml +4 -0
- package/app.plugin.js +1 -0
- package/build/BluetoothSdk.types.d.ts +498 -0
- package/build/BluetoothSdk.types.d.ts.map +1 -0
- package/build/BluetoothSdk.types.js +23 -0
- package/build/BluetoothSdk.types.js.map +1 -0
- package/build/BluetoothSdkModule.d.ts +71 -0
- package/build/BluetoothSdkModule.d.ts.map +1 -0
- package/build/BluetoothSdkModule.js +106 -0
- package/build/BluetoothSdkModule.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/BluetoothSdkModule.swift +665 -0
- package/ios/MentraBluetoothSDK.podspec +77 -0
- package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
- package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
- package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
- package/ios/Packages/CoreObjC/attdet.c +92 -0
- package/ios/Packages/CoreObjC/attdet.h +44 -0
- package/ios/Packages/CoreObjC/bits.c +375 -0
- package/ios/Packages/CoreObjC/bits.h +315 -0
- package/ios/Packages/CoreObjC/bwdet.c +129 -0
- package/ios/Packages/CoreObjC/bwdet.h +69 -0
- package/ios/Packages/CoreObjC/common.h +151 -0
- package/ios/Packages/CoreObjC/energy.c +70 -0
- package/ios/Packages/CoreObjC/energy.h +43 -0
- package/ios/Packages/CoreObjC/fastmath.h +158 -0
- package/ios/Packages/CoreObjC/lc3.c +704 -0
- package/ios/Packages/CoreObjC/lc3.h +313 -0
- package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
- package/ios/Packages/CoreObjC/lc3_private.h +163 -0
- package/ios/Packages/CoreObjC/ltpf.c +905 -0
- package/ios/Packages/CoreObjC/ltpf.h +111 -0
- package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
- package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
- package/ios/Packages/CoreObjC/makefile.mk +35 -0
- package/ios/Packages/CoreObjC/mdct.c +469 -0
- package/ios/Packages/CoreObjC/mdct.h +57 -0
- package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
- package/ios/Packages/CoreObjC/meson.build +61 -0
- package/ios/Packages/CoreObjC/plc.c +61 -0
- package/ios/Packages/CoreObjC/plc.h +57 -0
- package/ios/Packages/CoreObjC/rnnoise.h +114 -0
- package/ios/Packages/CoreObjC/sns.c +880 -0
- package/ios/Packages/CoreObjC/sns.h +103 -0
- package/ios/Packages/CoreObjC/spec.c +907 -0
- package/ios/Packages/CoreObjC/spec.h +119 -0
- package/ios/Packages/CoreObjC/tables.c +3457 -0
- package/ios/Packages/CoreObjC/tables.h +94 -0
- package/ios/Packages/CoreObjC/tns.c +457 -0
- package/ios/Packages/CoreObjC/tns.h +99 -0
- package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
- package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
- package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +1659 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/cargs.h +162 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/c-api.h +1852 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/cxx-api.h +674 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +44 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/sherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a +0 -0
- package/ios/Packages/VAD/Common/VAD/VADQuality.swift +41 -0
- package/ios/Packages/VAD/Common/VAD/VADState.swift +26 -0
- package/ios/Packages/VAD/Common/VAD/VADStrategy.swift +29 -0
- package/ios/Packages/VAD/Common/VAD/VADType.swift +14 -0
- package/ios/Packages/VAD/Data/Configuration.swift +68 -0
- package/ios/Packages/VAD/Data/FrameSize.swift +39 -0
- package/ios/Packages/VAD/Data/Record.swift +13 -0
- package/ios/Packages/VAD/Data/Result.swift +22 -0
- package/ios/Packages/VAD/Data/SampleRate.swift +48 -0
- package/ios/Packages/VAD/Silero/Model/silero_vad.onnx +0 -0
- package/ios/Packages/VAD/Silero/SileroVAD.swift +284 -0
- package/ios/Packages/VAD/Silero/SileroVADStrategy.swift +64 -0
- package/ios/Packages/libbz2/module.modulemap +5 -0
- package/ios/Packages/libbz2/shim.h +1 -0
- package/ios/Source/Bridge.swift +353 -0
- package/ios/Source/Bridging-Header.h +16 -0
- package/ios/Source/DeviceManager.swift +1478 -0
- package/ios/Source/DeviceStore.swift +295 -0
- package/ios/Source/MentraBluetoothSDK.swift +2439 -0
- package/ios/Source/ObservableStore.swift +88 -0
- package/ios/Source/PrivacyInfo.xcprivacy +23 -0
- package/ios/Source/controllers/ControllerManager.swift +187 -0
- package/ios/Source/controllers/R1.swift +827 -0
- package/ios/Source/services/PhoneMic.swift +662 -0
- package/ios/Source/sgcs/Frame.swift +651 -0
- package/ios/Source/sgcs/G1.swift +2505 -0
- package/ios/Source/sgcs/G2.swift +3730 -0
- package/ios/Source/sgcs/Mach1.swift +543 -0
- package/ios/Source/sgcs/MentraLive.swift +4708 -0
- package/ios/Source/sgcs/MentraNex.swift +2479 -0
- package/ios/Source/sgcs/SGCManager.swift +243 -0
- package/ios/Source/sgcs/Simulated.swift +270 -0
- package/ios/Source/sgcs/mentraos_ble.pb.swift +3811 -0
- package/ios/Source/stt/STTTools.swift +154 -0
- package/ios/Source/stt/SherpaOnnxTranscriber.swift +401 -0
- package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
- package/ios/Source/utils/Constants.swift +74 -0
- package/ios/Source/utils/Enums.swift +95 -0
- package/ios/Source/utils/G1Text.swift +2067 -0
- package/ios/Source/utils/JSCExperiment.swift +241 -0
- package/ios/Source/utils/MemoryMonitor.swift +44 -0
- package/ios/Source/utils/MessageChunker.swift +164 -0
- package/ios/Source/utils/Models.swift +135 -0
- package/ios/Source/utils/PhoneAudioMonitor.swift +226 -0
- package/ios/Source/utils/TarBz2Extractor.swift +206 -0
- package/package.json +78 -0
- package/plugin/build/index.d.ts +6 -0
- package/plugin/build/index.js +12 -0
- package/plugin/build/withAndroid.d.ts +4 -0
- package/plugin/build/withAndroid.js +80 -0
- package/plugin/build/withIos.d.ts +4 -0
- package/plugin/build/withIos.js +64 -0
- package/src/BluetoothSdk.types.ts +581 -0
- package/src/BluetoothSdkModule.ts +259 -0
- 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
|
+
}
|