Android Runtime Permissions Tutorial/Example

Android MarshMallow brought one major change that is asking permissions at runtime. It is very important from user’s security point of view.Earlier all permissions were sought at the time of installation so user remained unconcerned about permissions later on. Android M brought entire new Mechanism to ask permissions at run time.

In Android 6.0, the application will not be granted any permission at installation time rather all permissions will be asked by the application at runtime.

Note – This will only work on Android M  when we set targetSdkVersion=23.

Important Point– This new runtime permission may bring some panic what don’t worry say you published your app 3 years. Will it work on Android M or crash? Don’t worry Android has taken care of that if your targetSdkVersion is less than 23 then your application will run perfectly fine on Android M as your targetSdkVersion is then 23 it means your application is not tested on Android M.

Although there is some permission that need not be asked and will be granted at installation time.These permissions are called Protection_Level Permissions Take a look at them.

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

just simply add them in AndroidManifest.xml and will work perfectly fine.

So, Let’s Start how to ask for permissions at runtime.

  1. Make sure our application supports new Runtime permission that is set targetSdkVersion 23 and compileSdkVersion 23.
  2. Methods used for runtime permissions :-
  3. checkSelfPermission(Permission) to check is permission is granted already or not.
  4. requestPermissions(String[] permissions, int requestCode) to request for permissions.
  5. onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults) to check for results whether permission is granted or not.

So, Let’s start to ask permission

private void askForPermission() {
       int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CAMERA);
       if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
           if(!shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
               showMessageOKCancel("You need to allow access to Contacts",
                       new DialogInterface.OnClickListener() {
                           @Override
                           public void onClick(DialogInterface dialog, int which) {
                               requestPermissions(new String[]{Manifest.permission.CAMERA},REQUEST_CODE_ASK_PERMISSIONS);
                           }
                       });
               return;
           }
           requestPermissions(new String[] {Manifest.permission.CAMERA},
                   REQUEST_CODE_ASK_PERMISSIONS);
           return;
       }

   }

   private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
       new AlertDialog.Builder(MainActivity.this)
               .setMessage(message)
               .setPositiveButton("OK", okListener)
               .setNegativeButton("Cancel", null)
               .create()
               .show();
   }

Next step would add permission to AndroidManifest.xml

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

then Check for Results.

@Override
   public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
       switch (requestCode) {
           case REQUEST_CODE_ASK_PERMISSIONS:
               if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                   Toast.makeText(MainActivity.this, " Permission Granted", Toast.LENGTH_SHORT)
                           .show();
                   // Permission Granted put your code here
                  
               } else {
                   // Permission Denied
                   Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT)
                           .show();
               }
               break;
           default:
               super.onRequestPermissionsResult(requestCode, permissions, grantResults);
       }
   }

So, Final Code Will be

MainActivity.java

package com.coderzpassion.askingpersample;

import android.Manifest;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.OperationApplicationException;
import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    final private int REQUEST_CODE_ASK_PERMISSIONS = 123;
    private static final String TAG = "Contacts";
    Button askpermission;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        askpermission=(Button)findViewById(R.id.askpermission);
        askpermission.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                askForPermission();
            }
        });
    }
    private void askForPermission() {
        int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CAMERA);
        if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
            if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
                showMessageOKCancel("You need to allow access to Contacts",
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                requestPermissions(new String[] {Manifest.permission.CAMERA},
                                        REQUEST_CODE_ASK_PERMISSIONS);
                            }
                        });
                return;
            }
            requestPermissions(new String[] {Manifest.permission.CAMERA},
                    REQUEST_CODE_ASK_PERMISSIONS);
            return;
        }

    }

    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(MainActivity.this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", null)
                .create()
                .show();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_ASK_PERMISSIONS:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(MainActivity.this, " Permission Granted", Toast.LENGTH_SHORT)
                            .show();
                    // Permission Granted put your code here

                } else {
                    // Permission Denied
                    Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT)
                            .show();
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

//layout for MainActivity.java

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">


    <Button
        android:id="@+id/askpermission"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:text="Test"/>

</RelativeLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.coderzpassion.askingpersample" >
    <uses-permission android:name="android.permission.CAMERA"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.coderzpassion.askingpersample"
        minSdkVersion 23
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.1.1'
}

Output

Screen Shot 2016-02-29 at 9.55.13 PM Screen Shot 2016-02-29 at 9.56.14 PM Screen Shot 2016-02-29 at 9.56.31 PM