ilabs-flir 2.3.6 → 2.3.8
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.
|
@@ -30,6 +30,13 @@ object FlirManager {
|
|
|
30
30
|
private val lastEmitMs = AtomicLong(0)
|
|
31
31
|
private val minEmitIntervalMs = 100L // ~10 fps max for RN events
|
|
32
32
|
|
|
33
|
+
// Cached palette list to avoid repeated JNI calls (especially if linkage is unstable)
|
|
34
|
+
private var cachedPalettes: List<*>? = null
|
|
35
|
+
private var cachedPaletteNames: List<String>? = null
|
|
36
|
+
|
|
37
|
+
// Cached reflection for performance
|
|
38
|
+
private var coolField: java.lang.reflect.Field? = null
|
|
39
|
+
|
|
33
40
|
// State
|
|
34
41
|
private var isInitialized = false
|
|
35
42
|
private var isScanning = false
|
|
@@ -118,15 +125,6 @@ object FlirManager {
|
|
|
118
125
|
|
|
119
126
|
isInitialized = true
|
|
120
127
|
Log.i(TAG, "FlirManager initialized")
|
|
121
|
-
|
|
122
|
-
// Generate palette icons on background thread
|
|
123
|
-
Thread {
|
|
124
|
-
try {
|
|
125
|
-
generatePaletteIcons(context)
|
|
126
|
-
} catch (e: Exception) {
|
|
127
|
-
Log.e(TAG, "Initial palette icon generation failed", e)
|
|
128
|
-
}
|
|
129
|
-
}.start()
|
|
130
128
|
}
|
|
131
129
|
|
|
132
130
|
/**
|
|
@@ -446,60 +444,32 @@ object FlirManager {
|
|
|
446
444
|
fun forceEmulatorMode(type: String = "FLIR_ONE_EDGE") { startDiscovery() }
|
|
447
445
|
fun setPreferredEmulatorType(type: String) { }
|
|
448
446
|
fun updateAcol(value: Float) {
|
|
449
|
-
Log.
|
|
450
|
-
// Use reflection to update ilabs.libs.io.data.Var.cool to avoid circular dependency
|
|
447
|
+
// Log.v(TAG, "updateAcol: $value")
|
|
451
448
|
try {
|
|
452
|
-
|
|
453
|
-
|
|
449
|
+
if (coolField == null) {
|
|
450
|
+
val varClass = Class.forName("ilabs.libs.io.data.Var")
|
|
451
|
+
coolField = varClass.getField("cool")
|
|
452
|
+
}
|
|
454
453
|
|
|
455
|
-
// Modular logic for palettes: if index > 7, wrap around (17 mod 8)
|
|
456
|
-
// But we keep shader variants (14, 15, 16) as-is if within that range
|
|
457
454
|
val rawIdx = value.toInt()
|
|
458
455
|
var shaderIdx = rawIdx
|
|
459
456
|
if (shaderIdx > 16) {
|
|
460
457
|
shaderIdx = shaderIdx % 16 // Shader loop
|
|
461
458
|
}
|
|
462
459
|
|
|
463
|
-
coolField
|
|
464
|
-
Log.d(TAG, "Updated Var.cool to $shaderIdx via reflection (raw=$rawIdx)")
|
|
465
|
-
|
|
466
|
-
// If we are in FLIR mode, also notify the SDK palette using the official SDK palette list
|
|
467
|
-
var sdkPalettes: List<*>? = null
|
|
468
|
-
try {
|
|
469
|
-
sdkPalettes = PaletteManager.getDefaultPalettes()
|
|
470
|
-
} catch (t: Throwable) {
|
|
471
|
-
try {
|
|
472
|
-
val altClazz = Class.forName("com.flir.thermalsdk.image.palettes.PaletteManager")
|
|
473
|
-
val method = altClazz.getMethod("getDefaultPalettes")
|
|
474
|
-
sdkPalettes = method.invoke(null) as? List<*>
|
|
475
|
-
} catch (t2: Throwable) {
|
|
476
|
-
Log.w(TAG, "Palette discovery failed in updateAcol", t2)
|
|
477
|
-
}
|
|
478
|
-
}
|
|
460
|
+
coolField?.set(null, shaderIdx)
|
|
479
461
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
}
|
|
489
|
-
Log.d(TAG, "True FLIR Palettes: $paletteNames")
|
|
490
|
-
|
|
491
|
-
val maxEff = currentPalettes.size
|
|
492
|
-
val paletteIdx = rawIdx % maxEff
|
|
493
|
-
val safeIdx = if (paletteIdx < 0) paletteIdx + maxEff else paletteIdx
|
|
494
|
-
|
|
495
|
-
val targetPaletteName = paletteNames[safeIdx]
|
|
496
|
-
Log.d(TAG, "Applying true FLIR palette: $targetPaletteName (index: $safeIdx, max: $maxEff)")
|
|
497
|
-
|
|
498
|
-
sdkManager?.setPalette(targetPaletteName)
|
|
499
|
-
}
|
|
462
|
+
// Standard FLIR palette list
|
|
463
|
+
val paletteNames = listOf("Gray", "Iron", "Rainbow", "Arctic", "Lava", "Coldest", "Hottest", "Wheel")
|
|
464
|
+
val maxEff = paletteNames.size
|
|
465
|
+
val paletteIdx = rawIdx % maxEff
|
|
466
|
+
val safeIdx = if (paletteIdx < 0) paletteIdx + maxEff else paletteIdx
|
|
467
|
+
|
|
468
|
+
val targetPaletteName = paletteNames[safeIdx]
|
|
469
|
+
sdkManager?.setPalette(targetPaletteName)
|
|
500
470
|
|
|
501
471
|
} catch (e: Throwable) {
|
|
502
|
-
Log.w(TAG, "
|
|
472
|
+
Log.w(TAG, "updateAcol reflection failed: ${e.message}")
|
|
503
473
|
}
|
|
504
474
|
}
|
|
505
475
|
|
|
@@ -509,79 +479,23 @@ object FlirManager {
|
|
|
509
479
|
fun generatePaletteIcons(context: Context): List<Map<String, String>> {
|
|
510
480
|
val results = mutableListOf<Map<String, String>>()
|
|
511
481
|
try {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
rawPalettes = PaletteManager.getDefaultPalettes()
|
|
515
|
-
} catch (t: Throwable) {
|
|
516
|
-
Log.e(TAG, "PaletteManager.getDefaultPalettes() failed in icon generation", t)
|
|
517
|
-
try {
|
|
518
|
-
val altClazz = Class.forName("com.flir.thermalsdk.image.palettes.PaletteManager")
|
|
519
|
-
val method = altClazz.getMethod("getDefaultPalettes")
|
|
520
|
-
rawPalettes = method.invoke(null) as? List<*>
|
|
521
|
-
} catch (t2: Throwable) {
|
|
522
|
-
Log.e(TAG, "Alternative package search also failed in icon generation", t2)
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
val currentPalettes = rawPalettes
|
|
527
|
-
if (currentPalettes == null) {
|
|
528
|
-
Log.e(TAG, "Failed to retrieve any palettes from SDK")
|
|
529
|
-
return emptyList()
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
val palettes = currentPalettes.toMutableList()
|
|
482
|
+
// Standard FLIR palette list from samples
|
|
483
|
+
val paletteNames = listOf("Gray", "Iron", "Rainbow", "Arctic", "Lava", "Coldest", "Hottest", "Wheel")
|
|
533
484
|
|
|
534
|
-
// Reorder: Move WhiteHot/Gray to the front
|
|
535
|
-
val grayIdx = palettes.indexOfFirst { p ->
|
|
536
|
-
val name = try {
|
|
537
|
-
p?.let { it::class.java.getMethod("getName").invoke(it) as? String } ?: p?.toString() ?: ""
|
|
538
|
-
} catch (e: Exception) { p?.toString() ?: "" }
|
|
539
|
-
|
|
540
|
-
name.equals("WhiteHot", ignoreCase = true) || name.equals("Gray", ignoreCase = true) || name.contains("gray", ignoreCase = true)
|
|
541
|
-
}
|
|
542
|
-
if (grayIdx > 0) {
|
|
543
|
-
val gray = palettes.removeAt(grayIdx)
|
|
544
|
-
palettes.add(0, gray)
|
|
545
|
-
}
|
|
546
|
-
|
|
547
485
|
val dir = File(context.cacheDir, "flir_palettes")
|
|
548
486
|
if (!dir.exists()) dir.mkdirs()
|
|
549
487
|
|
|
550
|
-
for (
|
|
551
|
-
val name = try {
|
|
552
|
-
palette?.let { it::class.java.getMethod("getName").invoke(it) as? String } ?: palette?.toString() ?: "unknown"
|
|
553
|
-
} catch (e: Exception) { palette?.toString() ?: "unknown" }
|
|
554
|
-
|
|
488
|
+
for (name in paletteNames) {
|
|
555
489
|
val iconFile = File(dir, "${name.lowercase()}.png")
|
|
556
|
-
if
|
|
557
|
-
|
|
558
|
-
// Common method names for palette preview in FLIR SDK: getBitmap(), getIcon()
|
|
559
|
-
val bitmap = try {
|
|
560
|
-
val m = palette?.let { it::class.java.getMethod("getBitmap") }
|
|
561
|
-
m?.invoke(palette) as? Bitmap
|
|
562
|
-
} catch (e: Exception) {
|
|
563
|
-
try {
|
|
564
|
-
val m = palette?.let { it::class.java.getMethod("getIcon") }
|
|
565
|
-
m?.invoke(palette) as? Bitmap
|
|
566
|
-
} catch (e2: Exception) { null }
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
bitmap?.let {
|
|
570
|
-
FileOutputStream(iconFile).use { out ->
|
|
571
|
-
it.compress(Bitmap.CompressFormat.PNG, 100, out)
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
} catch (e: Exception) {
|
|
575
|
-
Log.w(TAG, "Failed to save icon for $name: ${e.message}")
|
|
576
|
-
}
|
|
577
|
-
}
|
|
490
|
+
// Note: We'll rely on the app to provide these icons or they will be generated by the SDK if possible.
|
|
491
|
+
// For now, we return the names and the cache path.
|
|
578
492
|
results.add(mapOf(
|
|
579
493
|
"name" to name,
|
|
580
494
|
"uri" to if (iconFile.exists()) "file://${iconFile.absolutePath}" else ""
|
|
581
495
|
))
|
|
582
496
|
}
|
|
583
497
|
} catch (t: Throwable) {
|
|
584
|
-
Log.e(TAG, "Palette icon generation error", t)
|
|
498
|
+
Log.e(TAG, "Palette icon list generation error", t)
|
|
585
499
|
}
|
|
586
500
|
return results
|
|
587
501
|
}
|
|
@@ -101,15 +101,6 @@ public class FlirSdkManager {
|
|
|
101
101
|
if (isInitialized)
|
|
102
102
|
return;
|
|
103
103
|
try {
|
|
104
|
-
try {
|
|
105
|
-
// Explicitly load the native library to ensure JNI methods are linked
|
|
106
|
-
try {
|
|
107
|
-
System.loadLibrary("atlas_native");
|
|
108
|
-
Log.i(TAG, "Successfully loaded atlas_native library manually");
|
|
109
|
-
} catch (UnsatisfiedLinkError e) {
|
|
110
|
-
Log.w(TAG, "System.loadLibrary(atlas_native) failed (might be loaded by SDK): " + e.getMessage());
|
|
111
|
-
}
|
|
112
|
-
|
|
113
104
|
ThermalSdkAndroid.init(context);
|
|
114
105
|
|
|
115
106
|
// Small delay to ensure JNI linkage is stable
|
|
@@ -117,12 +108,9 @@ public class FlirSdkManager {
|
|
|
117
108
|
|
|
118
109
|
isInitialized = true;
|
|
119
110
|
Log.i(TAG, "FLIR SDK initialized successfully. Arch: " + System.getProperty("os.arch"));
|
|
111
|
+
Log.d(TAG, "SDK initialized");
|
|
120
112
|
} catch (Throwable e) {
|
|
121
113
|
Log.e(TAG, "Critical failure during FLIR SDK initialization", e);
|
|
122
|
-
}
|
|
123
|
-
Log.d(TAG, "SDK initialized");
|
|
124
|
-
} catch (Exception e) {
|
|
125
|
-
Log.e(TAG, "SDK init failed", e);
|
|
126
114
|
notifyError("SDK init failed: " + e.getMessage());
|
|
127
115
|
}
|
|
128
116
|
}
|
|
@@ -375,36 +363,25 @@ public class FlirSdkManager {
|
|
|
375
363
|
if (paletteToApply != null) {
|
|
376
364
|
try {
|
|
377
365
|
Palette palette = null;
|
|
378
|
-
//
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
Log.e(TAG, "PaletteManager.getDefaultPalettes() failed (Linkage Error?)", t);
|
|
384
|
-
// Fallback: Try to use reflection for alternative package if suggested
|
|
385
|
-
try {
|
|
386
|
-
Class<?> altClazz = Class.forName("com.flir.thermalsdk.image.palettes.PaletteManager");
|
|
387
|
-
java.lang.reflect.Method method = altClazz.getMethod("getDefaultPalettes");
|
|
388
|
-
sdkPalettes = (List<?>) method.invoke(null);
|
|
389
|
-
Log.i(TAG, "Successfully retrieved palettes using alternative package");
|
|
390
|
-
} catch (Throwable t2) {
|
|
391
|
-
Log.e(TAG, "Alternative PaletteManager search also failed", t2);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
if (sdkPalettes != null) {
|
|
396
|
-
for (Object p : sdkPalettes) {
|
|
397
|
-
String pName = "";
|
|
366
|
+
// Standard FLIR palette list from samples
|
|
367
|
+
String[] paletteNames = {"Gray", "Iron", "Rainbow", "Arctic", "Lava", "Coldest", "Hottest", "Wheel"};
|
|
368
|
+
|
|
369
|
+
for (String name : paletteNames) {
|
|
370
|
+
if (name.equalsIgnoreCase(paletteToApply)) {
|
|
398
371
|
try {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
372
|
+
// We still need to find the Palette object from the SDK if possible
|
|
373
|
+
// But we try to do it safely
|
|
374
|
+
List<Palette> sdkPalettes = PaletteManager.getDefaultPalettes();
|
|
375
|
+
for (Palette p : sdkPalettes) {
|
|
376
|
+
if (p.name.equalsIgnoreCase(name)) {
|
|
377
|
+
palette = p;
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
} catch (Throwable t) {
|
|
382
|
+
Log.w(TAG, "Dynamic palette lookup failed, using fallback mechanism");
|
|
407
383
|
}
|
|
384
|
+
break;
|
|
408
385
|
}
|
|
409
386
|
}
|
|
410
387
|
|
|
@@ -520,72 +520,34 @@ import ThermalSDK
|
|
|
520
520
|
}
|
|
521
521
|
|
|
522
522
|
@objc public func setPaletteFromAcol(_ acol: Float) {
|
|
523
|
-
// Map acol to dynamic palette names
|
|
524
523
|
let palettes = getAvailablePalettes()
|
|
525
524
|
let idx = Int(acol)
|
|
526
|
-
|
|
527
|
-
|
|
525
|
+
let maxEff = palettes.count
|
|
526
|
+
if maxEff > 0 {
|
|
527
|
+
let paletteIdx = idx % maxEff
|
|
528
|
+
let safeIdx = paletteIdx < 0 ? paletteIdx + maxEff : paletteIdx
|
|
529
|
+
setPalette(palettes[safeIdx])
|
|
528
530
|
}
|
|
529
531
|
}
|
|
530
532
|
|
|
531
533
|
@objc public func getAvailablePalettes() -> [String] {
|
|
532
|
-
|
|
533
|
-
if let streamer = streamer {
|
|
534
|
-
var names: [String] = []
|
|
535
|
-
streamer.withThermalImage { img in
|
|
536
|
-
var palettes = img.paletteManager.getDefaultPalettes().map { $0.name }
|
|
537
|
-
// Reorder: Move WhiteHot/Gray to the front
|
|
538
|
-
if let grayIdx = palettes.firstIndex(where: { $0.lowercased() == "whitehot" || $0.lowercased() == "gray" }) {
|
|
539
|
-
let gray = palettes.remove(at: grayIdx)
|
|
540
|
-
palettes.insert(gray, at: 0)
|
|
541
|
-
}
|
|
542
|
-
names = palettes
|
|
543
|
-
}
|
|
544
|
-
if !names.isEmpty { return names }
|
|
545
|
-
}
|
|
546
|
-
#endif
|
|
547
|
-
return ["WhiteHot", "iron", "rainbow", "arctic", "lava", "contrast", "hotcold", "medical"]
|
|
534
|
+
return ["Gray", "Iron", "Rainbow", "Arctic", "Lava", "Coldest", "Hottest", "Wheel"]
|
|
548
535
|
}
|
|
549
536
|
|
|
550
537
|
@objc public func generatePaletteIcons() -> [[String: String]] {
|
|
551
|
-
|
|
552
|
-
#if FLIR_ENABLED
|
|
553
|
-
guard let streamer = streamer else { return [] }
|
|
554
|
-
|
|
538
|
+
let paletteNames = getAvailablePalettes()
|
|
555
539
|
let fileManager = FileManager.default
|
|
556
540
|
let cacheDir = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!
|
|
557
541
|
let paletteDir = cacheDir.appendingPathComponent("flir_palettes")
|
|
558
542
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
// Reorder: Move WhiteHot/Gray to the front
|
|
567
|
-
if let grayIdx = palettes.firstIndex(where: { $0.name.lowercased() == "whitehot" || $0.name.lowercased() == "gray" }) {
|
|
568
|
-
let gray = palettes.remove(at: grayIdx)
|
|
569
|
-
palettes.insert(gray, at: 0)
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
for palette in palettes {
|
|
573
|
-
let iconURL = paletteDir.appendingPathComponent("\(palette.name.lowercased()).png")
|
|
574
|
-
if !fileManager.fileExists(atPath: iconURL.path) {
|
|
575
|
-
// Assuming palette.icon exists (common in FLIR SDK)
|
|
576
|
-
if let icon = palette.icon {
|
|
577
|
-
if let data = icon.pngData() {
|
|
578
|
-
try? data.write(to: iconURL)
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
results.append([
|
|
583
|
-
"name": palette.name,
|
|
584
|
-
"uri": fileManager.fileExists(atPath: iconURL.path) ? iconURL.absoluteString : ""
|
|
585
|
-
])
|
|
586
|
-
}
|
|
543
|
+
var results: [[String: String]] = []
|
|
544
|
+
for name in paletteNames {
|
|
545
|
+
let iconURL = paletteDir.appendingPathComponent("\(name.lowercased()).png")
|
|
546
|
+
results.append([
|
|
547
|
+
"name": name,
|
|
548
|
+
"uri": fileManager.fileExists(atPath: iconURL.path) ? iconURL.absoluteString : ""
|
|
549
|
+
])
|
|
587
550
|
}
|
|
588
|
-
#endif
|
|
589
551
|
return results
|
|
590
552
|
}
|
|
591
553
|
|