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

Fixed request camera permission flow to solve issue 173 #186

Merged
merged 4 commits into from
Apr 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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