Quering Android contacts

 

Working With Android Contacts

Introduction To Android Contacts

Learn to work with the Android contacts database. Basic knowledge of accessing SQLite in Android along with using Cursors is expected. See the Android SQLite and Cursor Article for more information. Google changed the contacts database moving from 1.x to 2.0 versions of Android. This tutorial will be broken into 3 sections. First covering accessing contacts in Android 2.0. The second page will deal with accessing the contacts in Android 1.6 and before. Third we’ll glue it all together with a class that abstracts specific classes for each version and a set of classes to manage the data from the contact records.

Create a new project called TestContacts in Eclipse setup for Android 2.0.

Android Contact API For 2.0

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 Details

Basic contact information stored in Contacts table with detailed information stored in individual tables for normalization. In Android 2.0 to query the base contact records the URI to query is stored in ContactsContract.Contacts.CONTENT_URI.

package higherpass.TestContacts;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;

public class TestContacts extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        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) {
 		    //Query phone here.  Covered next
 	        }
            }
 	}
    }
}

This application starts off as any other Android application. First create a ContentResolver isntance in cr. Then use the ContentResolver instance to query the database and return a Cursor with the contacts list. The query is perofrmed against the URI stored in ContactsContract.Contacts.CONTENT_URI. Next check if the cursor contains records and if so loop through them. The record ID field is stored in the id variable. This will be used as a where parameter later. Also the display name field is stored in the string name. For more details about working with cursors see Android Cursors Tutorial.

Phone Numbers

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 the SDK variable ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use a WHERE conditional to get the phone numbers for the specified contact.

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()) {
 		    // Do something with phones
 	        } 
 	        pCur.close();
 	    }

Perform a second query against the Android contacts SQLite database. The phone numbers are queried against the URI stored in ContactsContract.CommonDataKinds.Phone.CONTENT_URI. The contact ID is stored in the phone table as ContactsContract.CommonDataKinds.Phone.CONTACT_ID and the WHERE clause is used to limit the data returned.

Email Addresses

Querying email addresses is similar to phone numbers. A query must be performed to get email addresses from the database. Query the URI stored in ContactsContract.CommonDataKinds.Email.CONTENT_URI to query the email address table.

Cursor emailCur = cr.query( 
		ContactsContract.CommonDataKinds.Email.CONTENT_URI, 
		null,
		ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", 
		new String[]{id}, null); 
	while (emailCur.moveToNext()) { 
	    // This would allow you get several email addresses
            // if the email addresses were stored in an array
	    String email = emailCur.getString(
                      emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
 	    String emailType = emailCur.getString(
                      emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE)); 
 	} 
 	emailCur.close();

As with the phone query the field names for the email table are also stored under ContactsContract.CommonDataKinds. The email query is performed on the URI in ContactsContract.CommonDataKinds.Email.CONTENT_URI and the WHERE clause has to match the ContactsContract.CommonDataKinds.Email.CONTACT_ID field. Since multiple email addresses can be stored loop through the records returned in the Cursor.

Notes

Custom notes can be attached to each contact record. As before these are stored in a separate table and are related based on the contact ID.

String noteWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; 
        String[] noteWhereParams = new String[]{id, 
 		ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE}; 
                Cursor noteCur = cr.query(ContactsContract.Data.CONTENT_URI, null, noteWhere, noteWhereParams, null); 
 	if (noteCur.moveToFirst()) { 
 	    String note = noteCur.getString(noteCur.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE));
 	} 
 	noteCur.close();

Notes are stored in the Android Contacts generic data table. When accessing specific data the WHERE clause will need 2 conditionals. First the standard contact ID, second a MIMETYPE for the data that is being requested. The Android SDK comes with a series of auto-generated variables that take care of this. Use the ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE variable to limit the query to note records. The data table URI is stored at ContactsContract.Data.CONTENT_URI. Finally the note field name is stored in ContactsContract.CommonDataKinds.Note.NOTE.

Postal Addresses

Android can store multiple postal addresses per contact. Addresses are also stored in the data table like notes and queried via the URI stored in ContactsContract.Data.CONTENT_URI. Similar to the notes query a MIMETYPE must be added to the WHERE conditional. Also in Android 2.0 the Address record was split into multiple fields containing different parts of the address (PO-Box, stree, city, region, postal code). In earlier versions of the Android SDK this was a free-form string storage.

String addrWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; 
	String[] addrWhereParams = new String[]{id, 
		ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE}; 
	Cursor addrCur = cr.query(ContactsContract.Data.CONTENT_URI, 
                null, where, whereParameters, null); 
	while(addrCur.moveToNext()) {
		String poBox = addrCur.getString(
                     addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POBOX));
 		String street = addrCur.getString(
                     addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET));
 		String city = addrCur.getString(
                     addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY));
 		String state = addrCur.getString(
                     addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION));
 		String postalCode = addrCur.getString(
                     addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE));
 		String country = addrCur.getString(
                     addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY));
 		String type = addrCur.getString(
                     addrCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.TYPE));
 	} 
 	addrCur.close();

This code is similar to the previous example. Notice the field names for the address pieces are stored in ContactsContract.CommonDataKinds.StructuredPostal.

Instant Messenger (IM)

The instant messenger query performs just as the notes and address queries. Important field names for IM related data are stored in ContactsContract.CommonDataKinds.Im.

String imWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; 
 	String[] imWhereParams = new String[]{id, 
 	    ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE}; 
 	Cursor imCur = cr.query(ContactsContract.Data.CONTENT_URI, 
            null, imWhere, imWhereParams, null); 
 	if (imCur.moveToFirst()) { 
 	    String imName = imCur.getString(
                 imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA));
 	    String imType;
 	    imType = imCur.getString(
                 imCur.getColumnIndex(ContactsContract.CommonDataKinds.Im.TYPE));
 	} 
 	imCur.close();

Organizations

The last part of the contact record to be covered is the Organizations data. The Android contact record can contain information about Employment, professional, and social memberships as well as roles and titles. These records are queried from the URI stored in ContactsContract.Data.CONTENT_URI. Important field names for the organization data are stored in ContactsContract.CommonDataKinds.Organization.

String orgWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; 
 	String[] orgWhereParams = new String[]{id, 
 		ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE}; 
 	Cursor orgCur = cr.query(ContactsContract.Data.CONTENT_URI, 
                null, orgWhere, orgWhereParams, null);
 	if (orgCur.moveToFirst()) { 
 		String orgName = orgCur.getString(orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DATA));
 		String title = orgCur.getString(orgCur.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE));
 	} 
 	orgCur.close();