@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,791 @@
|
|
|
1
|
+
package com.mentra.bluetoothsdk.utils;
|
|
2
|
+
|
|
3
|
+
import android.content.BroadcastReceiver;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.content.Intent;
|
|
6
|
+
import android.content.IntentFilter;
|
|
7
|
+
import android.content.pm.PackageManager;
|
|
8
|
+
import android.util.Log;
|
|
9
|
+
import android.os.Build;
|
|
10
|
+
|
|
11
|
+
import org.json.JSONException;
|
|
12
|
+
import org.json.JSONObject;
|
|
13
|
+
import java.nio.charset.StandardCharsets;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Utility class for K900 BES2700 protocol formatting.
|
|
17
|
+
* Used for communication between AugmentOS Core and ASG Client.
|
|
18
|
+
*/
|
|
19
|
+
public class K900ProtocolUtils {
|
|
20
|
+
|
|
21
|
+
// Protocol constants
|
|
22
|
+
public static final byte[] CMD_START_CODE = new byte[]{0x23, 0x23}; // ##
|
|
23
|
+
public static final byte[] CMD_END_CODE = new byte[]{0x24, 0x24}; // $$
|
|
24
|
+
public static final byte CMD_TYPE_STRING = 0x30; // String/JSON type
|
|
25
|
+
public static final byte CMD_TYPE_PHOTO = 0x31; // Photo file type
|
|
26
|
+
public static final byte CMD_TYPE_VIDEO = 0x32; // Video file type
|
|
27
|
+
public static final byte CMD_TYPE_MUSIC = 0x33; // Music file type
|
|
28
|
+
public static final byte CMD_TYPE_AUDIO = 0x34; // Audio file type
|
|
29
|
+
public static final byte CMD_TYPE_DATA = 0x35; // Generic data type
|
|
30
|
+
|
|
31
|
+
// File transfer constants
|
|
32
|
+
public static final int FILE_PACK_SIZE = 400; // Max data size per packet
|
|
33
|
+
public static final int LENGTH_FILE_START = 2;
|
|
34
|
+
public static final int LENGTH_FILE_TYPE = 1;
|
|
35
|
+
public static final int LENGTH_FILE_PACKSIZE = 2;
|
|
36
|
+
public static final int LENGTH_FILE_PACKINDEX = 2;
|
|
37
|
+
public static final int LENGTH_FILE_SIZE = 4;
|
|
38
|
+
public static final int LENGTH_FILE_NAME = 16;
|
|
39
|
+
public static final int LENGTH_FILE_FLAG = 2;
|
|
40
|
+
public static final int LENGTH_FILE_VERIFY = 1;
|
|
41
|
+
public static final int LENGTH_FILE_END = 2;
|
|
42
|
+
|
|
43
|
+
// JSON Field constants
|
|
44
|
+
public static final String FIELD_C = "C"; // Command/Content field
|
|
45
|
+
public static final String FIELD_V = "V"; // Version field
|
|
46
|
+
public static final String FIELD_B = "B"; // Body field
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Pack a JSON string into the proper K900 format:
|
|
50
|
+
* 1. Wrap with C-field: {"C": jsonData}
|
|
51
|
+
* 2. Then pack with BES2700 protocol: ## + type + length + {"C": jsonData} + $$
|
|
52
|
+
*
|
|
53
|
+
* @param jsonData The JSON string to pack
|
|
54
|
+
* @return Byte array with packed data according to protocol format
|
|
55
|
+
*/
|
|
56
|
+
public static byte[] packJsonCommand(String jsonData) {
|
|
57
|
+
if (jsonData == null) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
// First wrap with C-field
|
|
63
|
+
JSONObject wrapper = new JSONObject();
|
|
64
|
+
wrapper.put(FIELD_C, jsonData);
|
|
65
|
+
|
|
66
|
+
// Convert to string
|
|
67
|
+
String wrappedJson = wrapper.toString();
|
|
68
|
+
|
|
69
|
+
// Then pack with BES2700 protocol format
|
|
70
|
+
byte[] jsonBytes = wrappedJson.getBytes(StandardCharsets.UTF_8);
|
|
71
|
+
return packDataCommand(jsonBytes, CMD_TYPE_STRING);
|
|
72
|
+
|
|
73
|
+
} catch (JSONException e) {
|
|
74
|
+
android.util.Log.e("K900ProtocolUtils", "Error creating JSON wrapper", e);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Pack raw byte data with K900 BES2700 protocol format
|
|
81
|
+
* Format: ## + command_type + length(2bytes) + data + $$
|
|
82
|
+
*
|
|
83
|
+
* @param data The raw data to pack
|
|
84
|
+
* @param cmdType The command type (use CMD_TYPE_STRING for JSON)
|
|
85
|
+
* @return Byte array with packed data according to protocol format
|
|
86
|
+
*/
|
|
87
|
+
public static byte[] packDataCommand(byte[] data, byte cmdType) {
|
|
88
|
+
if (data == null) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
int dataLength = data.length;
|
|
93
|
+
|
|
94
|
+
// Command structure: ## + type + length(2 bytes) + data + $$
|
|
95
|
+
byte[] result = new byte[dataLength + 7]; // 2(start) + 1(type) + 2(length) + data + 2(end)
|
|
96
|
+
|
|
97
|
+
// Start code ##
|
|
98
|
+
result[0] = CMD_START_CODE[0]; // #
|
|
99
|
+
result[1] = CMD_START_CODE[1]; // #
|
|
100
|
+
|
|
101
|
+
// Command type
|
|
102
|
+
result[2] = cmdType;
|
|
103
|
+
|
|
104
|
+
// Length (2 bytes, big-endian)
|
|
105
|
+
result[3] = (byte)((dataLength >> 8) & 0xFF); // MSB first
|
|
106
|
+
result[4] = (byte)(dataLength & 0xFF); // LSB second
|
|
107
|
+
|
|
108
|
+
// Original little-endian implementation (commented out)
|
|
109
|
+
// result[3] = (byte)(dataLength & 0xFF); // LSB first
|
|
110
|
+
// result[4] = (byte)((dataLength >> 8) & 0xFF); // MSB second
|
|
111
|
+
|
|
112
|
+
// Copy the data
|
|
113
|
+
System.arraycopy(data, 0, result, 5, dataLength);
|
|
114
|
+
|
|
115
|
+
// End code $$
|
|
116
|
+
result[5 + dataLength] = CMD_END_CODE[0]; // $
|
|
117
|
+
result[6 + dataLength] = CMD_END_CODE[1]; // $
|
|
118
|
+
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Pack raw byte data with K900 BES2700 protocol format for phone-to-device communication
|
|
124
|
+
* Format: ## + command_type + length(2bytes) + data + $$
|
|
125
|
+
* Uses little-endian byte order for length field
|
|
126
|
+
*
|
|
127
|
+
* @param data The raw data to pack
|
|
128
|
+
* @param cmdType The command type (use CMD_TYPE_STRING for JSON)
|
|
129
|
+
* @return Byte array with packed data according to protocol format
|
|
130
|
+
*/
|
|
131
|
+
public static byte[] packDataToK900(byte[] data, byte cmdType) {
|
|
132
|
+
if (data == null) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
int dataLength = data.length;
|
|
137
|
+
|
|
138
|
+
// Command structure: ## + type + length(2 bytes) + data + $$
|
|
139
|
+
byte[] result = new byte[dataLength + 7]; // 2(start) + 1(type) + 2(length) + data + 2(end)
|
|
140
|
+
|
|
141
|
+
// Start code ##
|
|
142
|
+
result[0] = CMD_START_CODE[0]; // #
|
|
143
|
+
result[1] = CMD_START_CODE[1]; // #
|
|
144
|
+
|
|
145
|
+
// Command type
|
|
146
|
+
result[2] = cmdType;
|
|
147
|
+
|
|
148
|
+
// Length (2 bytes, little-endian for phone-to-device)
|
|
149
|
+
result[3] = (byte) (dataLength & 0xFF); // LSB first
|
|
150
|
+
result[4] = (byte) ((dataLength >> 8) & 0xFF); // MSB second
|
|
151
|
+
|
|
152
|
+
// Copy the data
|
|
153
|
+
System.arraycopy(data, 0, result, 5, dataLength);
|
|
154
|
+
|
|
155
|
+
// End code $$
|
|
156
|
+
result[5 + dataLength] = CMD_END_CODE[0]; // $
|
|
157
|
+
result[6 + dataLength] = CMD_END_CODE[1]; // $
|
|
158
|
+
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Pack a JSON string for phone-to-K900 device communication
|
|
164
|
+
* 1. Wrap with C-field: {"C": jsonData}
|
|
165
|
+
* 2. Then pack with BES2700 protocol using little-endian: ## + type + length + {"C": jsonData} + $$
|
|
166
|
+
*
|
|
167
|
+
* @param jsonData The JSON string to pack
|
|
168
|
+
* @return Byte array with packed data according to protocol format
|
|
169
|
+
*/
|
|
170
|
+
public static byte[] packJsonToK900(String jsonData, boolean wakeup) {
|
|
171
|
+
if (jsonData == null) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
// First wrap with C-field
|
|
177
|
+
JSONObject wrapper = new JSONObject();
|
|
178
|
+
wrapper.put(FIELD_C, jsonData);
|
|
179
|
+
if (wakeup) {
|
|
180
|
+
wrapper.put("W", 1); // Add W field as seen in MentraLiveSGC
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Convert to string
|
|
184
|
+
String wrappedJson = wrapper.toString();
|
|
185
|
+
|
|
186
|
+
// Then pack with BES2700 protocol format using little-endian
|
|
187
|
+
byte[] jsonBytes = wrappedJson.getBytes(StandardCharsets.UTF_8);
|
|
188
|
+
return packDataToK900(jsonBytes, CMD_TYPE_STRING);
|
|
189
|
+
|
|
190
|
+
} catch (JSONException e) {
|
|
191
|
+
android.util.Log.e("K900ProtocolUtils", "Error creating JSON wrapper for K900", e);
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Formats a standard ASG-client JSON message for transmission to MentraLiveSGC
|
|
198
|
+
* This does both:
|
|
199
|
+
* 1. Wrap with C-field: {"C": jsonData}
|
|
200
|
+
* 2. Format with BES2700 protocol: ## + type + length + data + $$
|
|
201
|
+
*
|
|
202
|
+
* @param jsonData The JSON string to format (must be valid JSON)
|
|
203
|
+
* @return Formatted bytes ready for transmission
|
|
204
|
+
*/
|
|
205
|
+
public static byte[] formatMessageForTransmission(String jsonData) {
|
|
206
|
+
try {
|
|
207
|
+
android.util.Log.e("K900ProtocolUtils", "🔄 Formatting message: " + jsonData);
|
|
208
|
+
|
|
209
|
+
// Validate that input is proper JSON
|
|
210
|
+
new JSONObject(jsonData);
|
|
211
|
+
|
|
212
|
+
// First, create C wrapper: {"C": jsonData}
|
|
213
|
+
JSONObject wrapper = new JSONObject();
|
|
214
|
+
wrapper.put(FIELD_C, jsonData);
|
|
215
|
+
wrapper.put(FIELD_V, 1); // Optional version field
|
|
216
|
+
wrapper.put(FIELD_B, new JSONObject()); // Optional body field
|
|
217
|
+
String wrappedJson = wrapper.toString();
|
|
218
|
+
android.util.Log.e("K900ProtocolUtils", "🔄 After C-wrapping: " + wrappedJson);
|
|
219
|
+
|
|
220
|
+
// Now format with BES2700 protocol
|
|
221
|
+
byte[] result = packDataCommand(wrappedJson.getBytes(StandardCharsets.UTF_8), CMD_TYPE_STRING);
|
|
222
|
+
|
|
223
|
+
// Log some bytes for debugging
|
|
224
|
+
StringBuilder hexDump = new StringBuilder();
|
|
225
|
+
for (int i = 0; i < Math.min(result.length, 30); i++) {
|
|
226
|
+
hexDump.append(String.format("%02X ", result[i]));
|
|
227
|
+
}
|
|
228
|
+
//android.util.Log.e("K900ProtocolUtils", "🔄 After protocol formatting (first 30 bytes): " + hexDump);
|
|
229
|
+
//android.util.Log.e("K900ProtocolUtils", "🔄 Final length: " + result.length + " bytes");
|
|
230
|
+
|
|
231
|
+
return result;
|
|
232
|
+
|
|
233
|
+
} catch (JSONException e) {
|
|
234
|
+
android.util.Log.e("K900ProtocolUtils", "❌ Error in formatMessageForTransmission", e);
|
|
235
|
+
// Fallback: if json is invalid, still try to pack it without validation
|
|
236
|
+
return packJsonCommand(jsonData);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Create a C-wrapped JSON object ready for protocol formatting
|
|
242
|
+
* Format: {"C": content}
|
|
243
|
+
*
|
|
244
|
+
* @param content The content to wrap in the C field
|
|
245
|
+
* @return C-wrapped JSON string
|
|
246
|
+
*/
|
|
247
|
+
public static String createCWrappedJson(String content) {
|
|
248
|
+
try {
|
|
249
|
+
JSONObject wrapper = new JSONObject();
|
|
250
|
+
wrapper.put(FIELD_C, content);
|
|
251
|
+
return wrapper.toString();
|
|
252
|
+
} catch (JSONException e) {
|
|
253
|
+
android.util.Log.e("K900ProtocolUtils", "Error creating C-wrapped JSON", e);
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Check if data follows the K900 BES2700 protocol format
|
|
260
|
+
* Verifies if data starts with ## markers
|
|
261
|
+
*/
|
|
262
|
+
public static boolean isK900ProtocolFormat(byte[] data) {
|
|
263
|
+
if (data == null || data.length < 7) { // Minimum protocol size
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
Log.d("K900ProtocolUtils", "isK900ProtocolFormat: " + data[0] + " " + data[1]);
|
|
268
|
+
Log.d("K900ProtocolUtils", "CMD_START_CODE: " + CMD_START_CODE[0] + " " + CMD_START_CODE[1]);
|
|
269
|
+
|
|
270
|
+
return data[0] == CMD_START_CODE[0] &&
|
|
271
|
+
data[1] == CMD_START_CODE[1];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Check if a JSON string is already properly formatted for K900 protocol
|
|
276
|
+
* This can either be:
|
|
277
|
+
* 1. Simple C-wrapped format: {"C": "content"}
|
|
278
|
+
* 2. Full K900 format: {"C": "command", "V": value, "B": body}
|
|
279
|
+
*
|
|
280
|
+
* @return true if already in proper format, false otherwise
|
|
281
|
+
*/
|
|
282
|
+
public static boolean isCWrappedJson(String jsonStr) {
|
|
283
|
+
try {
|
|
284
|
+
JSONObject json = new JSONObject(jsonStr);
|
|
285
|
+
|
|
286
|
+
// Check for simple C-wrapping {"C": "content"} - only one field
|
|
287
|
+
if (json.has(FIELD_C) && json.length() == 1) {
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Check for full K900 format {"C": "command", "V": val, "B": body}
|
|
292
|
+
if (json.has(FIELD_C) && json.has(FIELD_V) && json.has(FIELD_B)) {
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return false;
|
|
297
|
+
} catch (JSONException e) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Extract payload from K900 protocol formatted data
|
|
304
|
+
* @return Raw payload data or null if format is invalid
|
|
305
|
+
*/
|
|
306
|
+
public static byte[] extractPayload(byte[] protocolData) {
|
|
307
|
+
if (!isK900ProtocolFormat(protocolData) || protocolData.length < 7) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Extract length (big-endian)
|
|
312
|
+
int length = ((protocolData[3] & 0xFF) << 8) | (protocolData[4] & 0xFF);
|
|
313
|
+
|
|
314
|
+
// Original little-endian implementation (commented out)
|
|
315
|
+
// int length = (protocolData[3] & 0xFF) | ((protocolData[4] & 0xFF) << 8);
|
|
316
|
+
|
|
317
|
+
if (length + 7 > protocolData.length) {
|
|
318
|
+
return null; // Invalid length
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Extract payload
|
|
322
|
+
byte[] payload = new byte[length];
|
|
323
|
+
System.arraycopy(protocolData, 5, payload, 0, length);
|
|
324
|
+
return payload;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Extract payload from K900 protocol formatted data received from device
|
|
329
|
+
* Uses little-endian byte order for length field
|
|
330
|
+
* @return Raw payload data or null if format is invalid
|
|
331
|
+
*/
|
|
332
|
+
public static byte[] extractPayloadFromK900(byte[] protocolData) {
|
|
333
|
+
if (!isK900ProtocolFormat(protocolData) || protocolData.length < 7) {
|
|
334
|
+
Log.e("K900ProtocolUtils", "extractPayloadFromK900: Not K900 format or too short. Length=" +
|
|
335
|
+
(protocolData != null ? protocolData.length : 0));
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Extract length (little-endian for device-to-phone)
|
|
340
|
+
int length = (protocolData[3] & 0xFF) | ((protocolData[4] & 0xFF) << 8);
|
|
341
|
+
|
|
342
|
+
Log.d("K900ProtocolUtils", "extractPayloadFromK900: Extracted length=" + length +
|
|
343
|
+
", message length=" + protocolData.length + ", expected total=" + (length + 7));
|
|
344
|
+
|
|
345
|
+
if (length + 7 > protocolData.length) {
|
|
346
|
+
Log.e("K900ProtocolUtils", "extractPayloadFromK900: Invalid length. Need " +
|
|
347
|
+
(length + 7) + " bytes but have " + protocolData.length);
|
|
348
|
+
return null; // Invalid length
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Extract payload
|
|
352
|
+
byte[] payload = new byte[length];
|
|
353
|
+
System.arraycopy(protocolData, 5, payload, 0, length);
|
|
354
|
+
return payload;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Process received bytes from Bluetooth into a JSON object
|
|
359
|
+
* Handles K900 protocol format detection, payload extraction, and C-field unwrapping
|
|
360
|
+
*
|
|
361
|
+
* @param data The raw bytes received from Bluetooth
|
|
362
|
+
* @return Parsed JSON object or null if not valid protocol data or valid JSON
|
|
363
|
+
*/
|
|
364
|
+
public static JSONObject processReceivedBytesToJson(byte[] data) {
|
|
365
|
+
android.util.Log.d("K900ProtocolUtils", "Processing received bytes for JSON extraction");
|
|
366
|
+
|
|
367
|
+
// Check for null or too small data
|
|
368
|
+
if (data == null || data.length < 7) {
|
|
369
|
+
android.util.Log.d("K900ProtocolUtils", "Received data is null or too short to be valid protocol data");
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Verify if this is K900 protocol format (starts with ##)
|
|
374
|
+
if (!isK900ProtocolFormat(data)) {
|
|
375
|
+
android.util.Log.d("K900ProtocolUtils", "Not in K900 protocol format (missing ## markers)");
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Extract the command type
|
|
380
|
+
byte commandType = data[2];
|
|
381
|
+
|
|
382
|
+
// Extract the length using big-endian format (MSB first)
|
|
383
|
+
int payloadLength = ((data[3] & 0xFF) << 8) | (data[4] & 0xFF);
|
|
384
|
+
|
|
385
|
+
android.util.Log.d("K900ProtocolUtils", "Command type: 0x" + String.format("%02X", commandType) +
|
|
386
|
+
", Payload length: " + payloadLength);
|
|
387
|
+
|
|
388
|
+
// Verify we have enough data and the right command type
|
|
389
|
+
if (commandType != CMD_TYPE_STRING) {
|
|
390
|
+
android.util.Log.d("K900ProtocolUtils", "Not a JSON/string command type (0x30), got: 0x" +
|
|
391
|
+
String.format("%02X", commandType));
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (data.length < payloadLength + 7) {
|
|
396
|
+
android.util.Log.d("K900ProtocolUtils", "Received data size (" + data.length +
|
|
397
|
+
") is less than expected size (" + (payloadLength + 7) + ")");
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Check for end markers ($$)
|
|
402
|
+
if (data[5 + payloadLength] != CMD_END_CODE[0] || data[6 + payloadLength] != CMD_END_CODE[1]) {
|
|
403
|
+
android.util.Log.d("K900ProtocolUtils", "End markers ($$) not found where expected");
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Extract the payload
|
|
408
|
+
byte[] payload = new byte[payloadLength];
|
|
409
|
+
System.arraycopy(data, 5, payload, 0, payloadLength);
|
|
410
|
+
|
|
411
|
+
// Convert to string
|
|
412
|
+
String payloadStr;
|
|
413
|
+
try {
|
|
414
|
+
payloadStr = new String(payload, StandardCharsets.UTF_8);
|
|
415
|
+
android.util.Log.d("K900ProtocolUtils", "Extracted payload: " + payloadStr);
|
|
416
|
+
} catch (Exception e) {
|
|
417
|
+
android.util.Log.e("K900ProtocolUtils", "Error converting payload to string", e);
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Check if it's valid JSON
|
|
422
|
+
if (!payloadStr.startsWith("{") || !payloadStr.endsWith("}")) {
|
|
423
|
+
android.util.Log.d("K900ProtocolUtils", "Payload is not valid JSON: " + payloadStr);
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
// Parse the JSON payload
|
|
429
|
+
JSONObject json = new JSONObject(payloadStr);
|
|
430
|
+
|
|
431
|
+
// Check if this is C-wrapped format {"C": "..."}
|
|
432
|
+
if (json.has(FIELD_C)) {
|
|
433
|
+
String innerContent = json.optString(FIELD_C, "");
|
|
434
|
+
android.util.Log.d("K900ProtocolUtils", "Detected C-wrapped format, inner content: " + innerContent);
|
|
435
|
+
|
|
436
|
+
// Try to parse the inner content as JSON
|
|
437
|
+
try {
|
|
438
|
+
JSONObject innerJson = new JSONObject(innerContent);
|
|
439
|
+
return innerJson;
|
|
440
|
+
} catch (JSONException e) {
|
|
441
|
+
android.util.Log.d("K900ProtocolUtils", "Inner content is not JSON, returning outer JSON object");
|
|
442
|
+
// If inner content is not JSON, return the outer JSON
|
|
443
|
+
return json;
|
|
444
|
+
}
|
|
445
|
+
} else {
|
|
446
|
+
// Not C-wrapped, return the JSON directly
|
|
447
|
+
return json;
|
|
448
|
+
}
|
|
449
|
+
} catch (JSONException e) {
|
|
450
|
+
android.util.Log.e("K900ProtocolUtils", "Error parsing JSON payload: " + e.getMessage(), e);
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Unified method to prepare data for transmission according to K900 protocol
|
|
457
|
+
* This handles all formatting cases:
|
|
458
|
+
* 1. Data already in protocol format
|
|
459
|
+
* 2. JSON data that needs C-wrapping
|
|
460
|
+
* 3. Raw data that needs protocol packaging
|
|
461
|
+
*
|
|
462
|
+
* @param data The raw data to prepare for transmission
|
|
463
|
+
* @return Properly formatted data according to K900 protocol
|
|
464
|
+
*/
|
|
465
|
+
public static byte[] prepareDataForTransmission(byte[] data) {
|
|
466
|
+
if (data == null || data.length == 0) {
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// If already in protocol format, don't modify
|
|
471
|
+
if (isK900ProtocolFormat(data)) {
|
|
472
|
+
return data;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Try to interpret as a JSON string that needs C-wrapping and protocol formatting
|
|
476
|
+
try {
|
|
477
|
+
// Convert to string for processing
|
|
478
|
+
String originalData = new String(data, "UTF-8");
|
|
479
|
+
|
|
480
|
+
// If looks like JSON but not C-wrapped, use the full formatting function
|
|
481
|
+
if (originalData.startsWith("{") && !isCWrappedJson(originalData)) {
|
|
482
|
+
android.util.Log.d("K900ProtocolUtils", "📦 JSON DATA BEFORE C-WRAPPING: " + originalData);
|
|
483
|
+
byte[] formattedData = formatMessageForTransmission(originalData);
|
|
484
|
+
|
|
485
|
+
// Debug log the formatting results if needed
|
|
486
|
+
if (android.util.Log.isLoggable("K900ProtocolUtils", android.util.Log.DEBUG)) {
|
|
487
|
+
StringBuilder hexDump = new StringBuilder();
|
|
488
|
+
for (int i = 0; i < Math.min(formattedData.length, 50); i++) {
|
|
489
|
+
hexDump.append(String.format("%02X ", formattedData[i]));
|
|
490
|
+
}
|
|
491
|
+
android.util.Log.d("K900ProtocolUtils", "📦 AFTER C-WRAPPING & PROTOCOL FORMATTING (first 50 bytes): " + hexDump.toString());
|
|
492
|
+
android.util.Log.d("K900ProtocolUtils", "📦 Total formatted length: " + formattedData.length + " bytes");
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return formattedData;
|
|
496
|
+
} else {
|
|
497
|
+
// Otherwise just apply protocol formatting
|
|
498
|
+
android.util.Log.d("K900ProtocolUtils", "📦 Data already C-wrapped or not JSON: " + originalData);
|
|
499
|
+
android.util.Log.d("K900ProtocolUtils", "Formatting data with K900 protocol (adding ##...)");
|
|
500
|
+
return packDataCommand(data, CMD_TYPE_STRING);
|
|
501
|
+
}
|
|
502
|
+
} catch (Exception e) {
|
|
503
|
+
// If we can't interpret as string, just apply protocol formatting to raw bytes
|
|
504
|
+
android.util.Log.d("K900ProtocolUtils", "Applying protocol format to raw bytes");
|
|
505
|
+
return packDataCommand(data, CMD_TYPE_STRING);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Check if the device is a K900
|
|
511
|
+
* @param context The application context
|
|
512
|
+
* @return true if the device is a K900, false otherwise
|
|
513
|
+
*/
|
|
514
|
+
public static boolean isK900Device(Context context) {
|
|
515
|
+
// Check for K900-specific broadcast receivers
|
|
516
|
+
try {
|
|
517
|
+
// Verify the SystemUI package exists
|
|
518
|
+
PackageManager pm = context.getPackageManager();
|
|
519
|
+
pm.getPackageInfo("com.android.systemui", 0);
|
|
520
|
+
|
|
521
|
+
// Check for K900-specific system action
|
|
522
|
+
try {
|
|
523
|
+
// Set up a result receiver to check if our probe was received
|
|
524
|
+
final boolean[] responseReceived = {false};
|
|
525
|
+
BroadcastReceiver testReceiver = new BroadcastReceiver() {
|
|
526
|
+
@Override
|
|
527
|
+
public void onReceive(Context context, Intent intent) {
|
|
528
|
+
responseReceived[0] = true;
|
|
529
|
+
try {
|
|
530
|
+
context.unregisterReceiver(this);
|
|
531
|
+
} catch (Exception e) {
|
|
532
|
+
// Ignore unregister failures
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
// Register for any response from our probe
|
|
538
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
539
|
+
context.registerReceiver(testReceiver,
|
|
540
|
+
new IntentFilter("com.xy.xsetting.response"),
|
|
541
|
+
Context.RECEIVER_NOT_EXPORTED);
|
|
542
|
+
} else {
|
|
543
|
+
context.registerReceiver(testReceiver,
|
|
544
|
+
new IntentFilter("com.xy.xsetting.response"),
|
|
545
|
+
Context.RECEIVER_NOT_EXPORTED);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Send a test probe
|
|
549
|
+
Intent testIntent = new Intent("com.xy.xsetting.action");
|
|
550
|
+
testIntent.setPackage("com.android.systemui");
|
|
551
|
+
testIntent.putExtra("cmd", "test_k900");
|
|
552
|
+
context.sendBroadcast(testIntent);
|
|
553
|
+
|
|
554
|
+
// In a real implementation, we would wait for a response
|
|
555
|
+
// For now, we check device model as a fallback
|
|
556
|
+
String model = android.os.Build.MODEL.toLowerCase();
|
|
557
|
+
return model.contains("k900") || model.contains("xyglasses");
|
|
558
|
+
} catch (Exception e) {
|
|
559
|
+
Log.e("K900ProtocolUtils", "Error checking for K900 specific broadcast", e);
|
|
560
|
+
}
|
|
561
|
+
} catch (Exception e) {
|
|
562
|
+
Log.d("K900ProtocolUtils", "Not a K900 device: " + e.getMessage());
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Inner class to represent file packet information
|
|
570
|
+
*/
|
|
571
|
+
public static class FilePacketInfo {
|
|
572
|
+
public byte fileType;
|
|
573
|
+
public int packSize;
|
|
574
|
+
public int packIndex;
|
|
575
|
+
public int fileSize;
|
|
576
|
+
public String fileName;
|
|
577
|
+
public int flags;
|
|
578
|
+
public byte[] data;
|
|
579
|
+
public byte verifyCode;
|
|
580
|
+
public boolean isValid;
|
|
581
|
+
|
|
582
|
+
public FilePacketInfo() {
|
|
583
|
+
this.isValid = false;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Pack a file packet according to K900 file transfer protocol
|
|
589
|
+
* Format: ## + fileType + packSize + packIndex + fileSize + fileName + flags + data + verify + $$
|
|
590
|
+
*
|
|
591
|
+
* @param fileData The file data chunk to send (max 400 bytes)
|
|
592
|
+
* @param packIndex The index of this packet (0-based)
|
|
593
|
+
* @param packSize The size of data in this packet
|
|
594
|
+
* @param fileSize The total file size
|
|
595
|
+
* @param fileName The file name (max 16 chars)
|
|
596
|
+
* @param flags Optional flags
|
|
597
|
+
* @param fileType The file type (CMD_TYPE_PHOTO, etc)
|
|
598
|
+
* @return Packed byte array ready for transmission
|
|
599
|
+
*/
|
|
600
|
+
public static byte[] packFilePacket(byte[] fileData, int packIndex, int packSize,
|
|
601
|
+
int fileSize, String fileName, int flags, byte fileType) {
|
|
602
|
+
if (fileData == null || packSize > FILE_PACK_SIZE) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Calculate total packet size
|
|
607
|
+
int totalSize = LENGTH_FILE_START + LENGTH_FILE_TYPE + LENGTH_FILE_PACKSIZE +
|
|
608
|
+
LENGTH_FILE_PACKINDEX + LENGTH_FILE_SIZE + LENGTH_FILE_NAME +
|
|
609
|
+
LENGTH_FILE_FLAG + packSize + LENGTH_FILE_VERIFY + LENGTH_FILE_END;
|
|
610
|
+
|
|
611
|
+
byte[] packet = new byte[totalSize];
|
|
612
|
+
int pos = 0;
|
|
613
|
+
|
|
614
|
+
// Start code ##
|
|
615
|
+
System.arraycopy(CMD_START_CODE, 0, packet, pos, LENGTH_FILE_START);
|
|
616
|
+
pos += LENGTH_FILE_START;
|
|
617
|
+
|
|
618
|
+
// File type
|
|
619
|
+
packet[pos] = fileType;
|
|
620
|
+
pos += LENGTH_FILE_TYPE;
|
|
621
|
+
|
|
622
|
+
// Pack size (2 bytes, big-endian like reference implementation)
|
|
623
|
+
packet[pos] = (byte)((packSize >> 8) & 0xFF);
|
|
624
|
+
packet[pos + 1] = (byte)(packSize & 0xFF);
|
|
625
|
+
pos += LENGTH_FILE_PACKSIZE;
|
|
626
|
+
|
|
627
|
+
// Pack index (2 bytes, big-endian)
|
|
628
|
+
packet[pos] = (byte)((packIndex >> 8) & 0xFF);
|
|
629
|
+
packet[pos + 1] = (byte)(packIndex & 0xFF);
|
|
630
|
+
pos += LENGTH_FILE_PACKINDEX;
|
|
631
|
+
|
|
632
|
+
// File size (4 bytes, big-endian)
|
|
633
|
+
packet[pos] = (byte)((fileSize >> 24) & 0xFF);
|
|
634
|
+
packet[pos + 1] = (byte)((fileSize >> 16) & 0xFF);
|
|
635
|
+
packet[pos + 2] = (byte)((fileSize >> 8) & 0xFF);
|
|
636
|
+
packet[pos + 3] = (byte)(fileSize & 0xFF);
|
|
637
|
+
pos += LENGTH_FILE_SIZE;
|
|
638
|
+
|
|
639
|
+
// File name (16 bytes, padded with zeros)
|
|
640
|
+
byte[] nameBytes = fileName.getBytes(StandardCharsets.UTF_8);
|
|
641
|
+
int nameLen = Math.min(nameBytes.length, LENGTH_FILE_NAME);
|
|
642
|
+
System.arraycopy(nameBytes, 0, packet, pos, nameLen);
|
|
643
|
+
// Pad with zeros if name is shorter than 16 bytes
|
|
644
|
+
for (int i = nameLen; i < LENGTH_FILE_NAME; i++) {
|
|
645
|
+
packet[pos + i] = 0;
|
|
646
|
+
}
|
|
647
|
+
pos += LENGTH_FILE_NAME;
|
|
648
|
+
|
|
649
|
+
// Flags (2 bytes, big-endian)
|
|
650
|
+
packet[pos] = (byte)((flags >> 8) & 0xFF);
|
|
651
|
+
packet[pos + 1] = (byte)(flags & 0xFF);
|
|
652
|
+
pos += LENGTH_FILE_FLAG;
|
|
653
|
+
|
|
654
|
+
// Data
|
|
655
|
+
System.arraycopy(fileData, 0, packet, pos, packSize);
|
|
656
|
+
pos += packSize;
|
|
657
|
+
|
|
658
|
+
// Calculate verify code (checksum of data bytes)
|
|
659
|
+
int checkSum = 0;
|
|
660
|
+
for (int i = 0; i < packSize; i++) {
|
|
661
|
+
checkSum += (fileData[i] & 0xFF);
|
|
662
|
+
}
|
|
663
|
+
packet[pos] = (byte)(checkSum & 0xFF);
|
|
664
|
+
pos += LENGTH_FILE_VERIFY;
|
|
665
|
+
|
|
666
|
+
// End code $$
|
|
667
|
+
System.arraycopy(CMD_END_CODE, 0, packet, pos, LENGTH_FILE_END);
|
|
668
|
+
|
|
669
|
+
return packet;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Extract file packet information from received protocol data
|
|
674
|
+
*
|
|
675
|
+
* @param protocolData The raw protocol data received
|
|
676
|
+
* @return FilePacketInfo object with parsed data, or null if invalid
|
|
677
|
+
*/
|
|
678
|
+
public static FilePacketInfo extractFilePacket(byte[] protocolData) {
|
|
679
|
+
if (!isK900ProtocolFormat(protocolData) || protocolData.length < 31) {
|
|
680
|
+
Log.e("K900ProtocolUtils", "extractFilePacket: Invalid format or too short. Length=" +
|
|
681
|
+
(protocolData != null ? protocolData.length : 0) +
|
|
682
|
+
", isK900Format=" + isK900ProtocolFormat(protocolData));
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
FilePacketInfo info = new FilePacketInfo();
|
|
687
|
+
int pos = LENGTH_FILE_START; // Skip start code
|
|
688
|
+
|
|
689
|
+
// File type
|
|
690
|
+
info.fileType = protocolData[pos];
|
|
691
|
+
pos += LENGTH_FILE_TYPE;
|
|
692
|
+
|
|
693
|
+
// Pack size (big-endian)
|
|
694
|
+
info.packSize = ((protocolData[pos] & 0xFF) << 8) | (protocolData[pos + 1] & 0xFF);
|
|
695
|
+
pos += LENGTH_FILE_PACKSIZE;
|
|
696
|
+
|
|
697
|
+
// Pack index (big-endian)
|
|
698
|
+
info.packIndex = ((protocolData[pos] & 0xFF) << 8) | (protocolData[pos + 1] & 0xFF);
|
|
699
|
+
pos += LENGTH_FILE_PACKINDEX;
|
|
700
|
+
|
|
701
|
+
// File size (big-endian)
|
|
702
|
+
info.fileSize = ((protocolData[pos] & 0xFF) << 24) |
|
|
703
|
+
((protocolData[pos + 1] & 0xFF) << 16) |
|
|
704
|
+
((protocolData[pos + 2] & 0xFF) << 8) |
|
|
705
|
+
(protocolData[pos + 3] & 0xFF);
|
|
706
|
+
pos += LENGTH_FILE_SIZE;
|
|
707
|
+
|
|
708
|
+
// File name
|
|
709
|
+
byte[] nameBytes = new byte[LENGTH_FILE_NAME];
|
|
710
|
+
System.arraycopy(protocolData, pos, nameBytes, 0, LENGTH_FILE_NAME);
|
|
711
|
+
// Find null terminator
|
|
712
|
+
int nameLen = 0;
|
|
713
|
+
for (int i = 0; i < LENGTH_FILE_NAME; i++) {
|
|
714
|
+
if (nameBytes[i] == 0) break;
|
|
715
|
+
nameLen++;
|
|
716
|
+
}
|
|
717
|
+
info.fileName = new String(nameBytes, 0, nameLen, StandardCharsets.UTF_8);
|
|
718
|
+
pos += LENGTH_FILE_NAME;
|
|
719
|
+
|
|
720
|
+
// Flags (big-endian)
|
|
721
|
+
info.flags = ((protocolData[pos] & 0xFF) << 8) | (protocolData[pos + 1] & 0xFF);
|
|
722
|
+
pos += LENGTH_FILE_FLAG;
|
|
723
|
+
|
|
724
|
+
// Verify packet has enough data
|
|
725
|
+
if (protocolData.length < pos + info.packSize + LENGTH_FILE_VERIFY + LENGTH_FILE_END) {
|
|
726
|
+
Log.e("K900ProtocolUtils", "File packet too short for data. Need: " +
|
|
727
|
+
(pos + info.packSize + LENGTH_FILE_VERIFY + LENGTH_FILE_END) +
|
|
728
|
+
", Have: " + protocolData.length +
|
|
729
|
+
", packSize=" + info.packSize + ", pos=" + pos);
|
|
730
|
+
return null;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Data
|
|
734
|
+
info.data = new byte[info.packSize];
|
|
735
|
+
System.arraycopy(protocolData, pos, info.data, 0, info.packSize);
|
|
736
|
+
pos += info.packSize;
|
|
737
|
+
|
|
738
|
+
// Verify code
|
|
739
|
+
info.verifyCode = protocolData[pos];
|
|
740
|
+
pos += LENGTH_FILE_VERIFY;
|
|
741
|
+
|
|
742
|
+
// Check end code
|
|
743
|
+
if (protocolData[pos] != CMD_END_CODE[0] || protocolData[pos + 1] != CMD_END_CODE[1]) {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Calculate and verify checksum
|
|
748
|
+
int checkSum = 0;
|
|
749
|
+
for (int i = 0; i < info.packSize; i++) {
|
|
750
|
+
checkSum += (info.data[i] & 0xFF);
|
|
751
|
+
}
|
|
752
|
+
byte calculatedVerify = (byte)(checkSum & 0xFF);
|
|
753
|
+
|
|
754
|
+
info.isValid = (calculatedVerify == info.verifyCode);
|
|
755
|
+
|
|
756
|
+
if (!info.isValid) {
|
|
757
|
+
Log.e("K900ProtocolUtils", "File packet checksum failed. Expected: " +
|
|
758
|
+
String.format("%02X", info.verifyCode) + ", Calculated: " +
|
|
759
|
+
String.format("%02X", calculatedVerify));
|
|
760
|
+
} else {
|
|
761
|
+
Log.d("K900ProtocolUtils", "File packet extracted successfully: index=" + info.packIndex +
|
|
762
|
+
", size=" + info.packSize + ", fileName=" + info.fileName);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return info;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Create a file transfer acknowledgment message
|
|
770
|
+
*
|
|
771
|
+
* @param state 1 for success, 0 for failure
|
|
772
|
+
* @param index The packet index being acknowledged
|
|
773
|
+
* @return JSON string ready to be sent
|
|
774
|
+
*/
|
|
775
|
+
public static String createFileTransferAck(int state, int index) {
|
|
776
|
+
try {
|
|
777
|
+
JSONObject body = new JSONObject();
|
|
778
|
+
body.put("state", state);
|
|
779
|
+
body.put("index", index);
|
|
780
|
+
|
|
781
|
+
JSONObject message = new JSONObject();
|
|
782
|
+
message.put("C", "cs_flts");
|
|
783
|
+
message.put("B", body); // Send as JSON object, not string
|
|
784
|
+
|
|
785
|
+
return message.toString();
|
|
786
|
+
} catch (JSONException e) {
|
|
787
|
+
Log.e("K900ProtocolUtils", "Error creating file transfer ack", e);
|
|
788
|
+
return null;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|