Showing
1 changed file
with
130 additions
and
0 deletions
| 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 | +} |
-
Please register or login to post a comment