Filter Android ContactsContract.Data by Company AND Display Name

58 Views Asked by At

I have something like this so far, but it seems like ContactsContract.Data URI returns multiple records with the same CONTACT_ID and LOOKUP_KEY. Is there any way to make this cursor return distinct records?

        private static final Uri URI = ContactsContract.Data.CONTENT_URI;

        @SuppressLint("InlinedApi")
        private static final String[] PROJECTION = {
                ContactsContract.Data._ID,
                ContactsContract.Data.CONTACT_ID,
                ContactsContract.Data.LOOKUP_KEY,
                ContactsContract.Data.DISPLAY_NAME_PRIMARY
        };

        private static final String SELECTION =
                ContactsContract.Data.DISPLAY_NAME_PRIMARY + " LIKE ?" +
                " AND " + ContactsContract.Data.MIMETYPE + " = " + ContactsContract.CommonDataKinds.Organization.MIMETYPE +
                " AND " + ContactsContract.CommonDataKinds.Organization.COMPANY + " LIKE ?";

        private static final String SORT_ORDER =
                ContactsContract.Data.DISPLAY_NAME_PRIMARY + " ASC";

        @Override
        public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
            String contactsFilter = getFilter(contactsSearch);
            String companyFilter = getFilter(companySearch);

            // Starts the query
            return new CursorLoader(
                    getActivity(),
                    URI,
                    PROJECTION,
                    SELECTION,
                    new String[] { contactsFilter, companyFilter},
                    SORT_ORDER
            );
        }

Here's an example of the dump of this cursor:

   42 {
       _id=74752
       contact_id=12603
       lookup=2645ie9ffe868ace3d43
       display_name=Person 1
    }
    43 {
       _id=74753
       contact_id=12603
       lookup=2645ie9ffe868ace3d43
       display_name=Person 1
    }
    44 {
       _id=74756
       contact_id=12603
       lookup=2645ie9ffe868ace3d43
       display_name=Person 1
    }

_ID is different, but I want the cursor to return 1 record per person and all 3 of these are the same person.

Thoughts?

1

There are 1 best solutions below

4
marmor On

The Contacts DB is organized in three main tables:

  1. Contacts - each entry represents one contact, and groups together one or more RawContacts
  2. RawContacts - each entry represents data about a contact that was synced in by some SyncAdapter (e.g. Whatsapp, Google, Facebook, Viber), this groups multiple Data entries
  3. Data - The actual data about a contact, emails, phones, etc. each line is a single piece of data that belongs to a single RawContact

Usually what happens is that an app (e.g. Google, Whatsapp, Linkedin) that wishes to create a new contact will create a new row in the RawContacts table that will usually contain just a name, and then use that row's _ID to add rows into the Data table for phones, emails, addresses, photos, etc.

You are querying over the Data table which means that if a certain contact has raw-contacts from 2 sources (e.g. 2 Google accounts) and both raw contacts contain a Data row with a certain company name, your cursor will return 2 results for that contact.

I would recommend not using CursorLoader here, instead create a regular Cursor from your projection/selection/selection-args, traverse it to get the data and then use a HashMap by contact-id (or some other method) to make the entries distinct by their Contact ID.