Initial Contribution
This commit is contained in:
347
samples/NotePad/src/com/example/android/notepad/NoteEditor.java
Normal file
347
samples/NotePad/src/com/example/android/notepad/NoteEditor.java
Normal file
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* 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.Notes;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.EditText;
|
||||
|
||||
/**
|
||||
* A generic activity for editing a note in a database. This can be used
|
||||
* either to simply view a note {@link Intent#ACTION_VIEW}, view and edit a note
|
||||
* {@link Intent#ACTION_EDIT}, or create a new note {@link Intent#ACTION_INSERT}.
|
||||
*/
|
||||
public class NoteEditor extends Activity {
|
||||
private static final String TAG = "Notes";
|
||||
|
||||
/**
|
||||
* Standard projection for the interesting columns of a normal note.
|
||||
*/
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
Notes._ID, // 0
|
||||
Notes.NOTE, // 1
|
||||
};
|
||||
/** The index of the note column */
|
||||
private static final int COLUMN_INDEX_NOTE = 1;
|
||||
|
||||
// This is our state data that is stored when freezing.
|
||||
private static final String ORIGINAL_CONTENT = "origContent";
|
||||
|
||||
// Identifiers for our menu items.
|
||||
private static final int REVERT_ID = Menu.FIRST;
|
||||
private static final int DISCARD_ID = Menu.FIRST + 1;
|
||||
private static final int DELETE_ID = Menu.FIRST + 2;
|
||||
|
||||
// The different distinct states the activity can be run in.
|
||||
private static final int STATE_EDIT = 0;
|
||||
private static final int STATE_INSERT = 1;
|
||||
|
||||
private int mState;
|
||||
private boolean mNoteOnly = false;
|
||||
private Uri mUri;
|
||||
private Cursor mCursor;
|
||||
private EditText mText;
|
||||
private String mOriginalContent;
|
||||
|
||||
/**
|
||||
* A custom EditText that draws lines between each line of text that is displayed.
|
||||
*/
|
||||
public static class LinedEditText extends EditText {
|
||||
private Rect mRect;
|
||||
private Paint mPaint;
|
||||
|
||||
// we need this constructor for LayoutInflater
|
||||
public LinedEditText(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
mRect = new Rect();
|
||||
mPaint = new Paint();
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setColor(0x800000FF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
int count = getLineCount();
|
||||
Rect r = mRect;
|
||||
Paint paint = mPaint;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int baseline = getLineBounds(i, r);
|
||||
|
||||
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
|
||||
}
|
||||
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
|
||||
// Do some setup based on the action being performed.
|
||||
|
||||
final String action = intent.getAction();
|
||||
if (Intent.ACTION_EDIT.equals(action)) {
|
||||
// Requested to edit: set that state, and the data being edited.
|
||||
mState = STATE_EDIT;
|
||||
mUri = intent.getData();
|
||||
} else if (Intent.ACTION_INSERT.equals(action)) {
|
||||
// Requested to insert: set that state, and create a new entry
|
||||
// in the container.
|
||||
mState = STATE_INSERT;
|
||||
mUri = getContentResolver().insert(intent.getData(), null);
|
||||
|
||||
// If we were unable to create a new note, then just finish
|
||||
// this activity. A RESULT_CANCELED will be sent back to the
|
||||
// original activity if they requested a result.
|
||||
if (mUri == null) {
|
||||
Log.e(TAG, "Failed to insert new note into " + getIntent().getData());
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// The new entry was created, so assume all will end well and
|
||||
// set the result to be returned.
|
||||
setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));
|
||||
|
||||
} else {
|
||||
// Whoops, unknown action! Bail.
|
||||
Log.e(TAG, "Unknown action, exiting");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the layout for this activity. You can find it in res/layout/note_editor.xml
|
||||
setContentView(R.layout.note_editor);
|
||||
|
||||
// The text view for our note, identified by its ID in the XML file.
|
||||
mText = (EditText) findViewById(R.id.note);
|
||||
|
||||
// Get the note!
|
||||
mCursor = managedQuery(mUri, PROJECTION, null, null, null);
|
||||
|
||||
// If an instance of this activity had previously stopped, we can
|
||||
// get the original text it started with.
|
||||
if (savedInstanceState != null) {
|
||||
mOriginalContent = savedInstanceState.getString(ORIGINAL_CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// If we didn't have any trouble retrieving the data, it is now
|
||||
// time to get at the stuff.
|
||||
if (mCursor != null) {
|
||||
// Make sure we are at the one and only row in the cursor.
|
||||
mCursor.moveToFirst();
|
||||
|
||||
// Modify our overall title depending on the mode we are running in.
|
||||
if (mState == STATE_EDIT) {
|
||||
setTitle(getText(R.string.title_edit));
|
||||
} else if (mState == STATE_INSERT) {
|
||||
setTitle(getText(R.string.title_create));
|
||||
}
|
||||
|
||||
// This is a little tricky: we may be resumed after previously being
|
||||
// paused/stopped. We want to put the new text in the text view,
|
||||
// but leave the user where they were (retain the cursor position
|
||||
// etc). This version of setText does that for us.
|
||||
String note = mCursor.getString(COLUMN_INDEX_NOTE);
|
||||
mText.setTextKeepState(note);
|
||||
|
||||
// If we hadn't previously retrieved the original text, do so
|
||||
// now. This allows the user to revert their changes.
|
||||
if (mOriginalContent == null) {
|
||||
mOriginalContent = note;
|
||||
}
|
||||
|
||||
} else {
|
||||
setTitle(getText(R.string.error_title));
|
||||
mText.setText(getText(R.string.error_message));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
// Save away the original text, so we still have it if the activity
|
||||
// needs to be killed while paused.
|
||||
outState.putString(ORIGINAL_CONTENT, mOriginalContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
// The user is going somewhere else, so make sure their current
|
||||
// changes are safely saved away in the provider. We don't need
|
||||
// to do this if only editing.
|
||||
if (mCursor != null) {
|
||||
String text = mText.getText().toString();
|
||||
int length = text.length();
|
||||
|
||||
// If this activity is finished, and there is no text, then we
|
||||
// do something a little special: simply delete the note entry.
|
||||
// Note that we do this both for editing and inserting... it
|
||||
// would be reasonable to only do it when inserting.
|
||||
if (isFinishing() && (length == 0) && !mNoteOnly) {
|
||||
setResult(RESULT_CANCELED);
|
||||
deleteNote();
|
||||
|
||||
// Get out updates into the provider.
|
||||
} else {
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
// This stuff is only done when working with a full-fledged note.
|
||||
if (!mNoteOnly) {
|
||||
// Bump the modification time to now.
|
||||
values.put(Notes.MODIFIED_DATE, System.currentTimeMillis());
|
||||
|
||||
// If we are creating a new note, then we want to also create
|
||||
// an initial title for it.
|
||||
if (mState == STATE_INSERT) {
|
||||
String title = text.substring(0, Math.min(30, length));
|
||||
if (length > 30) {
|
||||
int lastSpace = title.lastIndexOf(' ');
|
||||
if (lastSpace > 0) {
|
||||
title = title.substring(0, lastSpace);
|
||||
}
|
||||
}
|
||||
values.put(Notes.TITLE, title);
|
||||
}
|
||||
}
|
||||
|
||||
// Write our text back into the provider.
|
||||
values.put(Notes.NOTE, text);
|
||||
|
||||
// Commit all of our changes to persistent storage. When the update completes
|
||||
// the content provider will notify the cursor of the change, which will
|
||||
// cause the UI to be updated.
|
||||
getContentResolver().update(mUri, values, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
// Build the menus that are shown when editing.
|
||||
if (mState == STATE_EDIT) {
|
||||
menu.add(0, REVERT_ID, 0, R.string.menu_revert)
|
||||
.setShortcut('0', 'r')
|
||||
.setIcon(android.R.drawable.ic_menu_revert);
|
||||
if (!mNoteOnly) {
|
||||
menu.add(0, DELETE_ID, 0, R.string.menu_delete)
|
||||
.setShortcut('1', 'd')
|
||||
.setIcon(android.R.drawable.ic_menu_delete);
|
||||
}
|
||||
|
||||
// Build the menus that are shown when inserting.
|
||||
} else {
|
||||
menu.add(0, DISCARD_ID, 0, R.string.menu_discard)
|
||||
.setShortcut('0', 'd')
|
||||
.setIcon(android.R.drawable.ic_menu_delete);
|
||||
}
|
||||
|
||||
// If we are working on a full note, then append to the
|
||||
// menu items for any other activities that can do stuff with it
|
||||
// as well. This does a query on the system for any activities that
|
||||
// implement the ALTERNATIVE_ACTION for our data, adding a menu item
|
||||
// for each one that is found.
|
||||
if (!mNoteOnly) {
|
||||
Intent intent = new Intent(null, getIntent().getData());
|
||||
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
|
||||
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
|
||||
new ComponentName(this, NoteEditor.class), null, intent, 0, null);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle all of the possible menu actions.
|
||||
switch (item.getItemId()) {
|
||||
case DELETE_ID:
|
||||
deleteNote();
|
||||
finish();
|
||||
break;
|
||||
case DISCARD_ID:
|
||||
cancelNote();
|
||||
break;
|
||||
case REVERT_ID:
|
||||
cancelNote();
|
||||
break;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take care of canceling work on a note. Deletes the note if we
|
||||
* had created it, otherwise reverts to the original text.
|
||||
*/
|
||||
private final void cancelNote() {
|
||||
if (mCursor != null) {
|
||||
if (mState == STATE_EDIT) {
|
||||
// Put the original note text back into the database
|
||||
mCursor.close();
|
||||
mCursor = null;
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Notes.NOTE, mOriginalContent);
|
||||
getContentResolver().update(mUri, values, null, null);
|
||||
} else if (mState == STATE_INSERT) {
|
||||
// We inserted an empty note, make sure to delete it
|
||||
deleteNote();
|
||||
}
|
||||
}
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Take care of deleting a note. Simply deletes the entry.
|
||||
*/
|
||||
private final void deleteNote() {
|
||||
if (mCursor != null) {
|
||||
mCursor.close();
|
||||
mCursor = null;
|
||||
getContentResolver().delete(mUri, null, null);
|
||||
mText.setText("");
|
||||
}
|
||||
}
|
||||
}
|
||||
82
samples/NotePad/src/com/example/android/notepad/NotePad.java
Normal file
82
samples/NotePad/src/com/example/android/notepad/NotePad.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
/**
|
||||
* Convenience definitions for NotePadProvider
|
||||
*/
|
||||
public final class NotePad {
|
||||
public static final String AUTHORITY = "com.google.provider.NotePad";
|
||||
|
||||
// This class cannot be instantiated
|
||||
private NotePad() {}
|
||||
|
||||
/**
|
||||
* Notes table
|
||||
*/
|
||||
public static final class Notes implements BaseColumns {
|
||||
// This class cannot be instantiated
|
||||
private Notes() {}
|
||||
|
||||
/**
|
||||
* The content:// style URL for this table
|
||||
*/
|
||||
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");
|
||||
|
||||
/**
|
||||
* The MIME type of {@link #CONTENT_URI} providing a directory of notes.
|
||||
*/
|
||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";
|
||||
|
||||
/**
|
||||
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single note.
|
||||
*/
|
||||
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";
|
||||
|
||||
/**
|
||||
* The default sort order for this table
|
||||
*/
|
||||
public static final String DEFAULT_SORT_ORDER = "modified DESC";
|
||||
|
||||
/**
|
||||
* The title of the note
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String TITLE = "title";
|
||||
|
||||
/**
|
||||
* The note itself
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
public static final String NOTE = "note";
|
||||
|
||||
/**
|
||||
* The timestamp for when the note was created
|
||||
* <P>Type: INTEGER (long from System.curentTimeMillis())</P>
|
||||
*/
|
||||
public static final String CREATED_DATE = "created";
|
||||
|
||||
/**
|
||||
* The timestamp for when the note was last modified
|
||||
* <P>Type: INTEGER (long from System.curentTimeMillis())</P>
|
||||
*/
|
||||
public static final String MODIFIED_DATE = "modified";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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.Notes;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.UriMatcher;
|
||||
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.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
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 {
|
||||
|
||||
private static final String TAG = "NotePadProvider";
|
||||
|
||||
private static final String DATABASE_NAME = "note_pad.db";
|
||||
private static final int DATABASE_VERSION = 2;
|
||||
private static final String NOTES_TABLE_NAME = "notes";
|
||||
|
||||
private static HashMap<String, String> sNotesProjectionMap;
|
||||
|
||||
private static final int NOTES = 1;
|
||||
private static final int NOTE_ID = 2;
|
||||
|
||||
private static final UriMatcher sUriMatcher;
|
||||
|
||||
/**
|
||||
* This class helps open, create, and upgrade the database file.
|
||||
*/
|
||||
private static class DatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
@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"
|
||||
+ ");");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
|
||||
+ newVersion + ", which will destroy all old data");
|
||||
db.execSQL("DROP TABLE IF EXISTS notes");
|
||||
onCreate(db);
|
||||
}
|
||||
}
|
||||
|
||||
private DatabaseHelper mOpenHelper;
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
mOpenHelper = new DatabaseHelper(getContext());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
|
||||
String sortOrder) {
|
||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||
|
||||
switch (sUriMatcher.match(uri)) {
|
||||
case NOTES:
|
||||
qb.setTables(NOTES_TABLE_NAME);
|
||||
qb.setProjectionMap(sNotesProjectionMap);
|
||||
break;
|
||||
|
||||
case NOTE_ID:
|
||||
qb.setTables(NOTES_TABLE_NAME);
|
||||
qb.setProjectionMap(sNotesProjectionMap);
|
||||
qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URI " + uri);
|
||||
}
|
||||
|
||||
// If no sort order is specified use the default
|
||||
String orderBy;
|
||||
if (TextUtils.isEmpty(sortOrder)) {
|
||||
orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
|
||||
} else {
|
||||
orderBy = sortOrder;
|
||||
}
|
||||
|
||||
// Get the database and run the query
|
||||
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
|
||||
c.setNotificationUri(getContext().getContentResolver(), uri);
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri) {
|
||||
switch (sUriMatcher.match(uri)) {
|
||||
case NOTES:
|
||||
return Notes.CONTENT_TYPE;
|
||||
|
||||
case NOTE_ID:
|
||||
return Notes.CONTENT_ITEM_TYPE;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URI " + uri);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues initialValues) {
|
||||
// Validate the requested uri
|
||||
if (sUriMatcher.match(uri) != NOTES) {
|
||||
throw new IllegalArgumentException("Unknown URI " + uri);
|
||||
}
|
||||
|
||||
ContentValues values;
|
||||
if (initialValues != null) {
|
||||
values = new ContentValues(initialValues);
|
||||
} else {
|
||||
values = new ContentValues();
|
||||
}
|
||||
|
||||
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 (values.containsKey(NotePad.Notes.MODIFIED_DATE) == false) {
|
||||
values.put(NotePad.Notes.MODIFIED_DATE, now);
|
||||
}
|
||||
|
||||
if (values.containsKey(NotePad.Notes.TITLE) == false) {
|
||||
Resources r = Resources.getSystem();
|
||||
values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled));
|
||||
}
|
||||
|
||||
if (values.containsKey(NotePad.Notes.NOTE) == false) {
|
||||
values.put(NotePad.Notes.NOTE, "");
|
||||
}
|
||||
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
|
||||
if (rowId > 0) {
|
||||
Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
|
||||
getContext().getContentResolver().notifyChange(noteUri, null);
|
||||
return noteUri;
|
||||
}
|
||||
|
||||
throw new SQLException("Failed to insert row into " + uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String where, String[] whereArgs) {
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
int count;
|
||||
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;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URI " + uri);
|
||||
}
|
||||
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
int count;
|
||||
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;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URI " + uri);
|
||||
}
|
||||
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
return count;
|
||||
}
|
||||
|
||||
static {
|
||||
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
|
||||
sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
215
samples/NotePad/src/com/example/android/notepad/NotesList.java
Normal file
215
samples/NotePad/src/com/example/android/notepad/NotesList.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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.Notes;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SimpleCursorAdapter;
|
||||
|
||||
/**
|
||||
* Displays a list of notes. Will display notes from the {@link Uri}
|
||||
* provided in the intent if there is one, otherwise defaults to displaying the
|
||||
* contents of the {@link NotePadProvider}
|
||||
*/
|
||||
public class NotesList extends ListActivity {
|
||||
private static final String TAG = "NotesList";
|
||||
|
||||
// Menu item ids
|
||||
public static final int MENU_ITEM_DELETE = Menu.FIRST;
|
||||
public static final int MENU_ITEM_INSERT = Menu.FIRST + 1;
|
||||
|
||||
/**
|
||||
* The columns we are interested in from the database
|
||||
*/
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
Notes._ID, // 0
|
||||
Notes.TITLE, // 1
|
||||
};
|
||||
|
||||
/** The index of the title column */
|
||||
private static final int COLUMN_INDEX_TITLE = 1;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
|
||||
|
||||
// If no data was given in the intent (because we were started
|
||||
// as a MAIN activity), then use our default content provider.
|
||||
Intent intent = getIntent();
|
||||
if (intent.getData() == null) {
|
||||
intent.setData(Notes.CONTENT_URI);
|
||||
}
|
||||
|
||||
// Inform the list we provide context menus for items
|
||||
getListView().setOnCreateContextMenuListener(this);
|
||||
|
||||
// Perform a managed query. The Activity will handle closing and requerying the cursor
|
||||
// when needed.
|
||||
Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, null, null,
|
||||
Notes.DEFAULT_SORT_ORDER);
|
||||
|
||||
// Used to map notes entries from the database to views
|
||||
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.noteslist_item, cursor,
|
||||
new String[] { Notes.TITLE }, new int[] { android.R.id.text1 });
|
||||
setListAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
// This is our one standard application action -- inserting a
|
||||
// new note into the list.
|
||||
menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert)
|
||||
.setShortcut('3', 'a')
|
||||
.setIcon(android.R.drawable.ic_menu_add);
|
||||
|
||||
// Generate any additional actions that can be performed on the
|
||||
// overall list. In a normal install, there are no additional
|
||||
// actions found here, but this allows other applications to extend
|
||||
// our menu with their own actions.
|
||||
Intent intent = new Intent(null, getIntent().getData());
|
||||
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
|
||||
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
|
||||
new ComponentName(this, NotesList.class), null, intent, 0, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
final boolean haveItems = getListAdapter().getCount() > 0;
|
||||
|
||||
// If there are any notes in the list (which implies that one of
|
||||
// them is selected), then we need to generate the actions that
|
||||
// can be performed on the current selection. This will be a combination
|
||||
// of our own specific actions along with any extensions that can be
|
||||
// found.
|
||||
if (haveItems) {
|
||||
// This is the selected item.
|
||||
Uri uri = ContentUris.withAppendedId(getIntent().getData(), getSelectedItemId());
|
||||
|
||||
// Build menu... always starts with the EDIT action...
|
||||
Intent[] specifics = new Intent[1];
|
||||
specifics[0] = new Intent(Intent.ACTION_EDIT, uri);
|
||||
MenuItem[] items = new MenuItem[1];
|
||||
|
||||
// ... is followed by whatever other actions are available...
|
||||
Intent intent = new Intent(null, uri);
|
||||
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
|
||||
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, specifics, intent, 0,
|
||||
items);
|
||||
|
||||
// Give a shortcut to the edit action.
|
||||
if (items[0] != null) {
|
||||
items[0].setShortcut('1', 'e');
|
||||
}
|
||||
} else {
|
||||
menu.removeGroup(Menu.CATEGORY_ALTERNATIVE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_INSERT:
|
||||
// Launch activity to insert a new item
|
||||
startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
|
||||
AdapterView.AdapterContextMenuInfo info;
|
||||
try {
|
||||
info = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
} catch (ClassCastException e) {
|
||||
Log.e(TAG, "bad menuInfo", e);
|
||||
return;
|
||||
}
|
||||
|
||||
Cursor cursor = (Cursor) getListAdapter().getItem(info.position);
|
||||
if (cursor == null) {
|
||||
// For some reason the requested item isn't available, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup the menu header
|
||||
menu.setHeaderTitle(cursor.getString(COLUMN_INDEX_TITLE));
|
||||
|
||||
// Add a menu item to delete the note
|
||||
menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_delete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
AdapterView.AdapterContextMenuInfo info;
|
||||
try {
|
||||
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
||||
} catch (ClassCastException e) {
|
||||
Log.e(TAG, "bad menuInfo", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_DELETE: {
|
||||
// Delete the note that the context menu is for
|
||||
Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), info.id);
|
||||
getContentResolver().delete(noteUri, null, null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);
|
||||
|
||||
String action = getIntent().getAction();
|
||||
if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
|
||||
// The caller is waiting for us to return a note selected by
|
||||
// the user. The have clicked on one, so return it now.
|
||||
setResult(RESULT_OK, new Intent().setData(uri));
|
||||
} else {
|
||||
// Launch activity to view/edit the currently selected item
|
||||
startActivity(new Intent(Intent.ACTION_EDIT, uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
115
samples/NotePad/src/com/example/android/notepad/TitleEditor.java
Normal file
115
samples/NotePad/src/com/example/android/notepad/TitleEditor.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.Notes;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
/**
|
||||
* An activity that will edit the title of a note. Displays a floating
|
||||
* window with a text field.
|
||||
*/
|
||||
public class TitleEditor extends Activity implements View.OnClickListener {
|
||||
|
||||
/**
|
||||
* This is a special intent action that means "edit the title of a note".
|
||||
*/
|
||||
public static final String EDIT_TITLE_ACTION = "com.android.notepad.action.EDIT_TITLE";
|
||||
|
||||
/**
|
||||
* An array of the columns we are interested in.
|
||||
*/
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
NotePad.Notes._ID, // 0
|
||||
NotePad.Notes.TITLE, // 1
|
||||
};
|
||||
/** Index of the title column */
|
||||
private static final int COLUMN_INDEX_TITLE = 1;
|
||||
|
||||
/**
|
||||
* Cursor which will provide access to the note whose title we are editing.
|
||||
*/
|
||||
private Cursor mCursor;
|
||||
|
||||
/**
|
||||
* The EditText field from our UI. Keep track of this so we can extract the
|
||||
* text when we are finished.
|
||||
*/
|
||||
private EditText mText;
|
||||
|
||||
/**
|
||||
* The content URI to the note that's being edited.
|
||||
*/
|
||||
private Uri mUri;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.title_editor);
|
||||
|
||||
// Get the uri of the note whose title we want to edit
|
||||
mUri = getIntent().getData();
|
||||
|
||||
// Get a cursor to access the note
|
||||
mCursor = managedQuery(mUri, PROJECTION, null, null, null);
|
||||
|
||||
// Set up click handlers for the text field and button
|
||||
mText = (EditText) this.findViewById(R.id.title);
|
||||
mText.setOnClickListener(this);
|
||||
|
||||
Button b = (Button) findViewById(R.id.ok);
|
||||
b.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// Initialize the text with the title column from the cursor
|
||||
if (mCursor != null) {
|
||||
mCursor.moveToFirst();
|
||||
mText.setText(mCursor.getString(COLUMN_INDEX_TITLE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (mCursor != null) {
|
||||
// Write the title back to the note
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Notes.TITLE, mText.getText().toString());
|
||||
getContentResolver().update(mUri, values, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
// When the user clicks, just finish this activity.
|
||||
// onPause will be called, and we save our data there.
|
||||
finish();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user