androidandroid-contactscontentobserver

Selecting contacts from phone-book by mime type


I am trying to fetch contacts from phone by MIME-TYPE, so i can select contacts that has the type:

ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE

Here is the method i use:

public static ArrayList<Contact> fetchContactsFromPhone(@NonNull Context context) {
    ArrayList<Contact> contacts = new ArrayList<>();

    Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
    String _ID = ContactsContract.Contacts._ID;

    String DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME;
    String HAS_PHONE_NUMBER = ContactsContract.Contacts.HAS_PHONE_NUMBER;
    Uri PhoneCONTENT_URI = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String Phone_CONTACT_ID = ContactsContract.CommonDataKinds.Phone.CONTACT_ID;
    String NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER;
    ContentResolver contentResolver = context.getContentResolver();
    Cursor cursor = contentResolver.query(CONTENT_URI, null, null, null, null);

    if (cursor != null && cursor.getCount() > 0) {

        while (cursor.moveToNext()) {

            String contact_id = cursor.getString(cursor.getColumnIndex(_ID));

            String name = cursor.getString(cursor.getColumnIndex(DISPLAY_NAME));
            long hasPhoneNumber = Long.parseLong(cursor.getString(cursor.getColumnIndex(HAS_PHONE_NUMBER)));

            if (hasPhoneNumber > 0) {

                Cursor phoneCursor = contentResolver.query(
                        PhoneCONTENT_URI,
                        null,
                        Phone_CONTACT_ID + " = " + contact_id + " AND " + ContactsContract.Data.MIMETYPE + " = " + "'"+ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE+"'"
                        , null, null);


                if (phoneCursor != null) {
                    while (phoneCursor.moveToNext()) {
                        Contact contact = new Contact();

                        String phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
                        phoneNumber = phoneNumber.replaceAll("[()\\-\\s]", "").trim();

                        contact.setName(name);
                        contact.setPhoneNum(phoneNumber);

                        contacts.add(contact);
                    }
                    phoneCursor.close();
                }
            }
        }
        cursor.close();
    }

    //return data
    return contacts;
}

The problem is this query, return ZERO contacts.

Any Idea why?


Solution

  • You're querying the table CommonDataKinds.Phone.CONTENT_URI which contains only Data rows with MIMETYPE = CommonDataKinds.Phone.CONTENT_ITEM_TYPE. But you're asking for rows with MIMETYPE CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE so you're getting an empty cursor.

    It's an easy fix to your existing code, but even when fixed, you're code is very slow, it'll run a query per contact on the device, this can easily be hundreds or even thousands of queries. If you just need to get the name+number of all contacts, try the following code (one query to get all):

    ArrayList<Contact> contacts = new ArrayList<>();
    
    // Make sure you import Phone from ContactsContract.CommonDataKinds.Phone
    
    String[] projection = { Phone.CONTACT_ID, Phone.DISPLAY_NAME, Phone.NUMBER };
    Cursor cur = cr.query(Phone.CONTENT_URI, projection, null, null, null);
    
    while (cur != null && cur.moveToNext()) {
        long id = cur.getLong(0);
        String name = cur.getString(1);
        String number = cur.getString(2);
    
        Log.d(TAG, "got " + id + ", " + name + ", " + number);
    
        Contact contact = new Contact();
    
        contact.setName(name);
        contact.setPhoneNum(number);
        contacts.add(contact);
    }
    
    if (cur != null) {
        cur.close();
    }
    

    Note that similar to your code, this code might create multiple Contact objects for each contact, in case a contact has more then one phone. If you want only one Contact object per contact, you need to modify your Contact object to contain a list of phones, and change the ArrayList<Contact> to HashMap<Long, Contact> so you can add a phone to an existing object instead of creating a new one.