ZOFTINO.COM android and web dev tutorials

Android App Permissions Tutorial

In android, without permission from the user of the device, your app can’t use system data, hardware and other features on the device. If your app depends on certain system features or hardware, it needs to request for permissions to access those features on the device. If app uses less sensitive features or data, the system will automatically grant those permissions. For other permissions, user acceptance is required.

Table of Contents

Publicizing Permission

In your app, you need to list all the permissions required to access features and data in the AndroidManifest.xml. For example, if your app needs to write to device storage, you need to add WRITE_EXTERNAL_STORAGE permission to manifest xml file.

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zoftino.flights">

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  ......

</manifest> 

One of the purposes of listing the permission in manifest xml is to let system know all the required permissions so that it can grant automatically the permission for less sensitive features or data. Some of the less sensitive permissions are ACCESS_NETWORK_STATE, ACCESS_WIFI_STATE, BLUETOOTH, INTERNET, KILL_BACKGROUND_PROCESSES, SET_ALARM, SET_TIME_ZONE, SET_WALLPAPER and VIBRATE.

Publicizing Features

To make external entities know about features and data your app depends on, you need to list the features that your app uses in AndroidManifest.xml. For example, if your app uses camera, in addition to camera permission, you need to add camera feature in manifest xml file.

 <uses-feature android:name="android.hardware.camera" android:required="false" />    
<uses-permission android:name="android.permission.CAMERA"/>

External entities such as Google play store uses the users-feature elements to determine whether your app should be shown to user or not. If the user device doesn’t have the requested features and your app lists them as required, then your app will not be shown in the play store for the user to install. Setting the required attribute of uses-feature element to false tells that the feature is optional and user can use your app without existence of the feature on the device.

For example if camera feature is optional for your app, you can set the required attribute of uses-feature element to false. But in your app at runtime, you need to check whether the camera feature exists or not on the device it is running by calling hasSystemFeature method on PackageManger and based on the outcome the app features that use camera can be enabled or disabled.

 if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
    capturePic.setEnabled(false);
} 

Requesting Permission

For devices running Android 5.1.1 (API level 22) or lower, just listing the permissions is enough and at the time of installing your app, system prompts the user for acceptance of the permissions. If user accepts it, installation will continue otherwise it will be cancelled.

But on the devices running Android 6.0 (API level 23) or higher, apps need to request permissions at runtime. Before requesting permissions, it is a good practice to see if the permission is already granted or not. You can check whether a permission is already granted or not by calling ContextCompat.checkSelfPermission() method passing the context and permission to it. If permission is not granted, you can request for it using ActivityCompat.requestPermissions passing context and list of permission to it.

 if (ContextCompat.checkSelfPermission(this, "android.permission.READ_CONTACTS")
        != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
            new String[]{"android.permission.READ_CONTACTS"}, 2);
} 

On calling ActivityCompat.requestPermissions() method, system prompts the user with a dialog which gives the options to allow or deny the requested permission.

android permissions examples

Once user allows or denies the permission, system calls onRequestPermissionsResult method in the activity which requested the permissions. So, if you need to handle the permission response to know whether the requested permission is granted or denied, you have to implement onRequestPermissionsResult callback method.

 @Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case CONTACT_PERM_REQ: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this,"Read contacts granted"
                        ,Toast.LENGTH_LONG).show();
            }
            return;
        }
    }
}
 

Permission Don’t Ask Again Option

If user denies a request for permission first time and the same permission is requested again, there will be don’t ask again check box in the permission request dialog. This option allows user to tell the system not to prompt for the same permission again. In this scenario, if application request the same permission again, system will simply ignore it.

android permission request second time onwards

Permission Explanation

In case if user denies permission, it is better to provide information next time when the permission is requested as to why your app needs the permission to make the user understand the reasons and how the requested features are used in your app.

You can use the method shouldShowRequestPermissionRationale() in activity which returns true if user already denied the permission and provide explanation if it returns true. For example, you can show a dialog showing rationale behind requesting permission.

 if(shouldShowRequestPermissionRationale("android.permission.CAMERA")){
    AlertDialog alertDialog = new AlertDialog.Builder(this).create();
    alertDialog.setTitle("Camera Permission");
    alertDialog.setMessage("Camera permission is required to in order to " +
            "provide photo capture feature");
    alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.dismiss();
                }
            });
    alertDialog.show();
}
android permission examples

Permission Group

Android system organizes related permissions into groups. If user allows permission from a group and your app requests for second permission from the same group, system will automatically grant the permission. For example, if user accepts app’s requests for READ_CALENDAR permission and then requests for WRITE_CALENDAR permission, system will automatically grant WRITE_CALENDAR permission without prompting for user acceptance. This is because READ_CALENDAR and WRITE_CALENDAR permissions belong to CALENDAR group.

Similarly, READ_CONTACTS and WRITE_CONTACTS belong to CONTACTS group. If you notice in the screen shot above which shows permission request for READ_CONTACTS, the group name is mentioned in the permissions dialog. For more information about permission groups see android permission groups.

Custom Permissions

So far we used system provided permissions which enable apps to use device features and data. You can define custom permissions for your app to share your resource or services with other apps. You can create custom permissions in your app by defining permissions in manifest xml file using permission element.

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zoftino.flights">
    <permission
        android:name="com.zoftino.flights.permission.USER_ACTIVITY"
        android:label="Zoftino User Activity"
        android:description="This permission allows apps to get user activity data"
        android:protectionLevel="dangerous" />

You can use the custom permission to share your app activities, services and broadcast receivers, etc. You can enforce the custom permission to those components by adding permission attribute to the configuration of corresponding components in manifest xml.

 <activity android:name=".FlightsActivity"
android:permission="com.zoftino.flights.permission.USER_ACTIVITY"></activity> 

If custom permission is enforced to an activity in an app, other apps which depend on the activity need to request the permission and user has to accept it before the apps can start the activity otherwise SecurityException will be thrown.