1. Show that any application state should be saved in onStop() versus onPause(). 2. Remove the deprecated methods and start using CursorLoader instead of any managedQuery. 3. Remove deprecated LiveFolders usage. Change-Id: I65be6b91ee1d4d0980494fb8455ce0906691dc21
720 lines
30 KiB
Java
720 lines
30 KiB
Java
/*
|
|
* 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;
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* 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);
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* 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;
|
|
|
|
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:
|
|
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:
|
|
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;
|
|
}
|
|
}
|