Navaron Bracke

Clean up activity lifecycle handling

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