ilabs-flir 2.4.1 → 2.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/Flir/src/main/java/flir/android/FlirManager.kt +20 -1
- package/android/Flir/src/main/java/flir/android/FlirModule.kt +34 -9
- package/android/Flir/src/main/java/flir/android/FlirSdkManager.java +3 -1
- package/android/Flir/src/main/java/flir/android/FlirView.kt +2 -4
- package/ios/Flir/src/FlirManager.swift +17 -1
- package/ios/Flir/src/FlirModule.m +26 -5
- package/package.json +1 -1
|
@@ -44,6 +44,9 @@ object FlirManager {
|
|
|
44
44
|
private var isStreaming = false
|
|
45
45
|
private var connectedDeviceId: String? = null
|
|
46
46
|
private var connectedDeviceName: String? = null
|
|
47
|
+
|
|
48
|
+
// Manual gating
|
|
49
|
+
var manualOnly: Boolean = true
|
|
47
50
|
|
|
48
51
|
// Concurrency control
|
|
49
52
|
private val shouldProcessFrames = java.util.concurrent.atomic.AtomicBoolean(false)
|
|
@@ -124,17 +127,33 @@ object FlirManager {
|
|
|
124
127
|
*/
|
|
125
128
|
@Synchronized
|
|
126
129
|
fun startDiscovery(retry: Boolean = false) {
|
|
130
|
+
if (manualOnly && !retry) {
|
|
131
|
+
Log.w(TAG, "🔭 [FLIR] Discovery blocked: manualOnly is enabled. Use startManualDiscovery() or disable the gate.")
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
127
135
|
if (!isInitialized && reactContext != null) {
|
|
128
136
|
init(reactContext!!)
|
|
129
137
|
}
|
|
130
138
|
|
|
131
139
|
if (isScanning && !retry) return
|
|
132
140
|
|
|
133
|
-
Log.i(TAG, "Starting
|
|
141
|
+
Log.i(TAG, "🔭 [FLIR] Starting discovery (retry=$retry)...")
|
|
134
142
|
isScanning = true
|
|
135
143
|
emitDeviceState("discovering")
|
|
136
144
|
sdkManager?.scan()
|
|
137
145
|
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Explicitly starts discovery regardless of manualOnly flag.
|
|
149
|
+
* Use this for JS-triggered scans.
|
|
150
|
+
*/
|
|
151
|
+
@Synchronized
|
|
152
|
+
fun startManualDiscovery() {
|
|
153
|
+
Log.i(TAG, "🔭 [FLIR] Manual discovery requested - opening gate.")
|
|
154
|
+
manualOnly = false
|
|
155
|
+
startDiscovery(true)
|
|
156
|
+
}
|
|
138
157
|
|
|
139
158
|
/**
|
|
140
159
|
* Start discovery with React context
|
|
@@ -145,7 +145,9 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
145
145
|
palettes.forEach { result.pushString(it) }
|
|
146
146
|
promise?.resolve(result)
|
|
147
147
|
} catch (e: Throwable) {
|
|
148
|
-
|
|
148
|
+
try {
|
|
149
|
+
promise?.reject("ERR_FLIR_PALETTES", e)
|
|
150
|
+
} catch (ignored: Exception) {}
|
|
149
151
|
}
|
|
150
152
|
}
|
|
151
153
|
|
|
@@ -163,7 +165,9 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
163
165
|
}
|
|
164
166
|
promise?.resolve(result)
|
|
165
167
|
} catch (e: Throwable) {
|
|
166
|
-
|
|
168
|
+
try {
|
|
169
|
+
promise?.reject("ERR_FLIR_PALETTE_ICONS", e)
|
|
170
|
+
} catch (ignored: Exception) {}
|
|
167
171
|
}
|
|
168
172
|
}
|
|
169
173
|
|
|
@@ -234,7 +238,7 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
234
238
|
// Ensure SDK is initialized with context before starting discovery
|
|
235
239
|
FlirManager.init(reactContext)
|
|
236
240
|
// With simplified API, just start discovery - emulators are discovered like any device
|
|
237
|
-
FlirManager.
|
|
241
|
+
FlirManager.startManualDiscovery()
|
|
238
242
|
promise?.resolve(true)
|
|
239
243
|
} catch (e: Exception) {
|
|
240
244
|
promise?.reject("ERR_FLIR_EMULATOR", e)
|
|
@@ -281,7 +285,7 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
281
285
|
try {
|
|
282
286
|
// Ensure SDK is initialized with context before starting discovery
|
|
283
287
|
FlirManager.init(reactContext)
|
|
284
|
-
FlirManager.
|
|
288
|
+
FlirManager.startManualDiscovery()
|
|
285
289
|
promise?.resolve(true)
|
|
286
290
|
} catch (e: Exception) {
|
|
287
291
|
promise?.reject("ERR_FLIR_DISCOVERY", e)
|
|
@@ -336,7 +340,7 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
336
340
|
@ReactMethod
|
|
337
341
|
fun resumeFlirAfterPreview(promise: Promise?) {
|
|
338
342
|
try {
|
|
339
|
-
FlirManager.
|
|
343
|
+
FlirManager.startManualDiscovery()
|
|
340
344
|
promise?.resolve(true)
|
|
341
345
|
} catch (e: Exception) {
|
|
342
346
|
promise?.reject("ERR_RESUME_FLIR", e)
|
|
@@ -345,17 +349,26 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
345
349
|
|
|
346
350
|
@ReactMethod
|
|
347
351
|
fun captureRadiometricSnapshot(path: String, promise: Promise?) {
|
|
352
|
+
val snapshotPromise = promise
|
|
353
|
+
var settled = java.util.concurrent.atomic.AtomicBoolean(false)
|
|
354
|
+
|
|
348
355
|
try {
|
|
349
356
|
FlirManager.captureRadiometricSnapshot(path, object : FlirSdkManager.SnapshotCallback {
|
|
350
357
|
override fun onSnapshotSaved(savedPath: String) {
|
|
351
|
-
|
|
358
|
+
if (settled.compareAndSet(false, true)) {
|
|
359
|
+
snapshotPromise?.resolve(savedPath)
|
|
360
|
+
}
|
|
352
361
|
}
|
|
353
362
|
override fun onSnapshotError(message: String) {
|
|
354
|
-
|
|
363
|
+
if (settled.compareAndSet(false, true)) {
|
|
364
|
+
snapshotPromise?.reject("ERR_RADIOMETRIC_SAVE", message)
|
|
365
|
+
}
|
|
355
366
|
}
|
|
356
367
|
})
|
|
357
368
|
} catch (e: Exception) {
|
|
358
|
-
|
|
369
|
+
if (settled.compareAndSet(false, true)) {
|
|
370
|
+
promise?.reject("ERR_RADIOMETRIC_TRIGGER", e.message)
|
|
371
|
+
}
|
|
359
372
|
}
|
|
360
373
|
}
|
|
361
374
|
|
|
@@ -395,6 +408,16 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
395
408
|
}
|
|
396
409
|
}
|
|
397
410
|
|
|
411
|
+
@ReactMethod
|
|
412
|
+
fun setManualDiscoveryOnly(enabled: Boolean, promise: Promise?) {
|
|
413
|
+
try {
|
|
414
|
+
FlirManager.manualOnly = enabled
|
|
415
|
+
promise?.resolve(true)
|
|
416
|
+
} catch (e: Exception) {
|
|
417
|
+
promise?.reject("ERR_FLIR_GATE", e)
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
398
421
|
@ReactMethod
|
|
399
422
|
fun initializeSDK(promise: Promise?) {
|
|
400
423
|
try {
|
|
@@ -409,7 +432,9 @@ class FlirModule(private val reactContext: ReactApplicationContext) : ReactConte
|
|
|
409
432
|
result.putBoolean("initialized", false)
|
|
410
433
|
result.putString("error", e.message ?: "Unknown error")
|
|
411
434
|
result.putString("errorType", e.javaClass.simpleName)
|
|
412
|
-
|
|
435
|
+
try {
|
|
436
|
+
promise?.resolve(result)
|
|
437
|
+
} catch (ignored: Exception) {}
|
|
413
438
|
}
|
|
414
439
|
}
|
|
415
440
|
|
|
@@ -83,7 +83,7 @@ public class FlirSdkManager {
|
|
|
83
83
|
void onSnapshotError(String message);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
private SnapshotCallback snapshotCallback;
|
|
86
|
+
private volatile SnapshotCallback snapshotCallback;
|
|
87
87
|
|
|
88
88
|
private FlirSdkManager(Context context) {
|
|
89
89
|
this.context = context.getApplicationContext();
|
|
@@ -470,11 +470,13 @@ public class FlirSdkManager {
|
|
|
470
470
|
Log.i(TAG, "[SNAPSHOT] ✅ Success: Radiometric snapshot saved");
|
|
471
471
|
if (snapshotCallback != null) {
|
|
472
472
|
snapshotCallback.onSnapshotSaved(snapshotPath);
|
|
473
|
+
snapshotCallback = null;
|
|
473
474
|
}
|
|
474
475
|
} catch (java.io.IOException e) {
|
|
475
476
|
Log.e(TAG, "Failed to save radiometric snapshot", e);
|
|
476
477
|
if (snapshotCallback != null) {
|
|
477
478
|
snapshotCallback.onSnapshotError(e.getMessage());
|
|
479
|
+
snapshotCallback = null;
|
|
478
480
|
}
|
|
479
481
|
}
|
|
480
482
|
}
|
|
@@ -28,10 +28,8 @@ class FlirView(context: ThemedReactContext) : FrameLayout(context) {
|
|
|
28
28
|
|
|
29
29
|
override fun onAttachedToWindow() {
|
|
30
30
|
super.onAttachedToWindow()
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
FlirManager.startDiscoveryAndConnect(context as ThemedReactContext)
|
|
34
|
-
} catch (ignored: Throwable) {}
|
|
31
|
+
// GATING: Automatic discovery on attach is disabled to enforce manual discovery
|
|
32
|
+
// FlirManager.startDiscoveryAndConnect(context as ThemedReactContext)
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
override fun onDetachedFromWindow() {
|
|
@@ -66,6 +66,9 @@ import ThermalSDK
|
|
|
66
66
|
// Internal synchronization
|
|
67
67
|
private let stateLock = NSObject()
|
|
68
68
|
|
|
69
|
+
// Manual gating
|
|
70
|
+
@objc public var manualOnly: Bool = true
|
|
71
|
+
|
|
69
72
|
// Palette and Snapshot state
|
|
70
73
|
private var currentPaletteName: String = "WhiteHot"
|
|
71
74
|
private var pendingSnapshotPath: String?
|
|
@@ -113,7 +116,12 @@ import ThermalSDK
|
|
|
113
116
|
// MARK: - Discovery
|
|
114
117
|
|
|
115
118
|
@objc public func startDiscovery() {
|
|
116
|
-
|
|
119
|
+
if manualOnly {
|
|
120
|
+
NSLog("[FlirManager] 🔭 Discovery blocked: manualOnly is enabled. Use startManualDiscovery() or disable the gate.")
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
NSLog("[FlirManager] 🔭 startDiscovery (manualOnly=false)")
|
|
117
125
|
|
|
118
126
|
#if FLIR_ENABLED
|
|
119
127
|
discoveredDevices.removeAll()
|
|
@@ -133,6 +141,14 @@ import ThermalSDK
|
|
|
133
141
|
#endif
|
|
134
142
|
}
|
|
135
143
|
|
|
144
|
+
/// Explicitly starts discovery regardless of manualOnly flag.
|
|
145
|
+
/// Use this for JS-triggered scans.
|
|
146
|
+
@objc public func startManualDiscovery() {
|
|
147
|
+
NSLog("[FlirManager] 🔭 Manual discovery requested - opening gate.")
|
|
148
|
+
manualOnly = false
|
|
149
|
+
startDiscovery()
|
|
150
|
+
}
|
|
151
|
+
|
|
136
152
|
@objc public func stopDiscovery() {
|
|
137
153
|
objc_sync_enter(stateLock); defer { objc_sync_exit(stateLock) }
|
|
138
154
|
NSLog("[FlirManager] stopDiscovery")
|
|
@@ -151,13 +151,15 @@ RCT_EXPORT_METHOD(startDiscovery : (RCTPromiseResolveBlock)
|
|
|
151
151
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
152
152
|
id manager = flir_manager_shared();
|
|
153
153
|
if (manager &&
|
|
154
|
-
[manager respondsToSelector:sel_registerName("
|
|
155
|
-
NSLog(@"[FlirModule] [%@] ⏱ Calling FlirManager.
|
|
154
|
+
[manager respondsToSelector:sel_registerName("startManualDiscovery")]) {
|
|
155
|
+
NSLog(@"[FlirModule] [%@] ⏱ Calling FlirManager.startManualDiscovery",
|
|
156
156
|
[NSDate date]);
|
|
157
|
+
((void (*)(id, SEL))objc_msgSend)(manager,
|
|
158
|
+
sel_registerName("startManualDiscovery"));
|
|
159
|
+
} else if (manager && [manager respondsToSelector:sel_registerName("startDiscovery")]) {
|
|
160
|
+
// Fallback for older manager versions
|
|
157
161
|
((void (*)(id, SEL))objc_msgSend)(manager,
|
|
158
162
|
sel_registerName("startDiscovery"));
|
|
159
|
-
NSLog(@"[FlirModule] [%@] ⏱ FlirManager.startDiscovery returned",
|
|
160
|
-
[NSDate date]);
|
|
161
163
|
}
|
|
162
164
|
if (resolve) resolve(@(YES));
|
|
163
165
|
});
|
|
@@ -291,6 +293,11 @@ RCT_EXPORT_METHOD(startEmulator : (NSString *)emulatorType resolver : (
|
|
|
291
293
|
((void (*)(id, SEL, id))objc_msgSend)(
|
|
292
294
|
manager, sel_registerName("startEmulatorWithType:"), emulatorType ?: @"FLIR_ONE_EDGE");
|
|
293
295
|
|
|
296
|
+
// Opening the gate for emulator discovery too
|
|
297
|
+
if ([manager respondsToSelector:sel_registerName("setManualOnly:")]) {
|
|
298
|
+
((void (*)(id, SEL, BOOL))objc_msgSend)(manager, sel_registerName("setManualOnly:"), NO);
|
|
299
|
+
}
|
|
300
|
+
|
|
294
301
|
// Resolve immediately - connection status will come via events
|
|
295
302
|
if (resolve) resolve(@(YES));
|
|
296
303
|
} else {
|
|
@@ -445,7 +452,10 @@ RCT_EXPORT_METHOD(resumeFlirAfterPreview : (RCTPromiseResolveBlock)
|
|
|
445
452
|
resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
446
453
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
447
454
|
id manager = flir_manager_shared();
|
|
448
|
-
if (manager && [manager respondsToSelector:sel_registerName("
|
|
455
|
+
if (manager && [manager respondsToSelector:sel_registerName("startManualDiscovery")]) {
|
|
456
|
+
atomic_store(&_isCapturing, true);
|
|
457
|
+
((void (*)(id, SEL))objc_msgSend)(manager, sel_registerName("startManualDiscovery"));
|
|
458
|
+
} else if (manager && [manager respondsToSelector:sel_registerName("startDiscovery")]) {
|
|
449
459
|
atomic_store(&_isCapturing, true);
|
|
450
460
|
((void (*)(id, SEL))objc_msgSend)(manager, sel_registerName("startDiscovery"));
|
|
451
461
|
}
|
|
@@ -455,6 +465,17 @@ RCT_EXPORT_METHOD(resumeFlirAfterPreview : (RCTPromiseResolveBlock)
|
|
|
455
465
|
|
|
456
466
|
|
|
457
467
|
|
|
468
|
+
RCT_EXPORT_METHOD(setManualDiscoveryOnly : (BOOL)enabled resolver : (
|
|
469
|
+
RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
470
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
471
|
+
id manager = flir_manager_shared();
|
|
472
|
+
if (manager && [manager respondsToSelector:sel_registerName("setManualOnly:")]) {
|
|
473
|
+
((void (*)(id, SEL, BOOL))objc_msgSend)(manager, sel_registerName("setManualOnly:"), enabled);
|
|
474
|
+
}
|
|
475
|
+
if (resolve) resolve(@(YES));
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
458
479
|
RCT_EXPORT_METHOD(getSDKStatus : (RCTPromiseResolveBlock)
|
|
459
480
|
resolve rejecter : (RCTPromiseRejectBlock)reject) {
|
|
460
481
|
if (resolve) resolve(@{@"available" : @(YES), @"arch" : @"arm64", @"platform" : @"iOS"});
|