Runtime Permissions, ACTION_PICK, and Contacts
In my previous blog post, I wrote:
We are likely to stumble over these sorts of [corner] cases from time to time over the next year, as we collectively apply the runtime permissions system to our apps and see where things go haywire.
Stack Overflow user Venator85 ran into another case a few days ago.
If you use ACTION_PICK
to pick a contact out of ContactsContract.Contacts
,
the Uri
that you get back has read permissions automatically granted.
While you cannot read data for arbitrary contacts, you can read data
about this specific contact, by using query()
on a ContentResolver
(directly, via a CursorLoader
, etc.). You do not need the
READ_CONTACTS
permission for this.
Personally, I haven’t been a fan of this behavior, simply because I doubt that users realize that picking a contact grants the requesting app access to all details about that contact.
Perhaps you had a similar concern, and so you requested the
READ_CONTACTS
permission in your manifest, “in the interests of full
disclosure”. In general, this is a reasonable thing to do. However, it
does trip over a problem with the Android 6.0 legacy app support for
runtime permissions.
Because you requested READ_CONTACTS
, the Contacts permission group
will appear in the Permissions for your app in Settings. This is standard
behavior.
If your targetSdkVersion
is 23 or higher, everything is fine. Even
if you do not use requestPermissions()
to request READ_CONTACTS
,
you still have access to the details of the picked contact. This occurs
regardless of whether or not the user has manually granted rights to
the Contacts permission group in Settings. IOW, things work as expected.
However, if your targetSdkVersion
is lower than 23 (e.g., 22),
and your app is running on Android 6.0,
and the user goes into Settings and revokes READ_CONTACTS
, you can
no longer access this data. You do not get a SecurityException
, but
instead you get an empty Cursor
(no rows, no columns).
Why? It appears that you are getting legacy-app “app ops”-style behavior.
Even though you don’t need the permission, because the user revoked the
automatically-granted permission, all access to ContactsContract
behaves as though the user has no contacts.
The workarounds are:
-
get rid of
READ_CONTACTS
, as you do not need it, or -
upgrade your app to have
targetSdkVersion 23
and deal with runtime permissions, or -
detect the empty
Cursor
and deal with it accordingly
I filed an issue about this, though I am skeptical that it will be addressed.