ilabs-flir 1.0.1 → 1.0.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/Flir.podspec +31 -31
- package/README.md +1271 -1271
- package/android/Flir/build.gradle.kts +85 -80
- package/android/Flir/libs/flir-stubs.jar +0 -0
- package/android/Flir/src/main/AndroidManifest.xml +31 -31
- package/android/Flir/src/main/java/com/flir/thermalsdk/ErrorCodeException.java +14 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/image/ImageBuffer.java +11 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/image/JavaImageBuffer.java +35 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/image/Palette.java +15 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/image/PaletteManager.java +16 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/image/Point.java +11 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/image/ThermalImage.java +23 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/image/ThermalValue.java +9 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/live/CameraType.java +8 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/live/CommunicationInterface.java +16 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/live/Identity.java +23 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/live/IpSettings.java +9 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/live/connectivity/ConnectionStatusListener.java +7 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/live/remote/OnReceived.java +5 -0
- package/android/Flir/src/main/java/com/flir/thermalsdk/live/remote/OnRemoteError.java +7 -0
- package/android/Flir/src/main/java/flir/android/CameraHandler.java +224 -194
- package/android/Flir/src/main/java/flir/android/FlirCommands.java +111 -0
- package/android/Flir/src/main/java/flir/android/FlirConnectionManager.java +354 -0
- package/android/Flir/src/main/java/flir/android/FlirController.kt +11 -11
- package/android/Flir/src/main/java/flir/android/FlirDiscoveryManager.java +236 -0
- package/android/Flir/src/main/java/flir/android/FlirDownloadManager.kt +75 -75
- package/android/Flir/src/main/java/flir/android/FlirDownloadPackage.kt +16 -16
- package/android/Flir/src/main/java/flir/android/FlirFrameCache.kt +6 -6
- package/android/Flir/src/main/java/flir/android/FlirManager.kt +254 -248
- package/android/Flir/src/main/java/flir/android/FlirModule.kt +74 -74
- package/android/Flir/src/main/java/flir/android/FlirPackage.kt +19 -16
- package/android/Flir/src/main/java/flir/android/FlirSDKLoader.kt +195 -191
- package/android/Flir/src/main/java/flir/android/FlirSdkManager.java +890 -0
- package/android/Flir/src/main/java/flir/android/FlirStatus.kt +12 -12
- package/android/Flir/src/main/java/flir/android/FlirView.kt +48 -48
- package/android/Flir/src/main/java/flir/android/FlirViewManager.kt +13 -13
- package/android/Flir/src/main/java/flir/android/FrameDataHolder.java +14 -14
- package/app.plugin.js +264 -264
- package/expo-module.config.json +5 -5
- package/ios/Flir/Framework/ThermalSDK/FLIRBattery.h +76 -76
- package/ios/Flir/Framework/ThermalSDK/FLIRCalibration.h +108 -108
- package/ios/Flir/Framework/ThermalSDK/FLIRCamera.h +156 -156
- package/ios/Flir/Framework/ThermalSDK/FLIRCameraDeviceInfo.h +53 -53
- package/ios/Flir/Framework/ThermalSDK/FLIRCameraEvent.h +132 -132
- package/ios/Flir/Framework/ThermalSDK/FLIRCameraImport.h +204 -204
- package/ios/Flir/Framework/ThermalSDK/FLIRColorDistributionSettings.h +204 -204
- package/ios/Flir/Framework/ThermalSDK/FLIRColorizer.h +82 -82
- package/ios/Flir/Framework/ThermalSDK/FLIRDiscoveredCamera.h +44 -44
- package/ios/Flir/Framework/ThermalSDK/FLIRDiscovery.h +132 -132
- package/ios/Flir/Framework/ThermalSDK/FLIRDisplaySettings.h +29 -29
- package/ios/Flir/Framework/ThermalSDK/FLIRFocus.h +70 -70
- package/ios/Flir/Framework/ThermalSDK/FLIRFusion.h +192 -192
- package/ios/Flir/Framework/ThermalSDK/FLIRFusionController.h +136 -136
- package/ios/Flir/Framework/ThermalSDK/FLIRFusionTransformation.h +35 -35
- package/ios/Flir/Framework/ThermalSDK/FLIRIdentity.h +264 -264
- package/ios/Flir/Framework/ThermalSDK/FLIRImageBase.h +196 -196
- package/ios/Flir/Framework/ThermalSDK/FLIRImageColorizer.h +26 -26
- package/ios/Flir/Framework/ThermalSDK/FLIRImageStatistics.h +61 -61
- package/ios/Flir/Framework/ThermalSDK/FLIRIsotherms.h +208 -208
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementArea.h +38 -38
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementCollection.h +147 -147
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementDelta.h +62 -62
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementDimensions.h +33 -33
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementEllipse.h +49 -49
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementLine.h +66 -66
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementMarker.h +69 -69
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementParameters.h +41 -41
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementRectangle.h +36 -36
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementReference.h +27 -27
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementShape.h +46 -46
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementSpot.h +33 -33
- package/ios/Flir/Framework/ThermalSDK/FLIRMeasurementsController.h +160 -160
- package/ios/Flir/Framework/ThermalSDK/FLIRMeterLinkSensorPoll.h +247 -247
- package/ios/Flir/Framework/ThermalSDK/FLIROverlayController.h +27 -27
- package/ios/Flir/Framework/ThermalSDK/FLIRPalette.h +60 -60
- package/ios/Flir/Framework/ThermalSDK/FLIRPaletteController.h +36 -36
- package/ios/Flir/Framework/ThermalSDK/FLIRPaletteManager.h +97 -97
- package/ios/Flir/Framework/ThermalSDK/FLIRQuantification.h +55 -55
- package/ios/Flir/Framework/ThermalSDK/FLIRRemoteControl.h +393 -393
- package/ios/Flir/Framework/ThermalSDK/FLIRRenderer.h +35 -35
- package/ios/Flir/Framework/ThermalSDK/FLIRRendererImpl.h +17 -17
- package/ios/Flir/Framework/ThermalSDK/FLIRScale.h +99 -99
- package/ios/Flir/Framework/ThermalSDK/FLIRScaleController.h +44 -44
- package/ios/Flir/Framework/ThermalSDK/FLIRStream.h +109 -109
- package/ios/Flir/Framework/ThermalSDK/FLIRStreamer.h +124 -124
- package/ios/Flir/Framework/ThermalSDK/FLIRSystem.h +40 -40
- package/ios/Flir/Framework/ThermalSDK/FLIRTemperatureRange.h +43 -43
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalDelta.h +77 -77
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalImage.h +331 -331
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalImageFile.h +56 -56
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalParameters.h +31 -31
- package/ios/Flir/Framework/ThermalSDK/FLIRThermalValue.h +92 -92
- package/ios/Flir/Framework/ThermalSDK/FLIRWirelessCameraDetails.h +88 -88
- package/ios/Flir/Framework/ThermalSDK/ThermalSDK.h +73 -73
- package/ios/Flir/SDKLoader/FlirSDKLoader.m +13 -13
- package/ios/Flir/SDKLoader/FlirSDKLoader.swift +175 -175
- package/ios/Flir/src/FlirEventEmitter.h +12 -12
- package/ios/Flir/src/FlirEventEmitter.m +33 -33
- package/ios/Flir/src/FlirModule.h +10 -10
- package/ios/Flir/src/FlirModule.m +381 -381
- package/ios/Flir/src/FlirPreviewView.h +13 -13
- package/ios/Flir/src/FlirPreviewView.m +24 -24
- package/ios/Flir/src/FlirState.h +20 -20
- package/ios/Flir/src/FlirState.m +79 -79
- package/ios/Flir/src/FlirViewManager.h +9 -9
- package/ios/Flir/src/FlirViewManager.m +16 -16
- package/package.json +61 -61
- package/react-native.config.js +14 -14
- package/scripts/copy_ios_libs.sh +32 -32
- package/scripts/create_stubs.py +174 -174
- package/scripts/download-sdk.js +62 -62
- package/scripts/prepare-binaries.sh +171 -171
- package/sdk-manifest.json +30 -30
- package/src/FlirDownload.ts +78 -78
- package/src/index.d.ts +17 -17
- package/src/index.js +7 -7
- package/src/index.ts +7 -7
|
@@ -0,0 +1,890 @@
|
|
|
1
|
+
package flir.android;
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap;
|
|
4
|
+
import android.util.Log;
|
|
5
|
+
|
|
6
|
+
import java.lang.reflect.Method;
|
|
7
|
+
import java.lang.reflect.Proxy;
|
|
8
|
+
import java.util.List;
|
|
9
|
+
import java.io.File;
|
|
10
|
+
import java.io.FileOutputStream;
|
|
11
|
+
import java.util.zip.ZipEntry;
|
|
12
|
+
import java.util.zip.ZipFile;
|
|
13
|
+
import dalvik.system.DexClassLoader;
|
|
14
|
+
import java.util.concurrent.Executors;
|
|
15
|
+
import java.util.concurrent.ScheduledExecutorService;
|
|
16
|
+
import java.util.concurrent.TimeUnit;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Thin helper that wraps FLIR Atlas SDK emulator and streamer features.
|
|
20
|
+
* All SDK-specific reflection plumbing lives here so FlirManager stays small.
|
|
21
|
+
*/
|
|
22
|
+
class FlirSdkManager {
|
|
23
|
+
private static final String TAG = "FlirSdkManager";
|
|
24
|
+
|
|
25
|
+
interface Listener {
|
|
26
|
+
void onFrame(Bitmap bitmap);
|
|
27
|
+
|
|
28
|
+
void onTemperature(double temp, int x, int y);
|
|
29
|
+
|
|
30
|
+
void onDeviceFound(String name);
|
|
31
|
+
|
|
32
|
+
void onEmulatorEnabled();
|
|
33
|
+
|
|
34
|
+
void onStreamKindChanged(String kind);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private Listener listener;
|
|
38
|
+
|
|
39
|
+
// SDK objects
|
|
40
|
+
private Object discoveryFactory;
|
|
41
|
+
private Object cameraObj;
|
|
42
|
+
private Object streamerObj;
|
|
43
|
+
private ClassLoader sdkClassLoader = null;
|
|
44
|
+
private String sdkCurrentStreamKind = null;
|
|
45
|
+
|
|
46
|
+
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
|
47
|
+
private volatile Bitmap latestFrame = null;
|
|
48
|
+
|
|
49
|
+
FlirSdkManager(Listener listener) {
|
|
50
|
+
this.listener = listener;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
boolean startSdkEmulator() {
|
|
54
|
+
try {
|
|
55
|
+
Class<?> commIfaceClass = findSdkClass("com.flir.thermalsdk.live.CommunicationInterface");
|
|
56
|
+
Object emulatorInterface = Enum.valueOf((Class<Enum>) commIfaceClass, "EMULATOR");
|
|
57
|
+
Log.d(TAG, "[FLIR SDK] Found EMULATOR interface: " + emulatorInterface);
|
|
58
|
+
|
|
59
|
+
Class<?> discoveryFactoryClass = findSdkClass("com.flir.thermalsdk.live.discovery.DiscoveryFactory");
|
|
60
|
+
Method getInstance = discoveryFactoryClass.getMethod("getInstance");
|
|
61
|
+
discoveryFactory = getInstance.invoke(null);
|
|
62
|
+
|
|
63
|
+
Class<?> listenerClass = findSdkClass("com.flir.thermalsdk.live.discovery.DiscoveryEventListener");
|
|
64
|
+
Object discoveryListener = Proxy.newProxyInstance(
|
|
65
|
+
listenerClass.getClassLoader(),
|
|
66
|
+
new Class<?>[] { listenerClass },
|
|
67
|
+
(proxy, method, args) -> {
|
|
68
|
+
String methodName = method.getName();
|
|
69
|
+
switch (methodName) {
|
|
70
|
+
case "onCameraFound":
|
|
71
|
+
Object discovered = args[0];
|
|
72
|
+
Log.i(TAG, "[FLIR SDK] Camera found: " + discovered);
|
|
73
|
+
connectToSdkCamera(discovered);
|
|
74
|
+
return null;
|
|
75
|
+
|
|
76
|
+
case "onCameraLost":
|
|
77
|
+
Log.i(TAG, "[FLIR SDK] Camera lost");
|
|
78
|
+
cameraObj = null;
|
|
79
|
+
streamerObj = null;
|
|
80
|
+
return null;
|
|
81
|
+
default:
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Get NETWORK interface for FLIR ONE Edge
|
|
87
|
+
Object networkInterface = Enum.valueOf((Class<Enum>) commIfaceClass, "NETWORK");
|
|
88
|
+
|
|
89
|
+
Method scanMethod = discoveryFactoryClass.getMethod("scan", listenerClass,
|
|
90
|
+
java.lang.reflect.Array.newInstance(commIfaceClass, 0).getClass());
|
|
91
|
+
// Scan for BOTH NETWORK (FLIR ONE Edge) and EMULATOR
|
|
92
|
+
Object ifaceArray = java.lang.reflect.Array.newInstance(commIfaceClass, 2);
|
|
93
|
+
java.lang.reflect.Array.set(ifaceArray, 0, networkInterface);
|
|
94
|
+
java.lang.reflect.Array.set(ifaceArray, 1, emulatorInterface);
|
|
95
|
+
scanMethod.invoke(discoveryFactory, discoveryListener, ifaceArray);
|
|
96
|
+
Log.i(TAG, "[FLIR SDK] Started discovery scan for NETWORK and EMULATOR");
|
|
97
|
+
return true;
|
|
98
|
+
} catch (ClassNotFoundException cnf) {
|
|
99
|
+
Log.w(TAG, "[FLIR SDK] Classes not found: " + cnf.getMessage());
|
|
100
|
+
// Try to load classes from an AAR (on-device) via DexClassLoader
|
|
101
|
+
try {
|
|
102
|
+
if (attemptLoadSdkFromAar()) {
|
|
103
|
+
// If class is now available via sdkClassLoader retry using that loader
|
|
104
|
+
Log.i(TAG,
|
|
105
|
+
"[FLIR SDK] SDK classes found via DexClassLoader, retrying discovery using sdkClassLoader");
|
|
106
|
+
try {
|
|
107
|
+
return startSdkEmulatorWithClassLoader(sdkClassLoader);
|
|
108
|
+
} catch (Throwable t) {
|
|
109
|
+
Log.w(TAG, "[FLIR SDK] retry using sdkClassLoader failed: " + t.getMessage());
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
} catch (Throwable t) {
|
|
113
|
+
Log.w(TAG, "[FLIR SDK] DexClassLoader attempt failed: " + t.getMessage());
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
} catch (Throwable t) {
|
|
117
|
+
Log.w(TAG, "[FLIR SDK] startSdkEmulator failed: " + t.getMessage(), t);
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private String sdkJarPath = null;
|
|
123
|
+
|
|
124
|
+
private boolean attemptLoadSdkFromAar() {
|
|
125
|
+
// TODO: This is legacy code - context should be passed as parameter
|
|
126
|
+
android.content.Context ctx = null; // ilabs.libs.io.data.Var.getAppContext();
|
|
127
|
+
try {
|
|
128
|
+
// android.content.Context ctx = ilabs.libs.io.data.Var.getAppContext();
|
|
129
|
+
if (ctx == null) {
|
|
130
|
+
Log.w(TAG, "[FLIR SDK] No application context available for SDK load");
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
File filesDir = ctx.getFilesDir();
|
|
134
|
+
// Candidate search locations (ordered by preference)
|
|
135
|
+
java.util.List<File> candList = new java.util.ArrayList<>();
|
|
136
|
+
// Add internal app filesDir candidates
|
|
137
|
+
try {
|
|
138
|
+
candList.add(new File(filesDir, "flir-sdk/thermalsdk-release.aar"));
|
|
139
|
+
} catch (Throwable ignored) {
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
candList.add(new File(filesDir, "thermalsdk-release.aar"));
|
|
143
|
+
} catch (Throwable ignored) {
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
candList.add(new File(filesDir, "thermalsdk.aar"));
|
|
147
|
+
} catch (Throwable ignored) {
|
|
148
|
+
}
|
|
149
|
+
// Add external files dir candidates if available
|
|
150
|
+
try {
|
|
151
|
+
if (ctx.getExternalFilesDir(null) != null) {
|
|
152
|
+
candList.add(new File(ctx.getExternalFilesDir(null), "thermalsdk-release.aar"));
|
|
153
|
+
candList.add(new File(ctx.getExternalFilesDir(null), "thermalsdk.aar"));
|
|
154
|
+
}
|
|
155
|
+
} catch (Throwable ignored) {
|
|
156
|
+
}
|
|
157
|
+
// Add common sdcard and tmp locations
|
|
158
|
+
try {
|
|
159
|
+
candList.add(new File("/sdcard/Download/thermalsdk-release.aar"));
|
|
160
|
+
} catch (Throwable ignored) {
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
candList.add(new File("/sdcard/thermalsdk-release.aar"));
|
|
164
|
+
} catch (Throwable ignored) {
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
candList.add(new File("/sdcard/thermalsdk.aar"));
|
|
168
|
+
} catch (Throwable ignored) {
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
candList.add(new File("/data/local/tmp/thermalsdk-release.aar"));
|
|
172
|
+
} catch (Throwable ignored) {
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
candList.add(new File("/data/local/tmp/thermalsdk.aar"));
|
|
176
|
+
} catch (Throwable ignored) {
|
|
177
|
+
}
|
|
178
|
+
File candidate = null;
|
|
179
|
+
StringBuilder tried = new StringBuilder();
|
|
180
|
+
Log.i(TAG,
|
|
181
|
+
"[FLIR SDK] FilesDir=" + filesDir.getAbsolutePath() + ", ExternalFilesDir="
|
|
182
|
+
+ (ctx.getExternalFilesDir(null) != null ? ctx.getExternalFilesDir(null).getAbsolutePath()
|
|
183
|
+
: "null"));
|
|
184
|
+
for (File cand : candList) {
|
|
185
|
+
try {
|
|
186
|
+
if (cand == null) {
|
|
187
|
+
tried.append("null,");
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
boolean exists = false;
|
|
191
|
+
try {
|
|
192
|
+
exists = cand.exists();
|
|
193
|
+
} catch (Throwable ignored) {
|
|
194
|
+
}
|
|
195
|
+
tried.append(cand.getAbsolutePath()).append(exists ? "(exists)," : "(no),");
|
|
196
|
+
if (exists) {
|
|
197
|
+
candidate = cand;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
} catch (Throwable ignored) {
|
|
201
|
+
tried.append("err,");
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (candidate == null || !candidate.exists()) {
|
|
205
|
+
Log.w(TAG, "[FLIR SDK] No SDK AAR found. Tried: " + tried.toString());
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
Log.i(TAG, "[FLIR SDK] Found SDK AAR: " + candidate.getAbsolutePath());
|
|
209
|
+
Log.i(TAG, "[FLIR SDK] Candidate list tried: " + tried.toString());
|
|
210
|
+
ZipFile zf = new ZipFile(candidate);
|
|
211
|
+
ZipEntry classesEntry = zf.getEntry("classes.jar");
|
|
212
|
+
if (classesEntry == null) {
|
|
213
|
+
Log.w(TAG, "[FLIR SDK] classes.jar not found in AAR");
|
|
214
|
+
zf.close();
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
File outJar = new File(filesDir, "flir-classes.jar");
|
|
218
|
+
FileOutputStream fos = new FileOutputStream(outJar);
|
|
219
|
+
java.io.InputStream is = zf.getInputStream(classesEntry);
|
|
220
|
+
byte[] buf = new byte[8192];
|
|
221
|
+
int r;
|
|
222
|
+
while ((r = is.read(buf)) != -1)
|
|
223
|
+
fos.write(buf, 0, r);
|
|
224
|
+
is.close();
|
|
225
|
+
fos.close();
|
|
226
|
+
zf.close();
|
|
227
|
+
File dexOutDir = ctx.getDir("dex", android.content.Context.MODE_PRIVATE);
|
|
228
|
+
DexClassLoader dcl = new DexClassLoader(outJar.getAbsolutePath(), dexOutDir.getAbsolutePath(), null,
|
|
229
|
+
ctx.getClassLoader());
|
|
230
|
+
// verify class present
|
|
231
|
+
Class<?> test = Class.forName("com.flir.thermalsdk.live.CommunicationInterface", true, dcl);
|
|
232
|
+
if (test != null) {
|
|
233
|
+
sdkClassLoader = dcl;
|
|
234
|
+
Log.i(TAG, "[FLIR SDK] DexClassLoader created and class loaded from: " + outJar.getAbsolutePath());
|
|
235
|
+
try {
|
|
236
|
+
Log.i(TAG, "[FLIR SDK] DexClassLoader parent loader=" + dcl.getParent() + " (loader=" + dcl + ")");
|
|
237
|
+
} catch (Throwable ignored) {
|
|
238
|
+
}
|
|
239
|
+
sdkJarPath = outJar.getAbsolutePath();
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
} catch (Throwable t) {
|
|
243
|
+
Log.w(TAG, "[FLIR SDK] attemptLoadSdkFromAar failed: " + t.getMessage(), t);
|
|
244
|
+
try {
|
|
245
|
+
Log.i(TAG, "[FLIR SDK] Candidate list tried on failure: ");
|
|
246
|
+
} catch (Throwable ignored) {
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public boolean isSdkLoaded() {
|
|
253
|
+
return sdkClassLoader != null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
public String getLoadedSdkJarPath() {
|
|
257
|
+
return sdkJarPath;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private Class<?> findSdkClass(String name) throws ClassNotFoundException {
|
|
261
|
+
try {
|
|
262
|
+
return Class.forName(name);
|
|
263
|
+
} catch (ClassNotFoundException e) {
|
|
264
|
+
if (sdkClassLoader != null)
|
|
265
|
+
return Class.forName(name, true, sdkClassLoader);
|
|
266
|
+
throw e;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private boolean startSdkEmulatorWithClassLoader(ClassLoader loader) {
|
|
271
|
+
try {
|
|
272
|
+
Class<?> commIfaceClass = Class.forName("com.flir.thermalsdk.live.CommunicationInterface", true, loader);
|
|
273
|
+
Object emulatorInterface = Enum.valueOf((Class<Enum>) commIfaceClass, "EMULATOR");
|
|
274
|
+
Log.d(TAG, "[FLIR SDK] (DEX) CommunicationInterface found via loader: " + loader);
|
|
275
|
+
Log.d(TAG, "[FLIR SDK] Found EMULATOR interface (DEX): " + emulatorInterface);
|
|
276
|
+
|
|
277
|
+
Class<?> discoveryFactoryClass = Class.forName("com.flir.thermalsdk.live.discovery.DiscoveryFactory", true,
|
|
278
|
+
loader);
|
|
279
|
+
Method getInstance = discoveryFactoryClass.getMethod("getInstance");
|
|
280
|
+
discoveryFactory = getInstance.invoke(null);
|
|
281
|
+
Log.d(TAG, "[FLIR SDK] (DEX) DiscoveryFactory.getInstance() returned: " + (discoveryFactory != null));
|
|
282
|
+
|
|
283
|
+
Class<?> listenerClass = Class.forName("com.flir.thermalsdk.live.discovery.DiscoveryEventListener", true,
|
|
284
|
+
loader);
|
|
285
|
+
Object discoveryListener = Proxy.newProxyInstance(
|
|
286
|
+
loader,
|
|
287
|
+
new Class<?>[] { listenerClass },
|
|
288
|
+
(proxy, method, args) -> {
|
|
289
|
+
String methodName = method.getName();
|
|
290
|
+
switch (methodName) {
|
|
291
|
+
case "onCameraFound":
|
|
292
|
+
Object discovered = args[0];
|
|
293
|
+
Log.i(TAG, "[FLIR SDK] (DEX) Camera found: " + discovered);
|
|
294
|
+
connectToSdkCamera(discovered);
|
|
295
|
+
return null;
|
|
296
|
+
case "onCameraLost":
|
|
297
|
+
Log.i(TAG, "[FLIR SDK] (DEX) Camera lost");
|
|
298
|
+
cameraObj = null;
|
|
299
|
+
streamerObj = null;
|
|
300
|
+
return null;
|
|
301
|
+
default:
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// Get NETWORK interface for FLIR ONE Edge
|
|
307
|
+
Object networkInterface = Enum.valueOf((Class<Enum>) commIfaceClass, "NETWORK");
|
|
308
|
+
|
|
309
|
+
Method scanMethod = discoveryFactoryClass.getMethod("scan", listenerClass,
|
|
310
|
+
java.lang.reflect.Array.newInstance(commIfaceClass, 0).getClass());
|
|
311
|
+
// Scan for BOTH NETWORK (FLIR ONE Edge) and EMULATOR
|
|
312
|
+
Object ifaceArray = java.lang.reflect.Array.newInstance(commIfaceClass, 2);
|
|
313
|
+
java.lang.reflect.Array.set(ifaceArray, 0, networkInterface);
|
|
314
|
+
java.lang.reflect.Array.set(ifaceArray, 1, emulatorInterface);
|
|
315
|
+
scanMethod.invoke(discoveryFactory, discoveryListener, ifaceArray);
|
|
316
|
+
Log.i(TAG, "[FLIR SDK] (DEX) scan invoked on DiscoveryFactory");
|
|
317
|
+
Log.i(TAG, "[FLIR SDK] (DEX) Started discovery scan for NETWORK and EMULATOR");
|
|
318
|
+
return true;
|
|
319
|
+
} catch (Throwable t) {
|
|
320
|
+
Log.w(TAG, "[FLIR SDK] startSdkEmulatorWithClassLoader failed: " + t.getMessage());
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
private void connectToSdkCamera(Object discoveredCamera) {
|
|
326
|
+
try {
|
|
327
|
+
Method getIdentity = discoveredCamera.getClass().getMethod("getIdentity");
|
|
328
|
+
Object identity = getIdentity.invoke(discoveredCamera);
|
|
329
|
+
|
|
330
|
+
Class<?> cameraClass = findSdkClass("com.flir.thermalsdk.live.Camera");
|
|
331
|
+
cameraObj = cameraClass.newInstance();
|
|
332
|
+
|
|
333
|
+
Class<?> connStatusClass = findSdkClass("com.flir.thermalsdk.live.connectivity.ConnectionStatusListener");
|
|
334
|
+
Object connListener = Proxy.newProxyInstance(connStatusClass.getClassLoader(),
|
|
335
|
+
new Class<?>[] { connStatusClass }, (proxy, method, args) -> {
|
|
336
|
+
if (method.getName().equals("onDisconnected")) {
|
|
337
|
+
Log.w(TAG, "[FLIR SDK] Camera disconnected");
|
|
338
|
+
cameraObj = null;
|
|
339
|
+
streamerObj = null;
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Try various connect overloads to be compatible across SDK versions
|
|
345
|
+
boolean connected = false;
|
|
346
|
+
try {
|
|
347
|
+
Class<?> connectParamsClass = findSdkClass("com.flir.thermalsdk.live.ConnectParameters");
|
|
348
|
+
Object connectParams = null;
|
|
349
|
+
try {
|
|
350
|
+
connectParams = connectParamsClass.newInstance();
|
|
351
|
+
} catch (Throwable ignored) {
|
|
352
|
+
}
|
|
353
|
+
Method connectMethod3 = cameraClass.getMethod("connect", identity.getClass(), connStatusClass,
|
|
354
|
+
connectParamsClass);
|
|
355
|
+
connectMethod3.invoke(cameraObj, identity, connListener, connectParams);
|
|
356
|
+
connected = true;
|
|
357
|
+
} catch (Throwable ignored) {
|
|
358
|
+
try {
|
|
359
|
+
Method connectMethod2 = cameraClass.getMethod("connect", identity.getClass(), connStatusClass);
|
|
360
|
+
connectMethod2.invoke(cameraObj, identity, connListener);
|
|
361
|
+
connected = true;
|
|
362
|
+
} catch (Throwable ignored2) {
|
|
363
|
+
try {
|
|
364
|
+
Method connectSimple = cameraClass.getMethod("connect", identity.getClass());
|
|
365
|
+
connectSimple.invoke(cameraObj, identity);
|
|
366
|
+
connected = true;
|
|
367
|
+
} catch (Throwable ignored3) {
|
|
368
|
+
Log.w(TAG, "connect: All connect attempts failed: " + ignored3.getMessage());
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
String deviceName = "EMULATOR";
|
|
374
|
+
try {
|
|
375
|
+
Method getName = identity.getClass().getMethod("getName");
|
|
376
|
+
Object nm = getName.invoke(identity);
|
|
377
|
+
if (nm != null)
|
|
378
|
+
deviceName = nm.toString();
|
|
379
|
+
} catch (Throwable ignored) {
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (listener != null) {
|
|
383
|
+
listener.onDeviceFound(deviceName);
|
|
384
|
+
listener.onEmulatorEnabled();
|
|
385
|
+
}
|
|
386
|
+
Log.d(TAG, "[FLIR SDK] Scheduling startSdkStreaming; cameraObj=" + cameraObj + ", identity=" + identity
|
|
387
|
+
+ ", connected=" + connected);
|
|
388
|
+
scheduler.schedule(this::startSdkStreaming, 500, TimeUnit.MILLISECONDS);
|
|
389
|
+
} catch (Throwable t) {
|
|
390
|
+
Log.w(TAG, "connectToSdkCamera failed: " + t.getMessage(), t);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
private void startSdkStreaming() {
|
|
395
|
+
try {
|
|
396
|
+
Log.d(TAG, "[FLIR SDK] startSdkStreaming invoked; cameraObj=" + cameraObj + ", streamerObj=" + streamerObj);
|
|
397
|
+
if (cameraObj == null)
|
|
398
|
+
return;
|
|
399
|
+
Method getStreams = cameraObj.getClass().getMethod("getStreams");
|
|
400
|
+
Object streams = getStreams.invoke(cameraObj);
|
|
401
|
+
if (streams == null)
|
|
402
|
+
Log.i(TAG, "[FLIR SDK] No streams returned from camera.getStreams()");
|
|
403
|
+
Object chosenStream = null;
|
|
404
|
+
int streamCount = 0;
|
|
405
|
+
if (streams instanceof List) {
|
|
406
|
+
List<?> streamList = (List<?>) streams;
|
|
407
|
+
streamCount = streamList.size();
|
|
408
|
+
Log.i(TAG, "[FLIR SDK] getStreams returned list with size=" + streamList.size());
|
|
409
|
+
for (Object s : streamList) {
|
|
410
|
+
if (s == null)
|
|
411
|
+
continue;
|
|
412
|
+
try {
|
|
413
|
+
Method getName = null;
|
|
414
|
+
try {
|
|
415
|
+
getName = s.getClass().getMethod("getName");
|
|
416
|
+
} catch (Throwable ignored) {
|
|
417
|
+
}
|
|
418
|
+
String name = null;
|
|
419
|
+
if (getName != null)
|
|
420
|
+
name = getName.invoke(s).toString().toLowerCase();
|
|
421
|
+
|
|
422
|
+
Method getType = null;
|
|
423
|
+
try {
|
|
424
|
+
getType = s.getClass().getMethod("getStreamType");
|
|
425
|
+
} catch (Throwable ignored) {
|
|
426
|
+
}
|
|
427
|
+
if (getType == null)
|
|
428
|
+
try {
|
|
429
|
+
getType = s.getClass().getMethod("getType");
|
|
430
|
+
} catch (Throwable ignored) {
|
|
431
|
+
}
|
|
432
|
+
String type = null;
|
|
433
|
+
if (getType != null)
|
|
434
|
+
type = getType.invoke(s).toString().toLowerCase();
|
|
435
|
+
|
|
436
|
+
String test = (name != null ? name : "") + "|" + (type != null ? type : "");
|
|
437
|
+
Log.d(TAG, "[FLIR SDK] stream candidate: name='" + name + "', type='" + type + "', test='"
|
|
438
|
+
+ test + "'");
|
|
439
|
+
if (test.contains("fusion") || test.contains("palette") || test.contains("visual")
|
|
440
|
+
|| test.contains("msx")) {
|
|
441
|
+
chosenStream = s;
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
} catch (Throwable ignored) {
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (chosenStream == null && !streamList.isEmpty())
|
|
448
|
+
chosenStream = streamList.get(0);
|
|
449
|
+
}
|
|
450
|
+
if (chosenStream == null)
|
|
451
|
+
Log.w(TAG, "[FLIR SDK] No chosen stream found; streamCount=" + streamCount);
|
|
452
|
+
if (chosenStream == null)
|
|
453
|
+
return;
|
|
454
|
+
|
|
455
|
+
Class<?> thermalStreamerClass = findSdkClass("com.flir.thermalsdk.live.streaming.ThermalStreamer");
|
|
456
|
+
java.lang.reflect.Constructor<?> ctor = thermalStreamerClass
|
|
457
|
+
.getConstructor(findSdkClass("com.flir.thermalsdk.live.streaming.Stream"));
|
|
458
|
+
streamerObj = ctor.newInstance(chosenStream);
|
|
459
|
+
Log.i(TAG, "[FLIR SDK] ThermalStreamer instance created: "
|
|
460
|
+
+ (streamerObj != null ? streamerObj.getClass().getName() : "null"));
|
|
461
|
+
|
|
462
|
+
boolean listenerAttached = attachStreamerListener(streamerObj);
|
|
463
|
+
if (!listenerAttached)
|
|
464
|
+
startFramePolling();
|
|
465
|
+
Log.i(TAG, "[FLIR SDK] startSdkStreaming: listenerAttached=" + listenerAttached + ", streamerObj="
|
|
466
|
+
+ (streamerObj != null));
|
|
467
|
+
|
|
468
|
+
// Notify stream kind change
|
|
469
|
+
try {
|
|
470
|
+
Method getName = chosenStream.getClass().getMethod("getName");
|
|
471
|
+
Object nm = getName.invoke(chosenStream);
|
|
472
|
+
if (nm != null && listener != null)
|
|
473
|
+
listener.onStreamKindChanged(nm.toString());
|
|
474
|
+
try {
|
|
475
|
+
sdkCurrentStreamKind = nm != null ? nm.toString() : null;
|
|
476
|
+
} catch (Throwable ignored) {
|
|
477
|
+
}
|
|
478
|
+
} catch (Throwable ignored) {
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
} catch (Throwable t) {
|
|
482
|
+
Log.w(TAG, "startSdkStreaming failed: " + t.getMessage(), t);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
public boolean forceStartStreaming() {
|
|
487
|
+
try {
|
|
488
|
+
if (cameraObj == null) {
|
|
489
|
+
Log.i(TAG, "[FLIR SDK] forceStartStreaming: No cameraObj, attempting discovery scan");
|
|
490
|
+
try {
|
|
491
|
+
// Re-run discovery to find cameras
|
|
492
|
+
Class<?> commIfaceClass = findSdkClass("com.flir.thermalsdk.live.CommunicationInterface");
|
|
493
|
+
Object emulatorInterface = Enum.valueOf((Class<Enum>) commIfaceClass, "EMULATOR");
|
|
494
|
+
Class<?> discoveryFactoryClass = findSdkClass(
|
|
495
|
+
"com.flir.thermalsdk.live.discovery.DiscoveryFactory");
|
|
496
|
+
Method getInstance = discoveryFactoryClass.getMethod("getInstance");
|
|
497
|
+
Object df = getInstance.invoke(null);
|
|
498
|
+
Class<?> listenerClass = findSdkClass("com.flir.thermalsdk.live.discovery.DiscoveryEventListener");
|
|
499
|
+
Object discoveryListener = Proxy.newProxyInstance(
|
|
500
|
+
sdkClassLoader != null ? sdkClassLoader : discoveryFactoryClass.getClassLoader(),
|
|
501
|
+
new Class<?>[] { listenerClass },
|
|
502
|
+
(proxy, method, args) -> {
|
|
503
|
+
String methodName = method.getName();
|
|
504
|
+
if ("onCameraFound".equalsIgnoreCase(methodName) && args != null && args.length > 0) {
|
|
505
|
+
try {
|
|
506
|
+
Object discovered = args[0];
|
|
507
|
+
Log.i(TAG, "[FLIR SDK] forceStartStreaming: discovered camera: " + discovered);
|
|
508
|
+
connectToSdkCamera(discovered);
|
|
509
|
+
} catch (Throwable t) {
|
|
510
|
+
Log.w(TAG, "[FLIR SDK] forceStartStreaming onCameraFound handler error: "
|
|
511
|
+
+ t.getMessage());
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return null;
|
|
515
|
+
});
|
|
516
|
+
Method scanMethod = discoveryFactoryClass.getMethod("scan", listenerClass,
|
|
517
|
+
java.lang.reflect.Array.newInstance(commIfaceClass, 0).getClass());
|
|
518
|
+
Object ifaceArray = java.lang.reflect.Array.newInstance(commIfaceClass, 1);
|
|
519
|
+
java.lang.reflect.Array.set(ifaceArray, 0, emulatorInterface);
|
|
520
|
+
scanMethod.invoke(df, discoveryListener, ifaceArray);
|
|
521
|
+
} catch (Throwable t) {
|
|
522
|
+
Log.w(TAG, "[FLIR SDK] forceStartStreaming discovery scan failed: " + t.getMessage());
|
|
523
|
+
}
|
|
524
|
+
// if cameraObj still null - return false
|
|
525
|
+
if (cameraObj == null)
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
// If cameraObj present, start streaming
|
|
529
|
+
scheduler.submit(() -> startSdkStreaming());
|
|
530
|
+
Log.i(TAG, "[FLIR SDK] forceStartStreaming scheduled startSdkStreaming");
|
|
531
|
+
return true;
|
|
532
|
+
} catch (Throwable t) {
|
|
533
|
+
Log.w(TAG, "[FLIR SDK] forceStartStreaming failed: " + t.getMessage(), t);
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
private void startFramePolling() {
|
|
539
|
+
scheduler.scheduleAtFixedRate(() -> {
|
|
540
|
+
try {
|
|
541
|
+
if (streamerObj == null)
|
|
542
|
+
return;
|
|
543
|
+
Log.d(TAG, "[FLIR SDK] startFramePolling - streamerObj class=" + streamerObj.getClass().getName());
|
|
544
|
+
Method updateMethod = streamerObj.getClass().getMethod("update");
|
|
545
|
+
updateMethod.invoke(streamerObj);
|
|
546
|
+
|
|
547
|
+
Method getImage = streamerObj.getClass().getMethod("getImage");
|
|
548
|
+
Object thermalImage = getImage.invoke(streamerObj);
|
|
549
|
+
if (thermalImage != null) {
|
|
550
|
+
try {
|
|
551
|
+
// Prefer: direct getBitmap() if available
|
|
552
|
+
try {
|
|
553
|
+
Method getBitmap = thermalImage.getClass().getMethod("getBitmap");
|
|
554
|
+
Object bmp = getBitmap.invoke(thermalImage);
|
|
555
|
+
if (bmp instanceof Bitmap) {
|
|
556
|
+
latestFrame = (Bitmap) bmp;
|
|
557
|
+
if (listener != null) {
|
|
558
|
+
listener.onFrame((Bitmap) bmp);
|
|
559
|
+
Log.d(TAG, "[FLIR SDK] Frame emitted from polling: " + ((Bitmap) bmp).getWidth()
|
|
560
|
+
+ "x" + ((Bitmap) bmp).getHeight());
|
|
561
|
+
}
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
} catch (Throwable ignored) {
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Fallback: try using
|
|
568
|
+
// BitmapAndroid.createBitmap(thermalImage.getImage()).getBitMap()
|
|
569
|
+
try {
|
|
570
|
+
Object imageBase = null;
|
|
571
|
+
try {
|
|
572
|
+
Method getImageFromThermal = thermalImage.getClass().getMethod("getImage");
|
|
573
|
+
imageBase = getImageFromThermal.invoke(thermalImage);
|
|
574
|
+
} catch (Throwable ignored) {
|
|
575
|
+
}
|
|
576
|
+
if (imageBase == null)
|
|
577
|
+
imageBase = thermalImage;
|
|
578
|
+
Class<?> bitmapAndroidClass = findSdkClass(
|
|
579
|
+
"com.flir.thermalsdk.androidsdk.image.BitmapAndroid");
|
|
580
|
+
Method createBitmap = bitmapAndroidClass.getMethod("createBitmap", imageBase.getClass());
|
|
581
|
+
Object wrapper = createBitmap.invoke(null, imageBase);
|
|
582
|
+
if (wrapper != null) {
|
|
583
|
+
Method getBitMapMethod = wrapper.getClass().getMethod("getBitMap");
|
|
584
|
+
Object bmp = getBitMapMethod.invoke(wrapper);
|
|
585
|
+
if (bmp instanceof Bitmap) {
|
|
586
|
+
latestFrame = (Bitmap) bmp;
|
|
587
|
+
if (listener != null)
|
|
588
|
+
listener.onFrame((Bitmap) bmp);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
} catch (Throwable ignored) {
|
|
592
|
+
}
|
|
593
|
+
} catch (Throwable ignored) {
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
} catch (Throwable t) {
|
|
597
|
+
if (System.currentTimeMillis() % 5000 < 200)
|
|
598
|
+
Log.d(TAG, "Frame poll error: " + t.getMessage());
|
|
599
|
+
}
|
|
600
|
+
}, 100, 100, TimeUnit.MILLISECONDS);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
Bitmap getLatestFrame() {
|
|
604
|
+
return latestFrame;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
double getTemperatureAtPoint(int x, int y) {
|
|
608
|
+
// Try to query using SDK streamer if available
|
|
609
|
+
try {
|
|
610
|
+
if (streamerObj != null) {
|
|
611
|
+
Method getImage = streamerObj.getClass().getMethod("getImage");
|
|
612
|
+
Object thermalImage = getImage.invoke(streamerObj);
|
|
613
|
+
if (thermalImage != null) {
|
|
614
|
+
try {
|
|
615
|
+
Method getValueAt = thermalImage.getClass().getMethod("getValueAt",
|
|
616
|
+
android.graphics.Point.class);
|
|
617
|
+
android.graphics.Point p = new android.graphics.Point(x, y);
|
|
618
|
+
Object temp = getValueAt.invoke(thermalImage, p);
|
|
619
|
+
if (temp instanceof Double)
|
|
620
|
+
return (Double) temp;
|
|
621
|
+
if (temp instanceof Float)
|
|
622
|
+
return ((Float) temp).doubleValue();
|
|
623
|
+
} catch (NoSuchMethodException nsme) {
|
|
624
|
+
}
|
|
625
|
+
try {
|
|
626
|
+
Method getValues = thermalImage.getClass().getMethod("getValues");
|
|
627
|
+
Object values = getValues.invoke(thermalImage);
|
|
628
|
+
if (values != null) {
|
|
629
|
+
Method valGetAt = values.getClass().getMethod("getValueAt", int.class, int.class);
|
|
630
|
+
Object temp = valGetAt.invoke(values, x, y);
|
|
631
|
+
if (temp instanceof Double)
|
|
632
|
+
return (Double) temp;
|
|
633
|
+
}
|
|
634
|
+
} catch (Throwable ignored) {
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
} catch (Throwable t) {
|
|
639
|
+
}
|
|
640
|
+
return Double.NaN;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
boolean setPalette(String paletteName) {
|
|
644
|
+
try {
|
|
645
|
+
if (streamerObj == null && cameraObj == null)
|
|
646
|
+
return false;
|
|
647
|
+
Object thermalImage = null;
|
|
648
|
+
if (streamerObj != null) {
|
|
649
|
+
Method getImage = streamerObj.getClass().getMethod("getImage");
|
|
650
|
+
thermalImage = getImage.invoke(streamerObj);
|
|
651
|
+
}
|
|
652
|
+
if (thermalImage != null) {
|
|
653
|
+
Class<?> paletteManagerClass = null;
|
|
654
|
+
try {
|
|
655
|
+
paletteManagerClass = findSdkClass("com.flir.thermalsdk.image.palettes.PaletteManager");
|
|
656
|
+
} catch (Throwable ignored) {
|
|
657
|
+
try {
|
|
658
|
+
paletteManagerClass = findSdkClass("com.flir.thermalsdk.image.PaletteManager");
|
|
659
|
+
} catch (Throwable ignored2) {
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
if (paletteManagerClass == null)
|
|
663
|
+
return false;
|
|
664
|
+
Method getDefaultPalettes = paletteManagerClass.getMethod("getDefaultPalettes");
|
|
665
|
+
Object palettesResult = getDefaultPalettes.invoke(null);
|
|
666
|
+
Object target = null;
|
|
667
|
+
// Handle array or List return types
|
|
668
|
+
if (palettesResult instanceof Object[]) {
|
|
669
|
+
for (Object p : (Object[]) palettesResult) {
|
|
670
|
+
try {
|
|
671
|
+
Method getName = p.getClass().getMethod("getName");
|
|
672
|
+
String n = (String) getName.invoke(p);
|
|
673
|
+
if (n != null && n.equalsIgnoreCase(paletteName)) {
|
|
674
|
+
target = p;
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
} catch (Throwable ignored) {
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
} else if (palettesResult instanceof java.util.List) {
|
|
681
|
+
for (Object p : (java.util.List) palettesResult) {
|
|
682
|
+
try {
|
|
683
|
+
Method getName = p.getClass().getMethod("getName");
|
|
684
|
+
String n = (String) getName.invoke(p);
|
|
685
|
+
if (n != null && n.equalsIgnoreCase(paletteName)) {
|
|
686
|
+
target = p;
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
} catch (Throwable ignored) {
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
} else if (palettesResult != null && palettesResult.getClass().isArray()) {
|
|
693
|
+
int len = java.lang.reflect.Array.getLength(palettesResult);
|
|
694
|
+
for (int i = 0; i < len; i++) {
|
|
695
|
+
Object p = java.lang.reflect.Array.get(palettesResult, i);
|
|
696
|
+
try {
|
|
697
|
+
Method getName = p.getClass().getMethod("getName");
|
|
698
|
+
String n = (String) getName.invoke(p);
|
|
699
|
+
if (n != null && n.equalsIgnoreCase(paletteName)) {
|
|
700
|
+
target = p;
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
703
|
+
} catch (Throwable ignored) {
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
if (target != null) {
|
|
708
|
+
Class<?> paletteClass = null;
|
|
709
|
+
try {
|
|
710
|
+
paletteClass = findSdkClass("com.flir.thermalsdk.image.palettes.Palette");
|
|
711
|
+
} catch (Throwable ignored) {
|
|
712
|
+
try {
|
|
713
|
+
paletteClass = findSdkClass("com.flir.thermalsdk.image.Palette");
|
|
714
|
+
} catch (Throwable ignored2) {
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (paletteClass == null)
|
|
718
|
+
return false;
|
|
719
|
+
Method setPalette = thermalImage.getClass().getMethod("setPalette", paletteClass);
|
|
720
|
+
setPalette.invoke(thermalImage, target);
|
|
721
|
+
return true;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
} catch (Throwable t) {
|
|
725
|
+
Log.w(TAG, "setPalette failed: " + t.getMessage());
|
|
726
|
+
}
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
public boolean isStreamingActive() {
|
|
731
|
+
return streamerObj != null;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
public String getSdkCurrentStreamKind() {
|
|
735
|
+
return sdkCurrentStreamKind;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
private boolean attachStreamerListener(Object streamer) {
|
|
739
|
+
if (streamer == null)
|
|
740
|
+
return false;
|
|
741
|
+
try {
|
|
742
|
+
Class<?> streamerClass = streamer.getClass();
|
|
743
|
+
String[] candidates = new String[] { "setFrameListener", "setListener", "addListener", "addFrameListener",
|
|
744
|
+
"addStreamListener", "setOnImageAvailableListener", "addImageListener", "setDataListener",
|
|
745
|
+
"subscribe" };
|
|
746
|
+
for (String name : candidates) {
|
|
747
|
+
try {
|
|
748
|
+
for (Method m : streamerClass.getMethods()) {
|
|
749
|
+
if (!m.getName().equalsIgnoreCase(name))
|
|
750
|
+
continue;
|
|
751
|
+
Class<?>[] params = m.getParameterTypes();
|
|
752
|
+
if (params.length != 1 || !params[0].isInterface())
|
|
753
|
+
continue;
|
|
754
|
+
final Class<?> listenerInterface = params[0];
|
|
755
|
+
Object proxy = Proxy.newProxyInstance(listenerInterface.getClassLoader(),
|
|
756
|
+
new Class<?>[] { listenerInterface }, (proxyObj, method, args) -> {
|
|
757
|
+
try {
|
|
758
|
+
Log.d(TAG, "[FLIR SDK] Stream listener method invoked: " + method.getName());
|
|
759
|
+
if (args != null && args.length > 0) {
|
|
760
|
+
for (Object arg : args) {
|
|
761
|
+
if (arg == null)
|
|
762
|
+
continue;
|
|
763
|
+
try {
|
|
764
|
+
Method getFusion = arg.getClass().getMethod("getFusion");
|
|
765
|
+
if (getFusion != null) {
|
|
766
|
+
Object fusion = getFusion.invoke(arg);
|
|
767
|
+
if (fusion != null) {
|
|
768
|
+
try {
|
|
769
|
+
Method getPhoto = fusion.getClass()
|
|
770
|
+
.getMethod("getPhoto");
|
|
771
|
+
Object photo = getPhoto.invoke(fusion);
|
|
772
|
+
if (photo != null) {
|
|
773
|
+
try {
|
|
774
|
+
Method pb = photo.getClass()
|
|
775
|
+
.getMethod("getBitmap");
|
|
776
|
+
Object bmpObj = pb.invoke(photo);
|
|
777
|
+
if (bmpObj instanceof Bitmap) {
|
|
778
|
+
if (listener != null) {
|
|
779
|
+
listener.onFrame((Bitmap) bmpObj);
|
|
780
|
+
Log.d(TAG,
|
|
781
|
+
"[FLIR SDK] Streamer listener delivered bitmap via getBitmap");
|
|
782
|
+
}
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
} catch (Throwable ignored) {
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
} catch (Throwable ignored) {
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
} catch (Throwable ignored) {
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
Method getBitmap = arg.getClass().getMethod("getBitmap");
|
|
796
|
+
Object bmp = getBitmap.invoke(arg);
|
|
797
|
+
if (bmp instanceof Bitmap) {
|
|
798
|
+
if (listener != null) {
|
|
799
|
+
listener.onFrame((Bitmap) bmp);
|
|
800
|
+
Log.d(TAG,
|
|
801
|
+
"[FLIR SDK] Streamer listener delivered bitmap via direct getBitmap");
|
|
802
|
+
}
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
805
|
+
} catch (Throwable ignored) {
|
|
806
|
+
}
|
|
807
|
+
try {
|
|
808
|
+
Method getImage = arg.getClass().getMethod("getImage");
|
|
809
|
+
Object imgObj = getImage.invoke(arg);
|
|
810
|
+
if (imgObj instanceof Bitmap) {
|
|
811
|
+
if (listener != null) {
|
|
812
|
+
listener.onFrame((Bitmap) imgObj);
|
|
813
|
+
Log.d(TAG,
|
|
814
|
+
"[FLIR SDK] Streamer listener delivered bitmap via getImage");
|
|
815
|
+
}
|
|
816
|
+
return null;
|
|
817
|
+
}
|
|
818
|
+
// fallback to BitmapAndroid.createBitmap(imgObj).getBitMap()
|
|
819
|
+
try {
|
|
820
|
+
Class<?> bitmapAndroidClass = findSdkClass(
|
|
821
|
+
"com.flir.thermalsdk.androidsdk.image.BitmapAndroid");
|
|
822
|
+
Method createBitmap = bitmapAndroidClass
|
|
823
|
+
.getMethod("createBitmap", imgObj.getClass());
|
|
824
|
+
Object wrapper = createBitmap.invoke(null, imgObj);
|
|
825
|
+
if (wrapper != null) {
|
|
826
|
+
Method getBitMap = wrapper.getClass()
|
|
827
|
+
.getMethod("getBitMap");
|
|
828
|
+
Object bmpObj = getBitMap.invoke(wrapper);
|
|
829
|
+
if (bmpObj instanceof Bitmap) {
|
|
830
|
+
if (listener != null) {
|
|
831
|
+
listener.onFrame((Bitmap) bmpObj);
|
|
832
|
+
Log.d(TAG,
|
|
833
|
+
"[FLIR SDK] Streamer listener delivered bitmap via BitmapAndroid wrapper");
|
|
834
|
+
}
|
|
835
|
+
return null;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
} catch (Throwable ignored2) {
|
|
839
|
+
}
|
|
840
|
+
} catch (Throwable ignored) {
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
} catch (Throwable t) {
|
|
845
|
+
Log.w(TAG, "Streamer listener failed: " + t.getMessage());
|
|
846
|
+
}
|
|
847
|
+
return null;
|
|
848
|
+
});
|
|
849
|
+
try {
|
|
850
|
+
m.invoke(streamer, proxy);
|
|
851
|
+
} catch (Throwable e) {
|
|
852
|
+
Log.w(TAG, "attach proxy failed: " + e.getMessage(), e);
|
|
853
|
+
continue;
|
|
854
|
+
}
|
|
855
|
+
Log.i(TAG, "Attached streamer listener using: " + m.getName());
|
|
856
|
+
return true;
|
|
857
|
+
}
|
|
858
|
+
} catch (Throwable ignored) {
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
} catch (Throwable t) {
|
|
862
|
+
Log.w(TAG, "attachStreamerListener error: " + t.getMessage());
|
|
863
|
+
}
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
public void stop() {
|
|
868
|
+
try {
|
|
869
|
+
scheduler.shutdownNow();
|
|
870
|
+
if (streamerObj != null) {
|
|
871
|
+
try {
|
|
872
|
+
Method stop = streamerObj.getClass().getMethod("stop");
|
|
873
|
+
if (stop != null)
|
|
874
|
+
stop.invoke(streamerObj);
|
|
875
|
+
} catch (Throwable ignored) {
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
if (cameraObj != null) {
|
|
879
|
+
try {
|
|
880
|
+
Method disconnect = cameraObj.getClass().getMethod("disconnect");
|
|
881
|
+
if (disconnect != null)
|
|
882
|
+
disconnect.invoke(cameraObj);
|
|
883
|
+
} catch (Throwable ignored) {
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
} catch (Throwable t) {
|
|
887
|
+
Log.w(TAG, "Failed to stop SDK manager: " + t.getMessage());
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|