| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.example.android.notepad; |
| |
| import com.example.android.notepad.NotePad; |
| |
| import android.content.ClipDescription; |
| 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; |
| 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. |
| */ |
| public class NotePadProvider extends ContentProvider implements PipeDataWriter<Cursor> { |
| // 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; |
| |
| /** |
| * 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; |
| |
| /** |
| * Standard projection for the interesting columns of a normal note. |
| */ |
| private static final String[] READ_NOTE_PROJECTION = new String[] { |
| NotePad.Notes._ID, // Projection position 0, the note's id |
| NotePad.Notes.COLUMN_NAME_NOTE, // Projection position 1, the note's content |
| NotePad.Notes.COLUMN_NAME_TITLE, // Projection position 2, the note's title |
| }; |
| private static final int READ_NOTE_NOTE_INDEX = 1; |
| private static final int READ_NOTE_TITLE_INDEX = 2; |
| |
| /* |
| * 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. Set to package visibility |
| * for testing purposes. |
| */ |
| 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 " + 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); |
| } |
| } |
| |
| /** |
| * |
| * 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(NotePad.Notes.TABLE_NAME); |
| |
| /** |
| * Choose the projection and adjust the "where" clause based on URI pattern-matching. |
| */ |
| switch (sUriMatcher.match(uri)) { |
| // If the incoming URI is for notes, chooses the Notes projection |
| case NOTES: |
| qb.setProjectionMap(sNotesProjectionMap); |
| 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: |
| // If the incoming URI is from a live folder, chooses the live folder projection. |
| qb.setProjectionMap(sLiveFolderProjectionMap); |
| break; |
| |
| default: |
| // If the URI doesn't match any of the known patterns, throw an exception. |
| throw new IllegalArgumentException("Unknown URI " + uri); |
| } |
| |
| |
| 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; |
| } |
| |
| // Opens the database object in "read" mode, since no writes need to be done. |
| SQLiteDatabase db = mOpenHelper.getReadableDatabase(); |
| |
| /* |
| * 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; |
| } |
| |
| /** |
| * 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. |
| * |
| * @param uri The URI whose MIME type is desired. |
| * @return The MIME type of the URI. |
| * @throws IllegalArgumentException if the incoming URI pattern is invalid. |
| */ |
| @Override |
| 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 NotePad.Notes.CONTENT_TYPE; |
| |
| // If the pattern is for note IDs, returns the note ID content type. |
| case NOTE_ID: |
| return NotePad.Notes.CONTENT_ITEM_TYPE; |
| |
| // If the URI pattern doesn't match any permitted patterns, throws an exception. |
| default: |
| throw new IllegalArgumentException("Unknown URI " + uri); |
| } |
| } |
| |
| //BEGIN_INCLUDE(stream) |
| /** |
| * This describes the MIME types that are supported for opening a note |
| * URI as a stream. |
| */ |
| static ClipDescription NOTE_STREAM_TYPES = new ClipDescription(null, |
| new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }); |
| |
| /** |
| * Returns the types of available data streams. URIs to specific notes are supported. |
| * The application can convert such a note to a plain text stream. |
| * |
| * @param uri the URI to analyze |
| * @param mimeTypeFilter The MIME type to check for. This method only returns a data stream |
| * type for MIME types that match the filter. Currently, only text/plain MIME types match. |
| * @return a data stream MIME type. Currently, only text/plan is returned. |
| * @throws IllegalArgumentException if the URI pattern doesn't match any supported patterns. |
| */ |
| @Override |
| public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { |
| /** |
| * Chooses the data stream type based on the incoming URI pattern. |
| */ |
| switch (sUriMatcher.match(uri)) { |
| |
| // If the pattern is for notes or live folders, return null. Data streams are not |
| // supported for this type of URI. |
| case NOTES: |
| case LIVE_FOLDER_NOTES: |
| return null; |
| |
| // If the pattern is for note IDs and the MIME filter is text/plain, then return |
| // text/plain |
| case NOTE_ID: |
| return NOTE_STREAM_TYPES.filterMimeTypes(mimeTypeFilter); |
| |
| // If the URI pattern doesn't match any permitted patterns, throws an exception. |
| default: |
| throw new IllegalArgumentException("Unknown URI " + uri); |
| } |
| } |
| |
| |
| /** |
| * Returns a stream of data for each supported stream type. This method does a query on the |
| * incoming URI, then uses |
| * {@link android.content.ContentProvider#openPipeHelper(Uri, String, Bundle, Object, |
| * PipeDataWriter)} to start another thread in which to convert the data into a stream. |
| * |
| * @param uri The URI pattern that points to the data stream |
| * @param mimeTypeFilter A String containing a MIME type. This method tries to get a stream of |
| * data with this MIME type. |
| * @param opts Additional options supplied by the caller. Can be interpreted as |
| * desired by the content provider. |
| * @return AssetFileDescriptor A handle to the file. |
| * @throws FileNotFoundException if there is no file associated with the incoming URI. |
| */ |
| @Override |
| public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts) |
| throws FileNotFoundException { |
| |
| // Checks to see if the MIME type filter matches a supported MIME type. |
| String[] mimeTypes = getStreamTypes(uri, mimeTypeFilter); |
| |
| // If the MIME type is supported |
| if (mimeTypes != null) { |
| |
| // Retrieves the note for this URI. Uses the query method defined for this provider, |
| // rather than using the database query method. |
| Cursor c = query( |
| uri, // The URI of a note |
| READ_NOTE_PROJECTION, // Gets a projection containing the note's ID, title, |
| // and contents |
| null, // No WHERE clause, get all matching records |
| null, // Since there is no WHERE clause, no selection criteria |
| null // Use the default sort order (modification date, |
| // descending |
| ); |
| |
| |
| // If the query fails or the cursor is empty, stop |
| if (c == null || !c.moveToFirst()) { |
| |
| // If the cursor is empty, simply close the cursor and return |
| if (c != null) { |
| c.close(); |
| } |
| |
| // If the cursor is null, throw an exception |
| throw new FileNotFoundException("Unable to query " + uri); |
| } |
| |
| // Start a new thread that pipes the stream data back to the caller. |
| return new AssetFileDescriptor( |
| openPipeHelper(uri, mimeTypes[0], opts, c, this), 0, |
| AssetFileDescriptor.UNKNOWN_LENGTH); |
| } |
| |
| // If the MIME type is not supported, return a read-only handle to the file. |
| 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. |
| */ |
| @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) |
| |
| /** |
| * 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 Uri insert(Uri uri, ContentValues initialValues) { |
| |
| // 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()); |
| |
| // 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 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 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.COLUMN_NAME_TITLE, r.getString(android.R.string.untitled)); |
| } |
| |
| // 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(); |
| |
| // 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) { |
| // 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(); |
| String finalWhere; |
| |
| int count; |
| |
| // Does the delete based on the incoming URI pattern. |
| switch (sUriMatcher.match(uri)) { |
| |
| // 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: |
| /* |
| * Starts a final WHERE clause by restricting it to the |
| * desired note ID. |
| */ |
| finalWhere = |
| NotePad.Notes._ID + // The ID column name |
| " = " + // test for equality |
| uri.getPathSegments(). // the incoming note ID |
| get(NotePad.Notes.NOTE_ID_PATH_POSITION) |
| ; |
| |
| // If there were additional selection criteria, append them to the final |
| // WHERE clause |
| if (where != null) { |
| finalWhere = finalWhere + " AND " + where; |
| } |
| |
| // Performs the delete. |
| count = db.delete( |
| NotePad.Notes.TABLE_NAME, // The database table name. |
| finalWhere, // The final WHERE clause |
| 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#update(Uri,ContentValues,String,String[])} |
| * 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. |
| * |
| * @param uri The URI pattern to match and update. |
| * @param values A map of column names (keys) and new values (values). |
| * @param where An SQL "WHERE" clause that selects records based on their column values. If this |
| * is null, then all records that match the URI pattern are selected. |
| * @param whereArgs An array of selection criteria. If the "where" param contains value |
| * placeholders ("?"), then each placeholder is replaced by the corresponding element in the |
| * array. |
| * @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; |
| String finalWhere; |
| |
| // Does the update based on the incoming URI pattern |
| switch (sUriMatcher.match(uri)) { |
| |
| // If the incoming URI matches the general notes pattern, does the update based on |
| // the incoming data. |
| case NOTES: |
| |
| // 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); |
| |
| /* |
| * Starts creating the final WHERE clause by restricting it to the incoming |
| * note ID. |
| */ |
| finalWhere = |
| NotePad.Notes._ID + // The ID column name |
| " = " + // test for equality |
| uri.getPathSegments(). // the incoming note ID |
| get(NotePad.Notes.NOTE_ID_PATH_POSITION) |
| ; |
| |
| // If there were additional selection criteria, append them to the final WHERE |
| // clause |
| if (where !=null) { |
| finalWhere = finalWhere + " AND " + where; |
| } |
| |
| |
| // 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. |
| finalWhere, // The final WHERE clause to use |
| // placeholders for whereArgs |
| whereArgs // The where clause column values to select on, or |
| // null if the values are in the where argument. |
| ); |
| 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; |
| } |
| |
| /** |
| * 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; |
| } |
| } |