Navaron Bracke

Move permission code into permissions class

  1 +package dev.steenbakker.mobile_scanner
  2 +
  3 +import android.Manifest.permission
  4 +import android.app.Activity
  5 +import android.content.pm.PackageManager
  6 +import androidx.core.app.ActivityCompat
  7 +import androidx.core.content.ContextCompat
  8 +import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener
  9 +
  10 +/**
  11 + * This class handles the camera permissions for the Mobile Scanner.
  12 + */
  13 +class MobileScannerPermissions {
  14 + companion object {
  15 + const val CAMERA_ACCESS_DENIED = "CameraAccessDenied"
  16 + const val CAMERA_ACCESS_DENIED_MESSAGE = "Camera access permission was denied."
  17 + const val CAMERA_PERMISSIONS_REQUEST_ONGOING = "CameraPermissionsRequestOngoing"
  18 + const val CAMERA_PERMISSIONS_REQUEST_ONGOING_MESSAGE = "Another request is ongoing and multiple requests cannot be handled at once."
  19 +
  20 + /**
  21 + * When the application's activity is [androidx.fragment.app.FragmentActivity], requestCode can only use the lower 16 bits.
  22 + * @see androidx.fragment.app.FragmentActivity.validateRequestPermissionsRequestCode
  23 + */
  24 + const val REQUEST_CODE = 0x0786
  25 + }
  26 +
  27 + interface PermissionsRegistry {
  28 + @SuppressWarnings("deprecation")
  29 + fun addListener(handler: RequestPermissionsResultListener)
  30 + }
  31 +
  32 + interface ResultCallback {
  33 + fun onResult(errorCode: String?, errorDescription: String?)
  34 + }
  35 +
  36 + private var listener: RequestPermissionsResultListener? = null
  37 +
  38 + fun getPermissionListener(): RequestPermissionsResultListener? {
  39 + return listener
  40 + }
  41 +
  42 + private var ongoing: Boolean = false
  43 +
  44 + fun hasCameraPermission(activity: Activity) : Int {
  45 + val hasPermission = ContextCompat.checkSelfPermission(
  46 + activity,
  47 + permission.CAMERA,
  48 + ) == PackageManager.PERMISSION_GRANTED
  49 +
  50 + return if (hasPermission) {
  51 + 1
  52 + } else {
  53 + 0
  54 + }
  55 + }
  56 +
  57 + fun requestPermission(activity: Activity,
  58 + permissionsRegistry: PermissionsRegistry,
  59 + callback: ResultCallback) {
  60 + if (ongoing) {
  61 + callback.onResult(
  62 + CAMERA_PERMISSIONS_REQUEST_ONGOING, CAMERA_PERMISSIONS_REQUEST_ONGOING_MESSAGE)
  63 + return
  64 + }
  65 +
  66 + if(hasCameraPermission(activity) == 1) {
  67 + // Permissions already exist. Call the callback with success.
  68 + callback.onResult(null, null)
  69 + return
  70 + }
  71 +
  72 + if(listener == null) {
  73 + // Keep track of the listener, so that it can be unregistered later.
  74 + listener = MobileScannerPermissionsListener(
  75 + object: ResultCallback {
  76 + override fun onResult(errorCode: String?, errorDescription: String?) {
  77 + ongoing = false
  78 + callback.onResult(errorCode, errorDescription)
  79 + }
  80 + }
  81 + )
  82 + permissionsRegistry.addListener(listener)
  83 + }
  84 +
  85 + ongoing = true
  86 + ActivityCompat.requestPermissions(
  87 + activity,
  88 + arrayOf(permission.CAMERA),
  89 + REQUEST_CODE
  90 + )
  91 + }
  92 +}
  93 +
  94 +/**
  95 + * This class handles incoming camera permission results.
  96 + */
  97 +@SuppressWarnings("deprecation")
  98 +private class MobileScannerPermissionsListener(
  99 + private val resultCallback: MobileScannerPermissions.ResultCallback,
  100 +): RequestPermissionsResultListener {
  101 + // There's no way to unregister permission listeners in the v1 embedding, so we'll be called
  102 + // duplicate times in cases where the user denies and then grants a permission. Keep track of if
  103 + // we've responded before and bail out of handling the callback manually if this is a repeat
  104 + // call.
  105 + private var alreadyCalled: Boolean = false
  106 +
  107 + override fun onRequestPermissionsResult(
  108 + requestCode: Int,
  109 + permissions: Array<out String>,
  110 + grantResults: IntArray
  111 + ): Boolean {
  112 + if (alreadyCalled || requestCode != MobileScannerPermissions.REQUEST_CODE) {
  113 + return false
  114 + }
  115 +
  116 + alreadyCalled = true
  117 +
  118 + // grantResults could be empty if the permissions request with the user is interrupted
  119 + // https://developer.android.com/reference/android/app/Activity#onRequestPermissionsResult(int,%20java.lang.String[],%20int[])
  120 + if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
  121 + resultCallback.onResult(
  122 + MobileScannerPermissions.CAMERA_ACCESS_DENIED,
  123 + MobileScannerPermissions.CAMERA_ACCESS_DENIED_MESSAGE)
  124 + } else {
  125 + resultCallback.onResult(null, null)
  126 + }
  127 +
  128 + return true
  129 + }
  130 +}