ilabs-flir 1.0.4 → 1.0.5

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 (36) hide show
  1. package/android/Flir/build.gradle.kts +14 -27
  2. package/android/Flir/libs/androidsdk-release.aar +0 -0
  3. package/android/Flir/libs/thermalsdk-release.aar +0 -0
  4. package/android/Flir/src/main/java/flir/android/FlirDownloadManager.kt +23 -44
  5. package/android/Flir/src/main/java/flir/android/FlirModule.kt +32 -0
  6. package/android/Flir/src/main/java/flir/android/FlirSDKLoader.kt +35 -194
  7. package/android/Flir/src/main/java/flir/android/FlirSdkManager.java +410 -1161
  8. package/package.json +1 -1
  9. package/src/index.d.ts +21 -1
  10. package/android/Flir/libs/flir-stubs.jar +0 -0
  11. package/android/Flir/src/main/java/com/flir/thermalsdk/ErrorCode.java +0 -13
  12. package/android/Flir/src/main/java/com/flir/thermalsdk/ErrorCodeException.java +0 -14
  13. package/android/Flir/src/main/java/com/flir/thermalsdk/ThermalSdkAndroid.java +0 -16
  14. package/android/Flir/src/main/java/com/flir/thermalsdk/androidsdk/image/BitmapAndroid.java +0 -20
  15. package/android/Flir/src/main/java/com/flir/thermalsdk/image/ImageBuffer.java +0 -11
  16. package/android/Flir/src/main/java/com/flir/thermalsdk/image/JavaImageBuffer.java +0 -35
  17. package/android/Flir/src/main/java/com/flir/thermalsdk/image/Palette.java +0 -15
  18. package/android/Flir/src/main/java/com/flir/thermalsdk/image/PaletteManager.java +0 -16
  19. package/android/Flir/src/main/java/com/flir/thermalsdk/image/Point.java +0 -11
  20. package/android/Flir/src/main/java/com/flir/thermalsdk/image/ThermalImage.java +0 -23
  21. package/android/Flir/src/main/java/com/flir/thermalsdk/image/ThermalValue.java +0 -9
  22. package/android/Flir/src/main/java/com/flir/thermalsdk/live/Camera.java +0 -26
  23. package/android/Flir/src/main/java/com/flir/thermalsdk/live/CameraType.java +0 -8
  24. package/android/Flir/src/main/java/com/flir/thermalsdk/live/CommunicationInterface.java +0 -16
  25. package/android/Flir/src/main/java/com/flir/thermalsdk/live/ConnectParameters.java +0 -16
  26. package/android/Flir/src/main/java/com/flir/thermalsdk/live/Identity.java +0 -23
  27. package/android/Flir/src/main/java/com/flir/thermalsdk/live/IpSettings.java +0 -9
  28. package/android/Flir/src/main/java/com/flir/thermalsdk/live/RemoteControl.java +0 -16
  29. package/android/Flir/src/main/java/com/flir/thermalsdk/live/connectivity/ConnectionStatusListener.java +0 -7
  30. package/android/Flir/src/main/java/com/flir/thermalsdk/live/discovery/DiscoveryEventListener.java +0 -14
  31. package/android/Flir/src/main/java/com/flir/thermalsdk/live/discovery/DiscoveryFactory.java +0 -33
  32. package/android/Flir/src/main/java/com/flir/thermalsdk/live/remote/OnReceived.java +0 -5
  33. package/android/Flir/src/main/java/com/flir/thermalsdk/live/remote/OnRemoteError.java +0 -7
  34. package/android/Flir/src/main/java/com/flir/thermalsdk/live/streaming/Stream.java +0 -8
  35. package/android/Flir/src/main/java/com/flir/thermalsdk/live/streaming/ThermalStreamer.java +0 -28
  36. package/android/Flir/src/main/java/com/flir/thermalsdk/live/streaming/VisualStreamer.java +0 -18
@@ -14,21 +14,20 @@ android {
14
14
  testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
15
15
  }
16
16
 
17
- compileOptions {
18
- sourceCompatibility = JavaVersion.VERSION_17
19
- targetCompatibility = JavaVersion.VERSION_17
17
+ compileOptions {
18
+ sourceCompatibility = JavaVersion.VERSION_21
19
+ targetCompatibility = JavaVersion.VERSION_21
20
20
  }
21
21
 
22
22
  kotlinOptions {
23
- jvmTarget = "17"
23
+ jvmTarget = JavaVersion.VERSION_21.toString()
24
24
  }
25
-
26
- java {
27
- toolchain {
28
- languageVersion.set(JavaLanguageVersion.of(21))
29
- }
25
+
26
+ buildFeatures {
27
+ viewBinding = true
30
28
  }
31
29
 
30
+
32
31
  publishing {
33
32
  singleVariant("release") {
34
33
  withJavadocJar()
@@ -37,35 +36,23 @@ android {
37
36
  }
38
37
  }
39
38
 
40
- repositories {
41
- google()
42
- mavenCentral()
43
- // Resolve local AARs which will be installed into mavenLocal by CI (JitPack)
44
- mavenLocal()
45
- flatDir { dirs("libs") }
46
- }
47
-
48
39
  dependencies {
49
40
  // React Native
50
41
  implementation("com.facebook.react:react-native:+")
51
42
 
52
- // Kotlin coroutines for async downloads
43
+ // Kotlin coroutines
53
44
  implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
54
45
 
55
- // Play Feature Delivery (optional - for Play Store SDK delivery)
56
- implementation("com.google.android.play:feature-delivery:2.1.0")
57
- implementation("com.google.android.play:feature-delivery-ktx:2.1.0")
58
-
59
- // FLIR SDK - Use stub JAR for compilation (AARs are Java 21, stubs work with Java 17)
60
- // The actual SDK AARs are downloaded on-demand at runtime via FlirDownload.download()
61
- compileOnly(files("libs/flir-stubs.jar"))
46
+ // FLIR SDK - Use the actual AAR files from libs folder
47
+ // Using 'api' to expose SDK classes to consumers and Java source files
48
+ // flatDir must be configured in settings.gradle or root build.gradle
49
+ api(files("libs/androidsdk-release.aar"))
50
+ api(files("libs/thermalsdk-release.aar"))
62
51
 
63
52
  // Minimal compile deps to satisfy source references
64
53
  implementation("androidx.annotation:annotation:1.5.0")
65
54
 
66
-
67
55
  // Prevent duplicate SLF4J classes when a consumer also brings `org.slf4j:slf4j-api`
68
- // The vendor AAR may embed slf4j classes; exclude the API from being pulled transitively
69
56
  configurations.all {
70
57
  exclude(group = "org.slf4j", module = "slf4j-api")
71
58
  }
@@ -1,25 +1,28 @@
1
1
  package flir.android
2
2
 
3
3
  import com.facebook.react.bridge.*
4
- import com.facebook.react.modules.core.DeviceEventManagerModule
5
- import kotlinx.coroutines.*
6
4
 
5
+ /**
6
+ * FlirDownloadManager - React Native module for SDK status
7
+ *
8
+ * Since the SDK is now bundled in the AAR, this module just reports
9
+ * that the SDK is always available.
10
+ */
7
11
  class FlirDownloadManager(private val reactContext: ReactApplicationContext) :
8
12
  ReactContextBaseJavaModule(reactContext) {
9
13
 
10
- private var downloadJob: Job? = null
11
- private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
12
-
13
14
  override fun getName() = "FlirDownloadManager"
14
15
 
15
16
  @ReactMethod
16
17
  fun isFlirAvailable(promise: Promise) {
17
- promise.resolve(FlirSDKLoader.isSDKAvailable(reactContext))
18
+ // SDK is bundled - always available
19
+ promise.resolve(true)
18
20
  }
19
21
 
20
22
  @ReactMethod
21
23
  fun getDownloadSize(promise: Promise) {
22
- promise.resolve(FlirSDKLoader.getDownloadSize(reactContext).toDouble())
24
+ // No download needed
25
+ promise.resolve(0.0)
23
26
  }
24
27
 
25
28
  @ReactMethod
@@ -29,48 +32,24 @@ class FlirDownloadManager(private val reactContext: ReactApplicationContext) :
29
32
 
30
33
  @ReactMethod
31
34
  fun downloadFlirSDK(promise: Promise) {
32
- downloadJob = scope.launch {
33
- val result = FlirSDKLoader.downloadSDK(reactContext) { downloaded, total ->
34
- sendEvent("FlirDownloadProgress", Arguments.createMap().apply {
35
- putDouble("bytesDownloaded", downloaded.toDouble())
36
- putDouble("totalBytes", total.toDouble())
37
- putDouble("percent", (downloaded.toDouble() / total) * 100)
38
- })
39
- }
40
-
41
- result.fold(
42
- onSuccess = {
43
- sendEvent("FlirDownloadComplete", Arguments.createMap())
44
- promise.resolve(true)
45
- },
46
- onFailure = { error ->
47
- sendEvent("FlirDownloadError", Arguments.createMap().apply {
48
- putString("error", error.message)
49
- })
50
- promise.reject("E_DOWNLOAD", error.message, error)
51
- }
52
- )
53
- }
54
- }
55
-
56
- @ReactMethod
57
- fun cancelDownload() {
58
- downloadJob?.cancel()
35
+ // SDK is bundled - no download needed
36
+ promise.resolve(true)
59
37
  }
60
38
 
61
39
  @ReactMethod
62
- fun deleteSDK(promise: Promise) {
63
- promise.resolve(FlirSDKLoader.deleteSDK(reactContext))
40
+ fun getSDKStatus(promise: Promise) {
41
+ val status = Arguments.createMap().apply {
42
+ putBoolean("available", true)
43
+ putBoolean("bundled", true)
44
+ putString("arch", FlirSDKLoader.getDeviceArch())
45
+ putString("version", "4.16.0")
46
+ }
47
+ promise.resolve(status)
64
48
  }
65
49
 
66
50
  @ReactMethod
67
- fun addListener(eventName: String) {}
68
-
69
- @ReactMethod
70
- fun removeListeners(count: Int) {}
71
-
72
- private fun sendEvent(name: String, params: WritableMap) {
73
- reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
74
- .emit(name, params)
51
+ fun cancelDownload(promise: Promise) {
52
+ // Nothing to cancel
53
+ promise.resolve(true)
75
54
  }
76
55
  }
@@ -71,4 +71,36 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
71
71
  promise.reject("ERR_FLIR_DEVICE_INFO", e)
72
72
  }
73
73
  }
74
+
75
+ @ReactMethod
76
+ fun isSDKDownloaded(promise: Promise) {
77
+ try {
78
+ val available = FlirSDKLoader.isSDKAvailable(reactContext)
79
+ promise.resolve(available)
80
+ } catch (e: Exception) {
81
+ promise.reject("ERR_FLIR_SDK_CHECK", e)
82
+ }
83
+ }
84
+
85
+ @ReactMethod
86
+ fun getSDKStatus(promise: Promise) {
87
+ try {
88
+ val available = FlirSDKLoader.isSDKAvailable(reactContext)
89
+ val arch = FlirSDKLoader.getDeviceArch()
90
+ val dexPath = FlirSDKLoader.getDexPath(reactContext)
91
+ val nativeLibDir = FlirSDKLoader.getNativeLibDir(reactContext)
92
+
93
+ val result = com.facebook.react.bridge.Arguments.createMap()
94
+ result.putBoolean("available", available)
95
+ result.putString("arch", arch)
96
+ result.putString("dexPath", dexPath?.absolutePath ?: "not downloaded")
97
+ result.putString("nativeLibPath", nativeLibDir?.absolutePath ?: "not downloaded")
98
+ result.putBoolean("dexExists", dexPath?.exists() == true)
99
+ result.putBoolean("nativeLibsExist", nativeLibDir?.exists() == true)
100
+
101
+ promise.resolve(result)
102
+ } catch (e: Exception) {
103
+ promise.reject("ERR_FLIR_SDK_STATUS", e)
104
+ }
105
+ }
74
106
  }
@@ -3,67 +3,18 @@ package flir.android
3
3
  import android.content.Context
4
4
  import android.os.Build
5
5
  import android.util.Log
6
- import kotlinx.coroutines.*
7
- import org.json.JSONObject
8
- import java.io.File
9
- import java.io.FileOutputStream
10
- import java.net.HttpURLConnection
11
- import java.net.URL
12
- import java.util.zip.ZipInputStream
13
6
 
14
7
  /**
15
- * FlirSDKLoader - Downloads and manages architecture-specific FLIR SDK packages
8
+ * FlirSDKLoader - SDK availability checker
16
9
  *
17
- * Each package contains:
18
- * - classes.dex (combined DEX from thermalsdk + androidsdk)
19
- * - Native .so libraries in jni/{arch}/ folder
20
- *
21
- * URLs are read from sdk-manifest.json in assets folder
10
+ * Since the SDK is now bundled via AAR files, this class simply reports
11
+ * that the SDK is always available. The AAR files include native .so libraries
12
+ * for all supported architectures, which Android handles automatically.
22
13
  */
23
14
  object FlirSDKLoader {
24
15
 
25
16
  private const val TAG = "FlirSDKLoader"
26
17
 
27
- // Cached manifest data
28
- private var cachedManifest: SDKManifest? = null
29
-
30
- // Manifest data classes
31
- data class ArchPackage(val downloadUrl: String, val sizeBytes: Long)
32
- data class SDKManifest(val version: String, val packages: Map<String, ArchPackage>)
33
-
34
- private fun getSDKDirectory(context: Context) = File(context.filesDir, "FlirSDK")
35
-
36
- /**
37
- * Load manifest from assets
38
- */
39
- private fun loadManifest(context: Context): SDKManifest? {
40
- if (cachedManifest != null) return cachedManifest
41
-
42
- return try {
43
- val json = context.assets.open("sdk-manifest.json").bufferedReader().readText()
44
- val root = JSONObject(json)
45
- val android = root.getJSONObject("android")
46
- val packagesJson = android.getJSONObject("packages")
47
-
48
- val packages = mutableMapOf<String, ArchPackage>()
49
- packagesJson.keys().forEach { arch ->
50
- val pkg = packagesJson.getJSONObject(arch)
51
- packages[arch] = ArchPackage(
52
- downloadUrl = pkg.getString("downloadUrl"),
53
- sizeBytes = pkg.getLong("sizeBytes")
54
- )
55
- }
56
-
57
- SDKManifest(
58
- version = root.getString("version"),
59
- packages = packages
60
- ).also { cachedManifest = it }
61
- } catch (e: Exception) {
62
- Log.e(TAG, "Failed to load manifest: ${e.message}")
63
- null
64
- }
65
- }
66
-
67
18
  /**
68
19
  * Get the primary ABI for this device
69
20
  */
@@ -71,7 +22,7 @@ object FlirSDKLoader {
71
22
  val supportedAbis = Build.SUPPORTED_ABIS
72
23
  Log.d(TAG, "Device supported ABIs: ${supportedAbis.joinToString()}")
73
24
 
74
- val knownArchs = setOf("arm64-v8a", "armeabi-v7a", "x86_64")
25
+ val knownArchs = setOf("arm64-v8a", "armeabi-v7a", "x86_64", "x86")
75
26
  for (abi in supportedAbis) {
76
27
  if (abi in knownArchs) {
77
28
  Log.d(TAG, "Selected ABI: $abi")
@@ -82,162 +33,52 @@ object FlirSDKLoader {
82
33
  }
83
34
 
84
35
  /**
85
- * Check if SDK is already downloaded
36
+ * Check if SDK is available - always true since bundled in AAR
86
37
  */
87
38
  fun isSDKAvailable(context: Context): Boolean {
88
- val sdkDir = getSDKDirectory(context)
89
- val arch = getDeviceArch()
90
-
91
- val dexFile = File(sdkDir, "classes.dex")
92
- val soDir = File(sdkDir, "jni/$arch")
93
-
94
- val hasDex = dexFile.exists() && dexFile.length() > 0
95
- val hasSo = soDir.exists() && soDir.listFiles()?.isNotEmpty() == true
96
-
97
- Log.d(TAG, "SDK available: dex=$hasDex, so=$hasSo")
98
- return hasDex && hasSo
39
+ Log.d(TAG, "SDK is bundled in AAR - always available")
40
+ return true
99
41
  }
100
42
 
101
43
  /**
102
- * Get path to the DEX file
44
+ * No download needed - SDK is bundled
103
45
  */
104
- fun getDexPath(context: Context): File? {
105
- val dexFile = File(getSDKDirectory(context), "classes.dex")
106
- return if (dexFile.exists()) dexFile else null
107
- }
108
-
109
- /**
110
- * Get path to native libraries directory
111
- */
112
- fun getNativeLibDir(context: Context): File? {
113
- val arch = getDeviceArch()
114
- val libDir = File(getSDKDirectory(context), "jni/$arch")
115
- return if (libDir.exists()) libDir else null
46
+ suspend fun downloadSDK(
47
+ context: Context,
48
+ onProgress: ((progress: Int, bytesDownloaded: Long, totalBytes: Long) -> Unit)? = null
49
+ ): Boolean {
50
+ Log.d(TAG, "SDK is bundled - no download needed")
51
+ onProgress?.invoke(100, 0, 0)
52
+ return true
116
53
  }
117
54
 
118
55
  /**
119
- * Get estimated download size from manifest
56
+ * Get SDK status
120
57
  */
121
- fun getDownloadSize(context: Context): Long {
122
- val manifest = loadManifest(context) ?: return 15_000_000L
123
- val arch = getDeviceArch()
124
- return manifest.packages[arch]?.sizeBytes ?: 15_000_000L
58
+ fun getSDKStatus(context: Context): Map<String, Any> {
59
+ return mapOf(
60
+ "available" to true,
61
+ "bundled" to true,
62
+ "arch" to getDeviceArch(),
63
+ "version" to "4.16.0" // SDK version from AAR
64
+ )
125
65
  }
126
66
 
127
67
  /**
128
- * Download the SDK package for this device's architecture
68
+ * Get DEX path - not applicable when bundled via AAR
69
+ * Returns null since SDK is bundled in AAR, no separate DEX needed
129
70
  */
130
- suspend fun downloadSDK(
131
- context: Context,
132
- onProgress: (downloaded: Long, total: Long) -> Unit
133
- ): Result<Unit> = withContext(Dispatchers.IO) {
134
- try {
135
- val arch = getDeviceArch()
136
- val manifest = loadManifest(context)
137
- ?: return@withContext Result.failure(Exception("Failed to load manifest"))
138
-
139
- val archPackage = manifest.packages[arch]
140
- ?: return@withContext Result.failure(Exception("No package for architecture: $arch"))
141
-
142
- val downloadUrl = archPackage.downloadUrl
143
- Log.i(TAG, "Downloading SDK for $arch from $downloadUrl")
144
-
145
- val sdkDir = getSDKDirectory(context).apply { mkdirs() }
146
- val zipFile = File(context.cacheDir, "flir-sdk-$arch.zip")
147
-
148
- // Download with redirect handling (GitHub uses 302 redirects)
149
- var connection = URL(downloadUrl).openConnection() as HttpURLConnection
150
- connection.instanceFollowRedirects = true
151
- connection.connectTimeout = 30000
152
- connection.readTimeout = 60000
153
-
154
- // Handle redirects manually for cross-protocol redirects
155
- var redirectCount = 0
156
- while (connection.responseCode in 301..302 && redirectCount < 5) {
157
- val redirectUrl = connection.getHeaderField("Location")
158
- Log.d(TAG, "Redirect to: $redirectUrl")
159
- connection.disconnect()
160
- connection = URL(redirectUrl).openConnection() as HttpURLConnection
161
- connection.instanceFollowRedirects = true
162
- redirectCount++
163
- }
164
-
165
- if (connection.responseCode != HttpURLConnection.HTTP_OK) {
166
- return@withContext Result.failure(Exception("HTTP error ${connection.responseCode}"))
167
- }
168
-
169
- val totalSize = connection.contentLengthLong.let {
170
- if (it > 0) it else archPackage.sizeBytes
171
- }
172
-
173
- connection.inputStream.use { input ->
174
- FileOutputStream(zipFile).use { output ->
175
- val buffer = ByteArray(8192)
176
- var totalRead = 0L
177
- var bytesRead: Int
178
-
179
- while (input.read(buffer).also { bytesRead = it } != -1) {
180
- output.write(buffer, 0, bytesRead)
181
- totalRead += bytesRead
182
- withContext(Dispatchers.Main) {
183
- onProgress(totalRead, totalSize)
184
- }
185
- }
186
- }
187
- }
188
- connection.disconnect()
189
-
190
- Log.i(TAG, "Download complete: ${zipFile.length()} bytes")
191
-
192
- // Extract
193
- unzip(zipFile, sdkDir)
194
- zipFile.delete()
195
-
196
- // Verify
197
- val dexFile = File(sdkDir, "classes.dex")
198
- val soDir = File(sdkDir, "jni/$arch")
199
-
200
- if (!dexFile.exists()) {
201
- return@withContext Result.failure(Exception("DEX file not extracted"))
202
- }
203
-
204
- dexFile.setReadOnly()
205
- Log.i(TAG, "SDK installed: dex=${dexFile.length()} bytes, libs=${soDir.listFiles()?.size ?: 0} files")
206
-
207
- Result.success(Unit)
208
- } catch (e: Exception) {
209
- Log.e(TAG, "Download failed", e)
210
- Result.failure(e)
211
- }
71
+ fun getDexPath(context: Context): java.io.File? {
72
+ // SDK is bundled in AAR - no separate DEX file
73
+ return null
212
74
  }
213
75
 
214
76
  /**
215
- * Delete downloaded SDK
77
+ * Get native library directory - not applicable when bundled via AAR
78
+ * Returns null since native libs are included in AAR and handled by Android
216
79
  */
217
- fun deleteSDK(context: Context): Boolean {
218
- return getSDKDirectory(context).deleteRecursively()
219
- }
220
-
221
- private fun unzip(source: File, destination: File) {
222
- Log.d(TAG, "Extracting ${source.name} to ${destination.absolutePath}")
223
-
224
- ZipInputStream(source.inputStream()).use { zip ->
225
- var entry = zip.nextEntry
226
- while (entry != null) {
227
- val file = File(destination, entry.name)
228
- Log.d(TAG, " Extracting: ${entry.name}")
229
-
230
- if (entry.isDirectory) {
231
- file.mkdirs()
232
- } else {
233
- file.parentFile?.mkdirs()
234
- file.outputStream().use { output ->
235
- zip.copyTo(output)
236
- }
237
- }
238
- zip.closeEntry()
239
- entry = zip.nextEntry
240
- }
241
- }
80
+ fun getNativeLibDir(context: Context): java.io.File? {
81
+ // SDK native libs are bundled in AAR and extracted automatically by Android
82
+ return null
242
83
  }
243
- }
84
+ }