Popular Searches
Popular Course Categories
Popular Courses

Managing Android Runtime Permissions

Managing Android Runtime Permissions

Authentication, Permissions, and Device Features

Managing Android Runtime Permissions

Course: Android App Development

Topic: Managing Android Runtime Permissions

Course Link: Android App Development Course

Demo Link: Register for a Course Demo

Academy Website: JustAcademy


1. Introduction to Android Runtime Permissions

Android applications often need access to device features and user information, such as the camera, microphone, location, contacts, photos, or notifications. Because these resources can involve privacy and security, Android provides a permission system that controls how applications access them.

A runtime permission is a permission that an application must request from the user while the app is running, rather than relying only on a declaration in the Android manifest. For permissions classified as dangerous, the application generally needs to explain the feature, request permission at an appropriate time, and handle the user's decision.

Permission management is an important part of Android development because an application must continue to behave correctly when a user grants, denies, or later revokes access. A well-designed permission flow requests only the access needed for a clear feature and provides a useful alternative when permission is unavailable.

Examples of Runtime Permissions

  • Camera: Capture photographs or scan QR codes.
  • Microphone: Record audio or support voice communication.
  • Location: Provide navigation or location-based services.
  • Contacts: Access contacts for a user-requested feature.
  • Notifications: Display ordinary notifications on Android 13 and higher.
  • Selected photos and videos: Access media selected by the user, depending on the Android version and access method.

2. Learning Objectives

After completing this topic, learners should be able to:

  • Understand the Android permission model.
  • Distinguish normal permissions from dangerous runtime permissions.
  • Declare the required permissions in the Android manifest.
  • Check whether a permission has already been granted.
  • Request permissions using modern Android APIs.
  • Handle granted, denied, and restricted permission states.
  • Explain why the app needs a permission before requesting it.
  • Handle permission changes across Android versions.
  • Test permission behavior and avoid unnecessary permission requests.
  • Design privacy-conscious permission flows for real applications.

3. What Is an Android Permission?

An Android permission is a control that regulates whether an application can perform a particular operation or access a protected resource. Some permissions are granted automatically during installation, while others require explicit user approval at runtime.

Android permissions are not a substitute for application-level authorization. For example, permission to access a device's location does not automatically authorize a user to view another person's private account data on your server.

Why Permissions Are Important

  • Privacy: They help protect sensitive information such as location and contacts.
  • Security: They limit access to protected device resources.
  • User control: Users can decide whether to allow certain features.
  • Transparency: Permission explanations help users understand why access is requested.
  • Compliance: Correct permission handling supports Android platform and app-store requirements.

4. Types of Android Permissions

Permission Category Description Example
Normal permissions Cover resources that generally present limited privacy risk and are granted automatically when declared appropriately. Internet access using INTERNET.
Dangerous permissions Protect sensitive data or operations and generally require runtime approval. Camera, microphone, and location access.
Signature permissions Are generally available only to applications signed with the same certificate as the declaring application. Access to a resource restricted to a trusted app suite.
Special app access Uses dedicated system settings or approval flows rather than the ordinary runtime permission dialog. Some overlay or broad file-management access.

Exact permission behavior depends on the permission, target SDK, Android version, and system policy. Always consult the documentation for the specific capability being implemented.

5. The Android Runtime Permission Model

Runtime permissions allow users to decide whether an application can access certain sensitive resources. The application should check the current permission status before performing a protected operation.

A typical permission workflow looks like this:

User selects a feature
        |
        v
Explain why permission is needed
        |
        v
Check current permission status
        |
        +---- Permission granted ----> Continue feature
        |
        +---- Permission missing ----> Request permission
                                      |
                                      v
                               Handle user decision
                                      |
                    +-----------------+-----------------+
                    |                 |                 |
                 Granted           Denied        Not available
                    |                 |                 |
                    v                 v                 v
              Continue feature   Offer alternative   Explain or
                                                     guide to settings

The explanation is not always required as a separate screen, but it is good practice when the purpose of the permission may not be obvious. The app should not request permission until it is relevant to a user action or feature.

6. Step 1: Declare Permissions in AndroidManifest.xml

Permissions that require declaration must be listed in the application's manifest. Declaring a permission does not, by itself, grant a dangerous runtime permission.

For example, an application that uses the camera may declare:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

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

    <application
        android:label="Permission Demo"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar">

        <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>

Use the actual theme and activity configuration from your project. The example focuses on the manifest declaration for the camera permission.

Important Manifest Rules

  • Declare only the permissions required by the app's functionality.
  • Place <uses-permission> elements directly under <manifest>, not inside <application>.
  • Request dangerous permissions at runtime where required.
  • Do not assume that a manifest declaration means the user has approved access.
  • Review the merged manifest because libraries can contribute permission declarations.

7. Step 2: Check Whether a Permission Is Granted

Before requesting a permission, check its current status. AndroidX provides ContextCompat.checkSelfPermission() for this purpose.

import android.Manifest
import android.content.pm.PackageManager
import androidx.core.content.ContextCompat
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    private fun hasCameraPermission(): Boolean {
        return ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED
    }
}

The function returns true when camera permission is granted and false otherwise. Call it before starting a camera operation that requires this permission.

Why Should Permission Status Be Checked Again?

A user can change permissions in Android settings after granting them. Therefore, an application should not rely on an old permission result indefinitely. Recheck permission when the protected feature is about to be used, especially after returning from settings or resuming the application.

8. Step 3: Request Permissions with Activity Result APIs

For modern Android development, AndroidX Activity Result APIs are recommended for requesting runtime permissions. These APIs provide a lifecycle-aware way to launch the permission request and receive the result.

The following Kotlin example requests camera permission:

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {

    private val cameraPermissionLauncher =
        registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) { isGranted ->
            if (isGranted) {
                openCameraFeature()
            } else {
                showCameraPermissionDeniedMessage()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Call requestCameraPermission() after the user
        // selects a feature that needs the camera.
    }

    private fun requestCameraPermission() {
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.CAMERA
            ) == PackageManager.PERMISSION_GRANTED
        ) {
            openCameraFeature()
        } else {
            cameraPermissionLauncher.launch(
                Manifest.permission.CAMERA
            )
        }
    }

    private fun openCameraFeature() {
        // Start the camera workflow here.
    }

    private fun showCameraPermissionDeniedMessage() {
        // Explain that the camera feature is unavailable
        // without permission and offer an alternative.
    }
}

Register the launcher as a property of the activity or fragment, before the activity or fragment reaches the started state. Call the request method in response to an appropriate user action, such as tapping a button labeled “Scan QR Code.”

9. Step 4: Explain Why the App Needs Permission

Users are more likely to understand a permission request when it appears in the context of a feature they have chosen. An application should explain the purpose in plain language and avoid misleading users about what access is needed.

Example Explanation

private fun explainCameraPermission() {
    // Display a short explanation in your UI, such as:
    // "Camera access is needed to scan QR codes."
    //
    // After the user chooses to continue, call
    // requestCameraPermission().
}

This method is intentionally a placeholder for your UI implementation. You can use an explanatory dialog, an inline message, or a dedicated screen depending on the design. Avoid displaying the explanation repeatedly when the user already understands the feature.

10. Step 5: Handle Permission Denial

A permission denial should not cause the entire application to crash or become unusable. Instead, disable or adapt the feature that requires the permission and explain the available alternatives.

For example, if the user denies camera access, the app could offer manual entry of a QR code's content or allow the user to continue using other parts of the application.

private fun showCameraPermissionDeniedMessage() {
    // Update your UI to explain:
    // "Camera access is disabled. You can enter the
    // code manually or enable camera access in Settings."
    //
    // Keep unrelated app functionality available.
}

Good Denial Handling

  • Explain which feature is affected.
  • Keep unrelated features working normally.
  • Offer a practical alternative when possible.
  • Do not repeatedly trigger permission dialogs without a user action.
  • Provide a settings route only when it is appropriate and useful.

11. Understanding Should Show Rationale

Android provides ActivityCompat.shouldShowRequestPermissionRationale() to help determine whether an explanation should be shown before requesting a permission again. Its result must be interpreted carefully: a false result can mean the permission has not been requested before, or that the system will not show the regular permission dialog again. The function alone does not reliably distinguish every permission state.

import androidx.core.app.ActivityCompat

private fun shouldExplainCameraPermission(): Boolean {
    return ActivityCompat.shouldShowRequestPermissionRationale(
        this,
        android.Manifest.permission.CAMERA
    )
}

Use this information alongside your own permission-request history and the result returned by the Activity Result API. On a first request, the rationale function may return false; do not automatically interpret that as a permanent denial.

12. Handling a Permission That Cannot Be Requested Again

Depending on the permission and Android version, repeated denial or a system decision may result in the regular permission dialog no longer appearing. In this situation, the app can explain how to enable the permission through system settings.

Do not assume that every denial means the user has permanently blocked the request. The exact behavior varies with Android version, permission type, request history, and device policy.

Opening Application Settings

import android.content.Intent
import android.net.Uri
import android.provider.Settings

private fun openAppSettings() {
    val intent = Intent(
        Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
        Uri.fromParts("package", packageName, null)
    )

    startActivity(intent)
}

Use this function after explaining why the setting is relevant. When the app resumes, check the permission status again instead of assuming that the user enabled it.

13. Example: Managing Location Permission

Location permission can provide approximate or precise location, depending on the user's choice, Android version, and the permission requested. Apps should request only the level of location access that the feature actually needs.

For an application that needs location while it is in use, the manifest may include:

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

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

When requesting location, consider whether approximate location is sufficient. On supported Android versions, users may choose approximate access even when the app requests precise access.

Example for requesting approximate location:

private val locationPermissionLauncher =
    registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted ->
        if (isGranted) {
            // Continue with approximate location functionality.
        } else {
            // Offer a non-location alternative.
        }
    }

private fun requestApproximateLocation() {
    val permission =
        android.Manifest.permission.ACCESS_COARSE_LOCATION

    if (ContextCompat.checkSelfPermission(
            this,
            permission
        ) == PackageManager.PERMISSION_GRANTED
    ) {
        // Permission already granted.
    } else {
        locationPermissionLauncher.launch(permission)
    }
}

This is an illustrative example for a feature that can work with approximate location. If the application genuinely requires precise location, follow Android's documented request sequence for coarse and fine location together and handle the user's selected accuracy level.

14. Example: Managing Notification Permission

Android 13, API level 33, introduced the POST_NOTIFICATIONS runtime permission for ordinary app notifications. On Android versions below API 33, this runtime permission request is not needed, although users may still control notifications through system settings and other platform behavior.

Declare the permission where appropriate:

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

Then request it on Android 13 and higher:

import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat

private val notificationPermissionLauncher =
    registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted ->
        if (isGranted) {
            // Notifications may be shown, subject to
            // channel and device settings.
        } else {
            // Keep the application usable without them.
        }
    }

private fun requestNotificationPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        val permission = Manifest.permission.POST_NOTIFICATIONS

        if (ContextCompat.checkSelfPermission(
                this,
                permission
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            notificationPermissionLauncher.launch(permission)
        }
    } else {
        // No POST_NOTIFICATIONS runtime request is needed
        // on Android versions below API 33.
    }
}

Request notification permission at a suitable point in the user journey, ideally after explaining the value of notifications. A granted permission does not guarantee that every notification will appear; users can disable individual channels or change other system settings.

15. Request Multiple Runtime Permissions

Some features require more than one permission. For example, a voice-recording feature might need microphone access, while a location-sharing feature might require location permission. Request only the permissions required for the feature the user has chosen.

AndroidX provides ActivityResultContracts.RequestMultiplePermissions() to request multiple permissions and receive a map of permission names to grant results.

import android.Manifest
import android.content.pm.PackageManager
import androidx.activity.result.contract.ActivityResultContracts

private val multiplePermissionLauncher =
    registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { results ->
        val cameraGranted =
            results[Manifest.permission.CAMERA] == true

        val microphoneGranted =
            results[Manifest.permission.RECORD_AUDIO] == true

        if (cameraGranted && microphoneGranted) {
            // Continue with the feature that needs both.
        } else {
            // Explain which functionality is unavailable.
        }
    }

private fun requestCameraAndMicrophone() {
    multiplePermissionLauncher.launch(
        arrayOf(
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO
        )
    )
}

Declare the required permissions in the manifest before requesting them. In production, check the current status of each permission first and avoid asking for permissions that are already granted. If the feature can work with only one of the permissions, handle each result independently rather than blocking the entire feature.

16. Managing Permission Changes When the App Resumes

Users can change permission settings while the application is in the background. Therefore, permission-dependent functionality should check access again when the user returns to the relevant screen or initiates the protected action.

override fun onResume() {
    super.onResume()

    if (hasCameraPermission()) {
        // Enable camera-dependent controls if appropriate.
    } else {
        // Disable or adapt camera-dependent controls.
    }
}

This example assumes that the activity already contains the hasCameraPermission() function introduced earlier. Checking permission in onResume() can help refresh the interface after a return from system settings. You should still check immediately before accessing the protected resource.

17. Permissions and Android Version Compatibility

Permission requirements can change between Android releases. An application should consider both the device's Android version and its own target SDK when deciding which permissions to request and which APIs to use.

Android Version Permission Considerations
Android 5.1 and earlier The modern runtime permission model was not used in the same way as Android 6.0 and later.
Android 6.0 and later Dangerous permissions require runtime handling when applicable.
Android 8.0 and later Notification channels are required for ordinary notifications posted by apps targeting these versions.
Android 10 and later Location access and background location behavior have additional restrictions and requirements.
Android 11 and later Some permissions have one-time or more restrictive grant behavior; repeated denial can affect whether another system prompt appears.
Android 12 and later Users can choose approximate location for applications that support location access.
Android 13 and later Ordinary app notifications use the POST_NOTIFICATIONS runtime permission, subject to platform rules and target SDK behavior.
Later Android releases Additional privacy controls and changes may apply. Check current Android documentation for the specific permission and API level.

This table is a high-level guide, not a complete list of version-specific changes. Always verify current documentation before implementing location, media, background, or special permissions.

18. Special Permissions and Settings-Based Access

Not every protected capability uses the standard runtime permission dialog. Some capabilities require a dedicated settings screen, a system-mediated workflow, or a special app-access grant.

Examples include certain overlay operations, broad access to files, and specific background capabilities. The appropriate flow depends on the feature and the Android version.

Best Practices for Special Access

  • Read the documentation for the exact API being used.
  • Use the narrowest available access method.
  • Explain why the access is needed before directing the user to settings.
  • Check the access status after the user returns to the app.
  • Do not assume that opening a settings page means the user granted access.
  • Avoid requesting special access when a system picker or narrower API can accomplish the same task.

19. Avoid Unnecessary Permissions

Good permission management begins before any permission dialog appears. Developers should evaluate whether the app truly needs the protected resource or whether a system-provided alternative can accomplish the same task.

Requirement Possible Alternative
Select a photo Use the system photo picker when appropriate instead of requesting broad media access.
Choose a document Use the Storage Access Framework document picker where suitable.
Capture an image Consider a system camera capture intent if direct camera control is not needed.
Choose a location on a map Allow manual selection when live device location is not essential.
Show an optional notification Keep the main app experience available even when notification permission is denied.

These alternatives can reduce permission prompts, simplify implementation, and give users more control over what they share with the application.

20. Common Permission Management Errors

Error Why It Happens Recommended Solution
Permission dialog never appears The permission may already be granted, or the system may no longer display the normal prompt. Check permission status and rationale behavior; provide a settings route when appropriate.
App crashes after permission denial The code accesses a protected resource without checking permission. Check permission before every protected operation and handle denial gracefully.
Permission is requested at startup The app asks for access before the user understands why it is necessary. Request permission when the user chooses the relevant feature.
Permission is declared but access fails A manifest declaration alone does not grant a dangerous runtime permission. Check and request runtime permission where required.
App assumes permission remains granted The user can revoke access through system settings. Recheck the permission when the feature is used and when refreshing relevant UI.
Too many permissions are requested The app or one of its libraries requests unnecessary access. Review the merged manifest and remove permissions that are not needed.
Permission rationale appears repeatedly The app does not track the request flow or uses the rationale callback incorrectly. Use the rationale API together with current permission status and appropriate UI state.
App does not work on a newer Android version The platform introduces additional permission requirements or behavior changes. Test supported API levels and review current Android permission documentation.

21. Permission Management Best Practices

  • Request in context: Ask for access when the user initiates the feature that requires it.
  • Explain clearly: State what resource is needed and how it improves the feature.
  • Minimize access: Request only the permission required for the current task.
  • Check before use: Never assume a permission has been granted.
  • Handle denial gracefully: Keep unrelated app features available.
  • Respect user decisions: Avoid repeated or manipulative permission requests.
  • Support alternatives: Offer manual input or system pickers where suitable.
  • Recheck after settings changes: Permission status can change while the app is inactive.
  • Test different states: Verify first request, grant, denial, revocation, and restricted-access behavior.
  • Audit dependencies: Review permissions introduced by third-party libraries.
  • Protect sensitive data: Do not collect or retain more data than the feature needs.
  • Keep code maintainable: Centralize permission-related logic when multiple screens need the same behavior.

22. Practical Project: Android Permission Manager

Create a sample Android application that demonstrates camera, location, and notification permission handling. The application should request access only when the user chooses the related feature.

Project Requirements

  • Create a screen with buttons for Camera, Location, and Notifications.
  • Declare the necessary permissions in the manifest.
  • Use Activity Result APIs to request runtime permissions.
  • Check permission status before opening each feature.
  • Show a clear explanation where appropriate.
  • Handle granted and denied results separately.
  • Provide a route to application settings when useful.
  • Refresh permission-dependent controls when the app resumes.
  • Keep the app's unrelated features available if access is denied.
  • Test the application on more than one Android API level.

Suggested Project Structure

app/
  src/main/
    java/com/example/permissiondemo/
      MainActivity.kt
      PermissionHelper.kt
    res/
      layout/
        activity_main.xml
    AndroidManifest.xml

This is a suggested structure for a simple Views-based application. A Jetpack Compose application can implement the same permission flow using its existing UI architecture.

Testing Checklist

  • Permission declarations match the app's features.
  • The app does not request all permissions on launch.
  • Each protected feature checks permission before use.
  • The grant callback starts the appropriate feature.
  • The denial callback displays a useful message.
  • Optional functionality remains usable after denial.
  • Returning from settings refreshes permission status.
  • Android 13 notification permission is handled correctly.
  • The application behaves correctly after a permission is revoked.
  • No unnecessary permissions are included through the app or its dependencies.

23. Practice Exercises

  1. Create an Android activity that checks and requests camera permission.
  2. Implement a permission rationale screen with Continue and Cancel options.
  3. Use RequestMultiplePermissions() for a feature requiring two permissions.
  4. Request notification permission only on Android 13 and higher.
  5. Implement an application-settings shortcut for a permission that cannot be requested through the usual prompt.
  6. Build a location feature that works with approximate location when possible.
  7. Test the app after granting and revoking permission in system settings.
  8. Inspect the merged manifest and identify permissions introduced by libraries.
  9. Replace unnecessary broad access with an appropriate system picker.
  10. Document how the application behaves when every optional permission is denied.

24. Interview Questions and Answers

Q1. What is a runtime permission in Android?

Answer: A runtime permission is a permission that an app must request from the user while running when the permission and Android version require runtime approval.

Q2. What is the difference between a normal permission and a dangerous permission?

Answer: Normal permissions generally protect resources with limited privacy risk and are granted automatically when declared correctly. Dangerous permissions protect more sensitive resources and generally require runtime approval.

Q3. Why must permissions be declared in AndroidManifest.xml?

Answer: The manifest declares the permissions an application needs. For dangerous permissions, the declaration does not replace the runtime request.

Q4. What does checkSelfPermission() do?

Answer: It checks whether the application currently has the specified permission. The app should check before performing the protected operation.

Q5. What is ActivityResultContracts.RequestPermission()?

Answer: It is an AndroidX Activity Result contract that launches a request for a single runtime permission and returns the user's decision through a callback.

Q6. What is shouldShowRequestPermissionRationale() used for?

Answer: It helps determine whether the app should show an explanation before requesting a permission again. It does not independently reveal every aspect of the permission's history or state.

Q7. What should an app do if the user denies permission?

Answer: The app should explain which feature is affected, offer an alternative where possible, and keep unrelated features working.

Q8. Can a user revoke a permission after granting it?

Answer: Yes. Users can change app permissions in system settings, so applications should recheck permission status before accessing protected resources.

Q9. What is the POST_NOTIFICATIONS permission?

Answer: It is the runtime permission introduced for ordinary app notifications on Android 13 and higher. Apps should request it when appropriate and continue to work as well as possible if it is denied.

Q10. Why should an app avoid requesting every permission at startup?

Answer: Users may not understand the purpose of each request. Asking only when a relevant feature is used improves transparency and reduces unnecessary access.

Q11. What is the difference between runtime permissions and special app access?

Answer: Runtime permissions use the standard permission-request flow, while special app access often requires a dedicated system settings or approval workflow.

Q12. How should developers test permission handling?

Answer: Test granted, denied, revoked, and restricted states across supported Android versions, and verify that the application does not crash when access is unavailable.

25. Quick Revision

  • Runtime permissions protect sensitive resources and operations.
  • Declare required permissions in the Android manifest.
  • Check permission status before accessing a protected resource.
  • Use Activity Result APIs for modern permission requests.
  • Explain permission requests in the context of a user-selected feature.
  • Use rationale behavior carefully and do not assume a single callback explains every state.
  • Handle permission denial without crashing or unnecessarily blocking the app.
  • Recheck permissions after the user returns from system settings.
  • Use system pickers or narrower alternatives when possible.
  • Test permissions across Android versions and different user choices.

26. Official Learning Resources

27. Conclusion

Managing Android runtime permissions is an essential skill for building secure, reliable, and user-friendly applications. Developers must understand the permission model, declare necessary permissions, check current access, request permission at the right time, and handle every possible result.

Good permission management also means minimizing data access, explaining the purpose of requests, supporting alternative workflows, and testing how the application behaves when permissions are denied or revoked. These practices help developers build applications that respect user privacy without unnecessarily limiting functionality.

To learn more about Android development, visit the JustAcademy Android App Development Course, register for a course demo, or explore the JustAcademy website.

Previous Next
whatsapp