Introduction¶
Before Android 6.0 (API level 23), requesting permissions was straightforward. You simply added the required permissions to the AndroidManifest.xml configuration file. For example, if you needed four permissions, your manifest would look like this:
<!--Make a phone call-->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!--Use the camera-->
<uses-permission android:name="android.permission.CAMERA" />
<!--Write to external storage-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--Read from external storage-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
However, starting from Android 6.0 (API level 23), this approach is no longer sufficient. This is because requesting permissions this way gives apps full access to all requested permissions as soon as they are installed, which can lead to privacy concerns. Thus, Android 6.0 introduced the requirement for dangerous permissions to be requested dynamically at runtime. Below is a list of these dangerous permissions categorized by permission groups:
| Permission Group | Permissions |
|---|---|
| CALENDAR | • READ_CALENDAR • WRITE_CALENDAR |
| CAMERA | • CAMERA |
| CONTACTS | • READ_CONTACTS • WRITE_CONTACTS • GET_ACCOUNTS |
| LOCATION | • ACCESS_FINE_LOCATION • ACCESS_COARSE_LOCATION |
| MICROPHONE | • RECORD_AUDIO |
| PHONE | • READ_PHONE_STATE • CALL_PHONE • READ_CALL_LOG • WRITE_CALL_LOG • ADD_VOICEMAIL • USE_SIP • PROCESS_OUTGOING_CALLS |
| SENSORS | • BODY_SENSORS |
| SMS | • SEND_SMS • RECEIVE_SMS • READ_SMS • RECEIVE_WAP_PUSH • RECEIVE_MMS |
| STORAGE | • READ_EXTERNAL_STORAGE • WRITE_EXTERNAL_STORAGE |
To use these dangerous permissions, you must:
1. Declare them in AndroidManifest.xml.
2. Request them dynamically in your Java code.
This guide will explain how to request single and multiple dangerous permissions.
Dynamic Request for a Single Permission¶
Suppose your app needs to make phone calls, which is a dangerous permission.
Step 1: Declare the Permission in AndroidManifest.xml¶
<!--Make a phone call-->
<uses-permission android:name="android.permission.CALL_PHONE" />
Step 2: Implement the Dynamic Permission Request in Java Code¶
// Request a single permission
private void requestPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
// Request the permission (request code 1001 will be used in the callback)
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CALL_PHONE}, 1001);
} else {
Toast.makeText(this, "You already have the permission to make a call", Toast.LENGTH_LONG).show();
}
}
Step 3: Handle the Permission Request Result¶
// Callback when permission request results are received
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1001:
// Check if the permission was granted
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "Permission granted! You can now make calls.", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Permission denied! Call functionality will not be available.", Toast.LENGTH_LONG).show();
}
break;
}
}
Step 4: Add a Button to Trigger the Permission Request¶
In your onCreate method:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button requestPermissionBtn = (Button) findViewById(R.id.request_permission_btn);
// Set click listener to trigger permission request
requestPermissionBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
requestPermission();
}
});
}
Step 5: Layout XML (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"
android:orientation="vertical"
tools:context="com.yeyupiaoling.testpermission.MainActivity">
<Button
android:id="@+id/request_permission_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Request Single Permission" />
</LinearLayout>
Testing¶
When you first run the app, the permission dialog will appear. If the user grants permission, you can proceed with the phone call functionality. If not, the functionality will be disabled. Subsequent requests will not show the dialog again if the permission was already granted.
Dynamic Request for Multiple Permissions¶
For multiple permissions, you need to follow similar steps but manage a list of permissions.
Step 1: Declare All Permissions in AndroidManifest.xml¶
<!--Use the camera-->
<uses-permission android:name="android.permission.CAMERA" />
<!--Write to external storage-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--Read from external storage-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Note: WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE are in the same STORAGE group. If one is granted, the other is automatically granted, so no additional dialog will be shown.
Step 2: Request Multiple Permissions in Java Code¶
// Request multiple permissions
private void requestMultiplePermissions() {
List<String> permissionList = new ArrayList<>();
// Check each permission and add to the list if not granted
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.CAMERA);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
// If permissions are missing, request them all at once
if (!permissionList.isEmpty()) {
ActivityCompat.requestPermissions(this,
permissionList.toArray(new String[permissionList.size()]), 1002);
} else {
Toast.makeText(this, "All permissions are already granted.", Toast.LENGTH_LONG).show();
}
}
Step 3: Handle Multiple Permission Results¶
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1002:
// Check each permission's result
if (grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
Toast.makeText(MainActivity.this, permissions[i] + " permission is denied.", Toast.LENGTH_SHORT).show();
}
}
}
break;
}
}
Step 4: Add a Button to Trigger Multiple Permission Request¶
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button requestPermissionsBtn = (Button) findViewById(R.id.request_permissions_btn);
requestPermissionsBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
requestMultiplePermissions();
}
});
}
Step 5: Update Layout XML (Add the New Button)¶
<?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"
android:orientation="vertical"
tools:context="com.yeyupiaoling.testpermission.MainActivity">
<Button
android:id="@+id/request_permission_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Request Single Permission" />
<Button
android:id="@+id/request_permissions_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Request Multiple Permissions" />
</LinearLayout>
Testing¶
When you click the “Request Multiple Permissions” button, you’ll see a dialog requesting all the missing permissions. If any permission is denied, you’ll be notified, and the app should handle it appropriately.
Conclusion¶
This guide has shown you how to handle both single and multiple dangerous permissions in Android. The key steps are:
1. Declare permissions in AndroidManifest.xml.
2. Dynamically request permissions at runtime using ActivityCompat.requestPermissions().
3. Handle the results in onRequestPermissionsResult().
For more details, refer to the official Android documentation: Android Permissions Guide.