Starting from Android 2.0 (API Level 5),
the Android platform provides an improved Contacts API for managing and
integrating contacts from multiple accounts and from other data sources. To
handle overlapping data from multiple sources, the contacts content provider
aggregates similar contacts and presents them to users as a single entity. This
article describes how to use the new API to manage (insert, update, delete,
view) contacts.
The new Contacts API is defined in the
android.provider.ContactsContract
and related classes. The older API is still supported, although
deprecated.
We need to understand the underlying
structure of storage to better manipulate the contacts. We have three distinct
types of tables – Contacts, Raw Contacts and Data.
All data related to a contact is stored in
this generic data table with each row telling what is the data it stores
through its MIME type. So we could have a Phone.CONTENT_ITEM_TYPE as the MIME
type of the data row, it contains Phone data. Similarly, if we have
Email.CONTENT_ITEM_TYPE as the row’s MIME type, then it stores email data. Like
this lot of data rows are associated with a single Raw Contact.
Each Raw Contact refers to a specific
contact’s data coming from one single source – say, you gmail account or your
office Microsoft account.
The Contact is the topmost in the hierarchy
which aggregates similar looking data from various sources into one single
contact – a very handy feature when you have redundant data coming about the
same contact from you various accounts – like a facebook account, orkut
account, yahoo account and goggle account.
So the hierarchy looks like this:
So, when we want to insert a new contact,
we always insert a Raw Contact. When we want to update an existing contact, we
most often deal with the data tables which are accessible through a series of
CommonDataKind classes. Because this would be to update particular types of
data like phone or email.
Coming to the example:
I create an activity with four buttons to
View, Add, Modify and Delete Contacts.
Button view =
(Button)findViewById(R.id.viewButton);
Button add =
(Button)findViewById(R.id.createButton);
Button modify =
(Button)findViewById(R.id.updateButton);
Button delete =
(Button)findViewById(R.id.deleteButton);
view.setOnClickListener(new OnClickListener() {
public void onClick(View v){
displayContacts();
Log.i("NativeContentProvider", "Completed Displaying Contact list");
}
});
On the click of each of the buttons I
invoke their respective methods: like displayContacts(), createContact(), updatecContact() and deleteContact(). We will now see each of these methods.
displayContacts() is pretty straightforward. Access to each of the tables mentioned
above is through a content URI. I use the topmost level ‘Contacts’ URI to
iterate through all the existing contacts and display their names and phone
numbers (Toast them).
We know Contacts is a ContentProvider and hence we need to query through a ContentResolver which returns all the data of the contacts.
private void
displayContacts() {
ContentResolver
cr = getContentResolver();
Cursor cur =
cr.query(ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String
id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String
name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(
cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" =
?",
new String[]{id}, null);
while (pCur.moveToNext()) {
String phoneNo =
pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Toast.makeText(NativeContentProvider.this, "Name:
" + name + ",
Phone No: " + phoneNo, Toast.LENGTH_SHORT).show();
}
pCur.close();
}
}
}
}
I will try to briefly explain
the above method. Line 1 gets a handle
to the ContentResolver. Line 2 queries the Contacts URI (ContactsContract.Contacts.CONTENT_URI ) without any mention of the specific columns or “where” clause of an
SQL query. Notice all the 4 parameters are null. This means that we are not
making any conditional query into the contacts table and hence all data is returned
into the cursor.
Next, I check that the
cursor is not empty and iterate through the cursor data. I retrieve the _ID and DISPLAY_NAME from the Contacts and then, I check for the flag if the contact has a
phone number. This information is available in contacts table itself. But the Phone
number details are in the data tables. Hence after checking for the flag, I
query the CommonDataKings.Phone.CONTENT_URI for the phone data of that specific ID. From
this new cursor named pCur, I retrieve the Phone
Number. If there are multiple phone number for one contact, all of them will be
retrieved and toasted one after another.
Now, let us see how to
create or insert a new contact.
In the createContact() method which is called when you click on the “Add
Contact” button, I first query to see if the hardcoded name “Sample Name”
already exists. If so, I toast a message stating the same. If not, then I get
into actually inserting the name along with a phone number. The first part of
the check you can view in the complete source code available for download. Only
the second part of inserting a contact is explained here. For this, we need to
use a ContentResolver
always.
A ContentResolverprovides an applyBatch(…) method which takes an array of ContentProviderOperation classes as a parameter. All the data built
into the ContentProviderOperations are committed or inserted into the ContentProvider that we are working on. IN this case, the ContentProvider we are working on are Contacts and the
authority associated with the same is ContactsContract.AUTHORITY
Here is the code for the same:
ArrayList<ContentProviderOperation> ops = new
ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, "accountname@gmail.com")
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, "com.google")
.build());
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, name)
.build());
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, phone)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_HOME)
.build());
try {
cr.applyBatch(ContactsContract.AUTHORITY, ops);
….
In the first element in the ops array,
I am setting the details of the account to which I want to add the contact. In
this case the gmail account type is accontname@gmail.com and the account name is “com.google”. The latter has to be unique
and hence it is recommended to use the internet URLs of the source of data.
In the second element, I am adding the name
of the contact and in the third the phone data. You notice that I use .withValueBackReference(..) as we still have not created the Raw contact and hence we do not
have the Id. The first row creates the id and hands over the id to the next
rows of data.
For updating the phone number of an existing
contact, I again use the ContentResolver
with the ContentProviderOperation array. However, now, I
pass the where clause and the parameters of the where clause – specifically indicating
that only the phone number of the “Sample Name” contact has to be updated.
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(where, params)
.withValue(ContactsContract.CommonDataKinds.Phone.DATA, phone)
.build());
Notice the .withSelection(where, params). The
where and params look like this:
String where = ContactsContract.Data.DISPLAY_NAME + " = ? AND
" +
ContactsContract.Data.MIMETYPE + " = ? AND
" +
String.valueOf(ContactsContract.CommonDataKinds.Phone.TYPE) + " = ?
";
String[] params = new String[] {name,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
String.valueOf(ContactsContract.CommonDataKinds.Phone.TYPE_HOME)};
Delete too is done in a very similar manner
with no values but only the selection criteria is provided for which contact to
be deleted.
ContentResolver
cr = getContentResolver();
String
where = ContactsContract.Data.DISPLAY_NAME + " = ? ";
String[]
params = new String[]
{name};
ArrayList<ContentProviderOperation>
ops = new
ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI)
.withSelection(where, params)
.build());
try {
cr.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
….
I really scouted the internet a lot to find
a comprehensive tutorial on the new Contacts Content Provider API but could not
find anything that easily. Hope this helps all who of you who are looking for
the same.
NOTE: Many have been asking me questions on why the contacts that have just been added through this app are not visible in the phone contacts. All your contacts on phone are linked to your google account on the phone. However, the contacts from the above code have got added to psuedo google account and hence will not be visible directly. You search for the just added contact and you will be able to find it.
Hope this helps.
Hi, this seems to be just what it is I need for my current task. However, the part I need to see is the code for creating a contact. I have downloaded the source code from your link, but I am unable to open the .zip archive. Can you re-post, or send directly?
ReplyDeleteHi Ken,
ReplyDeleteI have uploaded the source code once again. Please try and let me know if you still have a problem.
- Sai
thanks ... its very informative
ReplyDeleteIt looks like the server is down and I can not download the source code.
ReplyDeleteandroid apps
Dear Geetha,
ReplyDeleteThanks a lot for this great blog. I got lots of details about Android basics.
Dear followers,
Any one looking for Android development job at Chennai. You can contact me at
Hemanand16@gmail.com
Hi,
ReplyDeleteThis is very useful.
I want to use same as Android Default Contact list.
So how to use it?
I know I need to use Expandable list view bt need more guidance..
Hi saigeetha,
ReplyDeletei tried to executed your your code.Its working without any error.But after createContact method i opened the android's contacts application.The contact i added using createContact is not there.when i click display contacts, it is displaying.Actually what is the problem?
Hi
ReplyDeleteGeetha you are code is working fine.According to my requirement. I should to get all contacts from android contacts(firstname,lastname,email,phone,company).When I click on the contact,the menu should appear with
1 make a call
2.send email.
3.send sms.
Could u please send me the source code
Regards
Sanjeev.
email:sanjeev9114@gmail.com
You are such a funny person Sanjeeev
DeleteHi, I have the same problem as sarath. It looks like it's working fine but isn't showing in my Contacts on the phone (or in my gmail account). I get the uris back from:
ReplyDeleteContentProviderResult[] results = getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
Any ideas?
Thanks for the reference.
i too have the same issue as sarath and julius.. i need help
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHi Sai Geetha,
ReplyDeleteCan you please post content for sending E-mails from android devices.
And on Maintaining Session data .
ReplyDeletei just wanted to say thanks alot for this great effort
ReplyDeleteThis is really very helpful. I am going to start new project where i have to implement this API. Thank you very much.
ReplyDeleteHi Sai,
ReplyDeleteSorry, it took me a while to get back to this issue. I tried downloading again today, but still no luck. I get a 606 byte .zip file which my version of WinZip (12.1) says is an invalid archive. Would it be possible to email the source files?
Thanks,
- Ken
Hi Sharath, Julius and balaji,
ReplyDeleteThe contacts have got added to psuedo google account and hence will not be visible directly. you search for the just added contact and you will be able to find it.
Hope this helps.
I think you mixed up account type and account name. I tried it with
Deleteaccount type = com.google
account name = my@account.xx
And I can see it in the contacts app without a problem.
Hi Ken,
ReplyDeleteHave you tried downloading from http://www.saigeetha.co.in/home/android-tutorial-code-for-download/NewContentProviderSample2.2.zip?attredirects=0&d=1
If you are still unable to download and unzip successfully, please pass on your email id and I can pass the source code to you
please send a copy here too - adorable.anshul@gmail.com. I can't open it too. Thanks in advance.
DeleteHI Geetha this is Madhav & im absolutely a fresher & looking for Android development.Pls help me.
ReplyDeleteRegards
Madhav
HI Sai Geetha,
ReplyDeleteIn the simulator while the loader is runing mean while i changed the rotation at that time my application crashing out. wwhat i need do without crashing.please reply as soon as possible with following mail id pavankumar.rebba@gmail.com
Thanks
pavan R
Hi Geetha,
ReplyDeleteI am running this sample on my phone. There are 3 contacts that have HAS_PHONE_NUMBER >0 but they don't have records in phone content uri. These contacts also have phone numbers, and I can see those numbers when I go to phone dialer. But these contacts are not visible on People application.
Can you please explain how it is possible. ?
hi Sai Geetha, well done doing well, God bless you. This is satnam singh from chandigarh(punjab). Working on applications like console, window, web, mobile, RIA, web services in java. As you written "Knowledge Grows When Shared!" its true. So i want to start technical discussions with you if possible. Plz reply ssubhi_2003@yahoo.com
ReplyDeletewhat is eclipise
ReplyDeletemam i dont know corejava knowedge
ReplyDeleteimoportant tops give me more suggestion mam
hiii mam "how to create a hexagonal shape clock in android" plz reply me( with code)
ReplyDeletemam i know little bit corejava knowledge....
ReplyDeleteplz tel me the most important topics for android
Hi Geetha, thanks for ur blog
ReplyDeletehi, this works great but when you have synced contacts from Facebook, i am not getting the contact numbers (which comes frm facebook) while i get the email and other stuff. Does it get stored some where else or am i missing something???
ReplyDeleteHey Geetha,
ReplyDeleteGreat conversation about the topic you discussed here.I really had great time on reading your blog since it has amazing information.
hi mam,
ReplyDeleteI could not not download the source code.would you mind sending the source code to my mail.balakrishna_225@yahoo.co.in
Hi,
Deletei am geeting stuck with my android app.
I am new to Java.
I need help.
contact me on pkunuma@gmail.com
If you contact is invisible replace this
ReplyDelete.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, "accountname@gmail.com")
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, "com.google")
.build());
WITH
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.build());
Hi,
ReplyDeletethank u very much for maintaining this blog, it is very useful to all.I suggested one thing that can you maintain android basics briefly in this blog.
It will useful for freshers.
Great stuff you have here and nice post. Whatever is being written here is certainly a big help.
ReplyDeleteThis is one of the most incredible blogs Ive read in a very long time. The amount of information in here is stunning, like you practically wrote the book on the subject. Your blog is great for anyone who wants to understand this subject more.
ReplyDeletethanks mam ur blog is so helpful for all android devlopers...
ReplyDeleteactually i want to insert image which are in sd card with contact detalis and i want to display it when i m clicking in view profile.so can u pls help me for this....thankyou so much
hello mam in ur application update code is not working properly means in update only toast is generated but the new value is not insertes in the place of old value.. so can u pls help me for this ..thanks in advance
ReplyDeleteI am very much impressed from your post.It has amazing information.I learned lot of new things which explores my knowledge in various developments.So i must appreciate your efforts on posting these information.
ReplyDeleteHi Geetha,
ReplyDeleteI was able to test your code on HTC Sensation device. It crashed when I ran the code / .apk as is on device. I am using Android 4.0.
I commented the code:
if (cur.getCount() > 0)
{
while (cur.moveToNext())
{
String existName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (existName.contains(contactName))
{
Toast.makeText(DatabaseActivity.this,"The contact name: " + contactName + " already exists", Toast.LENGTH_SHORT).show();
return;
}
}
}
After that, I noticed that contact was getting successfully added to phone contact list. I was able to view the contact.
However, the problem is: I cannot delete the contact from the phone at all!! How do we allow user to delete contact?
BR,
It was not working in the emulator but not working in phone (update),and one thing the Contact from your app is not visible in the inbuilt contacts of Phone and Emulator both.Can you please give solution for this ,my phone is Samsung Galaxy Fit.
ReplyDeletehi,
ReplyDeletethis was very helpful, thank u
hai geetha ,this is naveen ,small doubt in android , how to set the segmentcontrol in android plz send the sourecode......this is my emailid. methukunaveen@gmail.com
ReplyDeleteHey, Thanks a lot, I am 15 years old developing Android Apps, This code helped me a lot, Thanks.
ReplyDeleteHow can I show contacts in Contacts/people instead of psuedo google account?
ReplyDeletehi sai,
ReplyDeletei have created 2 contacts in emulator and when i tried to display these contacts i am getting following error
02-07 16:18:42.397: E/AndroidRuntime(573): FATAL EXCEPTION: main
02-07 16:18:42.397: E/AndroidRuntime(573): android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 2
02-07 16:18:42.397: E/AndroidRuntime(573): at android.database.AbstractCursor.checkPosition(AbstractCursor.java:580)
02-07 16:18:42.397: E/AndroidRuntime(573): at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:214)
02-07 16:18:42.397: E/AndroidRuntime(573): at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:41)
02-07 16:18:42.397: E/AndroidRuntime(573): at android.database.CursorWrapper.getString(CursorWrapper.java:135)
02-07 16:18:42.397: E/AndroidRuntime(573): at com.H3Innovations.MyBuddy.TestMenu.viewContact(TestMenu.java:67)
02-07 16:18:42.397: E/AndroidRuntime(573): at com.H3Innovations.MyBuddy.TestMenu.onClick(TestMenu.java:47)
02-07 16:18:42.397: E/AndroidRuntime(573): at android.view.View.performClick(View.java:2408)
02-07 16:18:42.397: E/AndroidRuntime(573): at android.view.View$PerformClick.run(View.java:8816)
02-07 16:18:42.397: E/AndroidRuntime(573): at android.os.Handler.handleCallback(Handler.java:587)
02-07 16:18:42.397: E/AndroidRuntime(573): at android.os.Handler.dispatchMessage(Handler.java:92)
02-07 16:18:42.397: E/AndroidRuntime(573): at android.os.Looper.loop(Looper.java:123)
02-07 16:18:42.397: E/AndroidRuntime(573): at android.app.ActivityThread.main(ActivityThread.java:4627)
02-07 16:18:42.397: E/AndroidRuntime(573): at java.lang.reflect.Method.invokeNative(Native Method)
02-07 16:18:42.397: E/AndroidRuntime(573): at java.lang.reflect.Method.invoke(Method.java:521)
02-07 16:18:42.397: E/AndroidRuntime(573): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
02-07 16:18:42.397: E/AndroidRuntime(573): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
02-07 16:18:42.397: E/AndroidRuntime(573): at dalvik.system.NativeStart.main(Native Method)
Hello mam, thnks for sharing...
ReplyDeleteUsing this I can see all contacts but I can not add new contact....if I click on new contact and check my phonebook list then it is not added to list of contacts, but nw If I press view contact again then I can get that value in toast..means using add contact methos it is storing new contact somewhere..but could not show to list of contact....so what could be proper solution for tht??
Hello Mam
ReplyDeleteif i want to show them in default android contact list then what to do?
Thanks in advance
Thanks a log Sai Geetha.
ReplyDeleteTo Others: Ask for 'how to do', but don't ask the source code. Behave being a developer, live being a developer.
Hi Geetha,
ReplyDeleteHow can i have a contact list of Gmail not PHONE ?
Thanks
Jigar
Thanks mam..... You solved my big big big problem.... Thank You Very Much.....
ReplyDeleteHI
ReplyDeleteContacts API 2.0 and above | Android Developer Tutorial
Great post! and incredible blog ! Very helpful post! I must say. Simple & interesting. Wonderful work!
thank you!
Thank you.
ReplyDeletehi
ReplyDeletehow to make default in another activity when a contact is clicked to send sms or dial.please provide me a solution..mail id suhasvm@gmail.com
hi sai geetha,
ReplyDeleteif i add a contact it is adding it to the google contact ? is it possible to add to local device? or is there anything like prompt window asking the user to select the type of storage (keep local or Add account)as in google Android API.
thanks in advance !!
hi
ReplyDeletei am using a search option in my application so using this option i need search whole application keywords and when i selected a key word i need to display all the details related to that keyword .like registered in database user name sai (keyword) then i need details of the sai like first name last name and contact no.from db
Quick question Sai, is there a better way to obtain the user's newly created record id (CONTACT_ID), rather than having to do a content resolver query with selection + selectionArgs?
ReplyDeleteThankx Geetha you saved my day
ReplyDeleteUsing this I can see all contacts but I can not add new contact....if I click on new contact and check my phonebook list then it is not added to list of contacts, but nw If I press view contact again then I can get that value in toast..means using add contact methos it is storing new contact somewhere..but could not show to list of contact....so what could be proper solution for tht??
ReplyDeletefix CommonDataKings to kinds
ReplyDeleteHi, At Professional Android Application Development, Our Team Specializes In Google Android App Development For Android Based Phones And Tablets. We Work Ultra-Fast And Deliver High Quality Apps For Android.
ReplyDeleteprofessional android Application Development
hi geetha,
ReplyDeletecode is nice...but have a query...display contacts method shows all contact details in toast...but how to add all in array list?? can u show me the code??
mail at: shatrunjay.doshi@gmail.com
regards,
shatrunjay(India)
Hi, excellent your tutorial, I have a question: How can I do a query from an specific name, for example I want to know the phone number and the email from user "Michael", is that possible.
ReplyDeleteThanks
Your articles are purely enough for me.
ReplyDeleterooting android tablet
The content on your website never confuses me
ReplyDeleteandroid news
hi this one is amazing...........
ReplyDeleteI can't download the source code? Can you please check it? Thanks....
ReplyDeleteThanks lot, its very very useful post.
ReplyDeletegood one..
ReplyDeleteNice work!!!
ReplyDeleteAndroid e-mails Sending Client : Simple exemple for free:
http://free-to-download-resources.blogspot.com/2013/06/android-gmails-sending-client-simple.html
Thank you so much :)
ReplyDeletehi geetha,
ReplyDeleteI was trying to do something similar but I have run into some problem. I want to save the birthday and anniversary date for the contact but I am unable to do so. Please check this http://stackoverflow.com/questions/17647372/unable-to-update-the-birthday-date-for-a-contact-in-android and let me know what is wrong.
Very informative, Thanks for sharing. Just read about a new android email API from Aspose by the name of Aspose.Email for Android. Here is the link: http://www.aspose.com/android/email-component.aspx It provides tools to create, read & convert Outlook MSG, PST, EML, EMLX, OST & MHT file formats. It creates & save appointments in draft format, extract & save calendar items from a PST, add Mapi Items such as Messages, Contacts, Notes, Journals & Tasks to a PST. I am sure it will be very useful for the users.
ReplyDeletehow to update contact name?
ReplyDeleteHi Geetha,
ReplyDeleteHow can i find if any contact is edited deleted or added in android.
If any of the event occurs on contacts i want to find that which is that contact.
Hi Geetha,
ReplyDeleteYou have mixed up account name and account type
ACCOUNT_NAME->accountname@gmail.com
ACCOUNT_TYPE->com.google
When is the need to create a new account type for Contacts. If we observer Whatsapp and Viber both create their own account types in contacts. What is the need to do so?
ReplyDeleteGreat posts, appreciate the hard work... very helpful in my understanding of contacts tables, columns etc.
ReplyDeleteHow to retrieve all contact details like Name,Email,Phone No,Address,ProfilePic[ContactsContract.Contacts] in a single query in Cursor Loader. I had tried various methods involving multiple queries.
ReplyDeleteHi mam,
ReplyDeleteGreat tutorial it helped me.I run the code as it is but the contacts are repeating twice some contacts thrice.please help me.
Why not make the first selection query for CONTENT_URI with selection:
ReplyDeleteContactsContract.Contacts.HAS_PHONE_NUMBER + " > 0"
instead of checking this field in Cursor?