Home > Android Marshmallow Runtime Permissions

Android Marshmallow Runtime Permissions

Android is a privilege separated operating system, i.e. each application in android is separated from another through a distinct id, and each application file / data is private to that application only. Each Android application is started in its own process thus are isolated from all other applications (even from system / default applications). As a result an Android application canít access any file or data outside its scope until and unless the file or data is shared with the application.

So, the conclusion is that if an application needs anything outside its scope, then it should request for permission to the user. Android comes with a set of predefined permissions (System permissions) for certain tasks. Every application can request required permissions. For example, an application may declare that it requires network access. It can also define new permissions.

1. Permission Workflow before and from(API 23)

Now the question arises how an application can request for or get permission? Or rather, what workflow the developer should follow to request and get permission for the app? Let us have a look. The permission model / workflow has been changed from API 23 Ė Android M.

> Permission Model before (API 23): Before API 23, the permission model was simpler to the developer but offered less control and security to the user Ė requested permissions are presented to the user before installing the application. The user needs to decide whether to give these permissions to the application and install it or to deny as a whole and donít install the application. Permissions cannot be denied or granted after the installation.Thus developers were required only to declare all needed permissions in the manifest and then just forget; if the app is running then it has all the requested permissions.

> Permission Model from (API 23): With Android 6.0 Marshmallow (API 23), a new runtime permission model has been introduced. According to this model users are not prompted for permission at the time of installing the app, rather developers need to check for and request permission at runtime (i.e. before performing any action that may require the particular permission), users can then allow or deny the permission, users can also grant or revoke permission anytime from settings. Making the user experience very secure on an Android device. But inversely this feature imposes a great deal of effort on development. Therefore developers have to handle all the use cases. Thankfully, requesting Android runtime permissions, is not that difficult.

Note: According to Google, beginning with Android 6.0 (API level 23), users can revoke permissions from any app at any time, even if the app targets a lower API level. You should test your app to verify that it behaves properly when itís missing a needed permission, regardless of what API level your app targets.


2. Permission levels

System permissions have different protection levels. The two most important protection levels are normal and dangerous permissions.

Normal Permissions: Those permissions which will have very little or zero effect on users privacy or security are categorized as normal permissions. The system itself grants normal permissions when requested instead of prompting to the user. Examples would be ACCESS_WIFI_STATE, WAKE_LOCK etc. Normal Permission List

Dangerous Permissions: Those permissions which may have a greater effect on users privacy or security are categorized as dangerous permissions. Examples would be the ability to read the userís contacts READ_CONTACTS, ACCESS_COARSE_LOCATION, CAMERA, WRITE_EXTERNAL_STORAGE. If an app requests a dangerous permission, the user has to explicitly grant the permission to the app. Dangerous Permission List


3. Creating Android Project

1. Create a new project in Android Studio from File ? New Project and fill the project details.


2. Open build.gradle (app level) and make sure that you have set minSdkVersion and targetSdkVersion as we have to support the permissions model in lower versions also. I am keeping minSdkVersion to 15 and targetSdkVersion to 25.

									
apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.amisun.marshmallowpermissions" minSdkVersion 15 targetSdkVersion 25 versionCode 1 versionName "1.0" } ...... }

3. Add the below permissions to AndroidManifest.xml file.

									
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.amisun.marshmallowpermissions"> <!-- camera permission --> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera" /> <!-- internet permission --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <!-- current location permission --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>

4. Now open MainActivity.java and add the below code.

								
public class MainActivity extends AppCompatActivity { private static final int PERMISSION_CALLBACK_CONSTANT = 1000; private static final int REQUEST_PERMISSION_SETTING = 1001; String[] requiredPermissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}; private SharedPreferences storePermissionStatus; private boolean sentToSettings = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); storePermissionStatus = getSharedPreferences("permission_status",MODE_PRIVATE); if(Build.VERSION.SDK_INT >= 23) { if (ActivityCompat.checkSelfPermission(MainActivity.this, requiredPermissions[0]) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(MainActivity.this, requiredPermissions[1]) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(MainActivity.this, requiredPermissions[2]) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(MainActivity.this, requiredPermissions[3]) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, requiredPermissions[0]) || ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, requiredPermissions[1]) || ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, requiredPermissions[2]) || ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, requiredPermissions[3])) { AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setTitle("Need Multiple Permissions"); builder.setMessage("This app needs Camera, Storage location permissions."); builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); ActivityCompat.requestPermissions(MainActivity.this, requiredPermissions, PERMISSION_CALLBACK_CONSTANT); } }); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); builder.show(); } else if (storePermissionStatus.getBoolean(requiredPermissions[0], false)) { AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setTitle("Need Multiple Permissions"); builder.setMessage("This app needs Camera, storage location permissions"); builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); sentToSettings = true; Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivityForResult(intent, REQUEST_PERMISSION_SETTING); Toast.makeText(getBaseContext(), "Go to Permissions to Grant Camera and external storage", Toast.LENGTH_LONG).show(); } }); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); builder.show(); } else { ActivityCompat.requestPermissions(MainActivity.this, requiredPermissions, PERMISSION_CALLBACK_CONSTANT); } SharedPreferences.Editor editor = storePermissionStatus.edit(); editor.putBoolean(requiredPermissions[0], true); editor.commit(); } else { NextActivity(); } }else{ NextActivity(); } } private void NextActivity(){ Intent intent = new Intent(MainActivity.this,SecondActivity.class); startActivity(intent); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantArrResults) { super.onRequestPermissionsResult(requestCode, permissions, grantArrResults); if(requestCode == PERMISSION_CALLBACK_CONSTANT){ boolean allpremissiongranted = false; for(int i=0;i<agrantArrResults.length;i++){ if(grantArrResults[i]==PackageManager.PERMISSION_GRANTED){ allpremissiongranted = true; } else { allpremissiongranted = false; break; } } if(allpremissiongranted){ NextActivity(); } else if(ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,requiredPermissions[0]) || ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,requiredPermissions[1]) || ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,requiredPermissions[2]) || ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,requiredPermissions[3])){ AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setTitle("Need Multiple Permissions"); builder.setMessage("This app needs Camera and External storage permissions."); builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); ActivityCompat.requestPermissions(MainActivity.this,requiredPermissions,PERMISSION_CALLBACK_CONSTANT); } }); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); builder.show(); } else { Toast.makeText(getBaseContext(),"Unable to get Permission",Toast.LENGTH_LONG).show(); } } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_PERMISSION_SETTING) { if (ActivityCompat.checkSelfPermission(MainActivity.this, requiredPermissions[0]) == PackageManager.PERMISSION_GRANTED) { NextActivity(); } } } @Override protected void onPostResume() { super.onPostResume(); if (sentToSettings) { if (ActivityCompat.checkSelfPermission(MainActivity.this, requiredPermissions[0]) == PackageManager.PERMISSION_GRANTED) { NextActivity(); } } } }

5. Output as below.

  • Camera Permission
  • External Storage Premission
  • Location Permission

I hope this article gave you very good overview of Marshmallow permission model. Feel free to ask any queries / doubts in comments section below.



Dheerendra Singh

Dheerendra Singh is a Mobile Developer(Android) & Web Developer(PHP) of Amisun IT Solutions, Master degree in Computer Science.


About Us

Amisun IT Solutions is an expert Software Development Company giving complete IT arrangements and going about as a seaward improvement community for abroad advancement firms.

We are an imaginative organization, situated in India that gives a progression of Web-based programming applications that have helped clients make fruitful online activities.

Our group of forward masterminds and reforming individuals tries to furnish you with the best of arrangements with flawlessness second to none. Our key concentration is dependably to furnish you with solid arrangements which are precisely planned and planned with stringent quality principles. ...   

Read more

Address

Shoppers Square Mall Shop No. 17 & 18, First Floor,
Shoppers Square Mall, Budhh Prakash Garg Marg, Block 14, Sector 10,
Raj Nagar, Ghaziabad, Uttar Pradesh 201002
P: (+91) 9899776200, (+91) 9899773200