24

How to get the following fields from Android contacts? I used Android 2.2.

  1. Name prefix
  2. First name
  3. Middle name
  4. Last name
  5. Name prefix
  6. Phonetic given name
  7. Phonetic middle name
  8. Phonetic family name
1

9 Answers 9

59

Look at ContactsContract.CommonDataKinds.StructuredName class. You can find there all columns you are looking for. Try sth like this:

    String whereName = ContactsContract.Data.MIMETYPE + " = ?";
    String[] whereNameParams = new String[] { ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE };
    Cursor nameCur = contentResolver.query(ContactsContract.Data.CONTENT_URI, null, whereName, whereNameParams, ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
    while (nameCur.moveToNext()) {
        String given = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
        String family = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
        String display = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME));
    }
    nameCur.close();

It returns all names in contacts. To be more precise you can add a contact id as an additional parameter to the query - you will get address for particular contact.

14
  • 5
    One note: above query returns ALL (I mean really all) contacts in your phone (even emails without excplicity given names). So you should filter them to get contacts you want Commented Jan 9, 2011 at 10:24
  • 4
    And one note from my side: the MIMETYPE is really required, otherwise you end up getting not what you expect. I overlooked this detail and it took me an hour to debug it. Commented Dec 27, 2011 at 15:32
  • 2
    how about getting the phone owner's first name and last name? is it doable? Commented Oct 26, 2012 at 10:18
  • @KrzysztofWolny how should I filter the results then? I'm able to retrieve the data, but I see duplicates for those contacts from multiple resources (Google contacts esp.)
    – xialin
    Commented Aug 19, 2014 at 17:50
  • some app like viber & telegram change first name Commented Dec 6, 2014 at 13:31
18

For a specified contact you can do this :

String whereName = ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?";
String[] whereNameParams = new String[] { ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, contact_ID };
Cursor nameCur = contentResolver.query(ContactsContract.Data.CONTENT_URI, null, whereName, whereNameParams, ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
while (nameCur.moveToNext()) {
    String given = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
    String family = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
    String display = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME));
}
nameCur.close();
8

As the other example (just for fun) but for fetching contact name of a single user:

// A contact ID is fetched from ContactList
Uri resultUri = data.getData(); 
Cursor cont = getContentResolver().query(resultUri, null, null, null, null);
if (!cont.moveToNext()) {   
    Toast.makeText(this, "Cursor contains no data", Toast.LENGTH_LONG).show(); 
                return;
}
int columnIndexForId = cont.getColumnIndex(ContactsContract.Contacts._ID);
String contactId = cont.getString(columnIndexForId);

// Fetch contact name with a specific ID
String whereName = ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = " + contactId; 
String[] whereNameParams = new String[] { ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE };
Cursor nameCur = getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, whereName, whereNameParams, ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
while (nameCur.moveToNext()) {
    String given = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
    String family = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
    String display = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME));
    Toast.makeText(this, "Name: " + given + " Family: " +  family + " Displayname: "  + display, Toast.LENGTH_LONG).show();
}
nameCur.close();
cont.close();
7

try to use this code to get the required information about the contact,the code is here-

import android.provider.ContactsContract.Contacts;
import android.database.Cursor;

// Form an array specifying which columns to return, you can add more.
String[] projection = new String[] {
                         ContactsContract.Contacts.DISPLAY_NAME,
                         ContactsContract.CommonDataKinds.Phone
                         ContactsContract.CommonDataKinds.Email
                      };

Uri contacts =  ContactsContract.Contacts.CONTENT_LOOKUP_URI;
// id of the Contact to return.
long id = 3;

// Make the query. 
Cursor managedCursor = managedQuery(contacts,
                     projection, // Which columns to return 
                     null,       // Which rows to return (all rows)
                                 // Selection arguments (with a given ID)
                     ContactsContract.Contacts._ID = "id", 
                                 // Put the results in ascending order by name
                     ContactsContract.Contacts.DISPLAY_NAME + " ASC");
2
  • This use of the projection array to get needed columns only is the cleanest way. And DISPLAY_NAME is also simpler than the StructuredName URI if you don't need separated first and last names. So, I like this one.
    – John
    Commented Sep 23, 2015 at 16:56
  • DISPLAY_NAME will be the phone-number when the contact has no name-information. Commented Apr 10, 2019 at 6:02
3

Some links to get you started, in addition to the suggestions from Raunak:

1

Experimenting with the ContactsContract.Data.CONTENT_URI in late 2015 on marshmallow. I'm unable to get the GIVEN_NAME or similar fields. I think the later apis have deprecated these. Run the following code to print out the columns you have on your phone

Uri uri = ContactsContract.Data.CONTENT_URI;
String selection = ContactsContract.Data.MIMETYPE + " = ?";
String[] selectionArgs = new String[] { ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE};
Cursor cursor = contentResolver.query(
            uri,       // URI representing the table/resource to be queried
            null,      // projection - the list of columns to return.  Null means "all"
            selection, // selection - Which rows to return (condition rows must match)
            selectionArgs,      // selection args - can be provided separately and subbed into selection.
            null);   // string specifying sort order

if (cursor.getCount() == 0) {
  return;
}
Log.i("Count:", Integer.toString(cursor.getCount())); // returns number of names on phone

while (cursor.moveToNext()) {
  // Behold, the firehose!
  Log.d(TAG, "-------------------new record\n");
  for(String column : cursor.getColumnNames()) {
    Log.d(TAG, column + ": " + cursor.getString(cursor.getColumnIndex(column)) + "\n");
  }
}
1
0

try this,

public void onActivityResult(int reqCode, int resultCode, Intent data) { super.onActivityResult(reqCode, resultCode, data);

    try {
        if (resultCode == Activity.RESULT_OK) {
            Uri contactData = data.getData();
            Cursor cur = managedQuery(contactData, null, null, null, null);
            ContentResolver contect_resolver = getContentResolver();

            if (cur.moveToFirst()) {
                String id = cur.getString(cur.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
                String name = "";
                String no = "";

                Cursor phoneCur = contect_resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]{id}, null);

                if (phoneCur.moveToFirst()) {
                    name = phoneCur.getString(phoneCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    no = phoneCur.getString(phoneCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                }

                Log.e("Phone no & name :***: ", name + " : " + no);
                txt.append(name + " : " + no + "\n");

                id = null;
                name = null;
                no = null;
                phoneCur = null;
            }
            contect_resolver = null;
            cur = null;
            //                      populateContacts();
        }
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
        Log.e("IllegalArgumentException::", e.toString());
    } catch (Exception e) {
        e.printStackTrace();
        Log.e("Error :: ", e.toString());
    }
}
0

Combining various solutions here, and seeing there are duplicate records from the results (due to multiple accounts), I've decided to make a function that will prioritize common account-types over others. On this sample, I also ignore the records of completely empty/null names (if all are as such), but you can change this if you wish:

@RequiresPermission(
    allOf = [Manifest.permission.READ_CONTACTS])
@WorkerThread
fun getContactIdToContactNameMap(context: Context): LongSparseArray<ContactObject> {
    val contactIdToContactObjectMap = LongSparseArray<ContactObject>()
    val contentResolver = context.contentResolver
    contentResolver.query(ContactsContract.Data.CONTENT_URI,
        arrayOf(
            ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID,
            ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
            ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,
            ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME,
            ContactsContract.RawContacts.ACCOUNT_TYPE),
        ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.Data.IN_VISIBLE_GROUP + " = ?",
        arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, "1"),
        null)?.use { cursor ->
        //            Log.d("AppLog", "got ${cursor.count} records for names")
        val colContactId = cursor.getColumnIndex(
            ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID)
        val colFirstName = cursor.getColumnIndex(
            ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME)
        val colFamilyName = cursor.getColumnIndex(
            ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME)
        val colMiddleName = cursor.getColumnIndex(
            ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME)
        val colAccountType =
            cursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE)
        val googleAccount = "com.google"
        //https://stackoverflow.com/a/44802016/878126
        val prioritizedAccountTypes =
            hashSetOf("vnd.sec.contact.phone", "com.htc.android.pcsc",
                "com.sonyericsson.localcontacts", "com.lge.sync", "com.lge.phone",
                "vnd.tmobileus.contact.phone", "com.android.huawei.phone",
                "Local Phone Account",
                "")
        val contactIdToAccountTypeMap = LongSparseArray<String>()
        while (cursor.moveToNext()) {
            val contactId = cursor.getLong(colContactId)
            val accountType = cursor.getString(colAccountType).orEmpty()
            val existingContact = contactIdToContactObjectMap.get(contactId)
            if (existingContact != null) {
                //this can occur, as we go over all of the items, including duplicate ones made by various sources
                //                        https://stackoverflow.com/a/4599474/878126
                val previousAccountType = contactIdToAccountTypeMap.get(contactId)
                //google account is most prioritized, so we skip current one if previous was of it
                if (previousAccountType == googleAccount)
                    continue
                if (accountType != googleAccount && previousAccountType != null && prioritizedAccountTypes.contains(
                        previousAccountType))
                //we got now a name of an account that isn't prioritized, but we already had a prioritized one, so ignore
                    continue
            }
            contactIdToAccountTypeMap.put(contactId, accountType)
            val firstName = cursor.getString(colFirstName)?.trim()
            val lastName = cursor.getString(colFamilyName)?.trim()
            val middleName = cursor.getString(colMiddleName)?.trim()
            if (firstName.isNullOrBlank() && lastName.isNullOrBlank() && middleName.isNullOrBlank())
                continue
            val contactObject = existingContact ?: ContactObject()
            contactObject.firstName = firstName
            contactObject.lastName = lastName
            contactObject.middleName = middleName
            contactIdToContactObjectMap.put(contactId, contactObject)
        }
    }
    return contactIdToContactObjectMap
}

class ContactObject {
    var firstName: String? = null
    var middleName: String? = null
    var lastName: String? = null
}

Usage:

thread {
    if (ActivityCompat.checkSelfPermission(this,
            Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
        val contactIdToContactNameMap = getContactIdToContactNameMap(this)
        Log.d("AppLog", "found ${contactIdToContactNameMap.size()} names for contacts")
    } else Log.d("AppLog", "no contacts permission...")
}
-3

Check here there is example code exactly for that: http://developer.android.com/guide/topics/ui/layout/listview.html

Not the answer you're looking for? Browse other questions tagged or ask your own question.