Introduction

In this blog post I will do a quick android phone contacts crash course. After reading this you will be able to: query all contacts from the phone and query additional commonly used information about a specific contact.

First I will present some real world situations when we need to retrieve the phone contacts, after that I will present the android architecture for storing contact information and finally I will give you the exact details to do all you want with the address book in code.

Real World Usage

Either you will want to develop a contact manager app that will heavily use android contacts provider, or if you just go for a social app that has to use address book contacts, it’s always good to know you way around contacts in an android mobile application.

Android Contact Structure

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.

The contacts content provider (android.provider.ContactsContract) aggregates similar contacts and presents them to users as a single entity.

The Contact is the topmost in the hierarchy which aggregates Raw Contacts.

Each Raw Contact refers to a specific contact’s data coming from one single source – say, your gmail account, your yahoo account or your Microsoft Live account.

All data related to a Raw Contact is stored in a 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.

Android Contact API

Granting Access

Before an application can query the contact records access must be granted through the AndroidManifest.xml file stored in the root of the project. Add the following uses-permission belows the uses-sdk statement.

uses-permission android:name=”android.permission.READ_CONTACTS”

Querying The Android Contact Database

Retrieving Contact List

First we will retrieve basic contact information stored in Contacts table. The focus is to query the columns containing the following Id:

ContactsContract.Contacts._ID ContactsContract.Contacts.DISPLAY_NAME ContactsContract.Contacts.HAS_PHONE_NUMBER
public Cursor GetContacts() { ContentResolver cr = localContext.getContentResolver();   try { Uri uri = ContactsContract.Contacts.CONTENT_URI;   String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER };   String where = ContactsContract.Contacts.IN_VISIBLE_GROUP + ” = ‘1’”;   String[] selectionArgs = null;   String sortOrder = ContactsContract.Contacts.DISPLAY_NAME;   return cr.query(uri, projection, where, selectionArgs, sortOrder); } catch (Exception ex) { String message = ex.getMessage(); Log.e(TAG, “Error: ” + message, ex);   return null; } }

Retrieving Contact Details

After having all the contacts we can go on and find out more data about each contact. I will give examples for phone number, email, birthday and also photo.

I will use the ContactId field to filter after only one record, including a where clause to limit the returned data.

Phone Number

Phone numbers are stored in their own table and need to be queried separately. To query the phone number table use the URI stored in this SDK variable:

ContactsContract.CommonDataKinds.Phone.CONTENT_URI
public Cursor GetContactPhone(int contactId) { ContentResolver cr = localContext.getContentResolver();   try { Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;   String[] projection = new String[] { ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.Data.MIMETYPE };   String where = ContactsContract.Data.CONTACT_ID + “=?” + ” AND ” + ContactsContract.Data.MIMETYPE + “=?”;   // Add contactId filter. String[] selectionArgs = new String[] { String.valueOf(contactId), ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE };   String sortOrder = null;   return cr.query(uri, projection, where, selectionArgs, sortOrder); } catch (Exception ex) { String message = ex.getMessage(); Log.d(TAG, “Error: ” + message);   return null; } }

Since multiple phone numbers can be stored loop through the records returned in the Cursor.

Email

Emails are also stored in their own table and need to be queried separately. To query the email address table use the URI stored in this SDK variable:

ContactsContract.CommonDataKinds.Email.CONTENT_URI
public Cursor GetContactEmail(int contactId) { ContentResolver cr = localContext.getContentResolver();   try { Uri uri = ContactsContract.CommonDataKinds.Email.CONTENT_URI;   String[] projection = new String[] { ContactsContract.CommonDataKinds.Email.CONTACT_ID, ContactsContract.CommonDataKinds.Email.DATA, ContactsContract.Data.MIMETYPE };   String where = ContactsContract.Data.CONTACT_ID + “=?” + ” AND ” + ContactsContract.Data.MIMETYPE + “=?”;   // Add contactId filter. String[] selectionArgs = new String[] { String.valueOf(contactId), ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE };   String sortOrder = null;   return cr.query(uri, projection, where, selectionArgs, sortOrder); } catch (Exception ex) { String message = ex.getMessage(); Log.d(TAG, “Error: ” + message); return null; } }

Since multiple email addresses can be stored loop through the records returned in the Cursor.

Birthday

Retrieving the Birthday is a bit more challenging as I have to use a MimeType to access the contacts date of birth:

ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY
public Cursor GetContactBirthday(int contactId) { ContentResolver cr = localContext.getContentResolver();   try { Uri uri = ContactsContract.Data.CONTENT_URI;   String[] projection = new String[] { ContactsContract.Data.CONTACT_ID, ContactsContract.CommonDataKinds.Event.START_DATE, ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Event.TYPE };   String where = ContactsContract.Data.CONTACT_ID + “=?” + ” AND ” + ContactsContract.Data.MIMETYPE + “=?” + ” AND ” + ContactsContract.CommonDataKinds.Event.TYPE + “=?”;   // Add contactId filter. String[] selectionArgs = new String[] { String.valueOf(contactId), ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, String.valueOf(ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) };   String sortOrder = null;   return cr.query(uri, projection, where, selectionArgs, sortOrder); } catch (Exception ex) { String message = ex.getMessage(); Log.d(TAG, “Error: ” + message);   return null; } }
Photo

The contact photos are stored as binary large objects (blob) in the Data table. We can directly get the input stream for the contact photo as shown below.

final public Bitmap GetContactPhoto(android.content.Context context) { ContentResolver cr = context.getContentResolver();   Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, ContactId);   InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);   if (input == null) { return null; }   return BitmapFactory.decodeStream(input); }
Other Data

Lots of other data can be stored for each contact, so depending on what are you after you could find. All of this data can be retrieved using this URI:

ContactsContract.Data.CONTENT_URI

This,and of course using different MIMETYPE in the where clause.

ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE //postal addreses ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE //instant messenger ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE //organizations ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE //notes

Summary and Look-out

The presented ways are implemented to show a clear and easy understandable way to access information about contacts, not for the best performance ( which will depend heavily on your application architecture and goals ).

Other information such as the address, instant messenger, notes, etc. can easily be queried analogous to the way shown above. For further data fields just look at the classes in the following package:

android.provider.ContactsContract.CommonDataKinds

Subscribe to our newsletter to get the latest news right in your inbox.

We use cookies to improve your experience on our website.
Privacy Policy
Got it!