Skip to content


Dealing with the new permission system in Android 6

My crash monitor (ACRA with Tracepot hosting) recently caught a crash saying something along those lines: “Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 […] requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS”.

Turns out the app wasn’t checking for permission before trying to read contacts and just assumed it was granted, causing a crash when it wasn’t upon calling context.getContentResolver().query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null);
This issue became obvious with Android 6, but it actually already exists in lower custom versions, provided they have an improve permission system (like CyanogenMod of OxygenOS) and that the user used it to remove the app’s read contact permission.

I found the core solution in this post on Stackoverflow, still I thought I’d share my slightly different implementation. The function to call is tryReadContact(), which will then handle the permission asking, etc

protected void myReadContactFunction() {
	// this is my function which needs to have READ_CONTACTS permission
	// I use a try catch so that it can always run (if permission denied, it returns an empty result instead of crashing)
	Map contactsMap = new HashMap<>();
	ContentResolver cr = c.getContentResolver();
	Cursor cursor=null;
	try {
		cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null);
	} catch(Exception e) {
		// we land here if no permission to read contacts
		Log.v("myReadContactFunction","reading phone contacts denied");
		return contactsMap;
	}
	if (cursor != null) {
		// do read contacts
	}
	return contactsMap;
}

protected void tryReadContact() {
	if(ActivityCompat.checkSelfPermission(this,Manifest.permission.READ_CONTACTS)==PackageManager.PERMISSION_DENIED) {
		ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, READ_CONTACT_REQUEST_CODE);
	} else {
		myReadContactFunction();
	}
}

@Override
public void onRequestPermissionsResult(int requestCode,@NonNull String[] permissions,@NonNull int[] grantResults) {
	// NB: the switch is here to demonstrate support for multiple types of permission requests
	switch (requestCode){
		case READ_CONTACT_REQUEST_CODE:
			if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
				Log.v("PeopleListActivity", "Contact permission has now been granted.");
			} else {
				Log.v("PeopleListActivity", "Contact permission was NOT granted.");
			}
			// in both cases we call myReadContactFunction, since the function reads more than phone contacts and can deal with non-granted permissions
			myReadContactFunction();
			break;
	}
}

The camera permissions are annoying too now. Got this error “android M java.lang.SecurityException: Permission Denial: starting Intent […] android.media.action.IMAGE_CAPTURE […] with revoked permission android.permission.CAMERA”.
We could just do the very same thing as above, but the Android documentation recommends to use intents rather than asking for permission whenever it is appropriate, and it was the case for me there. In such case, you must NOT declare the permission related to the intent, or if you do then you still have to request the permission: “if you app targets M and above and declares as using the CAMERA permission which is not granted, then attempting to use [ACTION_IMAGE_CAPTURE] will result in a SecurityException” (source ACTION_IMAGE_CAPTURE documentation). The reason for this makes sense, this is to avoid user confusion on an app appearing to be able to use the camera even after being denied the camera permission (source).
So basically, in my case all I had to do was to remove <uses-permission android:name="android.permission.CAMERA"/> from AndroidManifest.xml, and just call my new Intent(MediaStore.ACTION_IMAGE_CAPTURE) as I did before.

Posted in Android, programming.


0 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.



Some HTML is OK

or, reply to this post via trackback.

Sorry about the CAPTCHA that requires JS. If you really don't want to enable JS and still want to comment, you can send me your comment via e-mail and I'll post it for you.

Please solve the CAPTCHA below in order to fight spamWordPress CAPTCHA