@glassly/bluetooth-sdk 0.1.0-dev.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (548) hide show
  1. package/README.md +563 -0
  2. package/android/build.gradle +450 -0
  3. package/android/gradle.properties.example +9 -0
  4. package/android/lc3Lib/CMakeLists.txt +6 -0
  5. package/android/lc3Lib/build.gradle +212 -0
  6. package/android/lc3Lib/proguard-rules.pro +33 -0
  7. package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
  8. package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
  9. package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
  10. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
  11. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
  12. package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
  13. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
  14. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
  15. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
  16. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
  17. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
  18. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
  19. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
  20. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
  21. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
  22. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
  23. package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
  24. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
  25. package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
  26. package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
  27. package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
  28. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
  29. package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
  30. package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
  31. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
  32. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
  33. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
  34. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
  35. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
  36. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
  37. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
  38. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
  39. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
  40. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
  41. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
  42. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
  43. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
  44. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
  45. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
  46. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
  47. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
  48. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
  49. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
  50. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
  51. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
  52. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
  53. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
  54. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
  55. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
  56. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
  57. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
  58. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
  59. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
  60. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
  61. package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
  62. package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
  63. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
  64. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
  65. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
  66. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
  67. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
  68. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
  69. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
  70. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
  71. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
  72. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
  73. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
  74. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
  75. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
  76. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
  77. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
  78. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
  79. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
  80. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
  81. package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
  82. package/android/lc3Lib/src/main/java/com/glassly/lc3Lib/Lc3Cpp.java +38 -0
  83. package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
  84. package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
  85. package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
  86. package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
  87. package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
  88. package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
  89. package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
  90. package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
  91. package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
  92. package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
  93. package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
  94. package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
  95. package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
  96. package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
  97. package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
  98. package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
  99. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
  100. package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
  101. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
  102. package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
  103. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
  104. package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
  105. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
  106. package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
  107. package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
  108. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
  109. package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
  110. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
  111. package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
  112. package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
  113. package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
  114. package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
  115. package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
  116. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
  117. package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
  118. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
  119. package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
  120. package/android/settings.gradle +4 -0
  121. package/android/silero/LICENSE.md +17 -0
  122. package/android/silero/build.gradle +50 -0
  123. package/android/silero/proguard-rules.pro +24 -0
  124. package/android/silero/src/androidTest/assets/hello.wav +0 -0
  125. package/android/silero/src/androidTest/java/com/konovalov/vad/silero/VadSileroTest.kt +79 -0
  126. package/android/silero/src/main/assets/LICENSE +21 -0
  127. package/android/silero/src/main/assets/silero_vad.onnx +0 -0
  128. package/android/silero/src/main/java/com/konovalov/vad/silero/Vad.kt +160 -0
  129. package/android/silero/src/main/java/com/konovalov/vad/silero/VadSilero.kt +449 -0
  130. package/android/silero/src/main/java/com/konovalov/vad/silero/config/FrameSize.kt +15 -0
  131. package/android/silero/src/main/java/com/konovalov/vad/silero/config/Mode.kt +14 -0
  132. package/android/silero/src/main/java/com/konovalov/vad/silero/config/SampleRate.kt +12 -0
  133. package/android/silero/src/main/java/com/konovalov/vad/silero/utils/AudioUtils.kt +47 -0
  134. package/android/silero/src/main/java/com/konovalov/vad/silero/utils/TensorMap.kt +41 -0
  135. package/android/silero/src/test/java/com/konovalov/vad/silero/utils/AudioUtilsTest.kt +44 -0
  136. package/android/src/main/AndroidManifest.xml +42 -0
  137. package/android/src/main/assets/G2Firmware/README.md +11 -0
  138. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdk.kt +2325 -0
  139. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkAnalytics.kt +216 -0
  140. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDebug.kt +14 -0
  141. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDefaults.kt +7 -0
  142. package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkModule.kt +1088 -0
  143. package/android/src/main/java/com/glassly/bluetoothsdk/Bridge.kt +953 -0
  144. package/android/src/main/java/com/glassly/bluetoothsdk/DeviceManager.kt +2528 -0
  145. package/android/src/main/java/com/glassly/bluetoothsdk/DeviceStore.kt +360 -0
  146. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedChangelogCatalog.kt +8 -0
  147. package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedReleaseMetadata.kt +11 -0
  148. package/android/src/main/java/com/glassly/bluetoothsdk/LocalNetworkModule.kt +414 -0
  149. package/android/src/main/java/com/glassly/bluetoothsdk/ObservableStore.kt +88 -0
  150. package/android/src/main/java/com/glassly/bluetoothsdk/OtaManifest.kt +191 -0
  151. package/android/src/main/java/com/glassly/bluetoothsdk/ReleaseChangelog.kt +61 -0
  152. package/android/src/main/java/com/glassly/bluetoothsdk/ScopedNetworkReadiness.kt +17 -0
  153. package/android/src/main/java/com/glassly/bluetoothsdk/audio/AudioModels.kt +144 -0
  154. package/android/src/main/java/com/glassly/bluetoothsdk/camera/CameraModels.kt +486 -0
  155. package/android/src/main/java/com/glassly/bluetoothsdk/connection/ConnectionModels.kt +78 -0
  156. package/android/src/main/java/com/glassly/bluetoothsdk/controllers/ControllerManager.kt +158 -0
  157. package/android/src/main/java/com/glassly/bluetoothsdk/controllers/R1.kt +937 -0
  158. package/android/src/main/java/com/glassly/bluetoothsdk/debug/BleTraceLogger.kt +165 -0
  159. package/android/src/main/java/com/glassly/bluetoothsdk/events/BluetoothEvents.kt +178 -0
  160. package/android/src/main/java/com/glassly/bluetoothsdk/internal/MapParsing.kt +140 -0
  161. package/android/src/main/java/com/glassly/bluetoothsdk/net/LocalIpv4.kt +57 -0
  162. package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServer.kt +304 -0
  163. package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/OtaServerModule.kt +120 -0
  164. package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistry.java +108 -0
  165. package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoUploadServer.kt +622 -0
  166. package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/PhotoReceiverModule.kt +156 -0
  167. package/android/src/main/java/com/glassly/bluetoothsdk/requests/DisplayRequests.kt +56 -0
  168. package/android/src/main/java/com/glassly/bluetoothsdk/services/Foreground.kt +272 -0
  169. package/android/src/main/java/com/glassly/bluetoothsdk/services/PhoneMic.kt +1195 -0
  170. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Ar99.java +2653 -0
  171. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuard.kt +49 -0
  172. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapper.kt +27 -0
  173. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1.kt +3878 -0
  174. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizer.kt +38 -0
  175. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2.kt +6428 -0
  176. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassification.kt +49 -0
  177. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwRenderer.kt +1241 -0
  178. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCache.kt +270 -0
  179. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocol.kt +291 -0
  180. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2Flasher.kt +411 -0
  181. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/GlasslyBle.java +43189 -0
  182. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Mach1.kt +1280 -0
  183. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLive.kt +10817 -0
  184. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLiveL2capChannel.kt +274 -0
  185. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisement.kt +54 -0
  186. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraNex.kt +2011 -0
  187. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Nimo.kt +2532 -0
  188. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/SGCManager.kt +470 -0
  189. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Simulated.kt +228 -0
  190. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/Ar99OtaManager.java +566 -0
  191. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaByteUtils.java +18 -0
  192. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCommandConstants.java +35 -0
  193. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCrc32Util.java +13 -0
  194. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaGattTransport.java +11 -0
  195. package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaProtocol.java +92 -0
  196. package/android/src/main/java/com/glassly/bluetoothsdk/speakerid/SpeakerIdEngine.kt +525 -0
  197. package/android/src/main/java/com/glassly/bluetoothsdk/status/DeviceStatus.kt +669 -0
  198. package/android/src/main/java/com/glassly/bluetoothsdk/status/RuntimeState.kt +201 -0
  199. package/android/src/main/java/com/glassly/bluetoothsdk/status/WifiHotspotStatus.kt +189 -0
  200. package/android/src/main/java/com/glassly/bluetoothsdk/streaming/StreamModels.kt +518 -0
  201. package/android/src/main/java/com/glassly/bluetoothsdk/stt/STTTools.kt +391 -0
  202. package/android/src/main/java/com/glassly/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +518 -0
  203. package/android/src/main/java/com/glassly/bluetoothsdk/stt/VadGateSpeechPolicy.kt +229 -0
  204. package/android/src/main/java/com/glassly/bluetoothsdk/tts/TTSTools.kt +248 -0
  205. package/android/src/main/java/com/glassly/bluetoothsdk/types/DeviceModels.kt +96 -0
  206. package/android/src/main/java/com/glassly/bluetoothsdk/utils/AES.java +106 -0
  207. package/android/src/main/java/com/glassly/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
  208. package/android/src/main/java/com/glassly/bluetoothsdk/utils/AvifExifStripper.java +573 -0
  209. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
  210. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleJsonCompact.java +496 -0
  211. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadService.java +677 -0
  212. package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleWireProtocol.java +108 -0
  213. package/android/src/main/java/com/glassly/bluetoothsdk/utils/Constants.kt +46 -0
  214. package/android/src/main/java/com/glassly/bluetoothsdk/utils/G1Text.kt +436 -0
  215. package/android/src/main/java/com/glassly/bluetoothsdk/utils/HeifExifTagReader.java +199 -0
  216. package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
  217. package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleUploadService.java +77 -0
  218. package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900LengthCodec.java +115 -0
  219. package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtils.java +827 -0
  220. package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunkReassembler.java +228 -0
  221. package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunker.java +325 -0
  222. package/android/src/main/java/com/glassly/bluetoothsdk/utils/NexSGCUtils.kt +698 -0
  223. package/android/src/main/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitor.kt +348 -0
  224. package/android/src/main/java/com/glassly/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
  225. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Ar99OpusPcmDecoder.java +398 -0
  226. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
  227. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
  228. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
  229. package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PcmStreamPlayer.kt +328 -0
  230. package/android/src/main/res/values/strings.xml +4 -0
  231. package/android/src/test/java/com/glassly/bluetoothsdk/BluetoothSdkExceptionTest.kt +18 -0
  232. package/android/src/test/java/com/glassly/bluetoothsdk/OtaManifestDowngradeTest.kt +86 -0
  233. package/android/src/test/java/com/glassly/bluetoothsdk/OtaStartResponsePolicyTest.kt +30 -0
  234. package/android/src/test/java/com/glassly/bluetoothsdk/ReleaseChangelogTest.kt +13 -0
  235. package/android/src/test/java/com/glassly/bluetoothsdk/ScopedNetworkReadinessTest.kt +39 -0
  236. package/android/src/test/java/com/glassly/bluetoothsdk/StreamStatusEventTest.kt +29 -0
  237. package/android/src/test/java/com/glassly/bluetoothsdk/camera/PhotoRequestTest.kt +141 -0
  238. package/android/src/test/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServerTest.kt +82 -0
  239. package/android/src/test/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistryTest.java +75 -0
  240. package/android/src/test/java/com/glassly/bluetoothsdk/services/ForegroundServiceTypeTest.kt +69 -0
  241. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/Ar99AdvertisementMatcherTest.java +22 -0
  242. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuardTest.kt +73 -0
  243. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapperTest.kt +67 -0
  244. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/EvenRleTest.kt +63 -0
  245. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizerTest.kt +31 -0
  246. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassificationTest.kt +89 -0
  247. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwRendererTest.kt +344 -0
  248. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCacheTest.kt +200 -0
  249. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocolTest.kt +131 -0
  250. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLiveGattCharacteristicsTest.kt +39 -0
  251. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisementParserTest.kt +133 -0
  252. package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/NimoProtocolTest.kt +333 -0
  253. package/android/src/test/java/com/glassly/bluetoothsdk/utils/AvifExifStripperTest.java +46 -0
  254. package/android/src/test/java/com/glassly/bluetoothsdk/utils/BinaryMessageChunkerTest.java +84 -0
  255. package/android/src/test/java/com/glassly/bluetoothsdk/utils/BleJsonCompactTest.java +319 -0
  256. package/android/src/test/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadServiceTest.java +107 -0
  257. package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsEndiannessTest.java +172 -0
  258. package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsTest.java +24 -0
  259. package/android/src/test/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitorTest.kt +45 -0
  260. package/android/src/test/resources/avif_with_exif.avif +0 -0
  261. package/app.plugin.js +3 -0
  262. package/build/BluetoothSdk.types.d.ts +1354 -0
  263. package/build/BluetoothSdk.types.d.ts.map +1 -0
  264. package/build/BluetoothSdk.types.js +41 -0
  265. package/build/BluetoothSdk.types.js.map +1 -0
  266. package/build/_internal.d.ts +17 -0
  267. package/build/_internal.d.ts.map +1 -0
  268. package/build/_internal.js +16 -0
  269. package/build/_internal.js.map +1 -0
  270. package/build/_private/BluetoothSdkModule.d.ts +172 -0
  271. package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
  272. package/build/_private/BluetoothSdkModule.js +300 -0
  273. package/build/_private/BluetoothSdkModule.js.map +1 -0
  274. package/build/_private/LocalNetworkModule.d.ts +38 -0
  275. package/build/_private/LocalNetworkModule.d.ts.map +1 -0
  276. package/build/_private/LocalNetworkModule.js +3 -0
  277. package/build/_private/LocalNetworkModule.js.map +1 -0
  278. package/build/_private/cameraRequestPayload.d.ts +4 -0
  279. package/build/_private/cameraRequestPayload.d.ts.map +1 -0
  280. package/build/_private/cameraRequestPayload.js +32 -0
  281. package/build/_private/cameraRequestPayload.js.map +1 -0
  282. package/build/_private/photoRequestPayload.d.ts +6 -0
  283. package/build/_private/photoRequestPayload.d.ts.map +1 -0
  284. package/build/_private/photoRequestPayload.js +86 -0
  285. package/build/_private/photoRequestPayload.js.map +1 -0
  286. package/build/_private/sdkOtaManifest.d.ts +11 -0
  287. package/build/_private/sdkOtaManifest.d.ts.map +1 -0
  288. package/build/_private/sdkOtaManifest.js +15 -0
  289. package/build/_private/sdkOtaManifest.js.map +1 -0
  290. package/build/changelogs.d.ts +7 -0
  291. package/build/changelogs.d.ts.map +1 -0
  292. package/build/changelogs.js +46 -0
  293. package/build/changelogs.js.map +1 -0
  294. package/build/debug.d.ts +3 -0
  295. package/build/debug.d.ts.map +1 -0
  296. package/build/debug.js +8 -0
  297. package/build/debug.js.map +1 -0
  298. package/build/generated/changelogCatalog.d.ts +9 -0
  299. package/build/generated/changelogCatalog.d.ts.map +1 -0
  300. package/build/generated/changelogCatalog.js +12 -0
  301. package/build/generated/changelogCatalog.js.map +1 -0
  302. package/build/generated/releaseMetadata.d.ts +12 -0
  303. package/build/generated/releaseMetadata.d.ts.map +1 -0
  304. package/build/generated/releaseMetadata.js +10 -0
  305. package/build/generated/releaseMetadata.js.map +1 -0
  306. package/build/index.d.ts +6 -0
  307. package/build/index.d.ts.map +1 -0
  308. package/build/index.js +171 -0
  309. package/build/index.js.map +1 -0
  310. package/build/ota-server/OtaServer.types.d.ts +14 -0
  311. package/build/ota-server/OtaServer.types.d.ts.map +1 -0
  312. package/build/ota-server/OtaServer.types.js +2 -0
  313. package/build/ota-server/OtaServer.types.js.map +1 -0
  314. package/build/ota-server/OtaServerModule.d.ts +21 -0
  315. package/build/ota-server/OtaServerModule.d.ts.map +1 -0
  316. package/build/ota-server/OtaServerModule.js +3 -0
  317. package/build/ota-server/OtaServerModule.js.map +1 -0
  318. package/build/ota-server/OtaServerModule.web.d.ts +10 -0
  319. package/build/ota-server/OtaServerModule.web.d.ts.map +1 -0
  320. package/build/ota-server/OtaServerModule.web.js +12 -0
  321. package/build/ota-server/OtaServerModule.web.js.map +1 -0
  322. package/build/ota-server/index.d.ts +3 -0
  323. package/build/ota-server/index.d.ts.map +1 -0
  324. package/build/ota-server/index.js +3 -0
  325. package/build/ota-server/index.js.map +1 -0
  326. package/build/ota-transport/index.d.ts +67 -0
  327. package/build/ota-transport/index.d.ts.map +1 -0
  328. package/build/ota-transport/index.js +58 -0
  329. package/build/ota-transport/index.js.map +1 -0
  330. package/build/photo-receiver/PhotoReceiver.types.d.ts +18 -0
  331. package/build/photo-receiver/PhotoReceiver.types.d.ts.map +1 -0
  332. package/build/photo-receiver/PhotoReceiver.types.js +2 -0
  333. package/build/photo-receiver/PhotoReceiver.types.js.map +1 -0
  334. package/build/photo-receiver/PhotoReceiverModule.d.ts +10 -0
  335. package/build/photo-receiver/PhotoReceiverModule.d.ts.map +1 -0
  336. package/build/photo-receiver/PhotoReceiverModule.js +3 -0
  337. package/build/photo-receiver/PhotoReceiverModule.js.map +1 -0
  338. package/build/photo-receiver/PhotoReceiverModule.web.d.ts +10 -0
  339. package/build/photo-receiver/PhotoReceiverModule.web.d.ts.map +1 -0
  340. package/build/photo-receiver/PhotoReceiverModule.web.js +12 -0
  341. package/build/photo-receiver/PhotoReceiverModule.web.js.map +1 -0
  342. package/build/photo-receiver/index.d.ts +3 -0
  343. package/build/photo-receiver/index.d.ts.map +1 -0
  344. package/build/photo-receiver/index.js +3 -0
  345. package/build/photo-receiver/index.js.map +1 -0
  346. package/build/react/index.d.ts +5 -0
  347. package/build/react/index.d.ts.map +1 -0
  348. package/build/react/index.js +4 -0
  349. package/build/react/index.js.map +1 -0
  350. package/build/react/useBluetooth.d.ts +100 -0
  351. package/build/react/useBluetooth.d.ts.map +1 -0
  352. package/build/react/useBluetooth.js +167 -0
  353. package/build/react/useBluetooth.js.map +1 -0
  354. package/build/react/useBluetoothEvent.d.ts +6 -0
  355. package/build/react/useBluetoothEvent.d.ts.map +1 -0
  356. package/build/react/useBluetoothEvent.js +21 -0
  357. package/build/react/useBluetoothEvent.js.map +1 -0
  358. package/build/react/useBluetoothScan.d.ts +22 -0
  359. package/build/react/useBluetoothScan.d.ts.map +1 -0
  360. package/build/react/useBluetoothScan.js +135 -0
  361. package/build/react/useBluetoothScan.js.map +1 -0
  362. package/build/react/useBluetoothStatus.d.ts +16 -0
  363. package/build/react/useBluetoothStatus.d.ts.map +1 -0
  364. package/build/react/useBluetoothStatus.js +137 -0
  365. package/build/react/useBluetoothStatus.js.map +1 -0
  366. package/build/react/useGlassesConnection.d.ts +29 -0
  367. package/build/react/useGlassesConnection.d.ts.map +1 -0
  368. package/build/react/useGlassesConnection.js +153 -0
  369. package/build/react/useGlassesConnection.js.map +1 -0
  370. package/build/types/index.d.ts +3 -0
  371. package/build/types/index.d.ts.map +1 -0
  372. package/build/types/index.js +2 -0
  373. package/build/types/index.js.map +1 -0
  374. package/expo-module.config.json +14 -0
  375. package/ios/BackgroundOtaArtifactDownloader.swift +125 -0
  376. package/ios/BluetoothSdkModule.swift +1034 -0
  377. package/ios/GlasslyBluetoothSDK.podspec +106 -0
  378. package/ios/LocalIPv4.swift +150 -0
  379. package/ios/LocalOtaServer.swift +309 -0
  380. package/ios/LocalPhotoUploadServer.swift +754 -0
  381. package/ios/OtaServerModule.swift +147 -0
  382. package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
  383. package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
  384. package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
  385. package/ios/Packages/CoreObjC/attdet.c +92 -0
  386. package/ios/Packages/CoreObjC/attdet.h +44 -0
  387. package/ios/Packages/CoreObjC/bits.c +375 -0
  388. package/ios/Packages/CoreObjC/bits.h +315 -0
  389. package/ios/Packages/CoreObjC/bwdet.c +129 -0
  390. package/ios/Packages/CoreObjC/bwdet.h +69 -0
  391. package/ios/Packages/CoreObjC/common.h +151 -0
  392. package/ios/Packages/CoreObjC/energy.c +70 -0
  393. package/ios/Packages/CoreObjC/energy.h +43 -0
  394. package/ios/Packages/CoreObjC/fastmath.h +158 -0
  395. package/ios/Packages/CoreObjC/include/PcmConverter.h +22 -0
  396. package/ios/Packages/CoreObjC/lc3.c +704 -0
  397. package/ios/Packages/CoreObjC/lc3.h +313 -0
  398. package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
  399. package/ios/Packages/CoreObjC/lc3_private.h +163 -0
  400. package/ios/Packages/CoreObjC/ltpf.c +905 -0
  401. package/ios/Packages/CoreObjC/ltpf.h +111 -0
  402. package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
  403. package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
  404. package/ios/Packages/CoreObjC/makefile.mk +35 -0
  405. package/ios/Packages/CoreObjC/mdct.c +469 -0
  406. package/ios/Packages/CoreObjC/mdct.h +57 -0
  407. package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
  408. package/ios/Packages/CoreObjC/meson.build +61 -0
  409. package/ios/Packages/CoreObjC/plc.c +61 -0
  410. package/ios/Packages/CoreObjC/plc.h +57 -0
  411. package/ios/Packages/CoreObjC/rnnoise.h +114 -0
  412. package/ios/Packages/CoreObjC/sns.c +880 -0
  413. package/ios/Packages/CoreObjC/sns.h +103 -0
  414. package/ios/Packages/CoreObjC/spec.c +907 -0
  415. package/ios/Packages/CoreObjC/spec.h +119 -0
  416. package/ios/Packages/CoreObjC/tables.c +3457 -0
  417. package/ios/Packages/CoreObjC/tables.h +94 -0
  418. package/ios/Packages/CoreObjC/tns.c +457 -0
  419. package/ios/Packages/CoreObjC/tns.h +99 -0
  420. package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
  421. package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
  422. package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +2383 -0
  423. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +48 -0
  424. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/c-api.h +4689 -0
  425. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -0
  426. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
  427. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/c-api.h +4689 -0
  428. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -0
  429. package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
  430. package/ios/Packages/libbz2/module.modulemap +5 -0
  431. package/ios/Packages/libbz2/shim.h +1 -0
  432. package/ios/PhotoReceiverModule.swift +129 -0
  433. package/ios/Source/BluetoothSDK.swift +2303 -0
  434. package/ios/Source/BluetoothSDKDebug.swift +12 -0
  435. package/ios/Source/BluetoothSdkDefaults.swift +29 -0
  436. package/ios/Source/Bridge.swift +708 -0
  437. package/ios/Source/Bridging-Header.h +16 -0
  438. package/ios/Source/DeviceManager.swift +2109 -0
  439. package/ios/Source/DeviceStore.swift +336 -0
  440. package/ios/Source/GeneratedChangelogCatalog.swift +7 -0
  441. package/ios/Source/GeneratedReleaseMetadata.swift +11 -0
  442. package/ios/Source/ObservableStore.swift +118 -0
  443. package/ios/Source/OtaManifest.swift +211 -0
  444. package/ios/Source/PrivacyInfo.xcprivacy +23 -0
  445. package/ios/Source/ReleaseChangelog.swift +65 -0
  446. package/ios/Source/Resources/G2Firmware/README.md +10 -0
  447. package/ios/Source/audio/AudioModels.swift +178 -0
  448. package/ios/Source/audio/PcmStreamPlayer.swift +410 -0
  449. package/ios/Source/camera/CameraModels.swift +866 -0
  450. package/ios/Source/connection/ScanSession.swift +27 -0
  451. package/ios/Source/controllers/ControllerManager.swift +184 -0
  452. package/ios/Source/controllers/R1.swift +829 -0
  453. package/ios/Source/errors/BluetoothSdkError.swift +19 -0
  454. package/ios/Source/events/BluetoothEvents.swift +342 -0
  455. package/ios/Source/internal/BleTraceLogger.swift +192 -0
  456. package/ios/Source/internal/BluetoothAvailability.swift +78 -0
  457. package/ios/Source/internal/BluetoothSdkAnalytics.swift +199 -0
  458. package/ios/Source/internal/ValueParsing.swift +99 -0
  459. package/ios/Source/requests/DisplayRequests.swift +82 -0
  460. package/ios/Source/services/PhoneMic.swift +662 -0
  461. package/ios/Source/sgcs/Ar99.swift +2451 -0
  462. package/ios/Source/sgcs/Frame.swift +649 -0
  463. package/ios/Source/sgcs/G1.swift +2554 -0
  464. package/ios/Source/sgcs/G2.swift +6887 -0
  465. package/ios/Source/sgcs/G2CfwClassification.swift +43 -0
  466. package/ios/Source/sgcs/G2CfwRenderer.swift +1279 -0
  467. package/ios/Source/sgcs/G2CfwTextureCache.swift +233 -0
  468. package/ios/Source/sgcs/G2FlashProtocol.swift +312 -0
  469. package/ios/Source/sgcs/G2Flasher.swift +773 -0
  470. package/ios/Source/sgcs/Mach1.swift +541 -0
  471. package/ios/Source/sgcs/MentraLive.swift +7011 -0
  472. package/ios/Source/sgcs/MentraLiveL2capChannel.swift +183 -0
  473. package/ios/Source/sgcs/MentraLivePairingAdvertisement.swift +64 -0
  474. package/ios/Source/sgcs/MentraNex.swift +3221 -0
  475. package/ios/Source/sgcs/Nimo.swift +1886 -0
  476. package/ios/Source/sgcs/SGCManager.swift +608 -0
  477. package/ios/Source/sgcs/Simulated.swift +274 -0
  478. package/ios/Source/sgcs/ar99/ota/Ar99OtaManager.swift +637 -0
  479. package/ios/Source/sgcs/glassly_ble.pb.swift +4354 -0
  480. package/ios/Source/speakerid/SpeakerIdEngine.swift +573 -0
  481. package/ios/Source/status/DeviceStatus.swift +981 -0
  482. package/ios/Source/status/RuntimeState.swift +359 -0
  483. package/ios/Source/status/WifiHotspotStatus.swift +345 -0
  484. package/ios/Source/streaming/StreamModels.swift +693 -0
  485. package/ios/Source/stt/STTTools.swift +191 -0
  486. package/ios/Source/stt/SherpaOnnxTranscriber.swift +466 -0
  487. package/ios/Source/tts/TTSTools.swift +171 -0
  488. package/ios/Source/types/DeviceModels.swift +177 -0
  489. package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
  490. package/ios/Source/utils/BinaryCodec.swift +61 -0
  491. package/ios/Source/utils/BleJsonCompact.swift +405 -0
  492. package/ios/Source/utils/BleWireProtocol.swift +92 -0
  493. package/ios/Source/utils/Constants.swift +78 -0
  494. package/ios/Source/utils/Enums.swift +95 -0
  495. package/ios/Source/utils/G1Text.swift +2096 -0
  496. package/ios/Source/utils/JSCExperiment.swift +241 -0
  497. package/ios/Source/utils/MemoryMonitor.swift +44 -0
  498. package/ios/Source/utils/MessageChunkReassembler.swift +190 -0
  499. package/ios/Source/utils/MessageChunker.swift +294 -0
  500. package/ios/Source/utils/Models.swift +135 -0
  501. package/ios/Source/utils/PhoneAudioMonitor.swift +230 -0
  502. package/ios/Source/utils/TarBz2Extractor.swift +257 -0
  503. package/ios/Tests/BluetoothSDKTests/G2CfwClassificationTests.swift +78 -0
  504. package/ios/Tests/BluetoothSDKTests/G2CfwRendererTests.swift +372 -0
  505. package/ios/Tests/BluetoothSDKTests/G2CfwTextureCacheTests.swift +162 -0
  506. package/ios/Tests/BluetoothSDKTests/G2FlashProtocolTests.swift +182 -0
  507. package/ios/Tests/MentraLivePairingAdvertisementTests.swift +160 -0
  508. package/ios/Tests/ReleaseChangelogTests.swift +13 -0
  509. package/package.json +129 -0
  510. package/plugin/build/index.d.ts +10 -0
  511. package/plugin/build/index.js +12 -0
  512. package/plugin/build/withAndroid.d.ts +3 -0
  513. package/plugin/build/withAndroid.js +190 -0
  514. package/plugin/build/withIos.d.ts +5 -0
  515. package/plugin/build/withIos.js +108 -0
  516. package/scripts/inject-ios-sdk-version.mjs +65 -0
  517. package/scripts/public-ota-api.test.mjs +37 -0
  518. package/scripts/verify-release-package.mjs +45 -0
  519. package/scripts/write-release-metadata.mjs +152 -0
  520. package/scripts/write-release-metadata.test.mjs +37 -0
  521. package/src/BluetoothSdk.types.ts +1623 -0
  522. package/src/_internal.ts +16 -0
  523. package/src/_private/BluetoothSdkModule.ts +684 -0
  524. package/src/_private/LocalNetworkModule.ts +50 -0
  525. package/src/_private/cameraRequestPayload.ts +34 -0
  526. package/src/_private/photoRequestPayload.ts +90 -0
  527. package/src/_private/sdkOtaManifest.ts +18 -0
  528. package/src/changelogs.ts +46 -0
  529. package/src/debug.ts +9 -0
  530. package/src/generated/changelogCatalog.ts +13 -0
  531. package/src/generated/releaseMetadata.ts +20 -0
  532. package/src/index.ts +321 -0
  533. package/src/ota-server/OtaServer.types.ts +10 -0
  534. package/src/ota-server/OtaServerModule.ts +23 -0
  535. package/src/ota-server/OtaServerModule.web.ts +17 -0
  536. package/src/ota-server/index.ts +2 -0
  537. package/src/ota-transport/index.ts +116 -0
  538. package/src/photo-receiver/PhotoReceiver.types.ts +20 -0
  539. package/src/photo-receiver/PhotoReceiverModule.ts +11 -0
  540. package/src/photo-receiver/PhotoReceiverModule.web.ts +17 -0
  541. package/src/photo-receiver/index.ts +2 -0
  542. package/src/react/index.ts +21 -0
  543. package/src/react/useBluetooth.ts +309 -0
  544. package/src/react/useBluetoothEvent.ts +35 -0
  545. package/src/react/useBluetoothScan.ts +173 -0
  546. package/src/react/useBluetoothStatus.ts +180 -0
  547. package/src/react/useGlassesConnection.ts +202 -0
  548. package/src/types/index.ts +12 -0
@@ -0,0 +1,414 @@
1
+ package com.glassly.bluetoothsdk
2
+
3
+ import android.net.ConnectivityManager
4
+ import android.net.Network
5
+ import android.net.NetworkCapabilities
6
+ import android.net.NetworkRequest
7
+ import android.net.wifi.WifiNetworkSpecifier
8
+ import android.os.Handler
9
+ import android.os.Looper
10
+ import android.util.Base64
11
+ import android.util.Log
12
+ import expo.modules.kotlin.Promise
13
+ import expo.modules.kotlin.modules.Module
14
+ import expo.modules.kotlin.modules.ModuleDefinition
15
+ import java.io.File
16
+ import java.io.FileOutputStream
17
+ import java.net.HttpURLConnection
18
+ import java.net.Inet4Address
19
+ import java.net.URL
20
+ import java.util.concurrent.ConcurrentHashMap
21
+ import java.util.concurrent.Executors
22
+
23
+ /** Glassly-internal transport for glasses-local traffic without process network binding. */
24
+ class LocalNetworkModule : Module() {
25
+ private companion object {
26
+ const val TAG = "LocalNetwork"
27
+ const val NETWORK_READINESS_TIMEOUT_MS = 5_000L
28
+ }
29
+
30
+ private val lock = Any()
31
+ private val executor = Executors.newCachedThreadPool()
32
+ private val handler = Handler(Looper.getMainLooper())
33
+ private val activeConnections = ConcurrentHashMap<String, HttpURLConnection>()
34
+ private val networkReadiness = ScopedNetworkReadiness<Network>()
35
+ private var localNetwork: Network? = null
36
+ private var networkCallback: ConnectivityManager.NetworkCallback? = null
37
+ private var pendingConnectPromise: Promise? = null
38
+ private var pendingReadinessTimeout: Runnable? = null
39
+
40
+ override fun definition() = ModuleDefinition {
41
+ Name("LocalNetwork")
42
+ Events("downloadProgress", "networkLost")
43
+
44
+ AsyncFunction("connect") { ssid: String, password: String, promise: Promise ->
45
+ connect(ssid, password, promise)
46
+ }
47
+
48
+ AsyncFunction("request") {
49
+ requestId: String,
50
+ url: String,
51
+ method: String,
52
+ headers: Map<String, String>,
53
+ body: String?,
54
+ timeoutMs: Int,
55
+ promise: Promise ->
56
+ executor.execute { performRequest(requestId, url, method, headers, body, timeoutMs, promise) }
57
+ }
58
+
59
+ AsyncFunction("download") {
60
+ requestId: String,
61
+ url: String,
62
+ destination: String,
63
+ headers: Map<String, String>,
64
+ connectionTimeoutMs: Int,
65
+ readTimeoutMs: Int,
66
+ promise: Promise ->
67
+ executor.execute {
68
+ performDownload(
69
+ requestId,
70
+ url,
71
+ destination,
72
+ headers,
73
+ connectionTimeoutMs,
74
+ readTimeoutMs,
75
+ promise,
76
+ )
77
+ }
78
+ }
79
+
80
+ AsyncFunction("cancel") { requestId: String -> cancel(requestId) }
81
+ AsyncFunction("disconnect") { disconnect() }
82
+
83
+ OnDestroy {
84
+ disconnect()
85
+ }
86
+ }
87
+
88
+ private fun connectivityManager(): ConnectivityManager =
89
+ requireNotNull(appContext.reactContext?.getSystemService(ConnectivityManager::class.java)) {
90
+ "ConnectivityManager is unavailable"
91
+ }
92
+
93
+ private fun connect(ssid: String, password: String, promise: Promise) {
94
+ disconnect()
95
+ val manager = connectivityManager()
96
+ val specifier =
97
+ WifiNetworkSpecifier.Builder()
98
+ .setSsid(ssid)
99
+ .setWpa2Passphrase(password)
100
+ .build()
101
+ val request =
102
+ NetworkRequest.Builder()
103
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
104
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
105
+ .setNetworkSpecifier(specifier)
106
+ .build()
107
+
108
+ val callback =
109
+ object : ConnectivityManager.NetworkCallback() {
110
+ override fun onAvailable(network: Network) {
111
+ synchronized(lock) {
112
+ if (networkCallback !== this) {
113
+ Log.d(TAG, "Ignoring onAvailable from a stale network request")
114
+ return
115
+ }
116
+ networkReadiness.onAvailable(network)
117
+ }
118
+ Log.i(
119
+ TAG,
120
+ "Captured glasses WiFi network=$network; waiting for foreground capability " +
121
+ "processBoundNetwork=${manager.boundNetworkForProcess}",
122
+ )
123
+ scheduleReadinessTimeout(this, ssid)
124
+ }
125
+
126
+ override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
127
+ val connectPromise: Promise?
128
+ synchronized(lock) {
129
+ if (networkCallback !== this || localNetwork != null || pendingConnectPromise == null) return
130
+ if (!networkReadiness.isReady(
131
+ network,
132
+ capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND),
133
+ )
134
+ ) {
135
+ return
136
+ }
137
+ localNetwork = network
138
+ connectPromise = pendingConnectPromise
139
+ pendingConnectPromise = null
140
+ cancelReadinessTimeoutLocked()
141
+ }
142
+ Log.i(
143
+ TAG,
144
+ "Glasses WiFi network=$network is foreground and ready " +
145
+ "processBoundNetwork=${manager.boundNetworkForProcess}",
146
+ )
147
+ val localAddress =
148
+ manager.getLinkProperties(network)
149
+ ?.linkAddresses
150
+ ?.firstOrNull { it.address is Inet4Address }
151
+ ?.address
152
+ ?.hostAddress
153
+ connectPromise?.resolve(
154
+ buildMap<String, Any> {
155
+ put("connected", true)
156
+ put("ssid", ssid)
157
+ if (!localAddress.isNullOrBlank()) put("localAddress", localAddress)
158
+ },
159
+ )
160
+ }
161
+
162
+ override fun onUnavailable() {
163
+ synchronized(lock) {
164
+ if (networkCallback !== this) {
165
+ Log.d(TAG, "Ignoring onUnavailable from a stale network request")
166
+ return
167
+ }
168
+ }
169
+ rejectPendingConnect("ERR_LOCAL_WIFI_UNAVAILABLE", "Could not connect to $ssid")
170
+ clearNetworkCallback(this)
171
+ }
172
+
173
+ override fun onLost(network: Network) {
174
+ synchronized(lock) {
175
+ if (networkCallback !== this ||
176
+ (localNetwork != network && !networkReadiness.contains(network))
177
+ ) {
178
+ Log.d(TAG, "Ignoring onLost from a stale network request")
179
+ return
180
+ }
181
+ localNetwork = null
182
+ networkReadiness.clear()
183
+ }
184
+ cancelAll()
185
+ rejectPendingConnect("ERR_LOCAL_WIFI_LOST", "Lost connection to $ssid")
186
+ clearNetworkCallback(this)
187
+ sendEvent("networkLost", mapOf("ssid" to ssid))
188
+ }
189
+ }
190
+
191
+ synchronized(lock) {
192
+ pendingConnectPromise = promise
193
+ networkCallback = callback
194
+ }
195
+ try {
196
+ manager.requestNetwork(request, callback, 30_000)
197
+ } catch (error: Exception) {
198
+ clearNetworkCallback(callback)
199
+ rejectPendingConnect("ERR_LOCAL_WIFI_REQUEST", error.message ?: "Local WiFi request failed", error)
200
+ }
201
+ }
202
+
203
+ private fun performRequest(
204
+ requestId: String,
205
+ url: String,
206
+ method: String,
207
+ headers: Map<String, String>,
208
+ body: String?,
209
+ timeoutMs: Int,
210
+ promise: Promise,
211
+ ) {
212
+ var connection: HttpURLConnection? = null
213
+ try {
214
+ connection = openConnection(requestId, url)
215
+ connection.requestMethod = method
216
+ connection.connectTimeout = timeoutMs
217
+ connection.readTimeout = timeoutMs
218
+ headers.forEach(connection::setRequestProperty)
219
+ if (body != null) {
220
+ connection.doOutput = true
221
+ connection.outputStream.use { it.write(body.toByteArray(Charsets.UTF_8)) }
222
+ }
223
+ val status = connection.responseCode
224
+ val stream = if (status >= 400) connection.errorStream else connection.inputStream
225
+ val bytes = stream?.use { it.readBytes() } ?: ByteArray(0)
226
+ promise.resolve(
227
+ mapOf(
228
+ "status" to status,
229
+ "headers" to responseHeaders(connection),
230
+ "bodyBase64" to Base64.encodeToString(bytes, Base64.NO_WRAP),
231
+ ),
232
+ )
233
+ } catch (error: Exception) {
234
+ promise.reject("ERR_LOCAL_HTTP", error.message ?: "Local HTTP request failed", error)
235
+ } finally {
236
+ activeConnections.remove(requestId)
237
+ connection?.disconnect()
238
+ }
239
+ }
240
+
241
+ private fun performDownload(
242
+ requestId: String,
243
+ url: String,
244
+ destination: String,
245
+ headers: Map<String, String>,
246
+ connectionTimeoutMs: Int,
247
+ readTimeoutMs: Int,
248
+ promise: Promise,
249
+ ) {
250
+ var connection: HttpURLConnection? = null
251
+ try {
252
+ connection = openConnection(requestId, url)
253
+ connection.requestMethod = "GET"
254
+ connection.connectTimeout = connectionTimeoutMs
255
+ connection.readTimeout = readTimeoutMs
256
+ headers.forEach(connection::setRequestProperty)
257
+ val status = connection.responseCode
258
+ if (status !in 200..299) throw IllegalStateException("HTTP $status")
259
+ val contentLength = connection.contentLengthLong
260
+ val responseHeaders = responseHeaders(connection)
261
+
262
+ // Match RNFS's begin callback contract before the first response byte. Gallery
263
+ // resumable downloads need the real status and Content-Range to validate segments.
264
+ sendEvent(
265
+ "downloadProgress",
266
+ mapOf(
267
+ "requestId" to requestId,
268
+ "bytesWritten" to 0L,
269
+ "contentLength" to contentLength,
270
+ "statusCode" to status,
271
+ "headers" to responseHeaders,
272
+ ),
273
+ )
274
+
275
+ val destinationFile = File(destination)
276
+ destinationFile.parentFile?.mkdirs()
277
+ var bytesWritten = 0L
278
+ connection.inputStream.use { input ->
279
+ FileOutputStream(destinationFile, false).use { output ->
280
+ val buffer = ByteArray(64 * 1024)
281
+ while (true) {
282
+ val count = input.read(buffer)
283
+ if (count < 0) break
284
+ output.write(buffer, 0, count)
285
+ bytesWritten += count
286
+ sendEvent(
287
+ "downloadProgress",
288
+ mapOf(
289
+ "requestId" to requestId,
290
+ "bytesWritten" to bytesWritten,
291
+ "contentLength" to contentLength,
292
+ ),
293
+ )
294
+ }
295
+ }
296
+ }
297
+ promise.resolve(
298
+ mapOf(
299
+ "statusCode" to status,
300
+ "bytesWritten" to bytesWritten,
301
+ "headers" to responseHeaders,
302
+ ),
303
+ )
304
+ } catch (error: Exception) {
305
+ promise.reject("ERR_LOCAL_DOWNLOAD", error.message ?: "Local download failed", error)
306
+ } finally {
307
+ activeConnections.remove(requestId)
308
+ connection?.disconnect()
309
+ }
310
+ }
311
+
312
+ private fun openConnection(requestId: String, url: String): HttpURLConnection {
313
+ val network = synchronized(lock) { localNetwork }
314
+ ?: throw IllegalStateException("Local WiFi is not connected")
315
+ val connection = network.openConnection(URL(url)) as HttpURLConnection
316
+ activeConnections[requestId] = connection
317
+ return connection
318
+ }
319
+
320
+ private fun responseHeaders(connection: HttpURLConnection): Map<String, String> =
321
+ connection.headerFields
322
+ .filterKeys { it != null }
323
+ .mapValues { (_, values) -> values.joinToString(", ") }
324
+
325
+ private fun cancel(requestId: String) {
326
+ activeConnections.remove(requestId)?.disconnect()
327
+ }
328
+
329
+ private fun cancelAll() {
330
+ activeConnections.keys.toList().forEach(::cancel)
331
+ }
332
+
333
+ private fun scheduleReadinessTimeout(
334
+ callback: ConnectivityManager.NetworkCallback,
335
+ ssid: String,
336
+ ) {
337
+ val timeout =
338
+ Runnable {
339
+ val connectPromise = synchronized(lock) {
340
+ if (networkCallback !== callback || pendingConnectPromise == null) return@Runnable
341
+ pendingReadinessTimeout = null
342
+ val promise = pendingConnectPromise
343
+ pendingConnectPromise = null
344
+ promise
345
+ }
346
+ connectPromise?.reject(
347
+ "ERR_LOCAL_WIFI_NOT_READY",
348
+ "Connected to $ssid but the network did not become ready",
349
+ null,
350
+ )
351
+ clearNetworkCallback(callback)
352
+ }
353
+ synchronized(lock) {
354
+ if (networkCallback !== callback || pendingConnectPromise == null) return
355
+ cancelReadinessTimeoutLocked()
356
+ pendingReadinessTimeout = timeout
357
+ }
358
+ handler.postDelayed(timeout, NETWORK_READINESS_TIMEOUT_MS)
359
+ }
360
+
361
+ private fun cancelReadinessTimeoutLocked() {
362
+ pendingReadinessTimeout?.let(handler::removeCallbacks)
363
+ pendingReadinessTimeout = null
364
+ }
365
+
366
+ private fun disconnect() {
367
+ cancelAll()
368
+ val manager = appContext.reactContext?.getSystemService(ConnectivityManager::class.java)
369
+ val callback: ConnectivityManager.NetworkCallback?
370
+ synchronized(lock) {
371
+ callback = networkCallback
372
+ networkCallback = null
373
+ localNetwork = null
374
+ networkReadiness.clear()
375
+ cancelReadinessTimeoutLocked()
376
+ }
377
+ if (callback != null && manager != null) {
378
+ try {
379
+ manager.unregisterNetworkCallback(callback)
380
+ } catch (_: IllegalArgumentException) {
381
+ // Already unregistered by the platform.
382
+ }
383
+ }
384
+ rejectPendingConnect("ERR_LOCAL_WIFI_CANCELLED", "Local WiFi connection cancelled")
385
+ }
386
+
387
+ private fun clearNetworkCallback(callback: ConnectivityManager.NetworkCallback) {
388
+ val manager = appContext.reactContext?.getSystemService(ConnectivityManager::class.java)
389
+ synchronized(lock) {
390
+ if (networkCallback == callback) {
391
+ networkCallback = null
392
+ localNetwork = null
393
+ networkReadiness.clear()
394
+ cancelReadinessTimeoutLocked()
395
+ }
396
+ }
397
+ if (manager != null) {
398
+ try {
399
+ manager.unregisterNetworkCallback(callback)
400
+ } catch (_: IllegalArgumentException) {
401
+ // Callback was not registered or has already been removed.
402
+ }
403
+ }
404
+ }
405
+
406
+ private fun rejectPendingConnect(code: String, message: String, cause: Throwable? = null) {
407
+ val promise: Promise?
408
+ synchronized(lock) {
409
+ promise = pendingConnectPromise
410
+ pendingConnectPromise = null
411
+ }
412
+ promise?.reject(code, message, cause)
413
+ }
414
+ }
@@ -0,0 +1,88 @@
1
+ package com.glassly.bluetoothsdk
2
+
3
+ import java.util.UUID
4
+ import org.json.JSONObject
5
+
6
+ /** Observable state management with immediate event emission */
7
+ class ObservableStore {
8
+ companion object {
9
+ const val BLUETOOTH_CATEGORY = "bluetooth"
10
+ private const val LEGACY_CORE_CATEGORY = "core"
11
+
12
+ fun normalizeCategory(category: String): String =
13
+ if (category == LEGACY_CORE_CATEGORY) BLUETOOTH_CATEGORY else category
14
+ }
15
+
16
+ private val values = mutableMapOf<String, Any>()
17
+ private val emitListeners = linkedMapOf<String, (String, Map<String, Any>) -> Unit>()
18
+
19
+ @Synchronized
20
+ fun configure(onEmit: (String, Map<String, Any>) -> Unit) {
21
+ emitListeners["default"] = onEmit
22
+ }
23
+
24
+ @Synchronized
25
+ fun addListener(onEmit: (String, Map<String, Any>) -> Unit): String {
26
+ val id = UUID.randomUUID().toString()
27
+ emitListeners[id] = onEmit
28
+ return id
29
+ }
30
+
31
+ @Synchronized
32
+ fun removeListener(id: String) {
33
+ emitListeners.remove(id)
34
+ }
35
+
36
+ fun set(category: String, key: String, value: Any) {
37
+ val normalizedCategory: String
38
+ val listeners: List<(String, Map<String, Any>) -> Unit>
39
+
40
+ synchronized(this) {
41
+ normalizedCategory = normalizeCategory(category)
42
+ val fullKey = "$normalizedCategory.$key"
43
+ val oldValue = values[fullKey]
44
+
45
+ // Skip if unchanged
46
+ if (oldValue != null && toJson(oldValue) == toJson(value)) return
47
+
48
+ values[fullKey] = value
49
+ listeners = emitListeners.values.toList()
50
+ }
51
+
52
+ // Emit immediately, outside the store lock so callbacks can safely re-enter the store.
53
+ listeners.forEach { it(normalizedCategory, mapOf(key to value)) }
54
+ }
55
+
56
+ fun remove(category: String, key: String) {
57
+ val normalizedCategory: String
58
+ val updatedSnapshot: Map<String, Any>
59
+ val listeners: List<(String, Map<String, Any>) -> Unit>
60
+
61
+ synchronized(this) {
62
+ normalizedCategory = normalizeCategory(category)
63
+ val fullKey = "$normalizedCategory.$key"
64
+ if (!values.containsKey(fullKey)) return // already absent, no notification needed
65
+ values.remove(fullKey)
66
+ val prefix = "$normalizedCategory."
67
+ updatedSnapshot = values.filterKeys { it.startsWith(prefix) }
68
+ .mapKeys { it.key.removePrefix(prefix) }
69
+ listeners = emitListeners.values.toList()
70
+ }
71
+
72
+ // Emit the full updated category snapshot so UI listeners can clear the removed key.
73
+ listeners.forEach { it(normalizedCategory, updatedSnapshot) }
74
+ }
75
+
76
+ @Synchronized
77
+ fun get(category: String, key: String): Any? = values["${normalizeCategory(category)}.$key"]
78
+
79
+ @Synchronized
80
+ fun getCategory(category: String): Map<String, Any> {
81
+ val prefix = "${normalizeCategory(category)}."
82
+ return values.filterKeys { it.startsWith(prefix) }.mapKeys { it.key.removePrefix(prefix) }
83
+ }
84
+
85
+ private fun toJson(value: Any): String {
86
+ return JSONObject(mapOf("v" to value)).toString()
87
+ }
88
+ }
@@ -0,0 +1,191 @@
1
+ package com.glassly.bluetoothsdk
2
+
3
+ import java.net.HttpURLConnection
4
+ import java.net.URI
5
+ import java.net.URL
6
+ import org.json.JSONArray
7
+ import org.json.JSONObject
8
+
9
+ internal object OtaManifestDefaults {
10
+ // ASG builds before 39 ignore ota_start.ota_version_url, so SDK checks must
11
+ // use the same legacy production manifest those glasses will install from.
12
+ const val LEGACY_PROD_OTA_VERSION_URL = "https://ota.glassly.ai/prod_live_version.json"
13
+
14
+ fun defaultOtaVersionUrl(): String {
15
+ val manifestUrl = GeneratedReleaseMetadata.OTA_MANIFEST_URL.trim()
16
+ if (manifestUrl.isBlank()) {
17
+ throw BluetoothSdkException(
18
+ "ota_manifest_unconfigured",
19
+ "This source-built Bluetooth SDK has no embedded OTA manifest. Configure one with the debug API.",
20
+ )
21
+ }
22
+ return manifestUrl
23
+ }
24
+ }
25
+
26
+ internal object OtaManifestChecker {
27
+ private const val ASG_CLIENT_PACKAGE = "com.mentra.asg_client"
28
+
29
+ fun normalizeHttpUrl(value: String): String {
30
+ val trimmed = value.trim()
31
+ if (trimmed.isEmpty()) {
32
+ throw BluetoothSdkException("invalid_ota_url", "OTA version URL must be a non-empty http(s) URL.")
33
+ }
34
+
35
+ val uri =
36
+ try {
37
+ URI(trimmed)
38
+ } catch (error: Exception) {
39
+ throw BluetoothSdkException("invalid_ota_url", "OTA version URL must be a valid http(s) URL.", error)
40
+ }
41
+
42
+ val scheme = uri.scheme?.lowercase()
43
+ if ((scheme != "http" && scheme != "https") || uri.host.isNullOrBlank()) {
44
+ throw BluetoothSdkException("invalid_ota_url", "OTA version URL must be an http(s) URL.")
45
+ }
46
+
47
+ return uri.toString()
48
+ }
49
+
50
+ fun fetch(otaVersionUrl: String): JSONObject {
51
+ val connection = URL(otaVersionUrl).openConnection() as HttpURLConnection
52
+ connection.connectTimeout = 15_000
53
+ connection.readTimeout = 15_000
54
+ connection.requestMethod = "GET"
55
+ return try {
56
+ val status = connection.responseCode
57
+ if (status !in 200..299) {
58
+ throw BluetoothSdkException("ota_manifest_request_failed", "OTA manifest request failed with HTTP $status for $otaVersionUrl.")
59
+ }
60
+ JSONObject(connection.inputStream.bufferedReader().use { it.readText() })
61
+ } finally {
62
+ connection.disconnect()
63
+ }
64
+ }
65
+
66
+ fun hasUpdate(
67
+ currentBuildNumber: String,
68
+ currentMtkVersion: String,
69
+ currentBesVersion: String,
70
+ manifest: JSONObject,
71
+ // Downgrade floor: a non-positive value (the default) disables downgrades entirely,
72
+ // matching ASG's fail-closed DowngradeGate and the engine. OEM SDK consumers that do
73
+ // not set a floor therefore get upgrade-only behavior and are never told a downgrade is
74
+ // available that the glasses would refuse.
75
+ downgradeFloorVersionCode: Long = 0L,
76
+ ): Boolean =
77
+ hasApkUpdate(currentBuildNumber, manifest, downgradeFloorVersionCode) ||
78
+ hasMtkUpdate(manifest.optJSONArray("mtk_patches"), currentMtkVersion) ||
79
+ hasBesUpdate(manifest.optJSONObject("bes_firmware"), currentBesVersion)
80
+
81
+ fun hasMtkPatches(manifest: JSONObject): Boolean =
82
+ (manifest.optJSONArray("mtk_patches")?.length() ?: 0) > 0
83
+
84
+ fun hasBesFirmware(manifest: JSONObject): Boolean =
85
+ manifest.optJSONObject("bes_firmware") != null
86
+
87
+ private fun latestAppInfo(manifest: JSONObject): JSONObject {
88
+ val apps = manifest.optJSONObject("apps")
89
+ val app = apps?.optJSONObject(ASG_CLIENT_PACKAGE)
90
+ if (app != null && app.hasNumber("versionCode")) {
91
+ return app
92
+ }
93
+
94
+ if (manifest.hasNumber("versionCode")) {
95
+ return manifest
96
+ }
97
+
98
+ throw BluetoothSdkException("invalid_ota_manifest", "OTA manifest is missing ASG app versionCode.")
99
+ }
100
+
101
+ private fun hasApkUpdate(
102
+ currentBuildNumber: String,
103
+ manifest: JSONObject,
104
+ downgradeFloorVersionCode: Long,
105
+ ): Boolean {
106
+ val currentVersion =
107
+ currentBuildNumber.toLongOrNull()
108
+ ?: throw BluetoothSdkException(
109
+ "invalid_glasses_version",
110
+ "Cannot check OTA update because glasses build number is invalid.",
111
+ )
112
+ // Only apps-shaped manifests are exact pins. A legacy top-level manifest (versionCode at
113
+ // the root, no apps entry) is NOT a pin and stays strictly upgrade-only, matching the
114
+ // engine TS checker — otherwise a build newer than such a manifest would report a false
115
+ // downgrade the JS path ignores.
116
+ val isExactPin = manifest.optJSONObject("apps")?.optJSONObject(ASG_CLIENT_PACKAGE)?.hasNumber("versionCode") == true
117
+ val serverVersion = latestAppInfo(manifest).requiredLong("versionCode")
118
+ if (!isExactPin) {
119
+ return serverVersion > currentVersion
120
+ }
121
+ // Exact pin: any mismatch is an update in either direction (downgrades take the
122
+ // uninstall-then-reinstall detour on the glasses). A non-positive pin is only legitimate
123
+ // in the frozen legacy rescue manifests that pre-39 glasses are checked against; for
124
+ // modern glasses it means the manifest cannot verify anything, and that must surface as an
125
+ // error — never as "no update".
126
+ if (serverVersion <= 0) {
127
+ if (currentVersion >= 39) {
128
+ throw BluetoothSdkException(
129
+ "invalid_ota_manifest",
130
+ "OTA manifest ASG pin is missing or zero; cannot verify update state.",
131
+ )
132
+ }
133
+ return false
134
+ }
135
+ if (serverVersion > currentVersion) {
136
+ return true
137
+ }
138
+ // Exact match: already on the pin, no update.
139
+ if (serverVersion == currentVersion) {
140
+ return false
141
+ }
142
+ // Downgrade: only actionable at/above the enabled floor; a non-positive floor disables
143
+ // downgrades (fail closed, matching ASG and the engine).
144
+ return downgradeFloorVersionCode > 0 && serverVersion >= downgradeFloorVersionCode
145
+ }
146
+
147
+ private fun hasMtkUpdate(patches: JSONArray?, currentVersion: String): Boolean {
148
+ if (patches == null || patches.length() == 0) return false
149
+ if (currentVersion.isBlank()) return false
150
+
151
+ for (index in 0 until patches.length()) {
152
+ val patch = patches.optJSONObject(index) ?: continue
153
+ val startFirmware = patch.optString("start_firmware", "")
154
+ if (startFirmware == currentVersion) return true
155
+ val serverDate = if (startFirmware.contains("_")) startFirmware.substringAfterLast("_") else startFirmware
156
+ if (serverDate == currentVersion) return true
157
+ }
158
+ return false
159
+ }
160
+
161
+ private fun hasBesUpdate(besFirmware: JSONObject?, currentVersion: String): Boolean {
162
+ if (besFirmware == null) return false
163
+ val serverVersion = besFirmware.optString("version", "")
164
+ if (serverVersion.isBlank()) {
165
+ throw BluetoothSdkException("invalid_ota_manifest", "OTA manifest bes_firmware.version is missing.")
166
+ }
167
+ if (currentVersion.isBlank()) return true
168
+ return compareVersions(serverVersion, currentVersion) > 0
169
+ }
170
+
171
+ private fun compareVersions(version1: String, version2: String): Int {
172
+ if (version1.contains(".") && version2.contains(".")) {
173
+ val parts1 = version1.split(".")
174
+ val parts2 = version2.split(".")
175
+ val maxLength = maxOf(parts1.size, parts2.size)
176
+ for (index in 0 until maxLength) {
177
+ val value1 = parts1.getOrNull(index)?.toIntOrNull() ?: 0
178
+ val value2 = parts2.getOrNull(index)?.toIntOrNull() ?: 0
179
+ if (value1 != value2) return value1 - value2
180
+ }
181
+ return 0
182
+ }
183
+ return version1.compareTo(version2)
184
+ }
185
+
186
+ private fun JSONObject.hasNumber(key: String): Boolean = !isNull(key) && opt(key) is Number
187
+
188
+ private fun JSONObject.requiredLong(key: String): Long =
189
+ (opt(key) as? Number)?.toLong()
190
+ ?: throw BluetoothSdkException("invalid_ota_manifest", "OTA manifest is missing ASG app versionCode.")
191
+ }