Navaron Bracke

Move method call impl to different class

  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 +}