Search code examples
androidandroid-contactsandroid-contentresolver

Selecting RawContacts with special requirements in Android


Whenever I want to add new data to an existing Android contact, I use the following function to retrieve all RawContacts IDs for the given contact ID:

protected ArrayList<Long> getRawContactID(String contact_id) {
    ArrayList<Long> rawContactIDs = new ArrayList<Long>();
    String[] projection = new String[] { ContactsContract.RawContacts._ID };
    String where = ContactsContract.RawContacts.CONTACT_ID + " = ?";
    String[] selection = new String[] { contact_id };
    Cursor c = getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI, projection, where, selection, null);
    try {
        while (c.moveToNext()) {
            rawContactIDs.add(c.getLong(0));
        }
    }
    finally {
        c.close();
    }
    return rawContactIDs;
}

After that, I just insert the data using the ContentResolver:

getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);

This is done for all RawContacts IDs that have been found previously. The effect is, of course, that all data is added repeatedly. Thus I want to return only one result now, but this has to meet special requirements.

I would like to adjust my function above so that its result meets the following requirements:

  1. ContactsContract.RawContactsColumn.DELETED must be 0
  2. The RawContacts entry must not be a secured one like Facebook's
  3. ContactsContract.SyncColumns.ACCOUNT_TYPE is preferably "com.google". So if there is one entry that meets this requirement, it should be returned. If there is none, return any of the remaining entries.

How can I do this (most efficiently)? I don't want to make the query to complex.


Solution

  • I have given this some thought, from my experience with contact r/w, and with your needs in mind. I hope this helps you solve the issue and or points you in the direction you are looking for. Please note that i have no device available with any sync adapters such as facebook so unfortunately i cannot confirm my answer viability (the read only bit mainly which might changeable to a simple != '' ).

    Same getRawContactID function with some adjustments

    protected ArrayList<Long> getRawContactID(String contact_id) {
        HashMap<String,Long> rawContactIDs = new HashMap<String,Long>();
        String[] projection = new String[] { ContactsContract.RawContacts._ID, ContactsContract.RawContacts.ACCOUNT_TYPE };
        String where = ContactsContract.RawContacts.CONTACT_ID + " = ? AND " + ContactsContract.RawContacts.DELETED + " != 1 AND " + ContactsContract.RawContacts.RAW_CONTACT_IS_READ_ONLY + " != 1" ;
        String[] selection = new String[] { contact_id };
        Cursor c = getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI, projection, where, selection, null);
        try {
            while (c.moveToNext()) {
                rawContactIDs.put(c.getString(1),c.getLong(0));
            }
        }
        finally {
            c.close();
        }
        return getBestRawID(rawContactIDs);
    }
    

    And another getBestRawID function to find the best suited account -

    protected ArrayList<Long> getBestRawID(Map<String,Long> rawContactIDs)
    {
        ArrayList<Long> out = new ArrayList<Long>();
        for (String key : rawContactIDs.KeySet())
        {
           if (key.equals("com.google"))
           {
              out.clear(); // might be better to seperate handling of this to another function to prevent WW3.
              out.add(rawContactIDs.get(key));
              return out;
           } else {
              out.add(rawContactIDs.get(key));
           }
        }
        return out;
    }
    

    Also note - I wrote most of the code without running / testing it. Apologies in advance.