Skip to main content

Managing Permissions

1. Declaring Permissions in Manifest

Permission Group Description Protection Level
android.permission.ACCESS_COARSE_LOCATION Location Allows an app to access approximate location Normal
android.permission.ACCESS_FINE_LOCATION Location Allows an app to access precise location Signature
android.permission.CAMERA Camera Allows an app to open camera Normal
android.permission.READ_CONTACTS Contacts Allows an app to read the user's contacts Normal
android.permission.RECORD_AUDIO Microphone Allows an app to record audio Normal
android.permission.WRITE_EXTERNAL_STORAGE Storage Allows an app to write to external storage Normal

Example: Declaring Permissions in AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <application ... >
        ...
    </application>
</manifest>

2. Requesting Runtime Permissions

Permission Type Description Group
android.permission.CAMERA Normal Allows access to camera hardware Camera
android.permission.ACCESS_FINE_LOCATION Signature Allows access to precise location data Location
android.permission.READ_CONTACTS Normal Allows reading contact data Contacts
android.permission.RECORD_AUDIO Normal Allows recording audio Microphone

Example: Requesting Camera Permission

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

class MainActivity : AppCompatActivity() {
    private val CAMERA_PERMISSION_CODE = 100

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

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.CAMERA),
                CAMERA_PERMISSION_CODE
            )
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == CAMERA_PERMISSION_CODE) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission granted, proceed with camera usage
            } else {
                // Permission denied, handle accordingly
            }
        }
    }
}
Note: Runtime permissions are only required for dangerous permissions. Normal permissions are automatically granted.
Warning: If a user denies a permission, you should provide clear feedback and explain why the permission is needed.

3. Checking Permission Status

Permission Status Description
android.permission.CAMERA PackageManager.PERMISSION_GRANTED User has granted camera access
android.permission.ACCESS_FINE_LOCATION PackageManager.PERMISSION_GRANTED User has granted precise location access
android.permission.READ_CONTACTS PackageManager.PERMISSION_GRANTED User has granted contact read access

Example: Check Camera Permission

val cameraPermission = "android.permission.CAMERA"
val permissionStatus = ContextCompat.checkSelfPermission(this, cameraPermission)

if (permissionStatus == PackageManager.PERMISSION_GRANTED) {
    // Proceed with camera usage
} else {
    // Request permission or show rationale
}
Note: Runtime permissions must be checked before using sensitive APIs.

4. Handling Permission Results

Permission Status Description
android.permission.CAMERA NEW GRANTED Allows access to camera hardware
android.permission.ACCESS_FINE_LOCATION DENIED User denied location access
android.permission.READ_CONTACTS GRANTED Read contact list from device

Example: Requesting Camera Permission

class MainActivity : AppCompatActivity() {
    private val CAMERA_PERMISSION = Manifest.permission.CAMERA
    private val PERMISSION_REQUEST_CODE = 100

    fun requestCameraPermission() {
        if (ContextCompat.checkSelfPermission(this, CAMERA_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, arrayOf(CAMERA_PERMISSION), PERMISSION_REQUEST_CODE)
        } else {
            // Permission already granted
            openCamera()
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            PERMISSION_REQUEST_CODE -> {
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    openCamera()
                } else {
                    // Handle denied permission
                    showPermissionDeniedMessage()
                }
            }
        }
    }

    private fun openCamera() {
        // Launch camera intent
    }

    private fun showPermissionDeniedMessage() {
        Toast.makeText(this, "Camera permission required", Toast.LENGTH_SHORT).show()
    }
}
Note: Always check for permission status before using sensitive APIs. Handle both GRANTED and DENIED cases.
Warning: If a user permanently denies a permission, they must manually enable it in Settings.

Permission Handling Workflow

  • Check if permission is already granted
  • If not, request permission using ActivityCompat.requestPermissions()
  • Override onRequestPermissionsResult to handle result
  • Act based on permission status (grant or deny)

5. Using Permission Request Contracts

Permission Contract Type Description
android.permission.CAMERA ActivityResultContract Requests camera access for capturing photos or videos.
android.permission.ACCESS_FINE_LOCATION ActivityResultContract Requests permission to access precise location data.
android.permission.READ_CONTACTS ActivityResultContract Requests permission to read user's contacts.

Example: Requesting Camera Permission

class CameraPermissionContract : ActivityResultContract<Unit, Boolean>() {
    override fun createIntent(context: Context, input: Unit): Intent {
        return Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
            data = Uri.parse("package:" + context.packageName)
        }
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Boolean {
        return resultCode == Activity.RESULT_OK
    }
}

val cameraPermissionLauncher = registerForActivityResult(
    CameraPermissionContract()
) { granted ->
    if (granted) {
        // Proceed with camera usage
    } else {
        // Handle denied permission
    }
}

// Launch the permission request
cameraPermissionLauncher.launch(Unit)
Note: The ActivityResultContract approach is preferred for modern Android development as it simplifies handling permissions and results.

6. Understanding Permission Groups

Permission Group Description Permissions Included Protection Level
android.permission-group.CALENDAR Access to calendar events and reminders READ_CALENDAR, WRITE_CALENDAR NEW Dangerous
android.permission-group.CAMERA Access to camera functionality CAMERA Dangerous
android.permission-group.CONTACTS Access to contacts and phone numbers READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS Dangerous
android.permission-group.LOCATION Access to device location ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION Dangerous
android.permission-group.MICROPHONE Access to microphone for audio recording RECORD_AUDIO Dangerous
android.permission-group.PHONE Access to phone functionality READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG Dangerous
android.permission-group.SENSORS Access to sensor data (e.g., heart rate) BODY_SENSORS Dangerous
android.permission-group.STORAGE Access to external storage READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE Dangerous
android.permission-group.SYSTEM_ALERT_WINDOW Draw over other apps SYSTEM_ALERT_WINDOW DEPRECATED since API 23
android.permission-group.UNDEFINED Permissions not assigned to a group ACCESS_NETWORK_STATE, INTERNET Normal
Note: Beginning with Android 6.0 (API level 23), users grant permissions at runtime for dangerous permissions, including those in permission groups.

7. Handling Rationale UI

Example: Requesting Permission with Rationale UI

class MainActivity : AppCompatActivity() {
    private val PERMISSION_REQUEST_CODE = 100

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

        if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            // Permission already granted
            setupCamera()
        } else {
            // Request permission with rationale
            requestPermissions(
                arrayOf(Manifest.permission.CAMERA),
                PERMISSION_REQUEST_CODE
            )
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == PERMISSION_REQUEST_CODE) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                setupCamera()
            } else {
                // Show rationale if permission was denied
                showRationaleDialog()
            }
        }
    }

    private fun showRationaleDialog() {
        AlertDialog.Builder(this)
            .setTitle("Camera Permission Required")
            .setMessage("This app needs camera access to function properly. Please allow this permission in the settings.")
            .setPositiveButton("Go to Settings") { _, _ ->
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                val uri = Uri.fromParts("package", packageName, null)
                intent.data = uri
                startActivity(intent)
            }
            .setNegativeButton("Cancel") { dialog, _ ->
                dialog.dismiss()
            }
            .show()
    }

    private fun setupCamera() {
        // Camera setup logic here
    }
}
Note: The rationale UI should explain why the permission is necessary and guide the user to enable it in settings if they previously denied it.
Permission Required Description Rationale UI
CAMERA true Allows access to camera hardware Yes, for user guidance
READ_CONTACTS false Allows reading contact data Yes, for user guidance
ACCESS_FINE_LOCATION true Allows access to precise location Yes, for user guidance

Workflow: Handling Permission Requests with Rationale

  1. Check if permission is already granted using checkSelfPermission
  2. If not granted, request permission using requestPermissions
  3. Override onRequestPermissionsResult to handle the result
  4. If permission is denied, show rationale UI explaining why it's needed
  5. Provide option to navigate to app settings for manual permission enable

Comparison: Permission Request Methods

  • requestPermissions: Direct permission request with rationale support
  • shouldShowRequestPermissionRationale: Determines if rationale should be shown
  • ActivityCompat.requestPermissions: Backward compatible method for older Android versions

8. Working with Special Permissions

Permission Description Protection Level Notes
android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS Allows an app to bypass battery optimizations for itself. NEW API 23 Used for apps that need to run in background without battery restrictions. Requires user confirmation.
android.permission.ACCESS_NOTIFICATION_POLICY Allows an app to access the notification policy settings. NEW API 23 Used to control notification behavior, such as muting or silencing.
android.permission.SYSTEM_ALERT_WINDOW Allows an app to draw over other apps or system UI. NEW API 23 Used for overlay windows like floating action buttons or system overlays. Requires user permission.
android.permission.WRITE_SETTINGS Allows an app to modify system settings. DEPRECATED API 23 Replaced by android.permission.WRITE_SECURE_SETTINGS for secure settings. Requires special permissions.

Example: Requesting Special Permissions

val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
intent.data = Uri.parse("package:$packageName")
startActivity(intent)
Note: Special permissions often require the user to manually grant them through system settings or a special permission screen.
Warning: Apps requesting SYSTEM_ALERT_WINDOW must comply with Google Play policies and may be rejected if misused.

9. Managing Location Permissions

Permission Level Description Usage
ACCESS_FINE_LOCATION NEW Allows app to access precise location Required for GPS, Wi-Fi, and cell tower based location
ACCESS_COARSE_LOCATION Standard Allows app to access approximate location Useful for less precise location services like city-level

Example: Requesting Location Permissions

val LOCATION_PERMISSIONS = arrayOf(
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION
)

// Request permissions at runtime
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
    != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, LOCATION_PERMISSIONS, LOCATION_REQUEST_CODE)
}

Example: Handling Permission Results

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String>,
    grantResults: IntArray
) {
    when (requestCode) {
        LOCATION_REQUEST_CODE -> {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission granted, proceed with location access
                getCurrentLocation()
            } else {
                // Permission denied, show rationale or disable feature
                Toast.makeText(this, "Location permission required", Toast.LENGTH_SHORT).show()
            }
        }
    }
}
Note: Starting from Android 6.0 (API level 23), you must request permissions at runtime, even if they are declared in the manifest.
Warning: Users can deny permissions or revoke them later. Always check permission status before using location services.

10. Handling Permission Denials

Permission Status Description Handling Strategy
android.permission.CAMERA DEPRECATED Access to camera hardware Use runtime checks and user education for re-requesting
android.permission.ACCESS_FINE_LOCATION Required for accurate location Access to precise GPS data Implement rationale dialog before requesting again
android.permission.READ_CONTACTS Read-only access to contacts Access to user's contact list Provide clear explanation of why contacts are needed

Example: Requesting Permissions with Rationale

if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
        // Show an explanation to the user
        AlertDialog.Builder(this)
            .setTitle("Location Permission Required")
            .setMessage("This app needs access to your location to function properly.")
            .setPositiveButton("Allow") { _, _ ->
                ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
            }
            .setNegativeButton("Deny") { _, _ ->
                // Handle denial
            }
            .show()
    } else {
        // No explanation needed, request the permission
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
    }
}
Note: When a user denies a permission, it's important to provide context about why the permission is necessary for your app to function correctly.
Warning: If a user permanently denies a permission, you cannot request it again without directing them to the app settings.

11. Using Photo Picker

Property Description Values
PhotoPicker API for selecting photos from device PhotoPicker
Intent Used to launch the photo picker Intent(Intent.ACTION_PICK)
ContentResolver Used to resolve the selected image URI contentResolver

Example: Launching Photo Picker

val intent = Intent(Intent.ACTION_PICK).apply {
    type = "image/*"
}
startActivityForResult(intent, PICK_IMAGE_REQUEST)

Example: Handling Selected Image

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK) {
        val selectedImageUri = data?.data
        // Use the URI to load or process image
    }
}
Note: PhotoPicker is available from Android 13 (API level 33) and higher.

Was this article helpful?