How to get Android Contact details without READ_CONTACTS permission
Asked Answered
E

3

8

According to the official docs at https://developer.android.com/guide/components/intents-common#Contacts

You can use a pick intent

public void selectContact() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivityForResult(intent, REQUEST_SELECT_CONTACT);
}

}

For information about how to retrieve contact details once you have the contact URI, read Retrieving Details for a Contact. Remember, when you retrieve the contact URI with the above intent, you do not need the READ_CONTACTS permission to read details for that contact.

It points to https://developer.android.com/training/contacts-provider/retrieve-details for getting the details for the contact

When I follow the instructions in the link above I get

Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.contacts.ContactsProvider2 uri content://com.android.contacts/data from pid=5313, uid=10087 requires android.permission.READ_CONTACTS, or grantUriPermission()

I've tried to get the Contact details via

  • Loader (as in the link instructions)
  • getContentResolver().query()
  • tried both with lookupKey and getting the contact id

Every way gives the requires android.permission.READ_CONTACTS Exception. Is there an example of this that works the way the documentation says?

Minimal, Complete, and Verifiable example at

https://github.com/aaronvargas/ContactsSSCCE

To test both with and without READ_CONTACTS, you'll have to change it in System App Settings

-Edit

Created issue on Android Issue Tracker at https://issuetracker.google.com/issues/118400813

Echino answered 14/10, 2018 at 19:55 Comment(6)
Your exception suggests that you are not using the Uri that you get back from ACTION_PICK. Please provide a minimal reproducible example, including the complete stack trace plus the code that generates the stack trace.Shew
"tried both with lookupKey and getting the contact id" - not the way. you need to get the contactUri via data.getData() and query on that alone, without any selectionPuerperium
@CommonsWare, I added a SSCCE for reference. According to the docs I should have temp permission to Contact rows via lookupKey. That's how the docs point to getting contact detailsEchino
Did you ever get this sorted?Reichsmark
@Bink, Nope, the issue is 'assigned' so perhaps will get some attention. If you want to vote for it in the Google tracker (url above in the question) that would be appreciated!Echino
The status is marked as fixed in the tracker. But I am still facing this issue in updated version of Android 10/11 devices.Kaddish
P
6

Android's ContactsContract API data is stored in three different tables: Contacts, RawContacts and Data.

You're getting temp permission to read data via the contactUri, which means you can only read details from the Contacts table, and on the picked contact only.

These are the fields that are stored in the Contacts table that you can get, other fields like phone, email, etc. are stored in the Data table and requires the READ_CONTACTS permission

_id
contact_chat_capability
contact_last_updated_timestamp
contact_presence
contact_status
contact_status_icon
contact_status_label
contact_status_res_package
contact_status_ts
custom_ringtone
dirty_contact
display_name
display_name_alt
display_name_reverse
display_name_source
has_email
has_phone_number
in_default_directory
in_visible_group
is_private
is_user_profile
last_time_contacted
link
link_count
link_type1
lookup
name_raw_contact_id
phonebook_bucket
phonebook_bucket_alt
phonebook_label
phonebook_label_alt
phonetic_name
phonetic_name_style
photo_file_id
photo_id
photo_thumb_uri
photo_uri
pinned
sec_custom_alert
sec_custom_vibration
sec_led
send_to_voicemail
sort_key
sort_key_alt
starred
times_contacted

WHAT YOU CAN DO

If you need one of the following data items about a contact: phone, email, address, you can switch to using a specific ACTION_PICK intent that requests that specific type, and then you'll have access to a single info item about the selected contact. For example, if your app needs a phone number of the picked contact, do the following:

Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(CommonDataKinds.Phone.CONTENT_TYPE);
startActivityForResult(intent, PICK_CONTACT_REQUEST);

Then, in onActivityResult, you'll get the selected contact+phone:

if (resultCode == RESULT_OK) {
       Uri phoneUri = data.getData();
       Cursor cursor = getContentResolver().query(phoneUri, null, null, null, null);
       DatabaseUtils.dumpCursor(cursor);
}
Puerperium answered 15/10, 2018 at 18:11 Comment(1)
Your answer is very complete. So you think the documentation is just wrong then? It states that after you get the contact dataUri from the pick intent you can query the contact details. It points to the page showing the query by lookupKey, which doesn't appear to be working. So either 1) the documentation is wrong 2) there is a bug in Android that is not allowing permissions on querying rows by selected lookupKey or 3) I'm doing something incorrectly.Echino
P
0

remove android.permission.READ_CONTACTSandroid.permission.READ_CONTACTS,or add

    <uses-permission android:name="android.permission.READ_CONTACTS" tools:node="remove"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS" tools:node="remove"/>

to AndroidManifest.xml

Passmore answered 23/3, 2022 at 12:28 Comment(0)
L
-1
    You need this permission in android Manifest 
    <uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

   and need to grant the permission run something like this 

     private void requestContactPermission() {
        final String[] permissions = new String[]{Manifest.permission.READ_CONTACTS};
        ActivityCompat.requestPermissions(this, permissions, REQUEST_CONTACT_PERM);
    }

      private boolean isReadContactPermissionGranted() {
        return ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) 
          == PackageManager.PERMISSION_GRANTED;
       }

  on Permission granted, you would get callback to your activity  

        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode != REQUEST_CONTACT_PERM) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            return;
        }
     if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
            //call your contact pick method
              return;
        }
      }

So finally before calling contact picker method make sure you have permission check

            if (isReadContactPermissionGranted()) {
               //Start method
            } else {
                requestContactPermission();
            }
Lester answered 14/10, 2018 at 20:7 Comment(1)
According to the docs, it is very specific that I don't need that permission "Remember, when you retrieve the contact URI with the above intent, you do not need the READ_CONTACTS permission to read details for that contact."Echino

© 2022 - 2024 — McMap. All rights reserved.