How to easy implement android runtime permissions request in android app development

 

Hello developers today we are going to learn implementing android runtime permissions request in android app development.

 

As we know, If we need to make use of protected features of the device in any application we need to give permission request in AndroidManifest.xml of application, As below

 

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.app.myapp">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
...
</manifest>

 

After android 6.0 and up android permissions are categorized or grouped in two categories and new android runtime permissions model is added to improve security for sensitive user data.

1. Normal Permissions
2. Dangerous Permissions

For normal permissions we just need to continue follow above procedure(defining them in AndroidManifest.xml), but for dangerous permissions, we need to request them also at runtime, means first we need to define them in AndroidManifest.xml then we need to verify again using request them on action perform like button click, Here user can confirm or deny this data access request.

Below are the list of dangerous permissions:

 

READ_CALENDAR
WRITE_CALENDAR
CAMERA
READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
RECORD_AUDIO
READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
BODY_SENSORS
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

 

So if we need to make our application available for android 6.0 and up we need to implement this runtime permissions model in our application, otherwise application will crash or not work with Permission Denied error.

As a developer I can understand that this may difficult for some you guys, Here we simplified this process without using any other library or external SDK.

First we need to understand how this runtime permissions request process will work.

1. First it will check that the requested permission is already granted or not ?
2. If yes then related task will perform, otherwise it will request for permission using a popup message, here user have two options allow or deny.
3. Then if permission is granted by user it will perform requested operation, otherwise operation will not perform.

So let’s come to the implementation part, first of all we need to define permission as string globally in Activity class as below. (Here we are using READ_EXTERNAL_STORAGE permission for our example you can change it as per your requirement.)

 

String storagePermission = Manifest.permission.READ_EXTERNAL_STORAGE;

 

The second thing we need to add a permission requirement message/ why this permission is important to our application.(I will explain about importance of this, later in tutorial.)

 

String storagePermissionMessage = "Please \'Allow\' this permission request, Because app will use this permission to access images from your device memory, If you \'Deny\' this permission request, you will not able to use this feature of application.";

 

and last we need to add a unique request code for our permission request.

 

final int STORAGE_PERMISSION_CODE = 99;

 

Now on button click check the status of permission(Read storage in our case), that if the app is already having the permission then it will perform action.

 

boolean permissionStatus = isPermissionAllowed(storagePermission);

 

If the app does not have the permission then here we need to check one more condition “The request status”.

1. In Some case user previously denied this request and come again to use this feature. At this time first we need to show a permission importance message like why this permission is important to access this feature in application, so user will not again deny it. Then ask for permission after user approval.

2. If user first time here the directly ask/request for the permission.

Check below code block for under standing.

 

boolean requestStatus = checkRequestStatus(storagePermission);
if (requestStatus) {
// user denied previously this permission request
// We need to show here an information popup that why this permission is compulsory.
showPermissionImportanceMessage(storagePermission, STORAGE_PERMISSION_CODE, storagePermissionMessage);
} else {
// first time request
// ask for permission
askForPermission(storagePermission, STORAGE_PERMISSION_CODE);
}

 

Below are the methods we used above to

1. Check Permission status

 

//We will call this method to check the permission status
private boolean isPermissionAllowed(String permission) {
//Getting the permission status
int status = ContextCompat.checkSelfPermission(this, permission);
//If permission is granted returning true
if (status == PackageManager.PERMISSION_GRANTED)
return true;
//If permission is not granted returning false
return false;
}

 

2. In the case of permission not allowed. Check request status if previously asked or not.

 

//We will call this method to check request status of permission
private boolean checkRequestStatus(final String permission) {
//Check if the user has denied the permission previously
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission))
//Will return true if the user has denied the permission previously.
return true;
//Will return false if the user first time asking for request.
return false;
}

 

3. To show an information popup that why this permission is compulsory.

 

private void showPermissionImportanceMessage(final String permission, final int PERMISSION_CODE, final String permissionMessage) {
AlertDialog alertDialog = new AlertDialog.Builder(
RunTimePermissionActivity.this).create();
alertDialog.setTitle("Permission Required");
alertDialog.setMessage(permissionMessage);
alertDialog.setButton(DialogInterface.BUTTON_NEUTRAL, "OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
askForPermission(permission, PERMISSION_CODE);
}
});
alertDialog.show();
}

 

4. Ask/request for permission

 

private void askForPermission(final String permission, final int PERMISSION_CODE) {
//And finally ask for the permission
ActivityCompat.requestPermissions(RunTimePermissionActivity.this, new String[]{permission}, PERMISSION_CODE);
}

 

As we mentioned previously in our tutorial above, when system permission request is asked to user, There are two options for user, 1. To allow the access 2. To deny the access.

Whatever user select the result is handled in the below method specially for handling permission requests.

Here if user allowed/granted this request the respective action will be performed, if denied then we need to show a message to enable this permission manually by going to application settings.

Quick Tip : If user denied permission request with never ask again check, Then It will go automatically in denied case of below method when asked/requested for permission using askForPermission method.

 

//This method will be called as permission request result, it may be allow or deny by user
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//Checking the request code of our premission requests
switch (requestCode) {
case STORAGE_PERMISSION_CODE:
//Check if permission is granted
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission is granted now
// Do your work here
accessStorageMethod();
} else {
//Displaying setting popup if permission is not granted
showSettingsPopup();
}
break;
}
}

 

Below is the method we can use to redirect user to application settings for manual enabling this feature request.

 

private void showSettingsPopup() {
final AlertDialog alertDialog = new AlertDialog.Builder(
RunTimePermissionActivity.this).create();
alertDialog.setTitle("Permission Required");
alertDialog.setMessage("Please allow this permission by going to \'App Settings\' then click on \'Permissions\' tab and enable required permission.");
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Go to settings", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
final Intent settingsIntent = new Intent();
settingsIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
settingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
settingsIntent.setData(Uri.parse("package:" + getPackageName()));
startActivity(settingsIntent);
}
});
alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
alertDialog.show();
}

 

* Note : Below are the minimum required settings(The settings we used in this tutorial) from app level build.gradle file to implement run time permissions in any android app. (Very Important)*

 

// Under android
compileSdkVersion 23
buildToolsVersion "23.0.3"
// Under defaultConfig
targetSdkVersion 23
//Under dependencies
compile 'com.android.support:appcompat-v7:23.0.1'

 

Below is the full implementation of these above methods in an Activity class, You can use it directly and modify it as per your need.

 

package in.quicktips.runtimepermission;
import android.Manifest;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.widget.Button;
public class RunTimePermissionActivity extends Activity {
final int STORAGE_PERMISSION_CODE = 99;
Button btnStorage;
// Used for storage permission
String storagePermission = Manifest.permission.READ_EXTERNAL_STORAGE;
String storagePermissionMessage = "Please \'Allow\' this permission request, Because app will use this permission to access images from your device memory, If you \'Deny\' this permission request, you will not able to use this feature of application.";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_runtime_permission);
btnStorage = (Button) findViewById(R.id.request_storage);
btnStorage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// first check for permission status
boolean permissionStatus = isPermissionAllowed(storagePermission);
if (permissionStatus) {
// Permission is allowed
// Do your work here
accessStorageMethod();
} else {
// Permission is not allowed
// Check request status if previously asked or not
boolean requestStatus = checkRequestStatus(storagePermission);
if (requestStatus) {
// user denied previously this permission request
// We need to show here an information popup that why this permission is compulsory.
showPermissionImportanceMessage(storagePermission, STORAGE_PERMISSION_CODE, storagePermissionMessage);
} else {
// first time request
// ask for permission
askForPermission(storagePermission, STORAGE_PERMISSION_CODE);
}
}
}
});
}
private void accessStorageMethod() {
}
//We will call this method to check the permission status
private boolean isPermissionAllowed(String permission) {
//Getting the permission status
int status = ContextCompat.checkSelfPermission(this, permission);
//If permission is granted returning true
if (status == PackageManager.PERMISSION_GRANTED)
return true;
//If permission is not granted returning false
return false;
}
//We will call this method to Request permission
private boolean checkRequestStatus(final String permission) {
//Check if the user has denied the permission previously
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission))
//Will return true if the user has denied the permission previously.
return true;
//Will return false if the user first time asking for request.
return false;
}
private void showPermissionImportanceMessage(final String permission, final int PERMISSION_CODE, final String permissionMessage) {
AlertDialog alertDialog = new AlertDialog.Builder(
RunTimePermissionActivity.this).create();
alertDialog.setTitle("Permission Required");
alertDialog.setMessage(permissionMessage);
alertDialog.setButton(DialogInterface.BUTTON_NEUTRAL, "OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
askForPermission(permission, PERMISSION_CODE);
}
});
alertDialog.show();
}
private void askForPermission(final String permission, final int PERMISSION_CODE) {
//And finally ask for the permission
ActivityCompat.requestPermissions(RunTimePermissionActivity.this, new String[]{permission}, PERMISSION_CODE);
}
//This method will be called as permission request result, it may be allow or deny by user
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//Checking the request code of our premission requests
switch (requestCode) {
case STORAGE_PERMISSION_CODE:
//Check if permission is granted
if (grantResults.length &amp;gt; 0 &amp;amp;&amp;amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission is granted now
// Do your work here
accessStorageMethod();
} else {
//Displaying setting popup if permission is not granted
showSettingsPopup();
}
break;
}
}
private void showSettingsPopup() {
final AlertDialog alertDialog = new AlertDialog.Builder(
RunTimePermissionActivity.this).create();
alertDialog.setTitle("Permission Required");
alertDialog.setMessage("Please allow this permission by going to \'App Settings\' then click on \'Permissions\' tab and enable required permission.");
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Go to settings", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
final Intent settingsIntent = new Intent();
settingsIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
settingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
settingsIntent.setData(Uri.parse("package:" + getPackageName()));
startActivity(settingsIntent);
}
});
alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
alertDialog.show();
}
}

 

If you have any suggestions or queries regarding this tutorial please let us know in comments below.