Creating a new Content Provider
import android.content.*;
import android.database.Cursor;
import android.net.Uri;
import android.database.SQLException;
public class MyProvider extends ContentProvider {
@Override
public boolean onCreate() {
// TODO Construct the underlying database.
return true;
}
}
The general form for defining a Content Provider’s URI is:
content://com.<CompanyName>.provider.<ApplicationName>/<DataPath>
For example:
content://com.paad.provider.myapp/elements
Content URIs can represent either of two forms. The previous URI represents a request for all values of
that type (in this case all elements).
A trailing /<rownumber>, as shown in the following code, represents a request for a single record
(in this case the fifth element).
content://com.paad.provider.myapp/elements/5
It’s good practice to support access to your provider for both of these forms.
The simplest way to do this is to use a UriMatcher. Create and configure a Uri Matcher to parse
URIs and determine their forms. This is particularly useful when you’re processing Content Resolver
requests
public class MyProvider extends ContentProvider {
private static final String myURI = "content://com.paad.provider.myapp/items";
public static final Uri CONTENT_URI = Uri.parse(myURI);
@Override
public boolean onCreate() {
// TODO: Construct the underlying database.
return true;
}
// Create the constants used to differentiate between the different URI
// requests.
private static final int ALLROWS = 1;
private static final int SINGLE_ROW = 2;
private static final UriMatcher uriMatcher;
// Populate the UriMatcher object, where a URI ending in ‘items’ will
// correspond to a request for all items, and ‘items/[rowID]’
// represents a single row.
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("com.paad.provider.myApp", "items", ALLROWS);
uriMatcher.addURI("com.paad.provider.myApp", "items/#", SINGLE_ROW);
}
}
Exposing Access to the Data Source
Expose queries and transactions on your Content Provider by implementing the delete, insert,
update,and query methods.
Implementing queries and transactions within a Content Provider
@Override
public Cursor query(Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sort) {
// If this is a row query, limit the result set to the passed in row.
switch (uriMatcher.match(uri)) {
case SINGLE_ROW :
// TODO: Modify selection based on row id, where:
// rowNumber = uri.getPathSegments().get(1));
}
return null;
}
@Override
public Uri insert(Uri _uri, ContentValues _initialValues) {
long rowID = [ ... Add a new item ... ]
// Return a URI to the newly added item.
if (rowID > 0) {
return ContentUris.withAppendedId(CONTENT_URI, rowID);
}
throw new SQLException("Failed to add new item into " + _uri);
}
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
switch (uriMatcher.match(uri)) {
case ALLROWS:
case SINGLE_ROW:
default: throw new IllegalArgumentException("Unsupported URI:" + uri);
}
}
@Override
public int update(Uri uri, ContentValues values, String where, String[]
whereArgs) {
switch (uriMatcher.match(uri)) {
case ALLROWS:
case SINGLE_ROW:
default: throw new IllegalArgumentException("Unsupported URI:" + uri);
}
}
➤ Single item vnd.<companyname>.cursor.item/<contenttype>
➤ All items vnd.<companyName>.cursor.dir/<contenttype>
@Override
public String getType(Uri _uri) {
switch (uriMatcher.match(_uri)) {
case ALLROWS: return "vnd.paad.cursor.dir/myprovidercontent";
case SINGLE_ROW: return "vnd.paad.cursor.item/myprovidercontent";
default: throw new IllegalArgumentException("Unsupported URI: " + _uri);
}
}
Registering Your Provider
<provider android:name="MyProvider"
android:authorities="com.paad.provider.myapp"/>
USING CONTENT PROVIDERS
ContentResolver cr = getContentResolver();
Querying for Content
ContentResolver cr = getContentResolver();
// Return all rows
Cursor allRows = cr.query(MyProvider.CONTENT_URI, null, null, null, null);
// Return all columns for rows where column 3 equals a set value
// and the rows are ordered by column 5.
String where = KEY_COL3 + "=" + requiredValue;
String order = KEY_COL5;
Cursor someRows = cr.query(MyProvider.CONTENT_URI,
null, where, null, order);
Adding, Updating, and Deleting Content
To perform transactions on Content Providers, use the delete, update,and insert methods on the
ContentResolver object.
// Get the Content Resolver
ContentResolver cr = getContentResolver();
// Create a new row of values to insert.
ContentValues newValues = new ContentValues();
// Assign values for each row.
newValues.put(COLUMN_NAME, newValue);
[ ... Repeat for each column ... ]
Uri myRowUri = cr.insert(MyProvider.CONTENT_URI, newValues);
// Create a new row of values to insert.
ContentValues[] valueArray = new ContentValues[5];
// TODO: Create an array of new rows
int count = cr.bulkInsert(MyProvider.CONTENT_URI, valueArray);
ContentResolver cr = getContentResolver();
// Remove a specific row.
cr.delete(myRowUri, null, null);
// Remove the first five rows.
String where = "_id < 5";
cr.delete(MyProvider.CONTENT_URI, where, null);
// Create a new row of values to insert.
ContentValues newValues = new ContentValues();
// Create a replacement map, specifying which columns you want to
// update, and what values to assign to each of them.
newValues.put(COLUMN_NAME, newValue);
// Apply to the first 5 rows.
String where = "_id < 5";
getContentResolver().update(MyProvider.CONTENT_URI, newValues, where, null);
NATIVE ANDROID CONTENT PROVIDERS
Android exposes several native databases using Content Providers.
You can access these Content Providers directly using the techniques described earlier in this chapter.
Alternatively, the android.provider package includes classes that can simplify access to many of the
most useful providers, including:
➤ Browser Use the browser Content Provider to read or modify bookmarks, browser history,
or web searches.
➤ CallLog View or update the call history, including both incoming and outgoing calls,
together with missed calls and call details like caller ID and call durations.
➤ ContactsContract Use the Contacts Contract provider to retrieve, modify, or store your
contacts’ details. This Content Provider replaces the Contact Content Provider.
➤ MediaStore The Media Store provides centralized, managed access to the multimedia on
your device, including audio, video, and images. You can store your own multimedia within
the media store and make it globally available, as shown in Chapter 11.
➤ Settings You can access the device’s preferences using the Settings provider.
You can view most system settings and modify some of them. More usefully, the
android.provider.Settings class includes a collection of Intent actions that can be used to
open the appropriate settings screen to let users modify their own settings.
➤ UserDictionary Access (or add to) the user defined words added to the dictionary for use in
IME predictive text input.
Using the Media Store Provider
// Get a cursor over every piece of audio on the external volume.
Cursor cursor =
getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
null, null, null, null);
// Let the activity manage the cursor lifecycle.
startManagingCursor(cursor);
// Use the convenience properties to get the index of the columns
int albumIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM);
int titleIdx = cursor. getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
String[] result = new String[cursor.getCount()];
if (cursor.moveToFirst())
do {
// Extract the song title.
String title = cursor.getString(titleIdx);
// Extract the album name.
String album = cursor.getString(albumIdx);
result[cursor.getPosition()] = title + " (" + album + ")";
} while(cursor.moveToNext());
Using the Contacts Provider
// Get a cursor over every aggregated contact.
Cursor cursor =
getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
// Let the activity manage the cursor lifecycle.
startManagingCursor(cursor);
// Use the convenience properties to get the index of the columns
int nameIdx =
cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME);
int idIdx = cursor. getColumnIndexOrThrow(ContactsContract.Contacts._ID);
String[] result = new String[cursor.getCount()];
if (cursor.moveToFirst())
do {
// Extract the name.
String name = cursor.getString(nameIdx);
// Extract the phone number.
String id = cursor.getString(idIdx);
result[cursor.getPosition()] = name + " (" + id + ")";
} while(cursor.moveToNext());
stopManagingCursor(cursor);
The ContactsContract.Data Content Provider is used to store all the contact details — such as
addresses, phone numbers, and e-mail addresses — making it the best approach when searching for
one of these details.
To simplify this lookup, Android provides the ContactsContract.Contacts.CONTENT_FILTER_URI
query URI. Append the full or partial name to lookup as an additional path segment to the URI. To
extract the associated contact details, find the _ID value from the returned Cursor and use it to create a
query on the Data table.
Finding contact details after finding a contact
// Find a contact using a partial name match
Uri lookupUri =
Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI, "kristy");
Cursor idCursor = getContentResolver().query(lookupUri, null, null, null,
null);
String id = null;
if (idCursor.moveToFirst()) {
int idIdx = idCursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID);
id = idCursor.getString(idIdx);
}
idCursor.close();
if (id != null) {
// Return all the contact details of type PHONE for the contact we found
String where = ContactsContract.Data.CONTACT_ID + " = " + id + " AND " +
ContactsContract.Data.MIMETYPE + " = ‘" +
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE +
"’";
Cursor dataCursor =
getContentResolver().query(ContactsContract.Data.CONTENT_URI,
null, where, null, null);
// Use the convenience properties to get the index of the columns
int nameIdx =
dataCursor.getColumnIndexOrThrow(ContactsContract.Data.DISPLAY_NAME);
int phoneIdx =
dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)
;
String[] result = new String[dataCursor.getCount()];
if (dataCursor.moveToFirst())
do {
// Extract the name.
String name = dataCursor.getString(nameIdx);
// Extract the phone number.
String number = dataCursor.getString(phoneIdx);
result[dataCursor.getPosition()] = name + " (" + number + ")";
} while(dataCursor.moveToNext());
dataCursor.close();
Performing a caller-ID lookup
String incomingNumber = "5551234";
Uri lookupUri =
Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
incomingNumber);
Cursor idCursor = getContentResolver().query(lookupUri, null, null, null,
null);
if (idCursor.moveToFirst()) {
int nameIdx =
idCursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME);
String caller = idCursor.getString(nameIdx);
Toast.makeText(getApplicationContext(), caller, Toast.LENGTH_LONG).show();
}
idCursor.close();