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.
- Make sure our application supports new Runtime permission that is set targetSdkVersion 23 and compileSdkVersion 23.
- Methods used for runtime permissions :-
- checkSelfPermission(Permission) to check is permission is granted already or not.
- requestPermissions(String[] permissions, int requestCode) to request for permissions.
- 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