Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
📱 Device Features  ·  Lesson 35

Runtime Permissions

Normal vs dangerous permissions

TypeExamplesWhat you do
NormalINTERNET, VIBRATE, ACCESS_NETWORK_STATEDeclare in manifest — granted automatically
Dangerous (runtime)CAMERA, location, RECORD_AUDIO, READ_CONTACTS, POST_NOTIFICATIONS (13+)Declare and ask the user while the app runs
Not needed any morePicking photos (Photo Picker), sharing (intents), dialing (ACTION_DIAL)Use the system UI instead

The permission flow

User taps a feature (e.g. Scan)ask at the moment it is neededcheckSelfPermission == GRANTED?yes → use the featureshouldShowRequestPermissionRationale?yes → explain in a dialog firstlauncher.launch(permission)system dialog: Allow / Don't allowCallback(granted)use feature or show a friendly message
Ask only when needed, explain why
9:41▮▮ 85%Student Diary⋮Maths homeworkHighAllow notifications?Student Diary wants to send…DON'T ALLOWALLOW
The system permission dialog (Android 13+)

Step 1: Declare in the manifest

XML
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />            <!-- normal -->
<uses-permission android:name="android.permission.CAMERA" />              <!-- dangerous -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />  <!-- dangerous, API 33+ -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Step 2: Check and request

Kotlin
class ScanActivity : AppCompatActivity() {

    // 1. register BEFORE the activity is started (as a property)
    private val cameraPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
        if (granted) openCamera()
        else Snackbar.make(binding.root, "Camera permission is needed to scan", Snackbar.LENGTH_LONG).show()
    }

    private fun onScanClicked() {
        when {
            // 2. already granted?
            ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ==
                PackageManager.PERMISSION_GRANTED -> openCamera()

            // 3. user denied once → explain why first
            shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> showRationale()

            // 4. ask
            else -> cameraPermission.launch(Manifest.permission.CAMERA)
        }
    }
}

Step 3: Explain and handle denial

Kotlin
private fun showRationale() {
    MaterialAlertDialogBuilder(this)
        .setTitle("Allow camera?")
        .setMessage("We use the camera only to scan your ID card. Photos stay on your phone.")
        .setNegativeButton("Not now", null)
        .setPositiveButton("Continue") { _, _ -> cameraPermission.launch(Manifest.permission.CAMERA) }
        .show()
}

// Permanently denied → open the app's settings page
private fun openAppSettings() {
    startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
        Uri.fromParts("package", packageName, null)))
}

Several permissions at once

Kotlin
private val locationPermissions = registerForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { result ->
    val fine = result[Manifest.permission.ACCESS_FINE_LOCATION] == true
    val coarse = result[Manifest.permission.ACCESS_COARSE_LOCATION] == true
    when {
        fine -> startPreciseLocation()
        coarse -> startApproximateLocation()
        else -> showNoLocationMessage()
    }
}

locationPermissions.launch(arrayOf(
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION
))

Real example: notifications (Android 13+)

Kotlin – Student Diary
// Student Diary – MainActivity
private val notificationPermission =
    registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
        if (!granted) {
            Snackbar.make(binding.root, R.string.notifications_off, Snackbar.LENGTH_LONG).show()
        }
    }

private fun askNotificationPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && !NotificationHelper.canNotify(this)) {
        notificationPermission.launch(Manifest.permission.POST_NOTIFICATIONS)
    }
}

// NotificationHelper
fun canNotify(context: Context): Boolean =
    Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU ||
        ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) ==
        PackageManager.PERMISSION_GRANTED

Common mistakes

  • Asking for every permission at app start → users deny; ask when the feature is used.
  • Calling registerForActivityResult inside a click → crash; register as a property.
  • Forgetting the manifest entry → the dialog never shows and the result is always false.
  • Requesting POST_NOTIFICATIONS on Android 12 or lower → not needed; check the SDK version.

Summary

  • Normal permissions: manifest only. Dangerous: manifest + runtime request.
  • checkSelfPermission → rationale → RequestPermission launcher → callback.
  • Prefer permission-free system UIs (Photo Picker, intents) when possible.
✅ Practice

Add a "Scan QR" button that asks for camera permission with a rationale dialog, and shows an "Open Settings" Snackbar action when the permission is permanently denied.

Frequently Asked Questions

Do I need storage permission to pick a photo?
No. The Android Photo Picker (PickVisualMedia) gives your app access to the chosen image without any permission.
What happens after the user denies twice?
On Android 11+ the system stops showing the dialog ("don't ask again"). The request returns false immediately; guide the user to the app's Settings page instead.
Is INTERNET a runtime permission?
No. INTERNET is a normal permission: declaring it in the manifest is enough.
← Android Tutorial (Kotlin)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicCamera & Gallery (Pick Image) Your progress: 35 / 43 (81%) · Lesson 36 / 43 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free