0

I need to get list of id, first name, last name, number(or numbers), email, website of an android device contacts. I know by getting id I can query about phone numbers this is not a big deal. But I don't know how I should make query to get all these columns correctly.

I supposed for names I need ContactsContract.CommonDataKinds.StructuredName for email I need ContactsContract.CommonDataKinds.Email.ADDRESS ,for id Contacts and for website ContactsContract.CommonDataKinds.Website.URL.

My code returns strange values like a single digit number for GIVEN_NAME, null for FAMILY_NAME, one of contact numbers for Email.ADDRESS.

However I think the problem is query URI, which one should I use?

ContentResolver cr = getActivity().getContentResolver();

String[] projection = new String[] {
                    Contacts._ID,
                  ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,
  ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME,
                    ContactsContract.CommonDataKinds.Website.URL,
                    ContactsContract.CommonDataKinds.Email.ADDRESS};

Cursor nameCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    projection,
                    null,
                    null,
                    null);
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 email = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS));
   Integer id= nameCur.getInt(nameCur.getColumnIndex(Contacts._ID));
   String website = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.Website.URL));
//do some work with strings...                
}
anothermh
  • 9,815
  • 3
  • 33
  • 52

2 Answers2

0

The problem is that all the sub-tables you're trying to access (Email, Phone, Website, etc.) are actually all stored in a single big table called Data. All those sub-tables share the same fields Data1-Data15, so by querying on the Phone.CONTENT_URI table, you're only getting Phone info, that's why trying to access StructuredName.GIVEN_NAME on the result is wrong.

Instead you query over the Data.CONTENT_URI table that contains all info, and you differentiate between rows of different data type via the value at Data.MIMETYPE.

See docs here: https://developer.android.com/reference/android/provider/ContactsContract.Data

I'm not sure if you needed the contact's info for all contacts on the device, or for a specific one.

Here's the code to get info of a single contact (you need to assign value to the contactId variable there)

String[] projection = {Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3};

// query only emails/phones/events
String selection = Data.CONTACT_ID + "=" + contactId + " AND " + 
                   Data.MIMETYPE + " IN ('" + StructuredName.CONTENT_ITEM_TYPE + "', '" + Phone.CONTENT_ITEM_TYPE + "', '" + Email.CONTENT_ITEM_TYPE"', '" + Website.CONTENT_ITEM_TYPE + "')";
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);

while (cur.moveToNext()) {
    long id = cur.getLong(0);
    String name = cur.getString(1); // full name
    String mime = cur.getString(2); // type of data (phone / birthday / email)
    String data = cur.getString(3); // the actual info, e.g. +1-212-555-1234

    String kind = "unknown";

    switch (mime) {
        case StructuredName.CONTENT_ITEM_TYPE: 
            String firstName = cur.getString(4);
            String lastName = cur.getString(5);
            Log.d(TAG, "got name: " + data + " - " + firstName + " " + lastName);
            break;
        case Phone.CONTENT_ITEM_TYPE: 
            Log.d(TAG, "got phone: " + data);
            break;
        case Email.CONTENT_ITEM_TYPE: 
            Log.d(TAG, "got email: " + data);
            break;
        case Website.CONTENT_ITEM_TYPE: 
            Log.d(TAG, "got website: " + data);
            break;
    }
}
cur.close();

To convert it to run over ALL contacts, simply remove the Data.CONTACT_ID + "=" + contactId part from the selection, and then you'll need to create some HashMap from contactId to an object containing the info about that contact (use the id variable for the key)

marmor
  • 27,641
  • 11
  • 107
  • 150
  • thank you for your code and answer, it was so helpful. by the way, I guess I must go deeper in android contact database. I found this link very informative https://www.dev2qa.com/android-contacts-fields-data-table-columns-and-data-mimetype-explain/ for others who want to learn. I will post the result soon. – paria shiri Jan 06 '19 at 21:20
0

here is my solution: first we need a query for getting all contact id in the table of "raw_contacts"

List<Integer> ret = new ArrayList<Integer>();
ContentResolver contentResolver = getActivity().getContentResolver();
// Row contacts content uri( access raw_contacts table. ).
Uri rawContactUri = ContactsContract.RawContacts.CONTENT_URI;
// Return _id column in contacts raw_contacts table.
String queryColumnArr[] = {ContactsContract.RawContacts._ID};
// Query raw_contacts table and return raw_contacts table _id.
Cursor cursor = contentResolver.query(rawContactUri, queryColumnArr, null, null, null);

then we query table "data" for extra information for each contact id:

// Data content uri (access data table. )
Uri dataContentUri = ContactsContract.Data.CONTENT_URI;
// Build query columns name array.
List<String> queryColumnList = new ArrayList<String>();
// ContactsContract.Data.CONTACT_ID = "contact_id";
queryColumnList.add(ContactsContract.Data.CONTACT_ID);
// ContactsContract.Data.MIMETYPE = "mimetype";
queryColumnList.add(ContactsContract.Data.MIMETYPE);
queryColumnList.add(ContactsContract.Data.DATA1);
queryColumnList.add(ContactsContract.Data.DATA2);
queryColumnList.add(ContactsContract.Data.DATA3);
queryColumnList.add(ContactsContract.Data.DATA4);
queryColumnList.add(ContactsContract.Data.DATA5);
queryColumnList.add(ContactsContract.Data.DATA6);
queryColumnList.add(ContactsContract.Data.DATA7);
queryColumnList.add(ContactsContract.Data.DATA8);
queryColumnList.add(ContactsContract.Data.DATA9);
queryColumnList.add(ContactsContract.Data.DATA10);
queryColumnList.add(ContactsContract.Data.DATA11);
queryColumnList.add(ContactsContract.Data.DATA12);
queryColumnList.add(ContactsContract.Data.DATA13);
queryColumnList.add(ContactsContract.Data.DATA14);
queryColumnList.add(ContactsContract.Data.DATA15);
// Translate column name list to array.
String queryColumnArr[] = queryColumnList.toArray(new String[queryColumnList.size()]);
// Build query condition string. Query rows by contact id.
StringBuffer whereClauseBuf = new StringBuffer();
whereClauseBuf.append(ContactsContract.Data.RAW_CONTACT_ID);
whereClauseBuf.append("=");
whereClauseBuf.append(rawContactId);
// Query data table and return related contact data.
Cursor cursor = contentResolver.query(dataContentUri, queryColumnArr, whereClauseBuf.toString(), null, null);

last cursor contains all the data of any contact and for get that data we need switch case:

String mimeType =cursor.getString(cursor.getColumnIndex(ContactsContract.Data.MIMETYPE));
switch (mimeType) {
            // Get email data.
            case ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE:
                // Email.ADDRESS == data1
                String emailAddress = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS));
                int emailType = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));
                data.setDataType(emailType);
                data.setDataValue(emailAddress);
                ret1.add(data);
                con.setEmailList(ret1);
                break;
            // Get organization data.
            case ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE:
                // Organization.COMPANY == data1
                String company = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.COMPANY));
             con.setCompany(company);
                break;
            // Get phone number.
            case ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE:
                // Phone.NUMBER == data1
                String phoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                // Phone.TYPE == data2
                int phoneTypeInt = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
                data.setDataType(phoneTypeInt);
                data.setDataValue(phoneNumber);
                ret1.add(data);
                con.addPhoneList(ret1);
                break;
            // Get display name.
            case ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE:
                // StructuredName.DISPLAY_NAME == data1
                String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME));
                // StructuredName.GIVEN_NAME == data2
                String givenName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
                // StructuredName.FAMILY_NAME == data3
                String familyName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
                ret.add("Display Name : " + displayName);
                ret.add("Given Name : " + givenName);
                ret.add("Family Name : " + familyName);           
                break;
            // Get website.
            case ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE:
                // Website.URL == data1
                String websiteUrl = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website.URL));
                // Website.TYPE == data2
                int websiteTypeInt = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website.TYPE));
                String websiteTypeStr = getEmailTypeString(websiteTypeInt);
                ret.add("Website Url : " + websiteUrl);
                ret.add("Website Type Integer : " + websiteTypeInt);
                ret.add("Website Type String : " + websiteTypeStr);
                break;
        }

this is not my compelete code just for getting idea. hope this will help someone!