Inserting and Updating a Contact in Android – Numbers, Addresses and Names – Part 1
I have finally got a working example of inserting and updating contacts using the new ContactsContract API, and I must say, it’s certainly not the prettiest API I’ve used. Sometimes it is downright malignant! I’m sure it made good sense when first created but I have found even the simplest actions like inserting an address somewhat of a chore.
The goal was to populate some values and display to the user the android edit screen. This could be done using the built-in USER_EDIT USER_INSERT or USER_INSERT_OR_UPDATE Activities like this:-
Intent i = new Intent(Intent.ACTION_INSERT); i.setType(Contacts.CONTENT_TYPE); i.putExtra(Insert.NAME, "Some Contact Name"); i.putExtra(Insert.EMAIL, "address@email.com"); i.putExtra(Insert.PHONE, "123-456-7890"); context.startActivity(i);
The problem here is that I CAN use Insert.POSTAL to insert an address, but it will insert the whole address on the ‘street’ entry, not break them into suburb etc. which looks rubbish. From memory this is the same with display name, with everything being in the firstname field.
Trawling through the API. there looks to be a new field called ‘data’ which may allow more advanced interaction with contacts however this is only available in honeycomb so at least for the next few years (assuming that it works how I expect it) it isn’t feasable.
So this left me looking for another solution, which was to insert the contact before showing the edit screen. Again, this isn’t optimal, but I figured it was easier for the user to delete an unwanted contact than it was to fix addresses to appear in the correct fields. This on the whole worked well using the ContactsContract API:-
array of contentProviderOperations we wish to run
ArrayList ops = new ArrayList();
Add a new contact to a selected account (google in this case)
ops.add(ContentProviderOperation
.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE,
"com.google")
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME,
mAccountName).build());Add the display name. withValueBackReference is used as the user hasn’t been created yet. It will use the RAW_CONTACT_ID that will be created in the previous operation
ops.add(ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(
ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
mDisplayName).build());Again using valueBackReference, we are inserting the phone number to the raw contact under a type of work.
ops.add(ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER,
rci.getNumber())
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.TYPE_WORK)
.build());Now to create the address insert operation. I have marked it as a work address, and we specify each item in the address.
Log.d(Constants.TAG, address.toString());
ContentProviderOperation.Builder operationBuilder = ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI);
operationBuilder.withValueBackReference(
ContactsContract.Data.RAW_CONTACT_ID, 0);
operationBuilder
.withValue(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
.withValue(
ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY,
mCountry)
.withValue(
ContactsContract.CommonDataKinds.StructuredPostal.REGION,
mState)
.withValue(
ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE,
mPostCode)
.withValue(
ContactsContract.CommonDataKinds.StructuredPostal.CITY,
mSuburb)
.withValue(
ContactsContract.CommonDataKinds.StructuredPostal.STREET,
mStreet)
.withValue(
ContactsContract.CommonDataKinds.StructuredPostal.TYPE,
ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK);
ops.add(operationBuilder.build());
}
}Last thing to do is to run the batch operation
Uri contactUri = _context.getContentResolver().applyBatch( ContactsContract.AUTHORITY, ops);
The URI returned from the batch operation can be used to bring up the Edit User Activity:-
Intent i = new Intent(Intent.ACTION_EDIT);
i.setData(contactUri);
context.startActivity(i);
I also do this within an AsyncTask as the UI will become unresponsive for a few seconds.
I will cover updates in part 2
Any questions, comments or suggestions, feel free to post a comment below.

Good post it was really helpfull.
I am facing one issue with this, I am not able to add LastName using this
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, “Mathew Hayden”).build());
Could u please shed some light.
Thanks mate
Are you trying to insert the first name too? possibly try inserting that in the same batch operation. In the code you provide it looks like you are inserting both names into FAMILY_NAME.
If you use DISPLAY_NAME it will automatically assign each name to first/last name, so one way would be using that.
Thanks, but, where is the part 2 ?
Drat, you are quite right to ask! I had started it a while back and completely forgot to finish it off – it’s been a busy year.
I will look at finishing it off after my current round of assignments are finished.
Ok, I’m currently on an app which uses content provider, I could help you if you want.
Contact me,
Regards,