Android Permissions: A New Path to Glory
By: Egemen Hamutçu
Tags: Arabam, Android, Android Permissions

Let’s start our adventure with an example for an Android permission process: When user wants to make a video call with an advertiser, s/he needs to give following permissions, Camera, Microphone & Phone. We have VideoCallActivity . It will extend PermissionActivity .

We will start calling checkPermissionsAreGranted(BusinessRequest.VIDEO_CALL, true) method implemented in PermissionActivity . It simply wants to make a video call, doesn’t worry about what permissions are needed. Lovely. Let’s see what happens in the method:

We pass optional parameter exitOnDenied true because the permissions are critical for VideoCallActivity . If user denies any of the permissions, we can’t do anything, so we will finish the activity in that case when exitOnDenied is true.

We put ourselves in PermissionManager ‘s arms. It will call getPermissionRequestsFromBusiness(businessRequest) mapping BusinessRequest.VIDEO_CALL to an array of PermissionRequest.CAMERA , PermissionRequest.MICROPHONE and PermissionRequest.PHONE . Then, it will check whether all these permissions are granted by calling areAllPermissionsGranted(this, permissionRequests) :

If all permissions are granted, it will simply call abstract function onPermissionsGranted(businessRequest) and VideoCallActivity will call makeVideoCall() function inside of it. However, if any of permissions are not granted yet, we will start preparation for permission process by calling prepareNativePermissionRequest(permissionsRequests) .

It will prepare an Android’s native permission request; an array of strings including Manifest.permission s, and a requestCode integer value to match the result:

When they are ready, the function will let PermissionActivity know that the request is ready by invoking onNativePermissionRequestReady(permissions, requestCode) method. Then, PermissionActivity will simply call ActivityCompat.requestPermissions(this, permissions, requestCode) inside of it.

The result will fall into onRequestPermissionResult method inside PermissionActivity . Our superhero, PermissionManager comes along to aid us again! We call its handleRequestPermissionsResult(...) method to handle all the result logic for us:

It will check whether all permissions are granted. If user grants all permissions, it will let PermissionActivity know by invoking grantPermissions(businessRequest) method. If user denies any of permissions, it will check whether any of denied permissions should show a rationale dialog. If so, we will call showPermissionRationaleDialog(...) , otherwise we must call showPermissionPermanentDenialDialog(...) because user denies all permissions permanently.

Rationale dialog will ask user to try again. If user taps on the positive button, it will invoke retry() method and all process will start over from checkPermissionsAreGranted(...) method. If user taps on the negative button, it will invoke deny() method and the process will be terminated.

Permanent Denial dialog will ask user to navigate to the settings menu of the application and grant necessary permissions for further process. If user taps on the positive button, it will invoke navigateToSettings() method and PermissionActivity will navigate to settings making isComingFromSettings as true to handle the result on onResume() method. (I once tried to handle it on onActivityResult but it was never called). If user taps on the negative button, it will invoke deny() method and the process will be terminated.

We handle the result by the following code in PermissionActivity :

PermissionManager helps us again with handleResume(this) to handle the result whether user grants permissions in the settings menu:

It will ask user to try again if s/he grants permissions in the settings menu. If user taps on the positive button, it will invoke retry() method and all process will start over from checkPermissionsAreGranted(...) method. If user taps on the negative button, it will invoke deny() method and the process will be terminated.

As you see, our VideoCallActivity did almost nothing about about the permission. Everything is handled by the help of PermissionActivity and PermissionManager .

Once upon a time, VideoCallActivity was quite fat and sad with permission works:

It had 136 lines of code, most of them work for permission issue. Our activities just don’t deserve this. Finally, it met with our savior PermissionManager and become a PermissionActivity :