<p>Android Marshmallow includes a new functionality to let users grant or deny permissions when running an app instead of granting them all when installing it. This approach gives the user more control over applications but requires developers to add lots of code just to get a single permission.</p>
<p>In this article, we will talk about how to add runtime permissions easily and quickly using <strong><span style="color: #008000;"><a style="color: #008000;" href="https://github.com/Karumi/Dexter" target="_blank" rel="nofollow noopener noreferrer">Dexter</a></span></strong> library. Dexter is an Android library that simplifies the process of requesting permissions at runtime.</p>
<p class="p1">This is an introductory article about the Dexter covering basic features offered by the library. Dexter provides other features like using it with SnackBar, different types of listeners, error handling and a few others. You can find more information on Dexter’s <strong><span style="color: #008000;"><a style="color: #008000;" href="https://github.com/Karumi/Dexter"><span class="s1">developer</span></a></span></strong> page.</p>
<p><strong>Get <span style="color: #008000;">GITHUB</span> code from <span style="color: #0000ff;"><a style="color: #0000ff;" href="https://github.com/arunk7839/RuntimePermissionUsingDexter">HERE</a>.</span></strong></p>
<p><amp-youtube layout="responsive" width="1200" height="675" data-videoid="l3QZZOU6KPU" title="Android Runtime Permissions with Dexter"><a placeholder href="https://youtu.be/l3QZZOU6KPU"><img src="https://i.ytimg.com/vi/l3QZZOU6KPU/hqdefault.jpg" layout="fill" object-fit="cover" alt="Android Runtime Permissions with Dexter"></a></amp-youtube></p>
<h3><span style="color: #000080;"><strong>Adding Dexter Library</strong></span></h3>
<p>To get started with Dexter library firstly you have to include it in your <span style="color: #008000;"><strong>build.gradle</strong></span></p>
<pre>dependencies{
<span style="color: #0000ff;"><strong> // Dexter runtime permissions</strong></span>
 implementation <span class="pl-s"><span class="pl-pds">'</span>com.karumi:dexter:6.0.0<span class="pl-pds">'</span></span>
}</pre>
<p>To start using the library you just need to call <strong><span style="color: #008000;">Dexter</span></strong> with a valid <strong><span style="color: #008000;">Activity </span></strong>:</p>
<pre><span class="pl-k">public</span> <span class="pl-smi">MyActivity</span> extends <span class="pl-smi">Activity</span> {
 <span class="pl-k">@Override</span> 
<span class="pl-k"> public</span> <span class="pl-k">void</span> onCreate() {
 <span class="pl-c1">super</span><span class="pl-k">.</span>onCreate();
 <span class="pl-smi">Dexter</span><span class="pl-k">.</span>withActivity(activity)
 .withPermission(permission)
 .withListener(listener)
 .check();
 }
}</pre>
<h3><span style="color: #000080;"><strong>Requesting Single Permission</strong></span></h3>
<p class="p1">To request single permission, you can use <strong><span style="color: #008000;">withPermission()</span></strong> method by passing the required permission. You also need a <span style="color: #008000;"><b>PermissionListener</b></span> callback to receive the state of the permission.</p>
<ul>
<li class="p1"><b> <span style="color: #0000ff;">onPermissionGranted()</span></b> will be called once the permission is granted.</li>
<li class="p1"><b> <span style="color: #0000ff;">onPermissionDenied()</span></b> will be called when the permission is denied. Here you can check whether the permission is permanently denied by using <span style="color: #008000;"><b>response.isPermanentlyDenied()</b></span> condition.</li>
<li><strong><span style="color: #0000ff;">onPermissionRationaleShouldBeShown() </span></strong><span style="color: #000000;">will be called if the user has already declined the permission once. This method contains PermissionToken parameter using which you can call any of the two methods :</span></li>
</ul>
<p><strong><span style="color: #0000ff;">continuePermissionRequest()</span> </strong>: Continues with the permission request process.</p>
<p><strong><span style="color: #0000ff;">cancelPermissionRequest()</span></strong> : Cancels the permission request process.</p>
<p class="p1">The below code requests <span style="color: #008000;"><b>CAMERA</b></span> permission.</p>
<pre><span class="pl-smi">Dexter</span><span class="pl-k">.</span>withActivity(<span class="pl-c1">this</span>)
 .withPermission(<span class="pl-smi">Manifest</span><span class="pl-k">.</span><span class="pl-smi">permission<span class="pl-k">.</span>CAMERA</span>)
 .withListener(<span class="pl-k">new</span> <span class="pl-smi">PermissionListener</span>() {
 
<span class="pl-k"> @Override</span> 
<span class="pl-k"> public</span> <span class="pl-k">void</span> <span class="pl-en">onPermissionGranted</span>(<span class="pl-smi">PermissionGrantedResponse</span> <span class="pl-v">response</span>) {
 <strong><span style="color: #0000ff;">//permission is granted, open the camera</span></strong>
 }
 <span class="pl-k">@Override</span> 
<span class="pl-k"> public</span> <span class="pl-k">void</span> <span class="pl-en">onPermissionDenied</span>(<span class="pl-smi">PermissionDeniedResponse</span> <span class="pl-v">response</span>) {
<code class="java comments"><strong><span style="color: #0000ff;"> // check for permanent denial of permission</span></strong>
 </code><code>if</code> <code class="java plain">(response.isPermanentlyDenied()) {
 </code><span style="color: #0000ff;"><strong><code><span style="color: #0000ff;">// navigate user to app settings</span></code><code class="java comments">
</code></strong></span><code class="java plain">}
 </code>} <span class="pl-k"> @Override</span> <span class="pl-k"> public</span> <span class="pl-k">void</span> <span class="pl-en">onPermissionRationaleShouldBeShown</span>(<span class="pl-smi">PermissionRequest</span> <span class="pl-v">permission</span>, <span class="pl-smi">PermissionToken</span> <span class="pl-v">token</span>) { token.continuePermissionRequest(); } }) <span class="pl-k"> .</span>check();</pre>
<h3><strong><span style="color: #000080;">Requesting Multiple Permissions</span></strong></h3>
<p>To request multiple permissions at the same time, you can use <span style="color: #008000;"><strong>withPermissions()</strong></span> method. Below code requests <span style="color: #0000ff;"><strong>STORAGE</strong></span> and <span style="color: #0000ff;"><strong>LOCATION</strong></span> permissions.</p>
<ul>
<li class="p1"><b><span style="color: #0000ff;">onPermissionsChecked()</span></b> will be called if all permissions are granted.</li>
<li><strong><span style="color: #0000ff;">onPermissionRationaleShouldBeShown() </span></strong><span style="color: #000000;">will be called if the user has already declined the permission once.</span></li>
</ul>
<pre style="padding-left: 30px;">Dexter.withActivity(this)
 .withPermissions(
 Manifest.permission.READ_EXTERNAL_STORAGE,
 Manifest.permission.WRITE_EXTERNAL_STORAGE,
 Manifest.permission.ACCESS_FINE_LOCATION)
 .withListener(new MultiplePermissionsListener() {
 @Override
 public void onPermissionsChecked(MultiplePermissionsReport report) {
 <strong><span style="color: #0000ff;">// check if all permissions are granted</span></strong>
 if (report.areAllPermissionsGranted()) {
 <strong><span style="color: #0000ff;">// do you work now</span></strong>
 }
 <strong><span style="color: #0000ff;">// check for permanent denial of any permission</span></strong>
 if (report.isAnyPermissionPermanentlyDenied()) {
<strong><span style="color: #0000ff;"> // permission is denied permenantly, navigate user to app settings</span></strong>
 
 }
 }

 @Override
 public void onPermissionRationaleShouldBeShown(List<;Permissionsrequest>; permissions, PermissionToken token) {
 token.continuePermissionRequest();
 }
})
 .check();</pre>
<h3><strong><span style="color: #000080;">Error Handling</span></strong></h3>
<p>You can also catch any errors occurred while integrating the library using <span style="color: #008000;"><strong>PermissionRequestErrorListener</strong></span>.</p>
<pre> Dexter.withActivity(this)
 .withPermissions(
 Manifest.permission.READ_EXTERNAL_STORAGE,
 Manifest.permission.WRITE_EXTERNAL_STORAGE,
 Manifest.permission.ACCESS_FINE_LOCATION)
 .withListener(listener) 
 .withErrorListener(new PermissionRequestErrorListener() {
 @Override
 public void onError(DexterError error) {
 Toast.makeText(getApplicationContext(), "Error occurred! "+ error.toString() , Toast.LENGTH_SHORT).show();
 }
})
 .check();</pre>
<p>Now let’s see how to use Dexter in an example project.</p>
<h3><span style="color: #000080;"><strong>Creating New Project</strong></span></h3>
<p><strong>1</strong>. Create a new project in <span style="color: #008000;"><strong>Android Studio</strong></span> from <span style="color: #008000;"><strong>File ⇒ New Project</strong></span> and fill the project details.</p>
<p><strong>2</strong>. Add the latest <strong><span style="color: #0000ff;"><a style="color: #0000ff;" href="https://github.com/Karumi/Dexter">Dexter</a></span></strong> dependency to your <span style="color: #008000;"><strong>build.gradle.</strong></span></p>
<p><span style="color: #0000ff;"><strong>build.gradle</strong></span></p>
<pre>dependencies {
 implementation fileTree(dir: 'libs', include: ['*.jar'])
 implementation 'androidx.appcompat:appcompat:1.1.0'
 implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

 <span style="color: #0000ff;"><strong>// Dexter runtime permissions</strong></span>
 <strong><span style="color: #008000;">implementation 'com.karumi:dexter:6.0.0'</span></strong>
 testImplementation 'junit:junit:4.12'
 androidTestImplementation 'androidx.test:runner:1.2.0'
 androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}</pre>
<p><strong>3</strong>. Open <strong><span style="color: #008000;">AndroidManifest</span></strong> file and add all the permissions which you want to request.</p>
<p><strong><span style="color: #0000ff;">AndroidManifest.xml </span></strong></p>
<!-- WP QUADS Content Ad Plugin v. 2.0.98.1 -->
<div class="quads-location quads-ad2" id="quads-ad2" style="float:none;margin:0px;">

</div>

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

 <strong><span style="color: #0000ff;"><;uses-permission android:name="android.permission.CAMERA" />;</span></strong>
<strong><span style="color: #0000ff;"> <;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />;</span></strong>
<strong><span style="color: #0000ff;"> <;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />;</span></strong>
<strong><span style="color: #0000ff;"> <;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>;</span></strong>

 <;application
 android:allowBackup="true"
 android:icon="@mipmap/ic_launcher"
 android:label="@string/app_name"
 android:roundIcon="@mipmap/ic_launcher_round"
 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>;</pre>
<p><strong>4</strong>. Open the layout file of your main activity (<span style="color: #008000;"><strong>activity_main.xml</strong> </span>) and add two buttons to test different permission methods.</p>
<p><span style="color: #0000ff;"><strong>activity_main.xml</strong> </span></p>
<pre><;?xml version="1.0" encoding="utf-8"?>;
<;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context=".MainActivity">;


 <;LinearLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_centerHorizontal="true"
 android:layout_marginTop="100dp"
 android:orientation="vertical"
 android:paddingLeft="16dp"
 android:paddingRight="16dp">;

 <;Button
 android:id="@+id/btn_camera_permission"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_marginBottom="16dp"
 android:text="CAMERA PERMISSION" />;

 <;Button
 android:id="@+id/btn_multiple_permissions"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="MULTIPLE PERMISSIONS" />;

 <;/LinearLayout>;

<;/RelativeLayout>;</pre>
<p class="p1"><b>5</b>. Open <span style="color: #008000;"><b>MainActivity.java</b></span> and do the modification as shown below.</p>
<ul>
<li class="p1"><b><span style="color: #0000ff;">requestCameraPermission()</span></b> requests for camera permission.</li>
<li class="p1"><b><span style="color: #0000ff;">requestMultiplePermission()</span></b> requests multiple permissions at once.</li>
<li class="p1"><span style="color: #0000ff;"><b>response.isPermanentlyDenied()</b> </span>and <span style="color: #0000ff;"><b>report.isAnyPermissionPermanentlyDenied()</b></span> checks if the permission is denied permanently. Here we have to navigate user to app settings screen by showing a dialog.</li>
</ul>
<p><span style="color: #0000ff;"><b>MainActivity.java</b></span></p>
<pre>package com.example.dexterpermissionsdemo;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.DexterError;
import com.karumi.dexter.listener.PermissionDeniedResponse;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.PermissionRequestErrorListener;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import com.karumi.dexter.listener.single.PermissionListener;

import java.util.List;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

 private Button btnCameraPermission, btnMutiplePermissions;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);


 btnCameraPermission = findViewById(R.id.btn_camera_permission);
 btnMutiplePermissions = findViewById(R.id.btn_multiple_permissions);

 btnCameraPermission.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View view) {
 requestCameraPermission();
 }
 });

 btnMutiplePermissions.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View view) {
 requestMutiplePermission();
 }
 });
 }

 <strong><span style="color: #0000ff;">/**
 * Requesting multiple permissions (storage and location) at once
 * This uses multiple permission model from dexter
 */</span></strong>
 private void requestMutiplePermission() {
 Dexter.withActivity(this)
 .withPermissions(
 Manifest.permission.READ_EXTERNAL_STORAGE,
 Manifest.permission.WRITE_EXTERNAL_STORAGE,
 Manifest.permission.ACCESS_FINE_LOCATION)
 .withListener(new MultiplePermissionsListener() {
 @Override
 public void onPermissionsChecked(MultiplePermissionsReport report) {
 <strong><span style="color: #0000ff;">// check if all permissions are granted</span></strong>
 if (report.areAllPermissionsGranted()) {
 Toast.makeText(getApplicationContext(), "All permissions are granted!", Toast.LENGTH_SHORT).show();
 }

 <strong><span style="color: #0000ff;">// check for permanent denial of any permission</span></strong>
 if (report.isAnyPermissionPermanentlyDenied()) {
 <strong><span style="color: #0000ff;">// show alert dialog navigating to Settings</span></strong>
 showSettingsDialog();
 }
 }

 @Override
 public void onPermissionRationaleShouldBeShown(List permissions, PermissionToken token) {
 token.continuePermissionRequest();
 }
 }).
 withErrorListener(new PermissionRequestErrorListener() {
 @Override
 public void onError(DexterError error) {
 Toast.makeText(getApplicationContext(), "Error occurred!"+ error.toString(), Toast.LENGTH_SHORT).show();
 }
 })
 .onSameThread()
 .check();
 }

 <strong><span style="color: #0000ff;">/**
 * Requesting camera permission
 * This uses single permission model from dexter
 * Once the permission granted, opens the camera
 */</span></strong>
 private void requestCameraPermission() {
 Dexter.withActivity(this)
 .withPermission(Manifest.permission.CAMERA)
 .withListener(new PermissionListener() {
 @Override
 public void onPermissionGranted(PermissionGrantedResponse response) {
 <strong><span style="color: #0000ff;">// permission is granted</span></strong>
 openCamera();
 }

 @Override
 public void onPermissionDenied(PermissionDeniedResponse response) {
 <strong><span style="color: #0000ff;">// check for permanent denial of permission</span></strong>
 if (response.isPermanentlyDenied()) {
 showSettingsDialog();
 }
 }

 @Override
 public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
 token.continuePermissionRequest();
 }
 }).check();
 }

 <strong><span style="color: #0000ff;">/**
 * Showing Alert Dialog with Settings option
 * Navigates user to app settings
 */</span></strong>
 private void showSettingsDialog() {
 AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
 builder.setTitle("Need Permissions");
 builder.setMessage("This app needs permission to use this feature. You can grant them in app settings.");
 builder.setPositiveButton("GOTO SETTINGS", new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 dialog.cancel();
 openSettings();
 }
 });
 builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
 @Override
 public void onClick(DialogInterface dialog, int which) {
 dialog.cancel();
 }
 });
 builder.show();

 }

 <strong><span style="color: #0000ff;">// navigating user to app settings</span></strong>
 private void openSettings() {
 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
 Uri uri = Uri.fromParts("package", getPackageName(), null);
 intent.setData(uri);
 startActivityForResult(intent, 101);
 }

 private void openCamera() {
 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
 startActivityForResult(intent, 100);
 }
}</pre>
<p>When you run your application it will look like this as shown below :</p>
<p><img class="alignnone wp-image-1276" src="https://c1ctech.com/wp-content/uploads/2019/11/Screenshot_1573117321.png" alt="Screenshot_1573117321" width="320" height="569" /> <img class="alignnone wp-image-1275" src="https://c1ctech.com/wp-content/uploads/2019/11/Screenshot_1573117433.png" alt="Screenshot_1573117433" width="320" height="569" />

