Requesting Android Runtime Permissions

Hello there, today we will discuss requesting Android runtime permissions and how to use them. Since the introduction of Android 6.0 Marshmallow (SDK 23), Android will prompt users to accept or deny the specific permissions to use some of the features within the application such as Camera, Location services, record audio, etc.

As the developers, of course, we must handle these new Android runtime permissions to use some specific features starting at SDK 23 above, otherwise, the app will crash. So how do we implement it?

What will you learn?

  • Know how to check and request a runtime permissions on Android app.
  • Understand how handle more than one Android runtime permissions.

Note: In this post, I used Android Studio Arctic Fox, make sure you use the latest Android Studio, or if you already install it, be sure to check the latest update. The Kotlin version that I used is Kotlin 1.6.10.

What will the app look like?

The app will look like this after you finish this tutorial:

Getting Started – Requesting Android Runtime Permissions

Open your Android Studio and choose to Start a new Android Studio Project. Then set the Application Name as you prefer, on this tutorial, I use RuntimePermissions and select Kotlin as the language. On the next screen, select Empty Activity and give the Activity Name MainActivity and wait until the Android Studio finishes preparing your project.

Preparing the XML Layout

The first is preparing the XML layout for our app here. Open the activity_main.xml inside the res/layout directory and put the code below:

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:padding="16dp"
    android:gravity="center">

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/buttonRequestLocationPermissions"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Request Location Permissions"
        />

    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/buttonRequestCameraPermissions"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Request Camera Permissions"
        android:layout_marginTop="20dp"
        />

</androidx.appcompat.widget.LinearLayoutCompat>

The XML contains only two buttons, the first one, buttonRequestLocationPermissions is to check and request location service. While the last one buttonRequestCameraPermissions is to check and request camera and audio recording permissions.

Declaring Permissions on Manifest

The next step is to add permissions that we will use on the AndroidManifest.xml file:

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

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

After adding those permissions, proceed to the next step that is the coding step to check and request the Android runtime permissions.

Check and request location permission

For a single permission request, I will give the example of requesting the location permission, go to MainActivity.kt file and insert this code inside onCreate method:

findViewById<AppCompatButton>(R.id.buttonRequestLocationPermissions).setOnClickListener {
    checkAndRequestLocationPermission()
}

Then add insert a new function checkAndRequestLocationPermission:

private fun checkAndRequestLocationPermission() {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
        // permission has not been granted, so request permission

        ActivityCompat.requestPermissions(
            this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_CODE
        )
    } else {
        // permission has been granted, continue as usual
        Toast.makeText(this, "Permission already been granted", Toast.LENGTH_SHORT).show()
    }
}

This function or method is to check the permission first using ActivityCompat.checkSelfPermission() and if the user has not granted the permissions, we request the permission using ActivityCompat.requestPermissions() function.

Proceed to the next step to handle user callback on granting android runtime permissions. Insert callback function like this:

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)

    // handling callback on request location permission
    if (requestCode == REQUEST_LOCATION_CODE) {
        if (grantResults.size == 1 && grantResults.first() == PackageManager.PERMISSION_GRANTED) {
            // permission has been granted, continue as usual
            Toast.makeText(this, "Permission already been granted", Toast.LENGTH_SHORT).show()
        } else {
            // Permission was denied or request was cancelled
            Toast.makeText(this, "Permission denied or cancelled", Toast.LENGTH_SHORT).show()
        }
    }
}

To handle the permission granting callbacks, we have to use onRequestPermissionsResult and check if specific permission has already been granted or denied.

When you run the app will be like this:

Requesting Android Runtime Permissions
Location Permission

Check and request more than one permission

For checking and requesting more than one permission, I will give you another example of requesting camera and audio recording permissions. Same with location before, just add more parameters on ActivityCompat.

This is the final code of MainActivity.kt that already include request location and camera permissions:

import android.Manifest
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.widget.AppCompatButton
import androidx.core.app.ActivityCompat

class MainActivity : AppCompatActivity() {

    private val REQUEST_LOCATION_CODE = 100
    private val REQUEST_CAMERA_CODE = 200

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<AppCompatButton>(R.id.buttonRequestLocationPermissions).setOnClickListener {
            checkAndRequestLocationPermission()
        }

        findViewById<AppCompatButton>(R.id.buttonRequestCameraPermissions).setOnClickListener {
            checkAndRequestCameraPermissions()
        }
    }

    private fun checkAndRequestLocationPermission() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {
            // permission has not been granted, so request permission

            ActivityCompat.requestPermissions(
                this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_CODE
            )
        } else {
            // permission has been granted, continue as usual
            Toast.makeText(this, "Permission already been granted", Toast.LENGTH_SHORT).show()
        }
    }

    private fun checkAndRequestCameraPermissions() {
        if (
            ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED &&
            ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED
        ) {
            // permission has not been granted, so request permission
            ActivityCompat.requestPermissions(
                this, arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO), REQUEST_CAMERA_CODE
            )
        } else {
            // permission has been granted, continue as usual
            Toast.makeText(this, "Permission already been granted", Toast.LENGTH_SHORT).show()
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        // handling callback on request location permission
        if (requestCode == REQUEST_LOCATION_CODE) {
            if (grantResults.size == 1 && grantResults.first() == PackageManager.PERMISSION_GRANTED) {
                // permission has been granted, continue as usual
                Toast.makeText(this, "Permission already been granted", Toast.LENGTH_SHORT).show()
            } else {
                // Permission was denied or request was cancelled
                Toast.makeText(this, "Permission denied or cancelled", Toast.LENGTH_SHORT).show()
            }
        }

        // handling callback on request camera and record audio permission
        if (requestCode == REQUEST_CAMERA_CODE) {
            if (
                grantResults.size == 2 &&
                grantResults[0] == PackageManager.PERMISSION_GRANTED &&
                grantResults[1] == PackageManager.PERMISSION_GRANTED
            ) {
                // permission has been granted, continue as usual
                Toast.makeText(this, "Permission already been granted", Toast.LENGTH_SHORT).show()
            } else {
                // Permission was denied or request was cancelled
                Toast.makeText(this, "Permission denied or cancelled", Toast.LENGTH_SHORT).show()
            }
        }
    }
}
Requesting Android Runtime Permissions
Camera and Record Audio Permissions

Where to go next?

You can download this full code from the link below:

Download final code

Be sure to check my other cool posts here about:

I hope you like my post, comment and share it with love!

You may also like...

Join the discussion...

This site uses Akismet to reduce spam. Learn how your comment data is processed.