diff --git a/android/build.gradle b/android/build.gradle index 80bbfaa..437c6b4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -34,7 +34,8 @@ android { main.java.srcDirs += 'src/main/kotlin' } defaultConfig { - minSdkVersion 19 + // minSdkVersion is determined by Native View. + minSdkVersion 20 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } lintOptions { diff --git a/android/src/main/kotlin/net/touchcapture/qr/flutterqr/FlutterQrPlugin.kt b/android/src/main/kotlin/net/touchcapture/qr/flutterqr/FlutterQrPlugin.kt index 9336335..ca59f08 100644 --- a/android/src/main/kotlin/net/touchcapture/qr/flutterqr/FlutterQrPlugin.kt +++ b/android/src/main/kotlin/net/touchcapture/qr/flutterqr/FlutterQrPlugin.kt @@ -1,25 +1,118 @@ package net.touchcapture.qr.flutterqr +import android.Manifest +import android.content.pm.PackageManager +import android.os.Build +import androidx.annotation.NonNull +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result -import io.flutter.plugin.common.PluginRegistry.Registrar +import io.flutter.plugin.common.PluginRegistry +import io.flutter.plugin.platform.PlatformViewRegistry -class FlutterQrPlugin : MethodCallHandler { + +class FlutterQrPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { + + var cameraPermissionContinuation: Runnable? = null + var requestingPermission = false + + /** Plugin registration embedding v1 */ companion object { @JvmStatic - fun registerWith(registrar: Registrar) { - registrar - .platformViewRegistry() - .registerViewFactory( - "net.touchcapture.qr.flutterqr/qrview", QRViewFactory(registrar)) + fun registerWith(registrar: PluginRegistry.Registrar) { + FlutterQrPlugin().onAttachedToV1(registrar) } } + private fun onAttachedToV1(registrar: PluginRegistry.Registrar) { + Shared.activity = registrar.activity() + registrar.addRequestPermissionsResultListener(CameraRequestPermissionsListener()) + checkAndRequestPermission(null) + onAttachedToEngines(registrar.platformViewRegistry(), registrar.messenger()) + } + + /** Plugin registration embedding v2 */ + override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + onAttachedToEngines(flutterPluginBinding.platformViewRegistry, flutterPluginBinding.binaryMessenger) + } + + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { + } + + /** Plugin start for both embedding v1 & v2 */ + private fun onAttachedToEngines(platformViewRegistry: PlatformViewRegistry, messenger: BinaryMessenger) { + platformViewRegistry + .registerViewFactory( + "net.touchcapture.qr.flutterqr/qrview", QRViewFactory(messenger)) + } + override fun onMethodCall(call: MethodCall, result: Result) { - when { - call.method == "getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}") - else -> result.notImplemented() + when (call.method) { + "checkAndRequestPermission" -> checkAndRequestPermission(result) + } + } + + override fun onAttachedToActivity(activityPluginBinding: ActivityPluginBinding) { + Shared.activity = activityPluginBinding.activity + activityPluginBinding.addRequestPermissionsResultListener(CameraRequestPermissionsListener()) + checkAndRequestPermission(null) + } + + override fun onDetachedFromActivityForConfigChanges() { + Shared.activity = null + } + + override fun onReattachedToActivityForConfigChanges(activityPluginBinding: ActivityPluginBinding) { + Shared.activity = activityPluginBinding.activity + } + + override fun onDetachedFromActivity() { + Shared.activity = null + } + + private inner class CameraRequestPermissionsListener : PluginRegistry.RequestPermissionsResultListener { + override fun onRequestPermissionsResult(id: Int, permissions: Array, grantResults: IntArray): Boolean { + if (id == QRView.CAMERA_REQUEST_ID && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + cameraPermissionContinuation?.run() + return true + } + return false + } + } + + private fun hasCameraPermission(): Boolean { + return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || + Shared.activity?.checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED + } + + private fun checkAndRequestPermission(result: Result?) { + if (cameraPermissionContinuation != null) { + result?.error("cameraPermission", "Camera permission request ongoing", null) + } + + cameraPermissionContinuation = Runnable { + cameraPermissionContinuation = null + if (!hasCameraPermission()) { + result?.error( + "cameraPermission", "MediaRecorderCamera permission not granted", null) + return@Runnable + } + } + + requestingPermission = false + if (hasCameraPermission()) { + cameraPermissionContinuation?.run() + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestingPermission = true + Shared.activity?.requestPermissions( + arrayOf(Manifest.permission.CAMERA), + QRView.CAMERA_REQUEST_ID) + } } } } diff --git a/android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRView.kt b/android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRView.kt index ae6260c..ede6fc2 100644 --- a/android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRView.kt +++ b/android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRView.kt @@ -1,12 +1,9 @@ package net.touchcapture.qr.flutterqr -import android.Manifest import android.app.Activity import android.app.Application import android.content.Context import android.content.pm.PackageManager -import android.content.pm.PackageManager.PERMISSION_GRANTED -import android.os.Build import android.os.Bundle import android.view.View import com.google.zxing.ResultPoint @@ -14,39 +11,34 @@ import android.hardware.Camera.CameraInfo import com.journeyapps.barcodescanner.BarcodeCallback import com.journeyapps.barcodescanner.BarcodeResult import com.journeyapps.barcodescanner.BarcodeView +import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.common.PluginRegistry import io.flutter.plugin.platform.PlatformView - -class QRView(private val registrar: PluginRegistry.Registrar, id: Int) : - PlatformView,MethodChannel.MethodCallHandler { +class QRView(messenger: BinaryMessenger, id: Int, private val context: Context) : + PlatformView, MethodChannel.MethodCallHandler { companion object { const val CAMERA_REQUEST_ID = 513469796 } var barcodeView: BarcodeView? = null - private val activity = registrar.activity() - var cameraPermissionContinuation: Runnable? = null - var requestingPermission = false + private var isTorchOn: Boolean = false val channel: MethodChannel init { - registrar.addRequestPermissionsResultListener(CameraRequestPermissionsListener()) - channel = MethodChannel(registrar.messenger(), "net.touchcapture.qr.flutterqr/qrview_$id") + channel = MethodChannel(messenger, "net.touchcapture.qr.flutterqr/qrview_$id") channel.setMethodCallHandler(this) - checkAndRequestPermission(null) - registrar.activity().application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { + Shared.activity?.application?.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { override fun onActivityPaused(p0: Activity) { - if (p0 == registrar.activity()) { + if (p0 == Shared.activity) { barcodeView?.pause() } } override fun onActivityResumed(p0: Activity) { - if (p0 == registrar.activity()) { + if (p0 == Shared.activity) { barcodeView?.resume() } } @@ -102,7 +94,7 @@ class QRView(private val registrar: PluginRegistry.Registrar, id: Int) : } private fun hasFlash(): Boolean { - return registrar.activeContext().packageManager + return context.packageManager .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH) } @@ -120,7 +112,7 @@ class QRView(private val registrar: PluginRegistry.Registrar, id: Int) : } private fun createBarCodeView(): BarcodeView? { - val barcode = BarcodeView(registrar.activity()) + val barcode = BarcodeView(Shared.activity) barcode.decodeContinuous( object : BarcodeCallback { override fun barcodeResult(result: BarcodeResult) { @@ -138,27 +130,8 @@ class QRView(private val registrar: PluginRegistry.Registrar, id: Int) : barcodeView = null } - private inner class CameraRequestPermissionsListener : PluginRegistry.RequestPermissionsResultListener { - override fun onRequestPermissionsResult(id: Int, permissions: Array, grantResults: IntArray): Boolean { - if (id == CAMERA_REQUEST_ID && grantResults[0] == PERMISSION_GRANTED) { - cameraPermissionContinuation?.run() - return true - } - return false - } - } - - private fun hasCameraPermission(): Boolean { - return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || - activity.checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED - } - - override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { - when(call?.method){ - "checkAndRequestPermission" -> { - checkAndRequestPermission(result) - } + when(call.method){ "flipCamera" -> { flipCamera() } @@ -174,33 +147,6 @@ class QRView(private val registrar: PluginRegistry.Registrar, id: Int) : } } - private fun checkAndRequestPermission(result: MethodChannel.Result?) { - if (cameraPermissionContinuation != null) { - result?.error("cameraPermission", "Camera permission request ongoing", null); - } - - cameraPermissionContinuation = Runnable { - cameraPermissionContinuation = null - if (!hasCameraPermission()) { - result?.error( - "cameraPermission", "MediaRecorderCamera permission not granted", null) - return@Runnable - } - } - requestingPermission = false - if (hasCameraPermission()) { - cameraPermissionContinuation?.run() - } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - requestingPermission = true - registrar - .activity() - .requestPermissions( - arrayOf(Manifest.permission.CAMERA), - CAMERA_REQUEST_ID) - } - } - } } diff --git a/android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRViewFactory.kt b/android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRViewFactory.kt index f9be661..a797084 100644 --- a/android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRViewFactory.kt +++ b/android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRViewFactory.kt @@ -1,17 +1,17 @@ package net.touchcapture.qr.flutterqr import android.content.Context -import io.flutter.plugin.common.PluginRegistry +import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.StandardMessageCodec import io.flutter.plugin.platform.PlatformView import io.flutter.plugin.platform.PlatformViewFactory -class QRViewFactory(private val registrar: PluginRegistry.Registrar) : +class QRViewFactory(private val messenger: BinaryMessenger) : PlatformViewFactory(StandardMessageCodec.INSTANCE) { override fun create(context: Context, id: Int, obj: Any?): PlatformView { - return QRView(registrar,id) + return QRView(messenger, id, context) } } \ No newline at end of file diff --git a/android/src/main/kotlin/net/touchcapture/qr/flutterqr/Shared.kt b/android/src/main/kotlin/net/touchcapture/qr/flutterqr/Shared.kt new file mode 100644 index 0000000..7823e01 --- /dev/null +++ b/android/src/main/kotlin/net/touchcapture/qr/flutterqr/Shared.kt @@ -0,0 +1,9 @@ +package net.touchcapture.qr.flutterqr + +import android.app.Activity +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding + + +object Shared { + var activity: Activity? = null +} \ No newline at end of file diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 18b4d50..a2c7d06 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -38,7 +38,8 @@ android { defaultConfig { applicationId "net.touchcapture.qr.flutterqrexample" - minSdkVersion 19 + // minSdkVersion is determined by Native View. + minSdkVersion 20 targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 8a40bfb..3407805 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -13,7 +13,6 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> - + + + android:name="io.flutter.embedding.android.SplashScreenDrawable" + android:resource="@drawable/launch_background" /> + + + diff --git a/example/android/app/src/main/kotlin/net/touchcapture/qr/flutterqrexample/MainActivity.kt b/example/android/app/src/main/kotlin/net/touchcapture/qr/flutterqrexample/MainActivity.kt index fcdee63..3a276af 100644 --- a/example/android/app/src/main/kotlin/net/touchcapture/qr/flutterqrexample/MainActivity.kt +++ b/example/android/app/src/main/kotlin/net/touchcapture/qr/flutterqrexample/MainActivity.kt @@ -1,13 +1,6 @@ package net.touchcapture.qr.flutterqrexample -import android.os.Bundle - -import io.flutter.app.FlutterActivity -import io.flutter.plugins.GeneratedPluginRegistrant +import io.flutter.embedding.android.FlutterActivity class MainActivity: FlutterActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - GeneratedPluginRegistrant.registerWith(this) - } } diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index 00fa441..3257023 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -1,8 +1,19 @@ + + + +