Skip to content
This repository has been archived by the owner on Oct 10, 2020. It is now read-only.

Commit

Permalink
Merge pull request #186 from mintware-de/fix_173
Browse files Browse the repository at this point in the history
Fixed request camera permission flow to solve issue 173
  • Loading branch information
devtronic committed Apr 12, 2020
2 parents 0c1e93d + a902b5f commit 55c7073
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 84 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## v2.0.2 - 2020-04-14

Bugfixes:
- [Fixed the request camera permission flow on Android](https://github.com/mintware-de/flutter_barcode_reader/pull/186) - @devtronic

## v2.0.1 - 2020-02-19

Bugfixes:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,48 @@
package de.mintware.barcode_scan

import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import de.mintware.barcode_scan.BarcodeScannerActivity.Companion.REQUEST_CAMERA_PERMISSION
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.Registrar

class BarcodeScanPlugin(private val registrar: Registrar) : MethodCallHandler, PluginRegistry.ActivityResultListener {
class BarcodeScanPlugin(private val registrar: Registrar) :
MethodCallHandler,
PluginRegistry.ActivityResultListener,
PluginRegistry.RequestPermissionsResultListener,
EventChannel.StreamHandler {
var result: Result? = null
var sink: EventChannel.EventSink? = null;

companion object {
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "de.mintware.barcode_scan")
val eventChannel = EventChannel(registrar.messenger(), "de.mintware.barcode_scan/events")
val plugin = BarcodeScanPlugin(registrar)
eventChannel.setStreamHandler(plugin);
channel.setMethodCallHandler(plugin)
registrar.addActivityResultListener(plugin)
registrar.addRequestPermissionsResultListener(plugin)
}
}

override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "scan") {
this.result = result
showBarcodeView()
} else if (call.method == "request_permission") {
result.success(requestCameraAccessIfNecessary())
} else {
result.notImplemented()
}
Expand Down Expand Up @@ -54,4 +70,66 @@ class BarcodeScanPlugin(private val registrar: Registrar) : MethodCallHandler, P
}
return false
}

private fun requestCameraAccessIfNecessary(): Boolean {
val array = arrayOf(Manifest.permission.CAMERA)
if (ContextCompat.checkSelfPermission(registrar.activity(), Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) {
return false
}

ActivityCompat.requestPermissions(registrar.activity(), array, REQUEST_CAMERA_PERMISSION)
return true
}

override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<out String>?,
grantResults: IntArray?
): Boolean {
if (requestCode != REQUEST_CAMERA_PERMISSION) {
return false;
}

if (PermissionUtil.verifyPermissions(grantResults)) {
sink?.success("PERMISSION_GRANTED");
} else {
sink?.success("PERMISSION_NOT_GRANTED");
}
return true;
}

override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
sink = events;
}

override fun onCancel(arguments: Any?) {
sink = null;
}
}

object PermissionUtil {

/**
* Check that all given permissions have been granted by verifying that each entry in the
* given array is of the value [PackageManager.PERMISSION_GRANTED].
* @see Activity.onRequestPermissionsResult
*/
fun verifyPermissions(grantResults: IntArray?): Boolean {
if (grantResults == null) {
return false;
}
// At least one result must be checked.
if (grantResults.size < 1) {
return false
}

// Verify that each required permission has been granted, otherwise return false.
for (result in grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
return false
}
}
return true
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
package de.mintware.barcode_scan

import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import android.view.Menu
import android.view.MenuItem
import com.google.zxing.Result
import me.dm7.barcodescanner.zxing.ZXingScannerView


class BarcodeScannerActivity : Activity(), ZXingScannerView.ResultHandler {

lateinit var scannerView: me.dm7.barcodescanner.zxing.ZXingScannerView
lateinit var scannerView: ZXingScannerView

companion object {
val REQUEST_TAKE_PHOTO_CAMERA_PERMISSION = 100
val TOGGLE_FLASH = 200
const val REQUEST_CAMERA_PERMISSION = 100
const val TOGGLE_FLASH = 200

}

Expand All @@ -34,15 +29,9 @@ class BarcodeScannerActivity : Activity(), ZXingScannerView.ResultHandler {
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
if (scannerView.flash) {
val item = menu.add(0,
TOGGLE_FLASH, 0, "Flash Off")
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
} else {
val item = menu.add(0,
TOGGLE_FLASH, 0, "Flash On")
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
}
val buttonText = if (scannerView.flash) "Flash Off" else "Flash On"
val item = menu.add(0, TOGGLE_FLASH, 0, buttonText)
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
return super.onCreateOptionsMenu(menu)
}

Expand All @@ -58,10 +47,7 @@ class BarcodeScannerActivity : Activity(), ZXingScannerView.ResultHandler {
override fun onResume() {
super.onResume()
scannerView.setResultHandler(this)
// start camera immediately if permission is already given
if (!requestCameraAccessIfNecessary()) {
scannerView.startCamera()
}
scannerView.startCamera()
}

override fun onPause() {
Expand All @@ -72,65 +58,7 @@ class BarcodeScannerActivity : Activity(), ZXingScannerView.ResultHandler {
override fun handleResult(result: Result?) {
val intent = Intent()
intent.putExtra("SCAN_RESULT", result.toString())
setResult(Activity.RESULT_OK, intent)
setResult(RESULT_OK, intent)
finish()
}

fun finishWithError(errorCode: String) {
val intent = Intent()
intent.putExtra("ERROR_CODE", errorCode)
setResult(Activity.RESULT_CANCELED, intent)
finish()
}

private fun requestCameraAccessIfNecessary(): Boolean {
val array = arrayOf(Manifest.permission.CAMERA)
if (ContextCompat
.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {

ActivityCompat.requestPermissions(this, array,
REQUEST_TAKE_PHOTO_CAMERA_PERMISSION)
return true
}
return false
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,grantResults: IntArray) {
when (requestCode) {
REQUEST_TAKE_PHOTO_CAMERA_PERMISSION -> {
if (PermissionUtil.verifyPermissions(grantResults)) {
scannerView.startCamera()
} else {
finishWithError("PERMISSION_NOT_GRANTED")
}
}
else -> {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
}
}

object PermissionUtil {

/**
* Check that all given permissions have been granted by verifying that each entry in the
* given array is of the value [PackageManager.PERMISSION_GRANTED].
* @see Activity.onRequestPermissionsResult
*/
fun verifyPermissions(grantResults: IntArray): Boolean {
// At least one result must be checked.
if (grantResults.size < 1) {
return false
}

// Verify that each required permission has been granted, otherwise return false.
for (result in grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
return false
}
}
return true
}
}
}
2 changes: 2 additions & 0 deletions ios/Classes/BarcodeScanPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
if ([@"scan" isEqualToString:call.method]) {
self.result = result;
[self showBarcodeView];
} else if ([@"request_permission" isEqualToString:call.method]) {
result(@(NO));
} else {
result(FlutterMethodNotImplemented);
}
Expand Down
35 changes: 34 additions & 1 deletion lib/barcode_scan.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import 'package:flutter/services.dart';
/// Barcode scanner plugin
/// Simply call `var barcode = await BarcodeScanner.scan()` to scan a barcode
class BarcodeScanner {
/// If the user has granted the access to the camera this code is returned.
static const CameraAccessGranted = 'PERMISSION_GRANTED';

/// If the user has not granted the access to the camera this code is thrown.
static const CameraAccessDenied = 'PERMISSION_NOT_GRANTED';

Expand All @@ -15,9 +18,39 @@ class BarcodeScanner {
static const MethodChannel _channel =
const MethodChannel('de.mintware.barcode_scan');

/// The event channel
static const EventChannel _eventChannel =
const EventChannel('de.mintware.barcode_scan/events');

/// Starts the camera for scanning the barcode, shows a preview window and
/// returns the barcode if one was scanned.
/// Can throw an exception.
/// See also [CameraAccessDenied] and [UserCanceled]
static Future<String> scan() async => await _channel.invokeMethod('scan');
static Future<String> scan() async {
var events = _eventChannel.receiveBroadcastStream();
var permissionsRequested =
await _channel.invokeMethod('request_permission');
if (permissionsRequested) {
var completer = Completer<String>();

StreamSubscription subscription;
subscription = events.listen((event) async {
if (event is String) {
if (event == CameraAccessGranted) {
subscription.cancel();
completer.complete(await _channel.invokeMethod('scan'));
} else if (event == CameraAccessDenied) {
subscription.cancel();
completer.completeError(
PlatformException(code: CameraAccessDenied),
);
}
}
});

return completer.future;
} else {
return await _channel.invokeMethod('scan');
}
}
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: barcode_scan
description: A flutter plugin for scanning 2D barcodes and QRCodes via camera.
version: 2.0.1
version: 2.0.2
homepage: https://github.com/mintware-de/flutter_barcode_reader

dependencies:
Expand Down

0 comments on commit 55c7073

Please sign in to comment.