summaryrefslogtreecommitdiff
path: root/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java
diff options
context:
space:
mode:
authorJoe Malin <jmalin@google.com>2010-06-07 16:26:25 -0700
committerJoe Malin <jmalin@google.com>2010-08-09 15:30:01 -0700
commit4124e0a1f07e4e54c37b0cfbb1b7438806ff02a6 (patch)
tree044d57a235802491100ea89ace9c8f56c9471e30 /samples/NotePad/src/com/example/android/notepad/NotePadProvider.java
parent4779ab6f9aa4d6b691f051e069ffac31475f850a (diff)
Revised Note Pad sample, new test app for Note Pad
Change-Id: Ia41a33d935ead704c1de439a0cfb0a55806cfe12
Diffstat (limited to 'samples/NotePad/src/com/example/android/notepad/NotePadProvider.java')
-rw-r--r--samples/NotePad/src/com/example/android/notepad/NotePadProvider.java618
1 files changed, 428 insertions, 190 deletions
diff --git a/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java b/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java
index d79be2427..c091d87bc 100644
--- a/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java
+++ b/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java
@@ -16,15 +16,11 @@
package com.example.android.notepad;
-import com.example.android.notepad.NotePad.Notes;
-
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
-import android.content.ContentProvider.PipeDataWriter;
-import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.SQLException;
@@ -32,340 +28,582 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
-import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
import android.provider.LiveFolders;
import android.text.TextUtils;
import android.util.Log;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
import java.util.HashMap;
/**
- * Provides access to a database of notes. Each note has a title, the note
- * itself, a creation date and a modified data.
+ * This is a content provider for a table of notes. Each note has a title, the note
+ * itself, a creation date and a modified data. The underlying data source is an SQLite
+ * database.
+ *
+ * Notes:
+ * SQLite database method signatures usually include a "where" argument and "whereArgs" argument.
+ * "where" can either specify a full "where" clause in the format used by SQL "WHERE", or a
+ * "where" clause in which the column names are followed by " = ?", or a combination of the two.
+ * If the " = ?" form is present, then whereArgs must be non-null. It is a String array that
+ * contains one element for each "?" present. In order, the "?" symbols are replace by elements
+ * in whereArgs. This feature helps create selection criteria without needing to repeatedly
+ * create a where clause from concatenations. In the comments, "where" is always annotated as
+ * the where clause columns, and "whereArgs" as the where clause values, although "where" can
+ * contain values and "whereArgs" can be null.
+ *
*/
-public class NotePadProvider extends ContentProvider implements PipeDataWriter<Cursor> {
+public class NotePadProvider extends ContentProvider {
+ // Used for debugging and logging
private static final String TAG = "NotePadProvider";
+ /**
+ * The database that the provider uses as its underlying data store
+ */
private static final String DATABASE_NAME = "note_pad.db";
+
+ /**
+ * The database version
+ */
private static final int DATABASE_VERSION = 2;
- private static final String NOTES_TABLE_NAME = "notes";
+ /**
+ * A projection map used to select columns from the database
+ */
private static HashMap<String, String> sNotesProjectionMap;
+
+ /**
+ * A projection map used to select columns from the database
+ */
private static HashMap<String, String> sLiveFolderProjectionMap;
+ /*
+ * Constants used by the Uri matcher to choose an action based on the pattern
+ * of the incoming URI
+ */
+ // The incoming URI matches the Notes URI pattern
private static final int NOTES = 1;
+
+ // The incoming URI matches the Note ID URI pattern
private static final int NOTE_ID = 2;
+
+ // The incoming URI matches the Live Folder URI pattern
private static final int LIVE_FOLDER_NOTES = 3;
+ /**
+ * A UriMatcher instance
+ */
private static final UriMatcher sUriMatcher;
+ // Handle to a new DatabaseHelper.
+ private DatabaseHelper mOpenHelper;
+
+ /**
+ * A block that instantiates and sets static objects
+ */
+ static {
+
+ /*
+ * Creates and initializes the URI matcher
+ */
+ // Create a new instance
+ sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+ // Add a pattern that routes URIs terminated with "notes" to a NOTES operation
+ sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
+
+ // Add a pattern that routes URIs terminated with "notes" plus an integer
+ // to a note ID operation
+ sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
+
+ // Add a pattern that routes URIs terminated with live_folders/notes to a
+ // live folder operation
+ sUriMatcher.addURI(NotePad.AUTHORITY, "live_folders/notes", LIVE_FOLDER_NOTES);
+
+ /*
+ * Creates and initializes a projection map that returns all columns
+ */
+
+ // Creates a new projection map instance. The map returns a column name
+ // given a string. The two are usually equal.
+ sNotesProjectionMap = new HashMap<String, String>();
+
+ // Maps the string "_ID" to the column name "_ID"
+ sNotesProjectionMap.put(NotePad.Notes._ID, NotePad.Notes._ID);
+
+ // Maps "title" to "title"
+ sNotesProjectionMap.put(NotePad.Notes.COLUMN_NAME_TITLE, NotePad.Notes.COLUMN_NAME_TITLE);
+
+ // Maps "note" to "note"
+ sNotesProjectionMap.put(NotePad.Notes.COLUMN_NAME_NOTE, NotePad.Notes.COLUMN_NAME_NOTE);
+
+ // Maps "created" to "created"
+ sNotesProjectionMap.put(NotePad.Notes.COLUMN_NAME_CREATE_DATE,
+ NotePad.Notes.COLUMN_NAME_CREATE_DATE);
+
+ // Maps "modified" to "modified"
+ sNotesProjectionMap.put(
+ NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE,
+ NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE);
+
+ /*
+ * Creates an initializes a projection map for handling Live Folders
+ */
+
+ // Creates a new projection map instance
+ sLiveFolderProjectionMap = new HashMap<String, String>();
+
+ // Maps "_ID" to "_ID AS _ID" for a live folder
+ sLiveFolderProjectionMap.put(LiveFolders._ID, NotePad.Notes._ID + " AS " + LiveFolders._ID);
+
+ // Maps "NAME" to "title AS NAME"
+ sLiveFolderProjectionMap.put(LiveFolders.NAME, NotePad.Notes.COLUMN_NAME_TITLE + " AS " +
+ LiveFolders.NAME);
+ }
+
+
+
/**
- * This class helps open, create, and upgrade the database file.
+ *
+ * This class helps open, create, and upgrade the database file. Set to package visibility
+ * for testing purposes.
*/
- private static class DatabaseHelper extends SQLiteOpenHelper {
+ static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
+
+ // calls the super constructor, requesting the default cursor factory.
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
+ /**
+ *
+ * Creates the underlying database with table name and column names taken from the
+ * NotePad class.
+ */
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + NOTES_TABLE_NAME + " ("
- + Notes._ID + " INTEGER PRIMARY KEY,"
- + Notes.TITLE + " TEXT,"
- + Notes.NOTE + " TEXT,"
- + Notes.CREATED_DATE + " INTEGER,"
- + Notes.MODIFIED_DATE + " INTEGER"
+ db.execSQL("CREATE TABLE " + NotePad.Notes.TABLE_NAME + " ("
+ + NotePad.Notes._ID + " INTEGER PRIMARY KEY,"
+ + NotePad.Notes.COLUMN_NAME_TITLE + " TEXT,"
+ + NotePad.Notes.COLUMN_NAME_NOTE + " TEXT,"
+ + NotePad.Notes.COLUMN_NAME_CREATE_DATE + " INTEGER,"
+ + NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE + " INTEGER"
+ ");");
}
+ /**
+ *
+ * Demonstrates that the provider must consider what happens when the
+ * underlying datastore is changed. In this sample, the database is upgraded the database
+ * by destroying the existing data.
+ * A real application should upgrade the database in place.
+ */
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+
+ // Logs that the database is being upgraded
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
+
+ // Kills the table and existing data
db.execSQL("DROP TABLE IF EXISTS notes");
+
+ // Recreates the database with a new version
onCreate(db);
}
}
- private DatabaseHelper mOpenHelper;
-
+ /**
+ *
+ * Initializes the provider by creating a new DatabaseHelper. onCreate() is called
+ * automatically when Android creates the provider in response to a resolver request from a
+ * client.
+ */
@Override
public boolean onCreate() {
+
+ // Creates a new helper object. Note that the database itself isn't opened until
+ // something tries to access it, and it's only created if it doesn't already exist.
mOpenHelper = new DatabaseHelper(getContext());
+
+ // Assumes that any failures will be reported by a thrown exception.
return true;
}
+ /**
+ * This method is called when a client calls
+ * {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)}.
+ * Queries the database and returns a cursor containing the results.
+ *
+ * @return A cursor containing the results of the query. The cursor exists but is empty if
+ * the query returns no results or an exception occurs.
+ * @throws IllegalArgumentException if the incoming URI pattern is invalid.
+ */
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
+
+ // Constructs a new query builder and sets its table name
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(NOTES_TABLE_NAME);
+ qb.setTables(NotePad.Notes.TABLE_NAME);
+ /**
+ * Choose the projection and adjust the "where" clause based on URI pattern-matching.
+ */
switch (sUriMatcher.match(uri)) {
- case NOTES:
- qb.setProjectionMap(sNotesProjectionMap);
- break;
+ // If the incoming URI is for notes, chooses the Notes projection
+ case NOTES:
+ qb.setProjectionMap(sNotesProjectionMap);
+ break;
- case NOTE_ID:
- qb.setProjectionMap(sNotesProjectionMap);
- qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
- break;
+ /* If the incoming URI is for a single note identified by its ID, chooses the
+ * note ID projection, and appends "_ID = <noteID>" to the where clause, so that
+ * it selects that single note
+ */
+ case NOTE_ID:
+ qb.setProjectionMap(sNotesProjectionMap);
+ qb.appendWhere(
+ NotePad.Notes._ID + // the name of the ID column
+ "=" +
+ // the position of the note ID itself in the incoming URI
+ uri.getPathSegments().get(NotePad.Notes.NOTE_ID_PATH_POSITION));
+ break;
- case LIVE_FOLDER_NOTES:
- qb.setProjectionMap(sLiveFolderProjectionMap);
- break;
+ case LIVE_FOLDER_NOTES:
+ // If the incoming URI is from a live folder, chooses the live folder projection.
+ qb.setProjectionMap(sLiveFolderProjectionMap);
+ break;
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
+ default:
+ // If the URI doesn't match any of the known patterns, throw an exception.
+ throw new IllegalArgumentException("Unknown URI " + uri);
}
- // If no sort order is specified use the default
+
String orderBy;
+ // If no sort order is specified, uses the default
if (TextUtils.isEmpty(sortOrder)) {
orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
} else {
+ // otherwise, uses the incoming sort order
orderBy = sortOrder;
}
- // Get the database and run the query
+ // Opens the database object in "read" mode, since no writes need to be done.
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
- // Tell the cursor what uri to watch, so it knows when its source data changes
+ /*
+ * Performs the query. If no problems occur trying to read the database, then a Cursor
+ * object is returned; otherwise, the cursor variable contains null. If no records were
+ * selected, then the Cursor object is empty, and Cursor.getCount() returns 0.
+ */
+ Cursor c = qb.query(
+ db, // The database to query
+ projection, // The columns to return from the query
+ selection, // The columns for the where clause
+ selectionArgs, // The values for the where clause
+ null, // don't group the rows
+ null, // don't filter by row groups
+ orderBy // The sort order
+ );
+
+ // Tells the Cursor what URI to watch, so it knows when its source data changes
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
- @Override
- public String getType(Uri uri) {
- switch (sUriMatcher.match(uri)) {
- case NOTES:
- case LIVE_FOLDER_NOTES:
- return Notes.CONTENT_TYPE;
-
- case NOTE_ID:
- return Notes.CONTENT_ITEM_TYPE;
-
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- }
-
-//BEGIN_INCLUDE(stream)
/**
- * Return the types of data streams we can return. Currently we only
- * support URIs to specific notes, and can convert such a note to a
- * plain text stream.
+ * This is called when a client calls {@link android.content.ContentResolver#getType(Uri)}.
+ * Returns the MIME data type of the URI given as a parameter.
+ *
+ * @return The MIME type of the URI.
+ * @throws IllegalArgumentException if the incoming URI pattern is invalid.
*/
@Override
- public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+ public String getType(Uri uri) {
+
+ /**
+ * Chooses the MIME type based on the incoming URI pattern
+ */
switch (sUriMatcher.match(uri)) {
+
+ // If the pattern is for notes or live folders, returns the general content type.
case NOTES:
case LIVE_FOLDER_NOTES:
- return null;
+ return NotePad.Notes.CONTENT_TYPE;
+ // If the pattern is for note IDs, returns the note ID content type.
case NOTE_ID:
- if (compareMimeTypes("text/plain", mimeTypeFilter)) {
- return new String[] { "text/plain" };
- }
- return null;
+ return NotePad.Notes.CONTENT_ITEM_TYPE;
+ // If the pattern doesn't match any permitted patterns, throws an exception.
default:
throw new IllegalArgumentException("Unknown URI " + uri);
- }
- }
-
- /**
- * Standard projection for the interesting columns of a normal note.
- */
- private static final String[] READ_NOTE_PROJECTION = new String[] {
- Notes._ID, // 0
- Notes.NOTE, // 1
- NotePad.Notes.TITLE, // 2
- };
- private static final int READ_NOTE_NOTE_INDEX = 1;
- private static final int READ_NOTE_TITLE_INDEX = 2;
-
- /**
- * Implement the other side of getStreamTypes: for each stream time we
- * report to support, we need to actually be able to return a stream of
- * data. This function simply retrieves a cursor for the URI of interest,
- * and uses ContentProvider's openPipeHelper() to start the work of
- * convering the data off into another thread.
- */
- @Override
- public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
- throws FileNotFoundException {
- // Check if we support a stream MIME type for this URI.
- String[] mimeTypes = getStreamTypes(uri, mimeTypeFilter);
- if (mimeTypes != null) {
- // Retrieve the note for this URI.
- Cursor c = query(uri, READ_NOTE_PROJECTION, null, null, null);
- if (c == null || !c.moveToFirst()) {
- if (c != null) {
- c.close();
- }
- throw new FileNotFoundException("Unable to query " + uri);
- }
- // Start a thread to pipe the data back to the client.
- return new AssetFileDescriptor(
- openPipeHelper(uri, mimeTypes[0], opts, c, this), 0,
- AssetFileDescriptor.UNKNOWN_LENGTH);
}
- return super.openTypedAssetFile(uri, mimeTypeFilter, opts);
}
/**
- * Implementation of {@link android.content.ContentProvider.PipeDataWriter}
- * to perform the actual work of converting the data in one of cursors to a
- * stream of data for the client to read.
+ * This is called when a client calls
+ * {@link android.content.ContentResolver#insert(Uri, ContentValues)}.
+ * Inserts a new row into the database. This method sets up default values for any
+ * columns that are not included in the incoming map.
+ * If rows were inserted, then listeners are notified of the change.
+ * @return The row ID of the inserted row.
+ * @throws SQLException if the insertion fails.
*/
@Override
- public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType,
- Bundle opts, Cursor c) {
- // We currently only support conversion-to-text from a single note entry,
- // so no need for cursor data type checking here.
- FileOutputStream fout = new FileOutputStream(output.getFileDescriptor());
- PrintWriter pw = null;
- try {
- pw = new PrintWriter(new OutputStreamWriter(fout, "UTF-8"));
- pw.println(c.getString(READ_NOTE_TITLE_INDEX));
- pw.println("");
- pw.println(c.getString(READ_NOTE_NOTE_INDEX));
- } catch (UnsupportedEncodingException e) {
- Log.w(TAG, "Ooops", e);
- } finally {
- c.close();
- if (pw != null) {
- pw.flush();
- }
- try {
- fout.close();
- } catch (IOException e) {
- }
- }
- }
-//END_INCLUDE(stream)
-
- @Override
public Uri insert(Uri uri, ContentValues initialValues) {
- // Validate the requested uri
+
+ // Validates the incoming URI. Only the full provider URI is allowed for inserts.
if (sUriMatcher.match(uri) != NOTES) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
+ // A map to hold the new record's values.
ContentValues values;
+
+ // If the incoming values map is not null, uses it for the new values.
if (initialValues != null) {
values = new ContentValues(initialValues);
+
} else {
+ // Otherwise, create a new value map
values = new ContentValues();
}
+ // Gets the current system time in milliseconds
Long now = Long.valueOf(System.currentTimeMillis());
- // Make sure that the fields are all set
- if (values.containsKey(NotePad.Notes.CREATED_DATE) == false) {
- values.put(NotePad.Notes.CREATED_DATE, now);
+ // If the values map doesn't contain the creation date, sets the value to the current time.
+ if (values.containsKey(NotePad.Notes.COLUMN_NAME_CREATE_DATE) == false) {
+ values.put(NotePad.Notes.COLUMN_NAME_CREATE_DATE, now);
}
- if (values.containsKey(NotePad.Notes.MODIFIED_DATE) == false) {
- values.put(NotePad.Notes.MODIFIED_DATE, now);
+ // If the values map doesn't contain the modification date, sets the value to the current
+ // time.
+ if (values.containsKey(NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE) == false) {
+ values.put(NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE, now);
}
- if (values.containsKey(NotePad.Notes.TITLE) == false) {
+ // If the values map doesn't contain a title, sets the value to the default title.
+ if (values.containsKey(NotePad.Notes.COLUMN_NAME_TITLE) == false) {
Resources r = Resources.getSystem();
- values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled));
+ values.put(NotePad.Notes.COLUMN_NAME_TITLE, r.getString(android.R.string.untitled));
}
- if (values.containsKey(NotePad.Notes.NOTE) == false) {
- values.put(NotePad.Notes.NOTE, "");
+ // If the values map doesn't contain note text, sets the value to an empty string.
+ if (values.containsKey(NotePad.Notes.COLUMN_NAME_NOTE) == false) {
+ values.put(NotePad.Notes.COLUMN_NAME_NOTE, "");
}
+ // Opens the database object in "write" mode.
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
+
+ // Performs the insert and returns the ID of the new note.
+ long rowId = db.insert(
+ NotePad.Notes.TABLE_NAME, // The table to insert into.
+ NotePad.Notes.COLUMN_NAME_NOTE, // A hack, SQLite sets this column value to null
+ // if values is empty.
+ values // A map of column names, and the values to insert
+ // into the columns.
+ );
+
+ // If the insert succeeded, the row ID exists.
if (rowId > 0) {
- Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
+ // Creates a URI with the note ID pattern and the new row ID appended to it.
+ Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_ID_URI_BASE, rowId);
+
+ // Notifies observers registered against this provider that the data changed.
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
+ // If the insert didn't succeed, then the rowID is <= 0. Throws an exception.
throw new SQLException("Failed to insert row into " + uri);
}
+ /**
+ * This is called when a client calls
+ * {@link android.content.ContentResolver#delete(Uri, String, String[])}.
+ * Deletes records from the database. If the incoming URI matches the note ID URI pattern,
+ * this method deletes the one record specified by the ID in the URI. Otherwise, it deletes a
+ * a set of records. The record or records must also match the input selection criteria
+ * specified by where and whereArgs.
+ *
+ * If rows were deleted, then listeners are notified of the change.
+ * @return If a "where" clause is used, the number of rows affected is returned, otherwise
+ * 0 is returned. To delete all rows and get a row count, use "1" as the where clause.
+ * @throws IllegalArgumentException if the incoming URI pattern is invalid.
+ */
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
+
+ // Opens the database object in "write" mode.
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+
int count;
+
+ // Does the delete based on the incoming URI pattern.
switch (sUriMatcher.match(uri)) {
- case NOTES:
- count = db.delete(NOTES_TABLE_NAME, where, whereArgs);
- break;
- case NOTE_ID:
- String noteId = uri.getPathSegments().get(1);
- count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId
- + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
- break;
+ // If the incoming pattern matches the general pattern for notes, does a delete
+ // based on the incoming "where" columns and arguments.
+ case NOTES:
+ count = db.delete(
+ NotePad.Notes.TABLE_NAME, // The database table name
+ where, // The incoming where clause column names
+ whereArgs // The incoming where clause values
+ );
+ break;
+
+ // If the incoming URI matches a single note ID, does the delete based on the
+ // incoming data, but modifies the where clause to restrict it to the
+ // particular note ID.
+ case NOTE_ID:
+ // From the incoming URI, get the note ID
+ String noteId = uri.getPathSegments().get(NotePad.Notes.NOTE_ID_PATH_POSITION);
+
+ // If no where clause was passed in, uses the note ID column name
+ // for a column and the note ID for a value.
+ if (TextUtils.isEmpty(where)) {
+ where = NotePad.Notes._ID + " = ?";
+ whereArgs[0] = noteId;
+
+ } else {
+
+ /*
+ * If where clause columns were passed in, appends the note ID column name to
+ * the list of columns using a replaceable parameter. This works even if the
+ * other columns have actual values.
+ */
+ // Appends the note ID column name as an AND condition using a replaceable
+ // parameter.
+ where = where + " AND " + NotePad.Notes._ID + " = ?";
+
+ // Appends the note ID value to the end of the where clause values.
+ whereArgs[whereArgs.length] = noteId;
+ }
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
+ // Performs the delete.
+ count = db.delete(
+ NotePad.Notes.TABLE_NAME, // The database table name.
+ where, // The incoming where clause column names.
+ whereArgs // The incoming where clause values.
+ );
+ break;
+
+ // If the incoming pattern is invalid, throws an exception.
+ default:
+ throw new IllegalArgumentException("Unknown URI " + uri);
}
+ /*Gets a handle to the content resolver object for the current context, and notifies it
+ * that the incoming URI changed. The object passes this along to the resolver framework,
+ * and observers that have registered themselves for the provider are notified.
+ */
getContext().getContentResolver().notifyChange(uri, null);
+
+ // Returns the number of rows deleted.
return count;
}
+ /**
+ * This is called when a client calls
+ * {@link android.content.ContentResolver#insert(Uri, ContentValues)}
+ * Updates records in the database. The column names specified by the keys in the values map
+ * are updated with new data specified by the values in the map. If the incoming URI matches the
+ * note ID URI pattern, then the method updates the one record specified by the ID in the URI;
+ * otherwise, it updates a set of records. The record or records must match the input
+ * selection criteria specified by where and whereArgs.
+ * If rows were updated, then listeners are notified of the change.
+ * @return The number of rows updated.
+ * @throws IllegalArgumentException if the incoming URI pattern is invalid.
+ */
@Override
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
+
+ // Opens the database object in "write" mode.
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
+
+ // Does the update based on the incoming URI pattern
switch (sUriMatcher.match(uri)) {
- case NOTES:
- count = db.update(NOTES_TABLE_NAME, values, where, whereArgs);
- break;
- case NOTE_ID:
- String noteId = uri.getPathSegments().get(1);
- count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId
- + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
- break;
+ // If the incoming URI matches the general notes pattern, does the update based on
+ // the incoming data.
+ case NOTES:
- default:
- throw new IllegalArgumentException("Unknown URI " + uri);
+ // Does the update and returns the number of rows updated.
+ count = db.update(
+ NotePad.Notes.TABLE_NAME, // The database table name.
+ values, // A map of column names and new values to use.
+ where, // The where clause column names.
+ whereArgs // The where clause column values to select on.
+ );
+ break;
+
+ // If the incoming URI matches a single note ID, does the update based on the incoming
+ // data, but modifies the where clause to restrict it to the particular note ID.
+ case NOTE_ID:
+ // From the incoming URI, get the note ID
+ String noteId = uri.getPathSegments().get(NotePad.Notes.NOTE_ID_PATH_POSITION);
+
+ // If no where clause was passed in, uses the note ID column name
+ // for a column and the note ID for a value.
+ if (TextUtils.isEmpty(where)) {
+ where = NotePad.Notes._ID + " = ?";
+ whereArgs[0] = noteId;
+
+ // If where clause columns were passed in, appends the note ID to the where
+ // clause
+ } else {
+
+ /*
+ * Appends the note ID column name to the list of columns, with a replaceable
+ * parameter. This will work even if the rest of the columns have been set with
+ * actual values.
+ */
+ // Appends the note ID column name as an AND condition with a replaceable
+ // parameter.
+ where = where + " AND " + NotePad.Notes._ID + " = ?";
+
+ // Appends the note ID value to the end of the where clause values.
+ whereArgs[whereArgs.length] = noteId;
+ }
+
+ // Does the update.
+ // Does the update and returns the number of rows updated.
+ count = db.update(
+ NotePad.Notes.TABLE_NAME, // The database table name.
+ values, // A map of column names and new values to use.
+ where, // The where clause column names.
+ whereArgs // The where clause column values to select on.
+ );
+ break;
+ // If the incoming pattern is invalid, throws an exception.
+ default:
+ throw new IllegalArgumentException("Unknown URI " + uri);
}
+ /*Gets a handle to the content resolver object for the current context, and notifies it
+ * that the incoming URI changed. The object passes this along to the resolver framework,
+ * and observers that have registered themselves for the provider are notified.
+ */
getContext().getContentResolver().notifyChange(uri, null);
+
+ // Returns the number of rows updated.
return count;
}
- static {
- sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
- sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
- sUriMatcher.addURI(NotePad.AUTHORITY, "live_folders/notes", LIVE_FOLDER_NOTES);
-
- sNotesProjectionMap = new HashMap<String, String>();
- sNotesProjectionMap.put(Notes._ID, Notes._ID);
- sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
- sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
- sNotesProjectionMap.put(Notes.CREATED_DATE, Notes.CREATED_DATE);
- sNotesProjectionMap.put(Notes.MODIFIED_DATE, Notes.MODIFIED_DATE);
-
- // Support for Live Folders.
- sLiveFolderProjectionMap = new HashMap<String, String>();
- sLiveFolderProjectionMap.put(LiveFolders._ID, Notes._ID + " AS " +
- LiveFolders._ID);
- sLiveFolderProjectionMap.put(LiveFolders.NAME, Notes.TITLE + " AS " +
- LiveFolders.NAME);
- // Add more columns here for more robust Live Folders.
+ /**
+ * A test package can call this to get a handle to the database underlying NotePadProvider,
+ * so it can insert test data into the database. The test case class is responsible for
+ * instantiating the provider in a test context; {@link android.test.ProviderTestCase2} does
+ * this during the call to setUp()
+ *
+ * @return a handle to the database helper object for the provider's data.
+ */
+ DatabaseHelper getOpenHelperForTest() {
+ return mOpenHelper;
}
}