ilabs-flir 1.0.3 → 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 (33) 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/FlirCommands.java +40 -15
  5. package/android/Flir/src/main/java/flir/android/FlirDownloadManager.kt +26 -46
  6. package/android/Flir/src/main/java/flir/android/FlirManager.kt +265 -42
  7. package/android/Flir/src/main/java/flir/android/FlirModule.kt +32 -0
  8. package/android/Flir/src/main/java/flir/android/FlirSDKLoader.kt +84 -195
  9. package/android/Flir/src/main/java/flir/android/FlirSdkManager.java +667 -797
  10. package/package.json +1 -1
  11. package/sdk-manifest.json +14 -7
  12. package/src/index.d.ts +21 -1
  13. package/android/Flir/libs/flir-stubs.jar +0 -0
  14. package/android/Flir/src/main/java/com/flir/thermalsdk/ErrorCodeException.java +0 -14
  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/CameraType.java +0 -8
  23. package/android/Flir/src/main/java/com/flir/thermalsdk/live/CommunicationInterface.java +0 -16
  24. package/android/Flir/src/main/java/com/flir/thermalsdk/live/Identity.java +0 -23
  25. package/android/Flir/src/main/java/com/flir/thermalsdk/live/IpSettings.java +0 -9
  26. package/android/Flir/src/main/java/com/flir/thermalsdk/live/connectivity/ConnectionStatusListener.java +0 -7
  27. package/android/Flir/src/main/java/com/flir/thermalsdk/live/remote/OnReceived.java +0 -5
  28. package/android/Flir/src/main/java/com/flir/thermalsdk/live/remote/OnRemoteError.java +0 -7
  29. package/android/Flir/src/main/java/flir/android/CameraHandler.java +0 -224
  30. package/android/Flir/src/main/java/flir/android/FlirConnectionManager.java +0 -354
  31. package/android/Flir/src/main/java/flir/android/FlirController.kt +0 -11
  32. package/android/Flir/src/main/java/flir/android/FlirDiscoveryManager.java +0 -236
  33. package/android/Flir/src/main/java/flir/android/FrameDataHolder.java +0 -14
@@ -4,6 +4,7 @@ import android.content.Context
4
4
  import android.graphics.Bitmap
5
5
  import android.util.Log
6
6
  import com.facebook.react.bridge.Arguments
7
+ import com.facebook.react.bridge.WritableArray
7
8
  import com.facebook.react.bridge.WritableMap
8
9
  import com.facebook.react.modules.core.DeviceEventManagerModule
9
10
  import com.facebook.react.uimanager.ThemedReactContext
@@ -13,16 +14,27 @@ import java.util.concurrent.atomic.AtomicLong
13
14
 
14
15
  object FlirManager {
15
16
  private val TAG = "FlirManager"
17
+ private val FLOW_TAG = "FLIR_FLOW" // Matching FlirSdkManager flow tag
16
18
  private var sdkManager: FlirSdkManager? = null
17
19
  private val lastEmitMs = AtomicLong(0)
18
20
  private val minEmitIntervalMs = 333L // ~3 fps
19
21
  private var discoveryStarted = false
20
22
  private var reactContext: ThemedReactContext? = null
23
+ private var appContext: Context? = null
24
+ private var frameCount = 0 // For tracking first frame
21
25
 
22
26
  // Emulator and device state tracking
23
27
  private var isEmulatorMode = false
24
28
  private var isPhysicalDeviceConnected = false
25
29
  private var connectedDeviceName: String? = null
30
+ private var connectedDeviceId: String? = null
31
+ private var isStreaming = false
32
+
33
+ // Current emulator type preference
34
+ private var preferredEmulatorType = FlirSdkManager.EmulatorType.FLIR_ONE_EDGE
35
+
36
+ // Discovered devices cache
37
+ private var discoveredDevices: List<FlirSdkManager.DeviceInfo> = emptyList()
26
38
 
27
39
  // GL texture callback support for native filters
28
40
  interface TextureUpdateCallback {
@@ -63,7 +75,17 @@ object FlirManager {
63
75
  /**
64
76
  * Check if a physical FLIR device is connected
65
77
  */
66
- fun isDeviceConnected(): Boolean = isPhysicalDeviceConnected
78
+ fun isDeviceConnected(): Boolean = isPhysicalDeviceConnected || isEmulatorMode
79
+
80
+ /**
81
+ * Check if currently streaming
82
+ */
83
+ fun isStreaming(): Boolean = isStreaming
84
+
85
+ /**
86
+ * Get list of discovered devices
87
+ */
88
+ fun getDiscoveredDevices(): List<FlirSdkManager.DeviceInfo> = discoveredDevices
67
89
 
68
90
  /**
69
91
  * Get information about the connected device
@@ -75,13 +97,37 @@ object FlirManager {
75
97
  else -> "Physical device ($connectedDeviceName)"
76
98
  }
77
99
  }
100
+
101
+ /**
102
+ * Set preferred emulator type (FLIR_ONE_EDGE or FLIR_ONE)
103
+ */
104
+ fun setPreferredEmulatorType(type: String) {
105
+ preferredEmulatorType = when (type.uppercase()) {
106
+ "FLIR_ONE" -> FlirSdkManager.EmulatorType.FLIR_ONE
107
+ else -> FlirSdkManager.EmulatorType.FLIR_ONE_EDGE
108
+ }
109
+ Log.d(TAG, "Preferred emulator type set to: $preferredEmulatorType")
110
+ sdkManager?.setEmulatorType(preferredEmulatorType)
111
+ }
78
112
 
79
113
  fun init(context: Context) {
114
+ // Avoid re-initialization if already done
115
+ if (sdkManager != null) {
116
+ Log.i(FLOW_TAG, "[FlirManager] init() called but already initialized, skipping")
117
+ return
118
+ }
119
+
120
+ appContext = context.applicationContext
121
+ Log.i(FLOW_TAG, "[FlirManager] init() called - initializing SDK Manager")
80
122
  try {
81
- // Initialize SDK manager with listener
123
+ // Initialize SDK manager with listener matching FlirSdkManager.Listener interface
82
124
  sdkManager = FlirSdkManager(object : FlirSdkManager.Listener {
83
125
  override fun onFrame(bitmap: Bitmap) {
84
126
  latestBitmap = bitmap
127
+ if (frameCount == 0) {
128
+ Log.i(FLOW_TAG, "[FlirManager] FIRST FRAME received: ${bitmap.width}x${bitmap.height}")
129
+ }
130
+ frameCount++
85
131
  textureCallback?.onTextureUpdate(bitmap, 0)
86
132
  emitFrameToReactNative(bitmap)
87
133
  }
@@ -90,64 +136,164 @@ object FlirManager {
90
136
  temperatureCallback?.onTemperatureData(temp, x, y)
91
137
  }
92
138
 
93
- override fun onDeviceFound(name: String) {
94
- connectedDeviceName = name
95
- isPhysicalDeviceConnected = true
96
- emitDeviceState("connected", true)
139
+ override fun onDeviceFound(deviceId: String, deviceName: String, isEmulator: Boolean) {
140
+ Log.i(FLOW_TAG, "[FlirManager] Device found: $deviceName (id=$deviceId, emulator=$isEmulator)")
141
+ Log.d(TAG, "Device found: $deviceName (id=$deviceId, emulator=$isEmulator)")
142
+ discoveryCallback?.onDeviceFound(deviceName)
97
143
  }
98
-
99
- override fun onEmulatorEnabled() {
100
- isEmulatorMode = true
101
- emitDeviceState("emulator", false)
144
+
145
+ override fun onDeviceListUpdated(devices: MutableList<FlirSdkManager.DeviceInfo>) {
146
+ discoveredDevices = devices.toList()
147
+ Log.i(FLOW_TAG, "[FlirManager] Device list updated: ${devices.size} devices")
148
+ Log.i(TAG, "Device list updated: ${devices.size} devices")
149
+ devices.forEach {
150
+ Log.d(TAG, " - ${it.deviceName} (${it.commInterface}, emu=${it.isEmulator})")
151
+ }
152
+ emitDevicesFound(devices)
153
+
154
+ // Auto-connect to first device if available
155
+ if (devices.isNotEmpty()) {
156
+ val first = devices[0]
157
+ connectedDeviceName = first.deviceName
158
+ connectedDeviceId = first.deviceId
159
+ isEmulatorMode = first.isEmulator
160
+ isPhysicalDeviceConnected = !first.isEmulator
161
+
162
+ Log.i(FLOW_TAG, "[FlirManager] Auto-connecting to first device: ${first.deviceName}")
163
+ // Connect to the device
164
+ sdkManager?.connectToDevice(first.deviceId)
165
+ }
102
166
  }
103
-
104
- override fun onStreamKindChanged(kind: String) {
105
- Log.d(TAG, "Stream kind changed: $kind")
167
+
168
+ override fun onDeviceConnected(deviceId: String, deviceName: String, isEmulator: Boolean) {
169
+ connectedDeviceId = deviceId
170
+ connectedDeviceName = deviceName
171
+ this@FlirManager.isEmulatorMode = isEmulator
172
+ isPhysicalDeviceConnected = !isEmulator
173
+
174
+ Log.i(TAG, "Device connected: $deviceName (id=$deviceId, emulator=$isEmulator)")
175
+ emitDeviceState("connected", !isEmulator)
176
+ }
177
+
178
+ override fun onDeviceDisconnected() {
179
+ Log.i(TAG, "Device disconnected")
180
+ isPhysicalDeviceConnected = false
181
+ isEmulatorMode = false
182
+ isStreaming = false
183
+ connectedDeviceId = null
184
+ connectedDeviceName = null
185
+ emitDeviceState("disconnected", false)
186
+ }
187
+
188
+ override fun onDiscoveryStarted() {
189
+ Log.i(TAG, "Discovery started")
190
+ emitDeviceState("discovering", false)
191
+ }
192
+
193
+ override fun onDiscoveryTimeout() {
194
+ Log.w(TAG, "Discovery timeout - no devices found")
195
+ discoveryCallback?.onDiscoveryTimeout()
196
+ emitDeviceState("discovery_timeout", false)
197
+ }
198
+
199
+ override fun onStreamStarted(streamType: String) {
200
+ isStreaming = true
201
+ Log.i(TAG, "Streaming started: $streamType")
202
+ emitDeviceState("streaming", isPhysicalDeviceConnected)
106
203
  }
107
- })
204
+
205
+ override fun onError(error: String) {
206
+ Log.e(TAG, "SDK Error: $error")
207
+ emitError(error)
208
+ }
209
+ }, context)
108
210
 
109
- // Try to initialize SDK via reflection
110
- try {
111
- val cls = Class.forName("com.flir.thermalsdk.live.ThermalSdkAndroid")
112
- val method = cls.getMethod("init", Context::class.java)
113
- method.invoke(null, context.applicationContext)
114
- Log.i(TAG, "FLIR SDK initialized via reflection")
115
- } catch (e: ClassNotFoundException) {
116
- Log.w(TAG, "FLIR SDK not found on classpath, will attempt DexClassLoader")
117
- } catch (e: Throwable) {
118
- Log.w(TAG, "FLIR SDK init failed: ${e.message}")
119
- }
211
+ // Set emulator type preference
212
+ sdkManager?.setEmulatorType(preferredEmulatorType)
213
+
214
+ Log.i(TAG, "FlirManager initialized with comprehensive SDK manager")
120
215
  } catch (t: Throwable) {
121
216
  Log.e(TAG, "FlirManager init failed", t)
122
217
  }
123
218
  }
124
219
 
125
- fun startDiscoveryAndConnect(context: ThemedReactContext) {
126
- if (discoveryStarted) return
220
+ /**
221
+ * Start discovery with the specified parameters
222
+ * @param isEmuMode If true, immediately start emulator without physical device discovery
223
+ */
224
+ fun startDiscoveryAndConnect(context: ThemedReactContext, isEmuMode: Boolean = false) {
225
+ Log.i(FLOW_TAG, "[FlirManager] startDiscoveryAndConnect called: isEmuMode=$isEmuMode, discoveryStarted=$discoveryStarted, preferredEmulatorType=$preferredEmulatorType")
226
+
227
+ if (discoveryStarted && !isEmuMode) {
228
+ Log.i(FLOW_TAG, "[FlirManager] Discovery already started, skipping")
229
+ return
230
+ }
127
231
  discoveryStarted = true
128
232
  reactContext = context
233
+ frameCount = 0 // Reset frame counter
129
234
 
130
235
  emitDeviceState("discovering", false)
131
236
 
132
237
  try {
133
- val started = sdkManager?.startSdkEmulator() ?: false
134
- if (!started) {
135
- Log.w(TAG, "Failed to start SDK emulator")
136
- emitDeviceState("error", false)
137
- }
238
+ // Set emulator type preference before discovery
239
+ Log.i(FLOW_TAG, "[FlirManager] Setting emulator type: $preferredEmulatorType")
240
+ sdkManager?.setEmulatorType(preferredEmulatorType)
241
+
242
+ // Start discovery (forceEmulator=isEmuMode)
243
+ Log.i(FLOW_TAG, "[FlirManager] Calling sdkManager.startDiscovery(forceEmulator=$isEmuMode)")
244
+ Log.i(TAG, "Starting discovery (forceEmulator=$isEmuMode)")
245
+ sdkManager?.startDiscovery(isEmuMode)
138
246
  } catch (t: Throwable) {
247
+ Log.e(FLOW_TAG, "[FlirManager] startDiscoveryAndConnect failed: ${t.message}")
139
248
  Log.e(TAG, "startDiscoveryAndConnect failed", t)
140
249
  emitDeviceState("error", false)
141
250
  }
142
251
  }
252
+
253
+ /**
254
+ * Legacy overload for backward compatibility
255
+ */
256
+ fun startDiscoveryAndConnect(context: ThemedReactContext) {
257
+ startDiscoveryAndConnect(context, isEmuMode = false)
258
+ }
259
+
260
+ /**
261
+ * Switch to a specific device by ID
262
+ */
263
+ fun switchToDevice(deviceId: String) {
264
+ if (deviceId == connectedDeviceId) {
265
+ Log.d(TAG, "Already connected to device: $deviceId")
266
+ return
267
+ }
268
+
269
+ Log.i(TAG, "Switching to device: $deviceId")
270
+ sdkManager?.connectToDevice(deviceId)
271
+ }
272
+
273
+ /**
274
+ * Start emulator mode
275
+ */
276
+ fun startEmulator(type: FlirSdkManager.EmulatorType = preferredEmulatorType) {
277
+ Log.i(TAG, "Starting emulator: $type")
278
+ sdkManager?.setEmulatorType(type)
279
+ sdkManager?.startDiscovery(true) // forceEmulator = true
280
+ }
143
281
 
144
282
  fun stop() {
283
+ Log.i(TAG, "Stopping FlirManager")
284
+
285
+ // Stop the SDK manager
286
+ sdkManager?.stop()
287
+
288
+ // Reset state
145
289
  discoveryStarted = false
146
290
  isPhysicalDeviceConnected = false
147
291
  isEmulatorMode = false
292
+ isStreaming = false
148
293
  connectedDeviceName = null
294
+ connectedDeviceId = null
149
295
  latestBitmap = null
150
- // Note: FlirSdkManager doesn't have a stop method, but we reset our state
296
+ discoveredDevices = emptyList()
151
297
  }
152
298
 
153
299
  fun getLatestFramePath(): String? {
@@ -193,15 +339,59 @@ object FlirManager {
193
339
  params.putString("state", state)
194
340
  params.putBoolean("isPhysical", isPhysical)
195
341
  params.putBoolean("isEmulator", isEmulatorMode)
196
- params.putBoolean("isConnected", isPhysicalDeviceConnected)
342
+ params.putBoolean("isConnected", isPhysicalDeviceConnected || isEmulatorMode)
343
+ params.putBoolean("isStreaming", isStreaming)
197
344
 
198
345
  connectedDeviceName?.let {
199
346
  params.putString("deviceName", it)
200
347
  }
348
+ connectedDeviceId?.let {
349
+ params.putString("deviceId", it)
350
+ }
201
351
 
202
352
  ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
203
353
  .emit("FlirDeviceConnected", params)
204
- } catch (e: Exception) {}
354
+ } catch (e: Exception) {
355
+ Log.e(TAG, "Failed to emit device state", e)
356
+ }
357
+ }
358
+
359
+ private fun emitDevicesFound(devices: List<FlirSdkManager.DeviceInfo>) {
360
+ val ctx = reactContext ?: return
361
+ try {
362
+ val params = Arguments.createMap()
363
+ val devicesArray: WritableArray = Arguments.createArray()
364
+
365
+ devices.forEach { device ->
366
+ val deviceMap: WritableMap = Arguments.createMap()
367
+ deviceMap.putString("id", device.deviceId)
368
+ deviceMap.putString("name", device.deviceName)
369
+ deviceMap.putString("communicationType", device.commInterface.name)
370
+ deviceMap.putBoolean("isEmulator", device.isEmulator)
371
+ devicesArray.pushMap(deviceMap)
372
+ }
373
+
374
+ params.putArray("devices", devicesArray)
375
+ params.putInt("count", devices.size)
376
+
377
+ ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
378
+ .emit("FlirDevicesFound", params)
379
+ } catch (e: Exception) {
380
+ Log.e(TAG, "Failed to emit devices found", e)
381
+ }
382
+ }
383
+
384
+ private fun emitError(message: String) {
385
+ val ctx = reactContext ?: return
386
+ try {
387
+ val params = Arguments.createMap()
388
+ params.putString("error", message)
389
+
390
+ ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
391
+ .emit("FlirError", params)
392
+ } catch (e: Exception) {
393
+ Log.e(TAG, "Failed to emit error", e)
394
+ }
205
395
  }
206
396
 
207
397
  // Compatibility for Java / FlirHelper
@@ -225,9 +415,10 @@ object FlirManager {
225
415
  }
226
416
 
227
417
  fun setEmulatorMode(enabled: Boolean) {
228
- isEmulatorMode = enabled
229
418
  if (enabled) {
230
- discoveryCallback?.onEmulatorEnabled()
419
+ isEmulatorMode = true
420
+ discoveryCallback?.onEmulatorEnabled()
421
+ startEmulator(preferredEmulatorType)
231
422
  }
232
423
  }
233
424
 
@@ -236,19 +427,51 @@ object FlirManager {
236
427
  }
237
428
 
238
429
  fun startDiscovery(retry: Boolean) {
239
- if (reactContext != null) {
240
- startDiscoveryAndConnect(reactContext!!)
241
- } else {
242
- // Fallback: try to start without React context
430
+ Log.i(FLOW_TAG, "[FlirManager] startDiscovery($retry) called, sdkManager=${if (sdkManager != null) "present" else "NULL"}, appContext=${if (appContext != null) "present" else "NULL"}")
431
+
432
+ // Auto-init if not initialized
433
+ if (sdkManager == null && appContext != null) {
434
+ Log.i(FLOW_TAG, "[FlirManager] Auto-initializing from startDiscovery()")
435
+ init(appContext!!)
436
+ }
437
+
438
+ val ctx = reactContext
439
+ if (ctx != null) {
440
+ // Reset discovery state if retrying
441
+ if (retry) {
442
+ discoveryStarted = false
443
+ }
444
+ startDiscoveryAndConnect(ctx, isEmuMode = false)
445
+ } else if (appContext != null) {
446
+ // Fallback: try to start discovery without React context
243
447
  try {
244
- sdkManager?.startSdkEmulator()
448
+ Log.w(TAG, "Starting discovery without React context")
449
+ Log.i(FLOW_TAG, "[FlirManager] Calling sdkManager.startDiscovery(false) without React context")
450
+ sdkManager?.startDiscovery(false)
245
451
  } catch (t: Throwable) {
246
452
  Log.e(TAG, "startDiscovery failed", t)
453
+ Log.e(FLOW_TAG, "[FlirManager] startDiscovery failed: ${t.message}")
247
454
  }
455
+ } else {
456
+ Log.e(FLOW_TAG, "[FlirManager] Cannot startDiscovery - no context available! Call init(context) first.")
248
457
  }
249
458
  }
250
459
 
251
460
  fun enableEmulatorMode() {
252
461
  setEmulatorMode(true)
253
462
  }
463
+
464
+ /**
465
+ * Force start with emulator (useful for testing)
466
+ */
467
+ fun forceEmulatorMode(type: String = "FLIR_ONE_EDGE") {
468
+ setPreferredEmulatorType(type)
469
+ val ctx = reactContext
470
+ if (ctx != null) {
471
+ discoveryStarted = false
472
+ startDiscoveryAndConnect(ctx, isEmuMode = true)
473
+ } else {
474
+ startEmulator(preferredEmulatorType)
475
+ }
476
+ }
254
477
  }
@@ -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
  }