Showing
1 changed file
with
217 additions
and
0 deletions
| 1 | +package dev.steenbakker.mobile_scanner | ||
| 2 | + | ||
| 3 | +import android.app.Activity | ||
| 4 | +import android.net.Uri | ||
| 5 | +import androidx.camera.core.CameraSelector | ||
| 6 | +import androidx.camera.core.ExperimentalGetImage | ||
| 7 | +import com.google.mlkit.vision.barcode.BarcodeScannerOptions | ||
| 8 | +import dev.steenbakker.mobile_scanner.objects.BarcodeFormats | ||
| 9 | +import dev.steenbakker.mobile_scanner.objects.DetectionSpeed | ||
| 10 | +import io.flutter.plugin.common.BinaryMessenger | ||
| 11 | +import io.flutter.plugin.common.MethodCall | ||
| 12 | +import io.flutter.plugin.common.MethodChannel | ||
| 13 | +import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener | ||
| 14 | +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding | ||
| 15 | +import io.flutter.view.TextureRegistry | ||
| 16 | +import java.io.File | ||
| 17 | + | ||
| 18 | +class MethodCallHandlerImpl( | ||
| 19 | + private val activity: Activity, | ||
| 20 | + private val barcodeHandler: BarcodeHandler, | ||
| 21 | + binaryMessenger: BinaryMessenger, | ||
| 22 | + private val permissions: MobileScannerPermissions, | ||
| 23 | + private val permissionsRegistry: MobileScannerPermissions.PermissionsRegistry, | ||
| 24 | + textureRegistry: TextureRegistry): MethodChannel.MethodCallHandler { | ||
| 25 | + | ||
| 26 | + private val analyzerCallback: AnalyzerCallback = { barcodes: List<Map<String, Any?>>?-> | ||
| 27 | + if (barcodes != null) { | ||
| 28 | + barcodeHandler.publishEvent(mapOf( | ||
| 29 | + "name" to "barcode", | ||
| 30 | + "data" to barcodes | ||
| 31 | + )) | ||
| 32 | + analyzerResult?.success(true) | ||
| 33 | + } else { | ||
| 34 | + analyzerResult?.success(false) | ||
| 35 | + } | ||
| 36 | + analyzerResult = null | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + private var analyzerResult: MethodChannel.Result? = null | ||
| 40 | + | ||
| 41 | + private val callback: MobileScannerCallback = { barcodes: List<Map<String, Any?>>, image: ByteArray? -> | ||
| 42 | + if (image != null) { | ||
| 43 | + barcodeHandler.publishEvent(mapOf( | ||
| 44 | + "name" to "barcode", | ||
| 45 | + "data" to barcodes, | ||
| 46 | + "image" to image | ||
| 47 | + )) | ||
| 48 | + } else { | ||
| 49 | + barcodeHandler.publishEvent(mapOf( | ||
| 50 | + "name" to "barcode", | ||
| 51 | + "data" to barcodes | ||
| 52 | + )) | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + private val errorCallback: MobileScannerErrorCallback = {error: String -> | ||
| 57 | + barcodeHandler.publishEvent(mapOf( | ||
| 58 | + "name" to "error", | ||
| 59 | + "data" to error, | ||
| 60 | + )) | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + private var methodChannel: MethodChannel? = null | ||
| 64 | + | ||
| 65 | + private var mobileScanner: MobileScanner? = null | ||
| 66 | + | ||
| 67 | + private val torchStateCallback: TorchStateCallback = {state: Int -> | ||
| 68 | + barcodeHandler.publishEvent(mapOf("name" to "torchState", "data" to state)) | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + init { | ||
| 72 | + methodChannel = MethodChannel(binaryMessenger, | ||
| 73 | + "dev.steenbakker.mobile_scanner/scanner/method") | ||
| 74 | + methodChannel!!.setMethodCallHandler(this) | ||
| 75 | + mobileScanner = MobileScanner(activity, textureRegistry, callback, errorCallback) | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + fun dispose(activityPluginBinding: ActivityPluginBinding) { | ||
| 79 | + methodChannel?.setMethodCallHandler(null) | ||
| 80 | + methodChannel = null | ||
| 81 | + mobileScanner = null | ||
| 82 | + | ||
| 83 | + val listener: RequestPermissionsResultListener? = permissions.getPermissionListener() | ||
| 84 | + | ||
| 85 | + if(listener != null) { | ||
| 86 | + activityPluginBinding.removeRequestPermissionsResultListener(listener) | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + @ExperimentalGetImage | ||
| 92 | + override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { | ||
| 93 | + if (mobileScanner == null) { | ||
| 94 | + result.error("MobileScanner", "Called ${call.method} before initializing.", null) | ||
| 95 | + return | ||
| 96 | + } | ||
| 97 | + when (call.method) { | ||
| 98 | + "state" -> result.success(permissions.hasCameraPermission(activity)) | ||
| 99 | + "request" -> permissions.requestPermission( | ||
| 100 | + activity, | ||
| 101 | + permissionsRegistry, | ||
| 102 | + object: MobileScannerPermissions.ResultCallback { | ||
| 103 | + override fun onResult(errorCode: String?, errorDescription: String?) { | ||
| 104 | + if(errorCode == null) { | ||
| 105 | + result.success(true) | ||
| 106 | + return | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + result.error(errorCode, errorDescription, null) | ||
| 110 | + } | ||
| 111 | + }) | ||
| 112 | + "start" -> start(call, result) | ||
| 113 | + "torch" -> toggleTorch(call, result) | ||
| 114 | + "stop" -> stop(result) | ||
| 115 | + "analyzeImage" -> analyzeImage(call, result) | ||
| 116 | + else -> result.notImplemented() | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + @ExperimentalGetImage | ||
| 121 | + private fun start(call: MethodCall, result: MethodChannel.Result) { | ||
| 122 | + val torch: Boolean = call.argument<Boolean>("torch") ?: false | ||
| 123 | + val facing: Int = call.argument<Int>("facing") ?: 0 | ||
| 124 | + val formats: List<Int>? = call.argument<List<Int>>("formats") | ||
| 125 | + val returnImage: Boolean = call.argument<Boolean>("returnImage") ?: false | ||
| 126 | + val speed: Int = call.argument<Int>("speed") ?: 1 | ||
| 127 | + val timeout: Int = call.argument<Int>("timeout") ?: 250 | ||
| 128 | + | ||
| 129 | + var barcodeScannerOptions: BarcodeScannerOptions? = null | ||
| 130 | + if (formats != null) { | ||
| 131 | + val formatsList: MutableList<Int> = mutableListOf() | ||
| 132 | + for (index in formats) { | ||
| 133 | + formatsList.add(BarcodeFormats.values()[index].intValue) | ||
| 134 | + } | ||
| 135 | + barcodeScannerOptions = if (formatsList.size == 1) { | ||
| 136 | + BarcodeScannerOptions.Builder().setBarcodeFormats(formatsList.first()) | ||
| 137 | + .build() | ||
| 138 | + } else { | ||
| 139 | + BarcodeScannerOptions.Builder().setBarcodeFormats( | ||
| 140 | + formatsList.first(), | ||
| 141 | + *formatsList.subList(1, formatsList.size).toIntArray() | ||
| 142 | + ).build() | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + val position = | ||
| 147 | + if (facing == 0) CameraSelector.DEFAULT_FRONT_CAMERA else CameraSelector.DEFAULT_BACK_CAMERA | ||
| 148 | + | ||
| 149 | + val detectionSpeed: DetectionSpeed = DetectionSpeed.values().first { it.intValue == speed} | ||
| 150 | + | ||
| 151 | + try { | ||
| 152 | + mobileScanner!!.start(barcodeScannerOptions, returnImage, position, torch, detectionSpeed, torchStateCallback, mobileScannerStartedCallback = { | ||
| 153 | + result.success(mapOf( | ||
| 154 | + "textureId" to it.id, | ||
| 155 | + "size" to mapOf("width" to it.width, "height" to it.height), | ||
| 156 | + "torchable" to it.hasFlashUnit | ||
| 157 | + )) | ||
| 158 | + }, | ||
| 159 | + timeout.toLong()) | ||
| 160 | + | ||
| 161 | + } catch (e: AlreadyStarted) { | ||
| 162 | + result.error( | ||
| 163 | + "MobileScanner", | ||
| 164 | + "Called start() while already started", | ||
| 165 | + null | ||
| 166 | + ) | ||
| 167 | + } catch (e: NoCamera) { | ||
| 168 | + result.error( | ||
| 169 | + "MobileScanner", | ||
| 170 | + "No camera found or failed to open camera!", | ||
| 171 | + null | ||
| 172 | + ) | ||
| 173 | + } catch (e: TorchError) { | ||
| 174 | + result.error( | ||
| 175 | + "MobileScanner", | ||
| 176 | + "Error occurred when setting torch!", | ||
| 177 | + null | ||
| 178 | + ) | ||
| 179 | + } catch (e: CameraError) { | ||
| 180 | + result.error( | ||
| 181 | + "MobileScanner", | ||
| 182 | + "Error occurred when setting up camera!", | ||
| 183 | + null | ||
| 184 | + ) | ||
| 185 | + } catch (e: Exception) { | ||
| 186 | + result.error( | ||
| 187 | + "MobileScanner", | ||
| 188 | + "Unknown error occurred..", | ||
| 189 | + null | ||
| 190 | + ) | ||
| 191 | + } | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + private fun stop(result: MethodChannel.Result) { | ||
| 195 | + try { | ||
| 196 | + mobileScanner!!.stop() | ||
| 197 | + result.success(null) | ||
| 198 | + } catch (e: AlreadyStopped) { | ||
| 199 | + result.success(null) | ||
| 200 | + } | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + private fun analyzeImage(call: MethodCall, result: MethodChannel.Result) { | ||
| 204 | + analyzerResult = result | ||
| 205 | + val uri = Uri.fromFile(File(call.arguments.toString())) | ||
| 206 | + mobileScanner!!.analyzeImage(uri, analyzerCallback) | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + private fun toggleTorch(call: MethodCall, result: MethodChannel.Result) { | ||
| 210 | + try { | ||
| 211 | + mobileScanner!!.toggleTorch(call.arguments == 1) | ||
| 212 | + result.success(null) | ||
| 213 | + } catch (e: AlreadyStopped) { | ||
| 214 | + result.error("MobileScanner", "Called toggleTorch() while stopped!", null) | ||
| 215 | + } | ||
| 216 | + } | ||
| 217 | +} |
-
Please register or login to post a comment