1

How do I update the display name for a contact? The operation in the code below completes without throwing anything and appears to work - that is, when I requeried the ContactsContract.Contact table, a row came back with the name changed. However, when I tried running the stock "people" app on my tablet, it crashed. Evidentally I did something wrong.

Here is the code. Early on, it fetches an id from the aggregate contacts as follows, where key is the lookup_key:

  String[] projection = new String[] {
    Contacts._ID, // 0
    Contacts.DISPLAY_NAME, // 1
  };

  Uri uri = Uri.parse (Contacts.CONTENT_LOOKUP_URI + "/" + key);
  ContentResolver cr = getContentResolver();
  Cursor cursor = cr.query (uri, projection, null, null, null);
  if (!cursor.moveToNext()) // move to first (and only) row.
    throw new IllegalStateException ("contact no longer exists for key");
  origId = cursor.getLong(0);
  cursor.close();

Then, after the user has done his edits, I call this block of code to update the display_name:

  ArrayList<ContentProviderOperation> opers = new ArrayList<ContentProviderOperation>();
  ContentProviderOperation.Builder builder = null;

  String[] args = { Long.toString (origId) };
  builder = ContentProviderOperation.newUpdate (Data.CONTENT_URI);
  builder.withSelection (RawContacts.CONTACT_ID + "=?", args);
  builder.withValue(CommonDataKinds.StructuredName.DISPLAY_NAME, name);
  opers.add(builder.build());

  ContentProviderResult[] results = null;
  try {
    results = getContentResolver().applyBatch(ContactsContract.AUTHORITY, opers);
  } catch ...

I realize I don't need the ContentProviderOperation for this example; that's for later when I have more stuff to update.

To be honest, I'm pretty confused about which ID I'm actually using. The names aren't that clear to me and I may be using the wrong ID for this operation.

For what it's worth, looking at results after the update I saw a result code of 5. I can't find any documentation for that, so have no idea if that is significant.

Peri Hartman
  • 19,314
  • 18
  • 55
  • 101

2 Answers2

6

The IDs (and altering contacts in general) can be pretty confusing... I had some dramas getting my head around them as well.

Here is some working code I use for updating. The main difference I can see is how you are declaring the raw ID; it needs to be included in as a content value.

Cursor cursor = _context.getContentResolver().query(contactUri,
            new String[] { Contacts._ID }, null, null, null);
    try {
        if (cursor.moveToFirst()) {
            String rawContactId = cursor.getString(0);
            ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
            ContentValues contentValues = new ContentValues();
            contentValues.put(Data.RAW_CONTACT_ID, rawContactId);

            contentValues
                    .put(ContactsContract.Data.MIMETYPE,
                            ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
            contentValues.put(
                    ContactsContract.CommonDataKinds.Phone.NUMBER,
                    phoneNumber);
            contentValues.put(ContactsContract.CommonDataKinds.Phone.TYPE,
                    ContactsContract.CommonDataKinds.Phone.TYPE_WORK);

            ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
                    .withValues(contentValues).build());
            String contactId = contactUri.getLastPathSegment();
            ops.add(ContentProviderOperation
                        .newUpdate(ContactsContract.Data.CONTENT_URI)
                        .withSelection(
                                ContactsContract.Data.CONTACT_ID
                                        + "=? AND "
                                        + ContactsContract.Data.MIMETYPE
                                        + "=?",
                                new String[] {
                                        contactId,
                                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE })
                        .withValue(
                                ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
                                newName).build());

            result = _context.getContentResolver().applyBatch(
                    ContactsContract.AUTHORITY, ops);
        }
    } finally {
        cursor.close();
    }

hopefully it helps!

Ben Neill
  • 2,811
  • 2
  • 22
  • 20
  • It might be working :) Can you verify a few things for me: (1) you use contactUri - is that ContactsContract.Data.CONTENT_URI? (2) is contactUri.getLastPathSegment() the id from ContactsContract.Contacts._ID? (3) it appears this technique will only update one raw contact; isn't there supposed to be a way to update a name in all raw contacts aggregated into the Contacts table? – Peri Hartman Dec 03 '12 at 17:56
  • (1) android.provider.ContactsContract.Contacts.CONTENT_URI is what I am using (2) That is correct. (3) I guess there would be a way to do that, but why would you want to? If you want to bulk change more than one at a time I guess you would do each as a separate operation... – Ben Neill Dec 03 '12 at 21:54
  • So, if you are starting with Data.CONTENT_URI, you already have the right id for the update. In my case, I'm starting with the Contacts table, so the update needs to relate back to that. Tell me, if you know, is RawContacts.CONTACT_ID the FK to Contacts._ID? I think I now see the other critical shema relations, too: Data.RAW_CONTACT_ID is the FK to RawContacts._ID and DATA.CONTACT_ID is the FK to Contacts._ID - right? I wish this was in the documentation... – Peri Hartman Dec 04 '12 at 06:18
  • That is how I understand it - RawContacts.CONTACT_ID is the parent, RawContacts._ID is its ID. I'm not so sure about Data.CONTACT_ID but the naming suggests it is. The whole contacts system does my head in - never found a decent, concise explanation, hence my attempts to detail it on my site! – Ben Neill Dec 05 '12 at 00:10
  • Yep, concur (the headache part, that is). Thanks for following through with this - it really helps! – Peri Hartman Dec 05 '12 at 00:44
0

Answer above is generally correct. However, when I inserted

ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME and then tried to do newUpdate

ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME

with code as above - it made contact displayed in Contacts app with name mixed of old and new data. I found out inserting and updating ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME for example works as I expect. In Contacts app on my Android 4x when editing contact I cannot see family and given separately, look to me DISPLAY_NAME is made of them by Android.

Alex Martian
  • 3,423
  • 7
  • 36
  • 71