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
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
package flir.android
|
|
2
|
-
|
|
3
|
-
import com.facebook.react.bridge.Promise
|
|
4
|
-
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
|
-
import com.facebook.react.bridge.ReactMethod
|
|
7
|
-
|
|
8
|
-
class FlirModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
|
9
|
-
override fun getName(): String = "FlirModule"
|
|
10
|
-
|
|
11
|
-
// Simple placeholder conversion: converts an ARGB color to a pseudo-temperature value.
|
|
12
|
-
// Replace with SDK call when integrating thermalsdk APIs.
|
|
13
|
-
@ReactMethod
|
|
14
|
-
fun getTemperatureFromColor(color: Int, promise: Promise) {
|
|
15
|
-
try {
|
|
16
|
-
val r = (color shr 16) and 0xFF
|
|
17
|
-
val g = (color shr 8) and 0xFF
|
|
18
|
-
val b = color and 0xFF
|
|
19
|
-
// Luminance-like value scaled to a plausible temperature range (0°C - 400°C)
|
|
20
|
-
val lum = 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
21
|
-
val temp = 0.0 + (lum / 255.0) * 400.0
|
|
22
|
-
promise.resolve(temp)
|
|
23
|
-
} catch (e: Exception) {
|
|
24
|
-
promise.reject("ERR_FLIR_CONVERT", e)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@ReactMethod
|
|
29
|
-
fun getLatestFramePath(promise: Promise) {
|
|
30
|
-
try {
|
|
31
|
-
val path = FlirFrameCache.latestFramePath
|
|
32
|
-
if (path != null) promise.resolve(path) else promise.resolve(null)
|
|
33
|
-
} catch (e: Exception) {
|
|
34
|
-
promise.reject("ERR_FLIR_PATH", e)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
@ReactMethod
|
|
39
|
-
fun getTemperatureAt(x: Int, y: Int, promise: Promise) {
|
|
40
|
-
try {
|
|
41
|
-
val temp = FlirManager.getTemperatureAt(x, y)
|
|
42
|
-
if (temp != null) promise.resolve(temp) else promise.reject("ERR_NO_DATA", "No temperature data available")
|
|
43
|
-
} catch (e: Exception) {
|
|
44
|
-
promise.reject("ERR_FLIR_SAMPLE", e)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@ReactMethod
|
|
49
|
-
fun isEmulator(promise: Promise) {
|
|
50
|
-
try {
|
|
51
|
-
promise.resolve(FlirManager.isEmulator())
|
|
52
|
-
} catch (e: Exception) {
|
|
53
|
-
promise.reject("ERR_FLIR_EMULATOR_CHECK", e)
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@ReactMethod
|
|
58
|
-
fun isDeviceConnected(promise: Promise) {
|
|
59
|
-
try {
|
|
60
|
-
promise.resolve(FlirManager.isDeviceConnected())
|
|
61
|
-
} catch (e: Exception) {
|
|
62
|
-
promise.reject("ERR_FLIR_DEVICE_CHECK", e)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
@ReactMethod
|
|
67
|
-
fun getConnectedDeviceInfo(promise: Promise) {
|
|
68
|
-
try {
|
|
69
|
-
promise.resolve(FlirManager.getConnectedDeviceInfo())
|
|
70
|
-
} catch (e: Exception) {
|
|
71
|
-
promise.reject("ERR_FLIR_DEVICE_INFO", e)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
1
|
+
package flir.android
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Promise
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
|
+
import com.facebook.react.bridge.ReactMethod
|
|
7
|
+
|
|
8
|
+
class FlirModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
|
9
|
+
override fun getName(): String = "FlirModule"
|
|
10
|
+
|
|
11
|
+
// Simple placeholder conversion: converts an ARGB color to a pseudo-temperature value.
|
|
12
|
+
// Replace with SDK call when integrating thermalsdk APIs.
|
|
13
|
+
@ReactMethod
|
|
14
|
+
fun getTemperatureFromColor(color: Int, promise: Promise) {
|
|
15
|
+
try {
|
|
16
|
+
val r = (color shr 16) and 0xFF
|
|
17
|
+
val g = (color shr 8) and 0xFF
|
|
18
|
+
val b = color and 0xFF
|
|
19
|
+
// Luminance-like value scaled to a plausible temperature range (0°C - 400°C)
|
|
20
|
+
val lum = 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
21
|
+
val temp = 0.0 + (lum / 255.0) * 400.0
|
|
22
|
+
promise.resolve(temp)
|
|
23
|
+
} catch (e: Exception) {
|
|
24
|
+
promise.reject("ERR_FLIR_CONVERT", e)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@ReactMethod
|
|
29
|
+
fun getLatestFramePath(promise: Promise) {
|
|
30
|
+
try {
|
|
31
|
+
val path = FlirFrameCache.latestFramePath
|
|
32
|
+
if (path != null) promise.resolve(path) else promise.resolve(null)
|
|
33
|
+
} catch (e: Exception) {
|
|
34
|
+
promise.reject("ERR_FLIR_PATH", e)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@ReactMethod
|
|
39
|
+
fun getTemperatureAt(x: Int, y: Int, promise: Promise) {
|
|
40
|
+
try {
|
|
41
|
+
val temp = FlirManager.getTemperatureAt(x, y)
|
|
42
|
+
if (temp != null) promise.resolve(temp) else promise.reject("ERR_NO_DATA", "No temperature data available")
|
|
43
|
+
} catch (e: Exception) {
|
|
44
|
+
promise.reject("ERR_FLIR_SAMPLE", e)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@ReactMethod
|
|
49
|
+
fun isEmulator(promise: Promise) {
|
|
50
|
+
try {
|
|
51
|
+
promise.resolve(FlirManager.isEmulator())
|
|
52
|
+
} catch (e: Exception) {
|
|
53
|
+
promise.reject("ERR_FLIR_EMULATOR_CHECK", e)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@ReactMethod
|
|
58
|
+
fun isDeviceConnected(promise: Promise) {
|
|
59
|
+
try {
|
|
60
|
+
promise.resolve(FlirManager.isDeviceConnected())
|
|
61
|
+
} catch (e: Exception) {
|
|
62
|
+
promise.reject("ERR_FLIR_DEVICE_CHECK", e)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@ReactMethod
|
|
67
|
+
fun getConnectedDeviceInfo(promise: Promise) {
|
|
68
|
+
try {
|
|
69
|
+
promise.resolve(FlirManager.getConnectedDeviceInfo())
|
|
70
|
+
} catch (e: Exception) {
|
|
71
|
+
promise.reject("ERR_FLIR_DEVICE_INFO", e)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
package flir.android
|
|
2
|
-
|
|
3
|
-
import com.facebook.react.ReactPackage
|
|
4
|
-
import com.facebook.react.bridge.NativeModule
|
|
5
|
-
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
-
import com.facebook.react.uimanager.ViewManager
|
|
7
|
-
|
|
8
|
-
class FlirPackage : ReactPackage {
|
|
9
|
-
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
10
|
-
return listOf(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
package flir.android
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class FlirPackage : ReactPackage {
|
|
9
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
10
|
+
return listOf(
|
|
11
|
+
FlirModule(reactContext),
|
|
12
|
+
FlirDownloadManager(reactContext)
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
17
|
+
return listOf(FlirViewManager())
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -1,191 +1,195 @@
|
|
|
1
|
-
package flir.android
|
|
2
|
-
|
|
3
|
-
import android.content.Context
|
|
4
|
-
import com.google.android.play.core.splitinstall.*
|
|
5
|
-
import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus
|
|
6
|
-
import kotlinx.coroutines.*
|
|
7
|
-
import org.json.JSONObject
|
|
8
|
-
import java.io.File
|
|
9
|
-
import java.io.FileOutputStream
|
|
10
|
-
import java.net.URL
|
|
11
|
-
import java.security.MessageDigest
|
|
12
|
-
import java.util.zip.ZipInputStream
|
|
13
|
-
|
|
14
|
-
object FlirSDKLoader {
|
|
15
|
-
|
|
16
|
-
private const val FEATURE_MODULE = "flir_sdk"
|
|
17
|
-
private var splitInstallManager: SplitInstallManager? = null
|
|
18
|
-
|
|
19
|
-
fun init(context: Context) {
|
|
20
|
-
splitInstallManager = SplitInstallManagerFactory.create(context)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
private fun getSDKDirectory(context: Context) = File(context.filesDir, "FlirSDK")
|
|
24
|
-
|
|
25
|
-
fun isSDKAvailable(context: Context): Boolean {
|
|
26
|
-
// Check Play Feature module
|
|
27
|
-
splitInstallManager?.installedModules?.let {
|
|
28
|
-
if (FEATURE_MODULE in it) return true
|
|
29
|
-
}
|
|
30
|
-
// Check direct download
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
val
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
val
|
|
80
|
-
val
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
val
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
1
|
+
package flir.android
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.google.android.play.core.splitinstall.*
|
|
5
|
+
import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus
|
|
6
|
+
import kotlinx.coroutines.*
|
|
7
|
+
import org.json.JSONObject
|
|
8
|
+
import java.io.File
|
|
9
|
+
import java.io.FileOutputStream
|
|
10
|
+
import java.net.URL
|
|
11
|
+
import java.security.MessageDigest
|
|
12
|
+
import java.util.zip.ZipInputStream
|
|
13
|
+
|
|
14
|
+
object FlirSDKLoader {
|
|
15
|
+
|
|
16
|
+
private const val FEATURE_MODULE = "flir_sdk"
|
|
17
|
+
private var splitInstallManager: SplitInstallManager? = null
|
|
18
|
+
|
|
19
|
+
fun init(context: Context) {
|
|
20
|
+
splitInstallManager = SplitInstallManagerFactory.create(context)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private fun getSDKDirectory(context: Context) = File(context.filesDir, "FlirSDK")
|
|
24
|
+
|
|
25
|
+
fun isSDKAvailable(context: Context): Boolean {
|
|
26
|
+
// Check Play Feature module
|
|
27
|
+
splitInstallManager?.installedModules?.let {
|
|
28
|
+
if (FEATURE_MODULE in it) return true
|
|
29
|
+
}
|
|
30
|
+
// Check direct download - look for either file from the manifest
|
|
31
|
+
val sdkDir = getSDKDirectory(context)
|
|
32
|
+
return File(sdkDir, "thermalsdk-release.aar").exists() ||
|
|
33
|
+
File(sdkDir, "androidsdk-release.aar").exists() ||
|
|
34
|
+
File(sdkDir, "thermalsdk.aar").exists()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fun getDownloadSize(context: Context): Long {
|
|
38
|
+
return loadManifest(context)?.android?.directDownload?.sizeBytes ?: 52_428_800L
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fun downloadViaPlayStore(
|
|
42
|
+
onProgress: (Float) -> Unit,
|
|
43
|
+
onComplete: () -> Unit,
|
|
44
|
+
onError: (String) -> Unit
|
|
45
|
+
) {
|
|
46
|
+
val manager = splitInstallManager ?: run {
|
|
47
|
+
onError("SplitInstallManager not initialized")
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
val request = SplitInstallRequest.newBuilder()
|
|
52
|
+
.addModule(FEATURE_MODULE)
|
|
53
|
+
.build()
|
|
54
|
+
|
|
55
|
+
manager.registerListener { state ->
|
|
56
|
+
when (state.status()) {
|
|
57
|
+
SplitInstallSessionStatus.DOWNLOADING -> {
|
|
58
|
+
val progress = state.bytesDownloaded().toFloat() / state.totalBytesToDownload()
|
|
59
|
+
onProgress(progress)
|
|
60
|
+
}
|
|
61
|
+
SplitInstallSessionStatus.INSTALLED -> onComplete()
|
|
62
|
+
SplitInstallSessionStatus.FAILED -> onError("Install failed: ${state.errorCode()}")
|
|
63
|
+
else -> {}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
manager.startInstall(request)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
suspend fun downloadDirect(
|
|
71
|
+
context: Context,
|
|
72
|
+
onProgress: (downloaded: Long, total: Long) -> Unit
|
|
73
|
+
): Result<Unit> = withContext(Dispatchers.IO) {
|
|
74
|
+
try {
|
|
75
|
+
val manifest = loadManifest(context) ?: return@withContext Result.failure(
|
|
76
|
+
Exception("Failed to load manifest")
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
val downloadUrl = manifest.android.directDownload.downloadUrl
|
|
80
|
+
val expectedHash = manifest.android.directDownload.sha256
|
|
81
|
+
val totalSize = manifest.android.directDownload.sizeBytes
|
|
82
|
+
|
|
83
|
+
val sdkDir = getSDKDirectory(context).apply { mkdirs() }
|
|
84
|
+
val zipFile = File(context.cacheDir, "flir-sdk.zip")
|
|
85
|
+
|
|
86
|
+
// Download
|
|
87
|
+
URL(downloadUrl).openStream().use { input ->
|
|
88
|
+
FileOutputStream(zipFile).use { output ->
|
|
89
|
+
val buffer = ByteArray(8192)
|
|
90
|
+
var totalRead = 0L
|
|
91
|
+
var bytesRead: Int
|
|
92
|
+
|
|
93
|
+
while (input.read(buffer).also { bytesRead = it } != -1) {
|
|
94
|
+
output.write(buffer, 0, bytesRead)
|
|
95
|
+
totalRead += bytesRead
|
|
96
|
+
withContext(Dispatchers.Main) {
|
|
97
|
+
onProgress(totalRead, totalSize)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Verify checksum
|
|
104
|
+
val actualHash = sha256(zipFile)
|
|
105
|
+
if (actualHash != expectedHash) {
|
|
106
|
+
zipFile.delete()
|
|
107
|
+
return@withContext Result.failure(SecurityException("Checksum mismatch"))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Extract
|
|
111
|
+
unzip(zipFile, sdkDir)
|
|
112
|
+
zipFile.delete()
|
|
113
|
+
|
|
114
|
+
Result.success(Unit)
|
|
115
|
+
} catch (e: Exception) {
|
|
116
|
+
Result.failure(e)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fun deleteSDK(context: Context): Boolean {
|
|
121
|
+
splitInstallManager?.deferredUninstall(listOf(FEATURE_MODULE))
|
|
122
|
+
return getSDKDirectory(context).deleteRecursively()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private fun loadManifest(context: Context): SDKManifest? {
|
|
126
|
+
return try {
|
|
127
|
+
val json = context.assets.open("sdk-manifest.json").bufferedReader().readText()
|
|
128
|
+
SDKManifest.fromJson(json)
|
|
129
|
+
} catch (e: Exception) { null }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private fun sha256(file: File): String {
|
|
133
|
+
val digest = MessageDigest.getInstance("SHA-256")
|
|
134
|
+
file.inputStream().use { input ->
|
|
135
|
+
val buffer = ByteArray(8192)
|
|
136
|
+
var bytesRead: Int
|
|
137
|
+
while (input.read(buffer).also { bytesRead = it } != -1) {
|
|
138
|
+
digest.update(buffer, 0, bytesRead)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return digest.digest().joinToString("") { "%02x".format(it) }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private fun unzip(source: File, destination: File) {
|
|
145
|
+
ZipInputStream(source.inputStream()).use { zip ->
|
|
146
|
+
var entry = zip.nextEntry
|
|
147
|
+
while (entry != null) {
|
|
148
|
+
val file = File(destination, entry.name)
|
|
149
|
+
if (entry.isDirectory) {
|
|
150
|
+
file.mkdirs()
|
|
151
|
+
} else {
|
|
152
|
+
file.parentFile?.mkdirs()
|
|
153
|
+
file.outputStream().use { zip.copyTo(it) }
|
|
154
|
+
}
|
|
155
|
+
entry = zip.nextEntry
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
data class SDKManifest(
|
|
162
|
+
val version: String,
|
|
163
|
+
val android: AndroidManifest
|
|
164
|
+
) {
|
|
165
|
+
data class AndroidManifest(
|
|
166
|
+
val playFeatureModule: String,
|
|
167
|
+
val directDownload: DirectDownload
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
data class DirectDownload(
|
|
171
|
+
val downloadUrl: String,
|
|
172
|
+
val sha256: String,
|
|
173
|
+
val sizeBytes: Long
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
companion object {
|
|
177
|
+
fun fromJson(json: String): SDKManifest {
|
|
178
|
+
val root = JSONObject(json)
|
|
179
|
+
val android = root.getJSONObject("android")
|
|
180
|
+
val direct = android.getJSONObject("directDownload")
|
|
181
|
+
|
|
182
|
+
return SDKManifest(
|
|
183
|
+
version = root.getString("version"),
|
|
184
|
+
android = AndroidManifest(
|
|
185
|
+
playFeatureModule = android.getString("playFeatureModule"),
|
|
186
|
+
directDownload = DirectDownload(
|
|
187
|
+
downloadUrl = direct.getString("downloadUrl"),
|
|
188
|
+
sha256 = direct.getString("sha256"),
|
|
189
|
+
sizeBytes = direct.getLong("sizeBytes")
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|