132 embedding v2flutter-beta
| @@ -34,7 +34,8 @@ android { | |||||
| main.java.srcDirs += 'src/main/kotlin' | main.java.srcDirs += 'src/main/kotlin' | ||||
| } | } | ||||
| defaultConfig { | defaultConfig { | ||||
| minSdkVersion 19 | |||||
| // minSdkVersion is determined by Native View. | |||||
| minSdkVersion 20 | |||||
| testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | ||||
| } | } | ||||
| lintOptions { | lintOptions { | ||||
| @@ -1,25 +1,118 @@ | |||||
| package net.touchcapture.qr.flutterqr | 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.MethodCall | ||||
| import io.flutter.plugin.common.MethodChannel.MethodCallHandler | import io.flutter.plugin.common.MethodChannel.MethodCallHandler | ||||
| import io.flutter.plugin.common.MethodChannel.Result | 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 { | companion object { | ||||
| @JvmStatic | @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) { | 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<String>, 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) | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,12 +1,9 @@ | |||||
| package net.touchcapture.qr.flutterqr | package net.touchcapture.qr.flutterqr | ||||
| import android.Manifest | |||||
| import android.app.Activity | import android.app.Activity | ||||
| import android.app.Application | import android.app.Application | ||||
| import android.content.Context | import android.content.Context | ||||
| import android.content.pm.PackageManager | import android.content.pm.PackageManager | ||||
| import android.content.pm.PackageManager.PERMISSION_GRANTED | |||||
| import android.os.Build | |||||
| import android.os.Bundle | import android.os.Bundle | ||||
| import android.view.View | import android.view.View | ||||
| import com.google.zxing.ResultPoint | import com.google.zxing.ResultPoint | ||||
| @@ -14,39 +11,34 @@ import android.hardware.Camera.CameraInfo | |||||
| import com.journeyapps.barcodescanner.BarcodeCallback | import com.journeyapps.barcodescanner.BarcodeCallback | ||||
| import com.journeyapps.barcodescanner.BarcodeResult | import com.journeyapps.barcodescanner.BarcodeResult | ||||
| import com.journeyapps.barcodescanner.BarcodeView | import com.journeyapps.barcodescanner.BarcodeView | ||||
| import io.flutter.plugin.common.BinaryMessenger | |||||
| import io.flutter.plugin.common.MethodCall | import io.flutter.plugin.common.MethodCall | ||||
| import io.flutter.plugin.common.MethodChannel | import io.flutter.plugin.common.MethodChannel | ||||
| import io.flutter.plugin.common.PluginRegistry | |||||
| import io.flutter.plugin.platform.PlatformView | 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 { | companion object { | ||||
| const val CAMERA_REQUEST_ID = 513469796 | const val CAMERA_REQUEST_ID = 513469796 | ||||
| } | } | ||||
| var barcodeView: BarcodeView? = null | var barcodeView: BarcodeView? = null | ||||
| private val activity = registrar.activity() | |||||
| var cameraPermissionContinuation: Runnable? = null | |||||
| var requestingPermission = false | |||||
| private var isTorchOn: Boolean = false | private var isTorchOn: Boolean = false | ||||
| val channel: MethodChannel | val channel: MethodChannel | ||||
| init { | 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) | channel.setMethodCallHandler(this) | ||||
| checkAndRequestPermission(null) | |||||
| registrar.activity().application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { | |||||
| Shared.activity?.application?.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks { | |||||
| override fun onActivityPaused(p0: Activity) { | override fun onActivityPaused(p0: Activity) { | ||||
| if (p0 == registrar.activity()) { | |||||
| if (p0 == Shared.activity) { | |||||
| barcodeView?.pause() | barcodeView?.pause() | ||||
| } | } | ||||
| } | } | ||||
| override fun onActivityResumed(p0: Activity) { | override fun onActivityResumed(p0: Activity) { | ||||
| if (p0 == registrar.activity()) { | |||||
| if (p0 == Shared.activity) { | |||||
| barcodeView?.resume() | barcodeView?.resume() | ||||
| } | } | ||||
| } | } | ||||
| @@ -102,7 +94,7 @@ class QRView(private val registrar: PluginRegistry.Registrar, id: Int) : | |||||
| } | } | ||||
| private fun hasFlash(): Boolean { | private fun hasFlash(): Boolean { | ||||
| return registrar.activeContext().packageManager | |||||
| return context.packageManager | |||||
| .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH) | .hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH) | ||||
| } | } | ||||
| @@ -120,7 +112,7 @@ class QRView(private val registrar: PluginRegistry.Registrar, id: Int) : | |||||
| } | } | ||||
| private fun createBarCodeView(): BarcodeView? { | private fun createBarCodeView(): BarcodeView? { | ||||
| val barcode = BarcodeView(registrar.activity()) | |||||
| val barcode = BarcodeView(Shared.activity) | |||||
| barcode.decodeContinuous( | barcode.decodeContinuous( | ||||
| object : BarcodeCallback { | object : BarcodeCallback { | ||||
| override fun barcodeResult(result: BarcodeResult) { | override fun barcodeResult(result: BarcodeResult) { | ||||
| @@ -138,27 +130,8 @@ class QRView(private val registrar: PluginRegistry.Registrar, id: Int) : | |||||
| barcodeView = null | barcodeView = null | ||||
| } | } | ||||
| private inner class CameraRequestPermissionsListener : PluginRegistry.RequestPermissionsResultListener { | |||||
| override fun onRequestPermissionsResult(id: Int, permissions: Array<String>, 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) { | override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { | ||||
| when(call?.method){ | |||||
| "checkAndRequestPermission" -> { | |||||
| checkAndRequestPermission(result) | |||||
| } | |||||
| when(call.method){ | |||||
| "flipCamera" -> { | "flipCamera" -> { | ||||
| 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) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -1,17 +1,17 @@ | |||||
| package net.touchcapture.qr.flutterqr | package net.touchcapture.qr.flutterqr | ||||
| import android.content.Context | 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.common.StandardMessageCodec | ||||
| import io.flutter.plugin.platform.PlatformView | import io.flutter.plugin.platform.PlatformView | ||||
| import io.flutter.plugin.platform.PlatformViewFactory | import io.flutter.plugin.platform.PlatformViewFactory | ||||
| class QRViewFactory(private val registrar: PluginRegistry.Registrar) : | |||||
| class QRViewFactory(private val messenger: BinaryMessenger) : | |||||
| PlatformViewFactory(StandardMessageCodec.INSTANCE) { | PlatformViewFactory(StandardMessageCodec.INSTANCE) { | ||||
| override fun create(context: Context, id: Int, obj: Any?): PlatformView { | override fun create(context: Context, id: Int, obj: Any?): PlatformView { | ||||
| return QRView(registrar,id) | |||||
| return QRView(messenger, id, context) | |||||
| } | } | ||||
| } | } | ||||
| @@ -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 | |||||
| } | |||||
| @@ -38,7 +38,8 @@ android { | |||||
| defaultConfig { | defaultConfig { | ||||
| applicationId "net.touchcapture.qr.flutterqrexample" | applicationId "net.touchcapture.qr.flutterqrexample" | ||||
| minSdkVersion 19 | |||||
| // minSdkVersion is determined by Native View. | |||||
| minSdkVersion 20 | |||||
| targetSdkVersion 30 | targetSdkVersion 30 | ||||
| versionCode flutterVersionCode.toInteger() | versionCode flutterVersionCode.toInteger() | ||||
| versionName flutterVersionName | versionName flutterVersionName | ||||
| @@ -13,7 +13,6 @@ | |||||
| additional functionality it is fine to subclass or reimplement | additional functionality it is fine to subclass or reimplement | ||||
| FlutterApplication and put your custom class here. --> | FlutterApplication and put your custom class here. --> | ||||
| <application | <application | ||||
| android:name="io.flutter.app.FlutterApplication" | |||||
| android:label="flutter_qr_example" | android:label="flutter_qr_example" | ||||
| android:icon="@mipmap/ic_launcher"> | android:icon="@mipmap/ic_launcher"> | ||||
| <activity | <activity | ||||
| @@ -23,13 +22,19 @@ | |||||
| android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density" | android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density" | ||||
| android:hardwareAccelerated="true" | android:hardwareAccelerated="true" | ||||
| android:windowSoftInputMode="adjustResize"> | android:windowSoftInputMode="adjustResize"> | ||||
| <!-- This keeps the window background of the activity showing | |||||
| until Flutter renders its first frame. It can be removed if | |||||
| there is no splash screen (such as the default splash screen | |||||
| defined in @style/LaunchTheme). --> | |||||
| <!-- Specify that the launch screen should continue being displayed --> | |||||
| <!-- until Flutter renders its first frame. --> | |||||
| <meta-data | <meta-data | ||||
| android:name="io.flutter.app.android.SplashScreenUntilFirstFrame" | |||||
| android:value="true" /> | |||||
| android:name="io.flutter.embedding.android.SplashScreenDrawable" | |||||
| android:resource="@drawable/launch_background" /> | |||||
| <!-- Theme to apply as soon as Flutter begins rendering frames --> | |||||
| <meta-data | |||||
| android:name="io.flutter.embedding.android.NormalTheme" | |||||
| android:resource="@style/NormalTheme" | |||||
| /> | |||||
| <meta-data | |||||
| android:name="flutterEmbedding" | |||||
| android:value="2" /> | |||||
| <intent-filter> | <intent-filter> | ||||
| <action android:name="android.intent.action.MAIN"/> | <action android:name="android.intent.action.MAIN"/> | ||||
| <category android:name="android.intent.category.LAUNCHER"/> | <category android:name="android.intent.category.LAUNCHER"/> | ||||
| @@ -1,13 +1,6 @@ | |||||
| package net.touchcapture.qr.flutterqrexample | 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() { | class MainActivity: FlutterActivity() { | ||||
| override fun onCreate(savedInstanceState: Bundle?) { | |||||
| super.onCreate(savedInstanceState) | |||||
| GeneratedPluginRegistrant.registerWith(this) | |||||
| } | |||||
| } | } | ||||
| @@ -1,8 +1,19 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | <resources> | ||||
| <!-- Theme applied to the Android Window while the process is starting --> | |||||
| <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> | <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> | ||||
| <!-- Show a splash screen on the activity. Automatically removed when | <!-- Show a splash screen on the activity. Automatically removed when | ||||
| Flutter draws its first frame --> | Flutter draws its first frame --> | ||||
| <item name="android:windowBackground">@drawable/launch_background</item> | <item name="android:windowBackground">@drawable/launch_background</item> | ||||
| </style> | </style> | ||||
| <!-- Theme applied to the Android Window as soon as the process has started. | |||||
| This theme determines the color of the Android Window while your | |||||
| Flutter UI initializes, as well as behind your Flutter UI while its | |||||
| running. | |||||
| This Theme is only used starting with V2 of Flutter's Android embedding. --> | |||||
| <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar"> | |||||
| <item name="android:windowBackground">@drawable/launch_background</item> | |||||
| </style> | |||||
| </resources> | </resources> | ||||