In Android, runtime permissions refer to the permissions that an app must request from the user while the app is running in order to access sensitive data or perform certain actions. These permissions are introduced in Android 6.0 (API level 23) as a part of the Android Runtime (ART) permission model, which allows users to have more control over the permissions granted to apps.
Before Android 6.0, users had to grant all permissions at the time of installation. With runtime permissions, apps only request permissions when they are actually needed, improving user privacy and control. Here’s how runtime permissions work:
- Permission Groups: Permissions are grouped based on their functionality, such as location, camera, contacts, etc.
(ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_CODE); }
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == CAMERA_PERMISSION_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission granted, proceed with using the camera } else { // Permission denied, handle accordingly } } }
(ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { // Permission is already granted, proceed with using the camera } else { // Request permission from the user }
It’s important to note that you should provide clear explanations to the user about why your app needs the requested permissions. Users are more likely to grant permissions if they understand why they are necessary.
Also, starting from Android 10 (API level 29), some permissions like location access have more nuanced options, such as allowing access only while the app is in use, and users can choose to grant permissions in those specific contexts.
Keep in mind that Android’s permission model might have evolved since my knowledge cutoff in September 2021, so be sure to refer to the official Android documentation for the most up-to-date information.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<Button
android:id="@+id/check_permission"
android:layout_width="match_parent"
android:layout_centerInParent="true"
android:layout_height="wrap_content"
android:text="Check Permission"/>
<Button
android:id="@+id/request_permission"
android:layout_below="@+id/check_permission"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Request Permission"/>
</LinearLayout>
MainActivity.kt
package com.androindian.perminssions
import android.content.DialogInterface
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import android.view.View
import android.widget.Button
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private var view: View? = null
private val PERMISSION_REQUEST_CODE = 200
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val check_permission = findViewById<View>(R.id.check_permission) as Button
val request_permission = findViewById<View>(R.id.request_permission) as Button
check_permission.setOnClickListener {
if (checkPermission()) {
Toast.makeText(this, "Permission already granted.", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this, "Please request permission.", Toast.LENGTH_SHORT).show()
}
}
request_permission.setOnClickListener {
if (!checkPermission()) {
requestPermission()
} else {
Toast.makeText(this, "Permission already granted.", Toast.LENGTH_SHORT).show()
}
}
}
private fun checkPermission(): Boolean {
val result =
ContextCompat.checkSelfPermission(this@MainActivity, android.Manifest.permission.ACCESS_FINE_LOCATION)
val result1 = ContextCompat.checkSelfPermission(applicationContext,android.Manifest.permission.CAMERA)
return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED
}
private fun requestPermission() {
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.CAMERA),
PERMISSION_REQUEST_CODE
)
}
@SuppressLint("MissingSuperCall")
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
when (requestCode) {
PERMISSION_REQUEST_CODE -> if (grantResults.size > 0) {
val locationAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED
val cameraAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED
if (locationAccepted && cameraAccepted)
Toast.makeText(this@MainActivity,"Permission Granted, Now you can access location data and camera.",Toast.LENGTH_SHORT).show()
else {
Toast.makeText(this@MainActivity,"Permission Denied, You cannot access location data and camera.",Toast.LENGTH_SHORT).show()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (shouldShowRequestPermissionRationale(android.Manifest.permission.ACCESS_FINE_LOCATION)) {
showMessageOKCancel(
"You need to allow access to both the permissions"
) { dialog, which ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(
arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.CAMERA),
PERMISSION_REQUEST_CODE
)
}
}
return
}
}
}
}
}
}
private fun showMessageOKCancel(message: String, okListener: DialogInterface.OnClickListener) {
AlertDialog.Builder(this@MainActivity)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show()
}
}
androidmanifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="CoarseFineLocation">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
tools:ignore="CoarseFineLocation"/>
<uses-permission android:name="android.permission.CAMERA"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Perminssions"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>