Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

Reading Contact Data Using a Content Provider

Published? true
FormatLanguage: WikiFormat

Problem:

You need to extract details, such as a phone number or email address, from the Contacts database.

Solution:

Use an Intent to let the user pick one contact. Use a ContentResolver to create an SQLite Query for the chosen contact. Use SQLite and pre-defined constants in the dunningly-named ContactContract class to retrieve the parts you want. Be aware that the Contacts database was designed for generality, not for simplicity.

Discussion:

This code is from TabbyText, my SMS Text Message sender for Tablets. The user has already picked the given contact (using the Contact app; see Retrieving Data from a Content Provider). In this code we want to extract the Mobile number and save it in a text field in the current Activity, so the user can post-edit it if need be, or even reject it, so we just set it on an EditText once we find it.

Finding it turns out to be the hard part. We start with a Query that we get from the Content Provider, to extract the ID field for the given contact. Information like phone numbers and emails are in their own tables, so we need a second query, to feed in the Id as part of the "select" part of the query. This query gives a list of the contact's phone numbers. We iterate through this, taking each valid phone number and setting it on the EditText.

A further elaboration would restrict this to only selecting the Mobile number (Contacts allows both Home Fax and Work Fax, but only one Mobile number, at least as of Honeycomb 3.2).

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == REQ_GET_CONTACT) {
			switch(resultCode) {
			case Activity.RESULT_OK:
				// The Contacts API is about the most complex to use.
				// First we have to retrieve the Contact, since we only get its URI from the Intent
				Uri resultUri = data.getData(); // e.g., content://contacts/people/123
				Cursor cont = getContentResolver().query(resultUri, null, null, null, null);
				if (!cont.moveToNext()) {	// expect 001 row(s)
					Toast.makeText(this, "Cursor contains no data", Toast.LENGTH_LONG).show(); 
					return;
				}
				int columnIndexForId = cont.getColumnIndex(ContactsContract.Contacts._ID);
				String contactId = cont.getString(columnIndexForId);
				int columnIndexForHasPhone = cont.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
				boolean hasAnyPhone = Boolean.parseBoolean(cont.getString(columnIndexForHasPhone));
				if (!hasAnyPhone) {
					Toast.makeText(this, "Selected contact seems to have no phone numbers ", Toast.LENGTH_LONG).show(); 
				}

				// Now we have to do another query to actually get the numbers!
				Cursor numbers = getContentResolver().query(
						ContactsContract.CommonDataKinds.Phone.CONTENT_URI, 
						null, 
						ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId, // "selection", 
						null, null);
				// XXX still need to restrict to Mobile number!
				while (numbers.moveToNext()) {
					String aNumber = numbers.getString(numbers.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
					System.out.println(aNumber);
					number.setText(aNumber);
				}
				if (cont.moveToNext()) {
					System.out.println("WARNING: More than one contact returned from picker!");
				}
				numbers.close();
				cont.close();
				break;
			case Activity.RESULT_CANCELED:
				// nothing to do here
				break;
			default:
				Toast.makeText(this, "Unexpected resultCode: " + resultCode, Toast.LENGTH_LONG).show(); 
				break;
			}
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

Download:

The source code for this project can be downloaded from http://projects.darwinsys.com/TabbyText-src.zip.