Dangerous Permission is a category of permissions in Android that require explicit user consent through a runtime dialog while the app is running. According to the Android Developer Guide, 2024, dangerous permissions have ProtectionLevel dangerous and provide access to sensitive data: camera, microphone, location, and contacts. Without explicit user consent, the app cannot use these features.
Key Takeaways
Dangerous Permission is a category of Android system permissions that provide access to sensitive user data. Unlike normal permissions, dangerous permissions are not granted automatically during installation — the app must explicitly request them at runtime through the runtime mechanism introduced in Android 6.0 Marshmallow (API 23).
The need for explicit request is due to the nature of the data these permissions protect: user location, personal contacts, camera and microphone content, call history, and SMS. Android considers this data sensitive and requires the user to consciously grant access. According to the Android Privacy Sandbox (2024), users decline about 30 percent of runtime requests on average.
A key feature of Dangerous Permission is the ability to revoke it at any time. The user can go to Settings — Apps — Permissions and toggle any dangerous permission off. The app must be prepared for a permission that was previously granted to be revoked at any time without a restart.
The dangerous protection level is set in the system permission definitions at the OS level. When an app declares uses-permission with this protectionLevel, the system marks the permission as requiring a runtime request. Unlike normal, dangerous permissions are always displayed in the system permission management UI and can be revoked.
All dangerous permissions are grouped into Permission Groups by functional category. For example, CAMERA and CAMERA2 are in the CAMERA group, ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION are in the LOCATION group. If a user has granted one permission from a group, the remaining permissions in the same group are granted automatically without an additional dialog.
Runtime request is a mechanism where the app calls a system API to display a permission request dialog. The user sees a modal window with the permission name and Allow and Deny buttons. After the response, the system calls the onRequestPermissionsResult callback with the result.
The complete cycle includes three steps: checking status via checkSelfPermission, calling requestPermissions if the permission is not granted, and handling the result in onRequestPermissionsResult. Status checking is mandatory because the user may have revoked the permission at any time through settings, and calling a function without checking will lead to a SecurityException.
fun checkAndRequestCameraPermission() {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
openCamera()
}
else -> {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CAMERA_CODE
)
}
}
}
Result handling occurs in ActivityResultLauncher or onRequestPermissionsResult. The recommended modern approach is to use ActivityResultContracts.RequestPermission, which provides a cleaner API without explicit request codes. This contract returns a Boolean — whether the permission was granted or not.
Request dangerous permissions strictly in the context of using the feature, not at app startup. If the user pressed the camera button — request CAMERA. If they opened a map — request LOCATION. Contextual requests yield twice as many grants as requesting all permissions at first launch. It is also recommended to request no more than one permission at a time so that the user understands which feature requires access.
Android defines several groups of dangerous permissions, each containing one or more constants. The most complete list is available in the Manifest.permission class. Below are the main groups and permissions used in development.
| Permission Group | Permissions | API Access |
|---|---|---|
| CAMERA | CAMERA | Camera API, CameraX |
| LOCATION | ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION | FusedLocationProvider, Geofence |
| MICROPHONE | RECORD_AUDIO | MediaRecorder, AudioRecord |
| PHONE | READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG | TelephonyManager |
| CONTACTS | READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS | ContactsContract |
| SMS | READ_SMS, SEND_SMS, RECEIVE_SMS | SmsManager |
| STORAGE | READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE | MediaStore, File API |
| CALENDAR | READ_CALENDAR, WRITE_CALENDAR | CalendarContract |
Starting with Android 12, Google has tightened requirements for some permissions. For example, BLUETOOTH_CONNECT and BLUETOOTH_SCAN have become dangerous and require a runtime request. The BODY_SENSORS_BACKGROUND permission has also been added for background access to sensors. Developers need to update targetSdkVersion and test requests on current OS versions.
Android 13 (API 33) introduced new permissions for notifications (POST_NOTIFICATIONS) and media files (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO), replacing the general READ_EXTERNAL_STORAGE. Now access to photos, videos, and audio is requested separately through specialized permissions without a single dialog.
Dangerous and Normal Permission differ fundamentally in how they are granted, whether they can be revoked, and their UX. Normal is granted automatically during installation, Dangerous requires an explicit runtime dialog. Normal cannot be revoked through settings, Dangerous can be disabled at any time. This asymmetry creates different development patterns.
From a code perspective, dangerous permissions require more work: checkSelfPermission, requestPermissions, handling denial. For normal permissions, one line in AndroidManifest.xml is enough. However, Dangerous Permission gives the user control, which increases trust, especially for sensitive features like the camera or location.
The choice between categories is not up to the developer — it is determined by the system. The developer only declares uses-permission, and the system determines the category based on protectionLevel. However, the strategy for requesting dangerous permissions affects user experience: frequent or inappropriate dialogs lower the app's rating.
The modern way to request permissions in Kotlin is to use ActivityResultContracts.RequestMultiplePermissions or RequestPermission. These contracts are part of the androidx.activity library and provide a clean API based on lambdas, without needing to override onRequestPermissionsResult.
class CameraActivity : AppCompatActivity() {
private val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
openCamera()
} else {
showPermissionDeniedMessage()
}
}
fun requestCamera() {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED ->
openCamera()
ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.CAMERA
) ->
showRationaleDialog()
else ->
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
}
When an app needs several dangerous permissions at the same time, use RequestMultiplePermissions. The contract returns Map<String, Boolean> where the key is the permission name and the value is the result. This is useful at first launch when you need to request CAMERA and RECORD_AUDIO for video recording.
If the user denies the request, the shouldShowRequestPermissionRationale method returns true. This signals to show an explanation of why the permission is needed. Best practice is to show a custom dialog with an explanation and a Retry button. If the user denies the request again with the Never Ask Again checkbox checked, shouldShowRequestPermissionRationale will return false, and you need to redirect to Settings.
Never Ask Again is a flag that the user can set when declining the runtime dialog for the second time. After this, the standard dialog is no longer shown for that permission. The only way to grant access is to redirect the user to the system app settings.
The developer needs to distinguish between two denial scenarios: first, when shouldShowRequestPermissionRationale returns true (the user declined but the dialog can still be shown), and second, when the method returns false (Never Ask Again is active or the permission is blocked by policy). In the second case, you should show an Open Settings button.
fun handlePermissionDenied(permission: String) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this, permission
)) {
showRationaleDialog(permission)
} else {
showSettingsRedirectDialog(permission)
}
}
private fun showSettingsRedirectDialog(permission: String) {
AlertDialog.Builder(this)
.setTitle("Access denied")
.setMessage(
"Permission blocked. Open settings."
)
.setPositiveButton("Settings") { _, _ ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts(
"package", packageName, null
)
)
startActivity(intent)
}
.show()
}
It is important not to request the permission again if shouldShowRequestPermissionRationale returned false. A repeated call to requestPermissions in this case will not show a dialog — the result will come back immediately with DENIED without explanation. The user will encounter unclear behavior, which negatively affects the app experience.
Frequently Asked Questions
Dangerous Permission includes permissions with ProtectionLevel dangerous: CAMERA, RECORD_AUDIO, ACCESS_FINE_LOCATION, READ_CONTACTS, READ_SMS, READ_CALENDAR, and others. The full list is available in the Manifest.permission class.
Use ContextCompat.checkSelfPermission, passing the context and the permission name. The method returns PERMISSION_GRANTED or PERMISSION_DENIED. The check should be performed before every API call that requires a dangerous permission.
A Permission Group groups related dangerous permissions together. If a user grants one permission from a group, the rest are granted automatically. For example, LOCATION includes ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION.
Check shouldShowRequestPermissionRationale after denial. If the method returns false and the permission is still not granted — Never Ask Again is active. Redirect the user to Settings via Intent with ACTION_APPLICATION_DETAILS_SETTINGS.
Yes, they remain mandatory. On Android 13+, some permissions have changed: POST_NOTIFICATIONS became a separate runtime permission, and READ_EXTERNAL_STORAGE was replaced by READ_MEDIA_IMAGES for granular access to media files.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also