Pick contact directly from contact picker intent
Asked Answered
H

8

22

Hello I want to pick a contact from our default contact book intent. I tried several ways to do it. Please find the code below. The problem with all those code is that they open one intermediate documents screen with few options there user has to select contact and than it opens contact book.

private void openContactIntent() {
     Intent intent = new Intent(Intent.ACTION_GET_CONTENT, ContactsContract.Contacts.CONTENT_URI);
     intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
     startActivityForResult(intent, REQ_CONTACT_DIRECTORY);
}

I also tried

Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, PICK_CONTACT);

and

Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
startActivityForResult(intent, PICK_CONTACT); 

What I see as an intermediate screen is enter image description here

Hoptoad answered 26/12, 2016 at 6:46 Comment(9)
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI); startActivityForResult(intent, PICK_CONTACT); It's working for me!Heartsick
Is it related to any OS ? I am running code on Android N. And for me it not working. I have not added any permissions.Hoptoad
I am running Android N too!Heartsick
And permissions ?Hoptoad
This is opening a side menu screen like attached screenshot in phone and not even showing contact inside it.Hoptoad
No permission needed! Paste your targetSdkVersionHeartsick
Let us continue this discussion in chat.Heartsick
I am able to solve the problem. There is some catch with the request code. I was using request code 10. The moment I use some odd number like 8500 it started working fine. Anyone knows the reason?Hoptoad
Does this answer your question? Trying to insert contact into edittext using contact pickerKnucklehead
E
20

I also had the same problem. Finally, I got rid of intermediate picker screen using below code,

Intent i=new Intent(Intent.ACTION_PICK);
i.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
startActivityForResult(i, SELECT_PHONE_NUMBER);

In onActivityResult get phone number as below

if (requestCode == SELECT_PHONE_NUMBER && resultCode == RESULT_OK) {
  // Get the URI and query the content provider for the phone number
  Uri contactUri = data.getData();
  String[] projection = new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER};
  Cursor cursor = getContext().getContentResolver().query(contactUri, projection,
      null, null, null);

  // If the cursor returned is valid, get the phone number
  if (cursor != null && cursor.moveToFirst()) {
    int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
    String number = cursor.getString(numberIndex);
    // Do something with the phone number
    ... 
  } 

  cursor.close();
}
Eskew answered 19/1, 2017 at 4:54 Comment(3)
This worked well for me except getContext needed to be replaced with a reference to the activity (this), otherwise I got a no instrumentation registered issue.Wellesz
Works well but the result code is random for some reason, could be an Android 11 issueMicropaleontology
For Android 11+, changes in AndroidManifest file like https://mcmap.net/q/571675/-pick-contact-directly-from-contact-picker-intentWarfare
B
14

Try the below code to pick contact:

Intent contactPickerIntent = new Intent(Intent.ACTION_PICK,
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
            startActivityForResult(contactPickerIntent, RESULT_PICK_CONTACT);

You can fetch the required information in onActivityResult as follows:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        switch (requestCode) {
            case RESULT_PICK_CONTACT:
                  Cursor cursor = null;
    try {
        String phoneNo = null;
        String name = null;

        Uri uri = data.getData();
        cursor = getContentResolver().query(uri, null, null, null, null);
        cursor.moveToFirst();
        int  phoneIndex =cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
        int  nameIndex =cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
        phoneNo = cursor.getString(phoneIndex);
        name = cursor.getString(nameIndex);

       Log.e("Name and Contact number is",name+","+phoneNo);

    } catch (Exception e) {
        e.printStackTrace();
    }
                break;
        }
    } else {
        Log.e("Failed", "Not able to pick contact");
    }
}
Bigelow answered 26/12, 2016 at 10:25 Comment(4)
oH..!! It's great..!!Bigelow
This actually still opens the file manager on some devices, better also add intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);Jago
here what is RESULT_PICK_CONTACT . it is string or other variable ?Earphone
@Ganesan J It's an int, have a look at Getting a result from an activity articleVaporimeter
S
8

Here is a way to pick name, phone number from Contact in Kotlin

private fun pickEmergencyFromContacts() {
    val i = Intent(Intent.ACTION_PICK)
    i.type = ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE
    startActivityForResult(i, SELECT_PHONE_NUMBER)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == SELECT_PHONE_NUMBER && resultCode == Activity.RESULT_OK) {
        val contactUri = data?.data ?: return
        val projection = arrayOf(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER)
        val cursor = requireContext().contentResolver.query(contactUri, projection,
                null, null, null)

        if (cursor != null && cursor.moveToFirst()) {
            val nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
            val numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
            val name = cursor.getString(nameIndex)
            val number = cursor.getString(numberIndex)

            // do something with name and phone
        }
        cursor?.close()
    }
}

companion object {

    private const val SELECT_PHONE_NUMBER = 111    
    ...
}

Hope it help

Shelah answered 13/6, 2019 at 6:27 Comment(1)
This only gives 1 contact, is there a way to select multiple contacts in one go?Manor
W
3

For Android 11+, need to add below code in AndroidManifest

......
</application>
    <queries>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="vnd.android.cursor.dir/contact" />
        </intent>
    </queries>
</manifest>
Warfare answered 19/5, 2021 at 8:58 Comment(0)
Q
3

StarActivityForResult is deprecated. So we can use below model in Kotlin.

In Manifest:

<uses-permission android:name="android.permission.READ_CONTACTS" />

Please implement run-time permission also. I haven't done in my code.

Below lines used to handle the result:

    private val openContacts = registerForActivityResult(ActivityResultContracts.PickContact()) {

    val contactData: Uri = it
    val phone: Cursor? = contentResolver.query(contactData!!, null, null, null, null)
    if (phone!!.moveToFirst()) {
        val contactName: String = phone.getString(phone.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))

        // To get number - runtime permission is mandatory.
        val id: String = phone.getString(phone.getColumnIndex(ContactsContract.Contacts._ID))
        if (phone.getString(phone.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)).toInt() > 0) {
            val phones = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id, null, null)
            while (phones!!.moveToNext()) {
                val phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
                Log.d("## Number", phoneNumber)
            }
            phones!!.close()
        }

        Log.d("## Contact Name", contactName)
    }

}

To open the contacts:

button.setOnClickListener {
        openContacts.launch(null)
    }
Quarrier answered 28/8, 2021 at 18:44 Comment(2)
Do you know how to call the pending intents using the registerActivityForResult. I am stuck with a compile-time error where .launch() function is expecting a pending intent.Doubleganger
I didn't try with pending intent. Below link answer may help to you, #10363025Quarrier
S
1

This works for me:

Intent it= new Intent(Intent.ACTION_PICK, 
     ContactsContract.Contacts.CONTENT_URI); 
startActivityForResult(it, requestCode);
Stefanstefanac answered 26/12, 2016 at 9:24 Comment(0)
F
1
 private static final int RESULT_PICK_CONTACT1= 1;
 public void pickContact1 (View v)
      {
        Intent contactPickerIntent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
        startActivityForResult(contactPickerIntent, RESULT_PICK_CONTACT1);
      }
 @Override
    protected void onActivityResult ( int requestCode, int resultCode, Intent data){
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case RESULT_PICK_CONTACT1:
                    contactPicked1(data);
                    break;
            }
        } else {
            Log.e("SetupActivity", "Failed to pick contact");
        }
    }

 private void contactPicked1 (Intent data){
        Cursor cursor = null;
        try {
            String phoneNo = null;
            String name = null;
            Uri uri = data.getData();
            cursor = getContentResolver().query(uri, null, null, null, null);
            cursor.moveToFirst();
            int phoneIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
            int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
            name = cursor.getString(nameIndex);
            phoneNo = cursor.getString(phoneIndex);
            ed11.setText(name);
            ed12.setText(phoneNo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

This will surely work.

Floss answered 15/9, 2018 at 17:9 Comment(0)
O
0

This is just a nice to have implementation (in Kotlin) that I'll add here to help getting the contact info from the cursor. You will also need to grant permissions and request runtime permission

<uses-permission android:name="android.permission.READ_CONTACTS" />

    @SuppressLint("Recycle")
    private fun getContactDataFrom(
        contentResolver: ContentResolver,
        contactUri: Uri
    ): ContactModel? {
        val projection = arrayOf(
            ContactsContract.Contacts._ID,
            ContactsContract.Contacts.DISPLAY_NAME,
            ContactsContract.Contacts.HAS_PHONE_NUMBER
        )

        try {
            val cursor = contentResolver.query(contactUri, projection, null, null, null) ?: return null
            if (!cursor.moveToFirst()) {
                return null
            }

            val id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID))
            val name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME))
            val hasNumber = (cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)))
            cursor.close()

            val email = getEmail(contentResolver, id)

            val phoneNumber = if (hasNumber > 0) {
                getPhoneNumber(contentResolver, id)
            } else {
                ""
            }
            return ContactModel(name, phoneNumber, email)
        } catch (e: Exception) {
            Log.e("Contacts", "Could not get contact info.", e)
            return null
        }
    }

    @SuppressLint("Recycle")
    private fun getPhoneNumber(contentResolver: ContentResolver, id: String?): String {
        var phoneNumber = ""

        val cursor = contentResolver.query(
            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
            null,
            ContactsContract.Contacts._ID + " = ?",
            arrayOf(id),
            null
        ) ?: return phoneNumber

        if (cursor.moveToFirst()) {
            phoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA))
        }

        cursor.close()
        return phoneNumber
    }

    @SuppressLint("Recycle")
    private fun getEmail(contentResolver: ContentResolver, id: String?): String {
        var email = ""

        val cursor = contentResolver.query(
            ContactsContract.CommonDataKinds.Email.CONTENT_URI,
            null,
            ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?",
            arrayOf(id),
            null
        ) ?: return email

        if (cursor.moveToFirst()) {
            email = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA))
        }

        cursor.close()
        return email
    }

Trigger:

    val intent = Intent(this, PickLabelActivity::class.java)               
    startActivityForResult(intent, PickLabelActivity.REQ_CODE_PICK_LABEL)

Usage in onActivityResult should be something like:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

         if (resultCode == RESULT_OK && requestCode == ConstantsHandler.INTENT_CODE_PICK_CONTACT) {
            val contactUri = data?.data ?: return
            val contactModel = getContactDataFrom(contentResolver, contactUri)

            inputName.setText(contactModel?.name)
            inputPhone.setText(contactModel?.phone)
            inputEmail.setText(contactModel?.email)
        }
    }

And that ContactModel is just a simple data class.

data class ContactModel(
    var name: String? = null,
    var phone: String? = null,
    var email: String? = null
) : Serializable
Oral answered 13/12, 2020 at 12:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.