Revert "Revised Note Pad sample, new test app for Note Pad"
This reverts commit 4124e0a1f0.
This commit is contained in:
@@ -16,11 +16,15 @@
|
||||
|
||||
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;
|
||||
@@ -28,582 +32,340 @@ 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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 {
|
||||
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;
|
||||
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
|
||||
* This class helps open, create, and upgrade the database file.
|
||||
*/
|
||||
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 {
|
||||
private 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"
|
||||
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"
|
||||
+ ");");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
private DatabaseHelper mOpenHelper;
|
||||
|
||||
@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);
|
||||
qb.setTables(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;
|
||||
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 NOTE_ID:
|
||||
qb.setProjectionMap(sNotesProjectionMap);
|
||||
qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
|
||||
break;
|
||||
|
||||
case LIVE_FOLDER_NOTES:
|
||||
// If the incoming URI is from a live folder, chooses the live folder projection.
|
||||
qb.setProjectionMap(sLiveFolderProjectionMap);
|
||||
break;
|
||||
case LIVE_FOLDER_NOTES:
|
||||
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);
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
// Opens the database object in "read" mode, since no writes need to be done.
|
||||
// Get the database and run the query
|
||||
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
|
||||
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
|
||||
|
||||
/*
|
||||
* 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
|
||||
// Tell 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.
|
||||
*
|
||||
* @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)) {
|
||||
case NOTES:
|
||||
case LIVE_FOLDER_NOTES:
|
||||
return Notes.CONTENT_TYPE;
|
||||
|
||||
// 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;
|
||||
case NOTE_ID:
|
||||
return Notes.CONTENT_ITEM_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 pattern doesn't match any permitted patterns, throws an exception.
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URI " + uri);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URI " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
//BEGIN_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.
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues initialValues) {
|
||||
public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
|
||||
switch (sUriMatcher.match(uri)) {
|
||||
case NOTES:
|
||||
case LIVE_FOLDER_NOTES:
|
||||
return null;
|
||||
|
||||
// Validates the incoming URI. Only the full provider URI is allowed for inserts.
|
||||
case NOTE_ID:
|
||||
if (compareMimeTypes("text/plain", mimeTypeFilter)) {
|
||||
return new String[] { "text/plain" };
|
||||
}
|
||||
return null;
|
||||
|
||||
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.
|
||||
*/
|
||||
@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
|
||||
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);
|
||||
// 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 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.MODIFIED_DATE) == false) {
|
||||
values.put(NotePad.Notes.MODIFIED_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) {
|
||||
if (values.containsKey(NotePad.Notes.TITLE) == false) {
|
||||
Resources r = Resources.getSystem();
|
||||
values.put(NotePad.Notes.COLUMN_NAME_TITLE, r.getString(android.R.string.untitled));
|
||||
values.put(NotePad.Notes.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, "");
|
||||
if (values.containsKey(NotePad.Notes.NOTE) == false) {
|
||||
values.put(NotePad.Notes.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.
|
||||
long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
|
||||
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.
|
||||
Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
|
||||
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;
|
||||
|
||||
// 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;
|
||||
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 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
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;
|
||||
|
||||
// If the incoming URI matches the general notes pattern, does the update based on
|
||||
// the incoming data.
|
||||
case NOTES:
|
||||
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;
|
||||
|
||||
// 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);
|
||||
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;
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user