Picking a contact using the Contacts app

There are to ways (besides implementing your own UI) to pick contact details through the Contacts app. One of them needs read access to your contacts list, the other does not.

Simple version

This version launches the Contact picker to find a phone number, and returns it to your app. You will only get the picked detail, not the name or other information of the contact.

Launching the Intent

val intent = Intent(Intent.ACTION_PICK).apply {
	type = ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE
}
startActivityForResult(intent, REQUEST_CONTACT)

Processing the result

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    if (requestCode == REQUEST_CONTACT && resultCode == RESULT_OK) {
        // Get the URI and query the content provider for the phone number
        val contactUri = data.getData()

        contactUri?.let { uri ->
            // Query for the phone number
            val projection = arrayOf<String>(ContactsContract.CommonDataKinds.Phone.NUMBER)
            val cursor = thisActivity.getContentResolver().query(uri, projection, null, null, null)

            // If the cursor returned is valid, get the phone number
            cursor?.let {
                if (it.moveToFirst()) {
                    val numberIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
                    val number = it.getString(numberIndex)

                    // TODO Store or use the phone number however you please
                    // storePhoneNumber(number)
                }
                it.close()
            }
        }
    }
}

Elaborate version

This version launches the Contact picker to pick a contact, and not just a contact detail. This allows you to get more information from the contact, like the name that goes with the phone number.

AndroidManifest.xml

This version requires the permission:

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

Permissions

First, make sure we have permission to read the contacts.

if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
    launchContactPicker()
} else {
    requestPermissions(arrayOf(Manifest.permission.READ_CONTACTS), REQUEST_CODE_PERMISSION)
}

The permissions result will arrive in onRequestPermissionsResult:

override public fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: Array<Int>) {
    if (requestCode == REQUEST_CODE_PERMISSION && grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        launchContactPicker()
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

Launching the Intent

Now you can launch the picker:

fun launchContactPicker() {
	val intent = Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
	startActivityForResult(intent, REQUEST_CONTACT)
}

Process the result

In the onActivityResult method, you can use the Uri in the result Intent to fetch the details you need. In the example below, we fetch the contact’s name and show an AlertDialog with all the phone numbers associated with the contact, so we can let the user pick one of them.

We’ll leave the implementation of fun storePhoneNumber(name: String, number: String) up to you.

fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    if (requestCode == REQUEST_CONTACT && resultCode == RESULT_OK) {
        
        // Get the URI and query the content provider for the phone number.
        // The id is the last bit in the path
        val id = data.getData()?.getLastPathSegment()

        id?.let {
            // Query for phone numbers for the selected contact id
            val cursor = thisActivity.getContentResolver().query(
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?",
                    arrayOf<String>(id), null)

            // If the cursor returned is valid, get the phone number
            cursor?.let {
                if (it.getCount() > 0 && it.moveToFirst()) {

                    val numberIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
                    val typeIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE)
                    var nameIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
                    if (nameIndex == -1) {
                        nameIndex = it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_SOURCE)
                    }
                    val name = it.getString(nameIndex)

                    if (it.getCount() > 1) {

                        // We'll generate a list of phone numbers and show it in an AlertDialog
                        val numbers = arrayOfNulls<CharSequence>(it.getCount())
                        var i = 0
                        while (!it.isAfterLast()) {
                            // For each phone number, add it to the numbers array
                            val type = ContactsContract.CommonDataKinds.Phone.getTypeLabel(
                                    thisActivity.getResources(), it.getInt(typeIndex), "") as String
                            val number = type + ": " + it.getString(numberIndex)
                            numbers[i++] = number
                            it.moveToNext()
                        }

                        // Show a simple dialog that allows the user to select a number:
                        val builder = AlertDialog.Builder(thisActivity)
                        builder.setTitle(getString(R.string.select_contact_phone_number))
                        builder.setItems(numbers, { dialog, item -> storePhoneNumber(name, numbers[item] as String) })
                        val alert = builder.create()
                        alert.setOwnerActivity(thisActivity)
                        alert.show()
                    } else {
                        val number = it.getString(numberIndex)
                        storePhoneNumber(name, number)
                    }
                }

                // Cleanup
                it.close()
            }
        }
    }
}