From 875234d9405358569599a203678a36f042aa6489 Mon Sep 17 00:00:00 2001 From: Scott Main Date: Tue, 19 Oct 2010 17:19:03 -0700 Subject: [PATCH] Do not merge. This is a cherry-pick from froyo change I392406824607e2bdae646e3156433d82a9ed6521 Revise NotePad application to use better practices such as - inflating menus from XML and supporting API Level 3 without the need for version qualifiers on resource directories. - to NOT include items in the options menu based on the 'selected' item (that's what a context menu is for). - include all drawables in the app, instead of using system resources. Add features: - the ability to edit the note title through the context menu - disable menu items in the editor based on menu groups - add a "save" button to the editor instead of assuming BACK functionality - and show the title of the current note in the activity title. - and probably others Change-Id: I5e6fa5315308edf1a9447ecadd5b289127776bd0 --- samples/NotePad/AndroidManifest.xml | 27 +-- .../res/drawable-hdpi-v6/app_notes.png | Bin 3941 -> 0 bytes .../NotePad/res/drawable-hdpi/app_notes.png | Bin 4881 -> 3941 bytes .../res/drawable-hdpi/ic_menu_compose.png | Bin 0 -> 2993 bytes .../res/drawable-hdpi/ic_menu_delete.png | Bin 0 -> 2343 bytes .../res/drawable-hdpi/ic_menu_discard.png | Bin 0 -> 4704 bytes .../res/drawable-hdpi/ic_menu_edit.png | Bin 0 -> 2310 bytes .../res/drawable-hdpi/ic_menu_revert.png | Bin 0 -> 2806 bytes .../res/drawable-hdpi/ic_menu_save.png | Bin 0 -> 2189 bytes .../live_folder_notes.png | Bin .../app_notes.png | Bin .../live_folder_notes.png | Bin .../NotePad/res/drawable-mdpi/app_notes.png | Bin 2879 -> 0 bytes .../res/drawable-mdpi/live_folder_notes.png | Bin 2900 -> 0 bytes .../app_notes.png | Bin .../NotePad/res/drawable/ic_menu_compose.png | Bin 0 -> 2014 bytes .../NotePad/res/drawable/ic_menu_delete.png | Bin 0 -> 1747 bytes .../NotePad/res/drawable/ic_menu_discard.png | Bin 0 -> 5306 bytes samples/NotePad/res/drawable/ic_menu_edit.png | Bin 0 -> 1661 bytes .../NotePad/res/drawable/ic_menu_revert.png | Bin 0 -> 1731 bytes samples/NotePad/res/drawable/ic_menu_save.png | Bin 0 -> 1645 bytes .../live_folder_notes.png | Bin samples/NotePad/res/layout/note_editor.xml | 10 +- samples/NotePad/res/layout/noteslist_item.xml | 2 +- .../NotePad/res/menu/editor_options_menu.xml | 20 ++ .../NotePad/res/menu/list_context_menu.xml | 7 + .../NotePad/res/menu/list_options_menu.xml | 8 + samples/NotePad/res/values/strings.xml | 45 ++-- .../example/android/notepad/NoteEditor.java | 208 ++++++++++-------- .../com/example/android/notepad/NotePad.java | 6 +- .../android/notepad/NotePadProvider.java | 60 ++--- .../example/android/notepad/NotesList.java | 121 ++++------ .../example/android/notepad/TitleEditor.java | 10 +- .../src/com/google/provider/NotePad.java | 65 ------ 34 files changed, 278 insertions(+), 311 deletions(-) delete mode 100644 samples/NotePad/res/drawable-hdpi-v6/app_notes.png mode change 100755 => 100644 samples/NotePad/res/drawable-hdpi/app_notes.png create mode 100644 samples/NotePad/res/drawable-hdpi/ic_menu_compose.png create mode 100644 samples/NotePad/res/drawable-hdpi/ic_menu_delete.png create mode 100644 samples/NotePad/res/drawable-hdpi/ic_menu_discard.png create mode 100644 samples/NotePad/res/drawable-hdpi/ic_menu_edit.png create mode 100644 samples/NotePad/res/drawable-hdpi/ic_menu_revert.png create mode 100644 samples/NotePad/res/drawable-hdpi/ic_menu_save.png rename samples/NotePad/res/{drawable-hdpi-v6 => drawable-hdpi}/live_folder_notes.png (100%) rename samples/NotePad/res/{drawable-ldpi-v6 => drawable-ldpi}/app_notes.png (100%) rename samples/NotePad/res/{drawable-ldpi-v6 => drawable-ldpi}/live_folder_notes.png (100%) delete mode 100644 samples/NotePad/res/drawable-mdpi/app_notes.png delete mode 100644 samples/NotePad/res/drawable-mdpi/live_folder_notes.png rename samples/NotePad/res/{drawable-mdpi-v6 => drawable}/app_notes.png (100%) create mode 100644 samples/NotePad/res/drawable/ic_menu_compose.png create mode 100755 samples/NotePad/res/drawable/ic_menu_delete.png create mode 100644 samples/NotePad/res/drawable/ic_menu_discard.png create mode 100755 samples/NotePad/res/drawable/ic_menu_edit.png create mode 100644 samples/NotePad/res/drawable/ic_menu_revert.png create mode 100644 samples/NotePad/res/drawable/ic_menu_save.png rename samples/NotePad/res/{drawable-mdpi-v6 => drawable}/live_folder_notes.png (100%) create mode 100644 samples/NotePad/res/menu/editor_options_menu.xml create mode 100644 samples/NotePad/res/menu/list_context_menu.xml create mode 100644 samples/NotePad/res/menu/list_options_menu.xml delete mode 100644 samples/NotePad/src/com/google/provider/NotePad.java diff --git a/samples/NotePad/AndroidManifest.xml b/samples/NotePad/AndroidManifest.xml index 04f4dbee5..b87dfe312 100644 --- a/samples/NotePad/AndroidManifest.xml +++ b/samples/NotePad/AndroidManifest.xml @@ -20,16 +20,15 @@ own application, the package name must be changed from "com.example.*" to come from a domain that you own or have control over. --> - - + package="com.example.android.notepad" > - + + + + @@ -50,16 +49,13 @@ + android:configChanges="keyboardHidden|orientation"> - + @@ -77,6 +73,7 @@ - + android:capitalize="sentences" /> diff --git a/samples/NotePad/res/layout/noteslist_item.xml b/samples/NotePad/res/layout/noteslist_item.xml index e11c5eed2..b16773416 100644 --- a/samples/NotePad/res/layout/noteslist_item.xml +++ b/samples/NotePad/res/layout/noteslist_item.xml @@ -16,7 +16,7 @@ + + + + + + + + + + \ No newline at end of file diff --git a/samples/NotePad/res/menu/list_context_menu.xml b/samples/NotePad/res/menu/list_context_menu.xml new file mode 100644 index 000000000..acc8edd63 --- /dev/null +++ b/samples/NotePad/res/menu/list_context_menu.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/samples/NotePad/res/menu/list_options_menu.xml b/samples/NotePad/res/menu/list_options_menu.xml new file mode 100644 index 000000000..975455432 --- /dev/null +++ b/samples/NotePad/res/menu/list_options_menu.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/samples/NotePad/res/values/strings.xml b/samples/NotePad/res/values/strings.xml index 168db92be..4100652a2 100644 --- a/samples/NotePad/res/values/strings.xml +++ b/samples/NotePad/res/values/strings.xml @@ -15,25 +15,28 @@ --> - Delete - Add note - Revert - Discard - - Edit note - Edit title - + NotePad + Notes + + Note title: Create note - Edit note - Note pad - Note - Note title: - - Note Pad - Notes - - OK - - Error - Error loading note - + Edit: \"%1$s\" + Notes + + Add note + Save + Delete + Open + Revert changes + Discard + + OK + Title: + + Edit note + Edit title + + Error + Error loading note + There is nothing to save + \ No newline at end of file diff --git a/samples/NotePad/src/com/example/android/notepad/NoteEditor.java b/samples/NotePad/src/com/example/android/notepad/NoteEditor.java index e45efd865..66f4ce682 100644 --- a/samples/NotePad/src/com/example/android/notepad/NoteEditor.java +++ b/samples/NotePad/src/com/example/android/notepad/NoteEditor.java @@ -16,13 +16,12 @@ 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.content.res.Resources; import android.database.Cursor; import android.graphics.Canvas; import android.graphics.Paint; @@ -32,8 +31,12 @@ import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.widget.EditText; +import android.widget.Toast; + +import com.example.android.notepad.NotePad.NoteColumns; /** * A generic activity for editing a note in a database. This can be used @@ -41,32 +44,29 @@ import android.widget.EditText; * {@link Intent#ACTION_EDIT}, or create a new note {@link Intent#ACTION_INSERT}. */ public class NoteEditor extends Activity { - private static final String TAG = "Notes"; + private static final String TAG = "NoteEditor"; /** * Standard projection for the interesting columns of a normal note. */ private static final String[] PROJECTION = new String[] { - Notes._ID, // 0 - Notes.NOTE, // 1 + NoteColumns._ID, // 0 + NoteColumns.NOTE, // 1 + NoteColumns.TITLE, // 2 }; /** The index of the note column */ private static final int COLUMN_INDEX_NOTE = 1; + /** The index of the title column */ + private static final int COLUMN_INDEX_TITLE = 2; // 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; @@ -112,7 +112,6 @@ public class NoteEditor extends Activity { 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. @@ -163,16 +162,21 @@ public class NoteEditor extends Activity { @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) { + // Requery in case something changed while paused (such as the title) + mCursor.requery(); // 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)); + // Set the title of the Activity to include the note title + String title = mCursor.getString(COLUMN_INDEX_TITLE); + Resources res = getResources(); + String text = String.format(res.getString(R.string.title_edit), title); + setTitle(text); } else if (mState == STATE_INSERT) { setTitle(getText(R.string.title_create)); } @@ -206,109 +210,129 @@ public class NoteEditor extends Activity { @Override protected void onPause() { super.onPause(); + // The user is going somewhere, so make sure changes are saved - // 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(); + 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); - } + // If this activity is finished, and there is no text, then we + // 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) && mCursor != null) { + setResult(RESULT_CANCELED); + deleteNote(); + } else { + saveNote(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); + // Inflate menu from XML resource + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.editor_options_menu, 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 + // 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); - } + 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; + return super.onCreateOptionsMenu(menu); + } + + + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + if (mState == STATE_EDIT) { + menu.setGroupVisible(R.id.menu_group_edit, true); + menu.setGroupVisible(R.id.menu_group_insert, false); + + // Check if note has changed and enable/disable the revert option + String savedNote = mCursor.getString(COLUMN_INDEX_NOTE); + String currentNote = mText.getText().toString(); + if (savedNote.equals(currentNote)) { + menu.findItem(R.id.menu_revert).setEnabled(false); + } else { + menu.findItem(R.id.menu_revert).setEnabled(true); + } + } else { + menu.setGroupVisible(R.id.menu_group_edit, false); + menu.setGroupVisible(R.id.menu_group_insert, true); + } + return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle all of the possible menu actions. switch (item.getItemId()) { - case DELETE_ID: + case R.id.menu_save: + saveNote(); + finish(); + break; + case R.id.menu_delete: deleteNote(); finish(); break; - case DISCARD_ID: - cancelNote(); - break; - case REVERT_ID: + case R.id.menu_revert: + case R.id.menu_discard: cancelNote(); break; } return super.onOptionsItemSelected(item); + + } + + private final void saveNote() { + // 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) { + // Get out updates into the provider. + ContentValues values = new ContentValues(); + + // Bump the modification time to now. + values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); + + String text = mText.getText().toString(); + int length = text.length(); + // If we are creating a new note, then we want to also create + // an initial title for it. + if (mState == STATE_INSERT) { + if (length == 0) { + Toast.makeText(this, R.string.nothing_to_save, Toast.LENGTH_SHORT).show(); + return; + } + 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(NoteColumns.TITLE, title); + } + + // Write our text back into the provider. + values.put(NoteColumns.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. + try { + getContentResolver().update(mUri, values, null, null); + } catch (NullPointerException e) { + Log.e(TAG, e.getMessage()); + } + + } } /** @@ -322,7 +346,7 @@ public class NoteEditor extends Activity { mCursor.close(); mCursor = null; ContentValues values = new ContentValues(); - values.put(Notes.NOTE, mOriginalContent); + values.put(NoteColumns.NOTE, mOriginalContent); getContentResolver().update(mUri, values, null, null); } else if (mState == STATE_INSERT) { // We inserted an empty note, make sure to delete it diff --git a/samples/NotePad/src/com/example/android/notepad/NotePad.java b/samples/NotePad/src/com/example/android/notepad/NotePad.java index 25be23e6e..09087db7b 100644 --- a/samples/NotePad/src/com/example/android/notepad/NotePad.java +++ b/samples/NotePad/src/com/example/android/notepad/NotePad.java @@ -23,7 +23,7 @@ import android.provider.BaseColumns; * Convenience definitions for NotePadProvider */ public final class NotePad { - public static final String AUTHORITY = "com.google.provider.NotePad"; + public static final String AUTHORITY = "com.example.notepad.provider.NotePad"; // This class cannot be instantiated private NotePad() {} @@ -31,9 +31,9 @@ public final class NotePad { /** * Notes table */ - public static final class Notes implements BaseColumns { + public static final class NoteColumns implements BaseColumns { // This class cannot be instantiated - private Notes() {} + private NoteColumns() {} /** * The content:// style URL for this table diff --git a/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java b/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java index 58cdc8fd5..5c349c54a 100644 --- a/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java +++ b/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java @@ -16,7 +16,7 @@ package com.example.android.notepad; -import com.example.android.notepad.NotePad.Notes; +import com.example.android.notepad.NotePad.NoteColumns; import android.content.ContentProvider; import android.content.ContentUris; @@ -44,7 +44,7 @@ public class NotePadProvider extends ContentProvider { private static final String TAG = "NotePadProvider"; - private static final String DATABASE_NAME = "note_pad.db"; + private static final String DATABASE_NAME = "notepad.db"; private static final int DATABASE_VERSION = 2; private static final String NOTES_TABLE_NAME = "notes"; @@ -69,11 +69,11 @@ public class NotePadProvider extends ContentProvider { @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" + + NoteColumns._ID + " INTEGER PRIMARY KEY," + + NoteColumns.TITLE + " TEXT," + + NoteColumns.NOTE + " TEXT," + + NoteColumns.CREATED_DATE + " INTEGER," + + NoteColumns.MODIFIED_DATE + " INTEGER" + ");"); } @@ -107,7 +107,7 @@ public class NotePadProvider extends ContentProvider { case NOTE_ID: qb.setProjectionMap(sNotesProjectionMap); - qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1)); + qb.appendWhere(NoteColumns._ID + "=" + uri.getPathSegments().get(1)); break; case LIVE_FOLDER_NOTES: @@ -121,7 +121,7 @@ public class NotePadProvider extends ContentProvider { // If no sort order is specified use the default String orderBy; if (TextUtils.isEmpty(sortOrder)) { - orderBy = NotePad.Notes.DEFAULT_SORT_ORDER; + orderBy = NoteColumns.DEFAULT_SORT_ORDER; } else { orderBy = sortOrder; } @@ -140,10 +140,10 @@ public class NotePadProvider extends ContentProvider { switch (sUriMatcher.match(uri)) { case NOTES: case LIVE_FOLDER_NOTES: - return Notes.CONTENT_TYPE; + return NoteColumns.CONTENT_TYPE; case NOTE_ID: - return Notes.CONTENT_ITEM_TYPE; + return NoteColumns.CONTENT_ITEM_TYPE; default: throw new IllegalArgumentException("Unknown URI " + uri); @@ -167,27 +167,27 @@ public class NotePadProvider extends ContentProvider { 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(NoteColumns.CREATED_DATE) == false) { + values.put(NoteColumns.CREATED_DATE, now); } - if (values.containsKey(NotePad.Notes.MODIFIED_DATE) == false) { - values.put(NotePad.Notes.MODIFIED_DATE, now); + if (values.containsKey(NoteColumns.MODIFIED_DATE) == false) { + values.put(NoteColumns.MODIFIED_DATE, now); } - if (values.containsKey(NotePad.Notes.TITLE) == false) { + if (values.containsKey(NoteColumns.TITLE) == false) { Resources r = Resources.getSystem(); - values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled)); + values.put(NoteColumns.TITLE, r.getString(android.R.string.untitled)); } - if (values.containsKey(NotePad.Notes.NOTE) == false) { - values.put(NotePad.Notes.NOTE, ""); + if (values.containsKey(NoteColumns.NOTE) == false) { + values.put(NoteColumns.NOTE, ""); } SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values); + long rowId = db.insert(NOTES_TABLE_NAME, NoteColumns.NOTE, values); if (rowId > 0) { - Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId); + Uri noteUri = ContentUris.withAppendedId(NoteColumns.CONTENT_URI, rowId); getContext().getContentResolver().notifyChange(noteUri, null); return noteUri; } @@ -206,7 +206,7 @@ public class NotePadProvider extends ContentProvider { case NOTE_ID: String noteId = uri.getPathSegments().get(1); - count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + count = db.delete(NOTES_TABLE_NAME, NoteColumns._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); break; @@ -229,7 +229,7 @@ public class NotePadProvider extends ContentProvider { case NOTE_ID: String noteId = uri.getPathSegments().get(1); - count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + count = db.update(NOTES_TABLE_NAME, values, NoteColumns._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); break; @@ -248,17 +248,17 @@ public class NotePadProvider extends ContentProvider { sUriMatcher.addURI(NotePad.AUTHORITY, "live_folders/notes", LIVE_FOLDER_NOTES); sNotesProjectionMap = new HashMap(); - 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); + sNotesProjectionMap.put(NoteColumns._ID, NoteColumns._ID); + sNotesProjectionMap.put(NoteColumns.TITLE, NoteColumns.TITLE); + sNotesProjectionMap.put(NoteColumns.NOTE, NoteColumns.NOTE); + sNotesProjectionMap.put(NoteColumns.CREATED_DATE, NoteColumns.CREATED_DATE); + sNotesProjectionMap.put(NoteColumns.MODIFIED_DATE, NoteColumns.MODIFIED_DATE); // Support for Live Folders. sLiveFolderProjectionMap = new HashMap(); - sLiveFolderProjectionMap.put(LiveFolders._ID, Notes._ID + " AS " + + sLiveFolderProjectionMap.put(LiveFolders._ID, NoteColumns._ID + " AS " + LiveFolders._ID); - sLiveFolderProjectionMap.put(LiveFolders.NAME, Notes.TITLE + " AS " + + sLiveFolderProjectionMap.put(LiveFolders.NAME, NoteColumns.TITLE + " AS " + LiveFolders.NAME); // Add more columns here for more robust Live Folders. } diff --git a/samples/NotePad/src/com/example/android/notepad/NotesList.java b/samples/NotePad/src/com/example/android/notepad/NotesList.java index ceaaa3c76..ec809021d 100644 --- a/samples/NotePad/src/com/example/android/notepad/NotesList.java +++ b/samples/NotePad/src/com/example/android/notepad/NotesList.java @@ -16,8 +16,6 @@ package com.example.android.notepad; -import com.example.android.notepad.NotePad.Notes; - import android.app.ListActivity; import android.content.ComponentName; import android.content.ContentUris; @@ -28,6 +26,7 @@ import android.os.Bundle; import android.util.Log; import android.view.ContextMenu; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ContextMenu.ContextMenuInfo; @@ -35,24 +34,22 @@ import android.widget.AdapterView; import android.widget.ListView; import android.widget.SimpleCursorAdapter; +import com.example.android.notepad.NotePad.NoteColumns; + /** * 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} + * contents of the {@link NoteProvider} */ 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 + NoteColumns._ID, // 0 + NoteColumns.TITLE, // 1 }; /** The index of the title column */ @@ -68,7 +65,7 @@ public class NotesList extends ListActivity { // as a MAIN activity), then use our default content provider. Intent intent = getIntent(); if (intent.getData() == null) { - intent.setData(Notes.CONTENT_URI); + intent.setData(NoteColumns.CONTENT_URI); } // Inform the list we provide context menus for items @@ -77,24 +74,20 @@ public class NotesList extends ListActivity { // 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); + NoteColumns.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 }); + new String[] { NoteColumns.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); - + // Inflate menu from XML resource + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.list_options_menu, menu); + // 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 @@ -104,54 +97,19 @@ public class NotesList extends ListActivity { 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; + return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case MENU_ITEM_INSERT: + case R.id.menu_add: // Launch activity to insert a new item startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData())); return true; + default: + return super.onOptionsItemSelected(item); } - return super.onOptionsItemSelected(item); } @Override @@ -170,11 +128,23 @@ public class NotesList extends ListActivity { return; } - // Setup the menu header + // Inflate menu from XML resource + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.list_context_menu, menu); + + // Set the context 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); + + // 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. + Intent intent = new Intent(null, Uri.withAppendedPath(getIntent().getData(), + Integer.toString((int) info.id) )); + intent.addCategory(Intent.CATEGORY_ALTERNATIVE); + menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, + new ComponentName(this, NotesList.class), null, intent, 0, null); } @Override @@ -186,30 +156,35 @@ public class NotesList extends ListActivity { Log.e(TAG, "bad menuInfo", e); return false; } + + Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), info.id); 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; - } + case R.id.context_open: + // Launch activity to view/edit the currently selected item + startActivity(new Intent(Intent.ACTION_EDIT, noteUri)); + return true; + case R.id.context_delete: + // Delete the note that the context menu is for + getContentResolver().delete(noteUri, null, null); + return true; + default: + return super.onContextItemSelected(item); } - return false; } @Override protected void onListItemClick(ListView l, View v, int position, long id) { - Uri uri = ContentUris.withAppendedId(getIntent().getData(), id); + Uri noteUri = 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)); + setResult(RESULT_OK, new Intent().setData(noteUri)); } else { // Launch activity to view/edit the currently selected item - startActivity(new Intent(Intent.ACTION_EDIT, uri)); + startActivity(new Intent(Intent.ACTION_EDIT, noteUri)); } } } diff --git a/samples/NotePad/src/com/example/android/notepad/TitleEditor.java b/samples/NotePad/src/com/example/android/notepad/TitleEditor.java index 50d38e5f6..fe232ed26 100644 --- a/samples/NotePad/src/com/example/android/notepad/TitleEditor.java +++ b/samples/NotePad/src/com/example/android/notepad/TitleEditor.java @@ -16,8 +16,6 @@ package com.example.android.notepad; -import com.example.android.notepad.NotePad.Notes; - import android.app.Activity; import android.content.ContentValues; import android.database.Cursor; @@ -27,6 +25,8 @@ import android.view.View; import android.widget.Button; import android.widget.EditText; +import com.example.android.notepad.NotePad.NoteColumns; + /** * An activity that will edit the title of a note. Displays a floating * window with a text field. @@ -42,8 +42,8 @@ public class TitleEditor extends Activity implements View.OnClickListener { * An array of the columns we are interested in. */ private static final String[] PROJECTION = new String[] { - NotePad.Notes._ID, // 0 - NotePad.Notes.TITLE, // 1 + NoteColumns._ID, // 0 + NoteColumns.TITLE, // 1 }; /** Index of the title column */ private static final int COLUMN_INDEX_TITLE = 1; @@ -102,7 +102,7 @@ public class TitleEditor extends Activity implements View.OnClickListener { if (mCursor != null) { // Write the title back to the note ContentValues values = new ContentValues(); - values.put(Notes.TITLE, mText.getText().toString()); + values.put(NoteColumns.TITLE, mText.getText().toString()); getContentResolver().update(mUri, values, null, null); } } diff --git a/samples/NotePad/src/com/google/provider/NotePad.java b/samples/NotePad/src/com/google/provider/NotePad.java deleted file mode 100644 index f8de69b6b..000000000 --- a/samples/NotePad/src/com/google/provider/NotePad.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.google.provider; - -import android.net.Uri; -import android.provider.BaseColumns; - -/** - * Convenience definitions for NotePadProvider - */ -public final class NotePad { - /** - * Notes table - */ - public static final class Notes implements BaseColumns { - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI - = Uri.parse("content://com.google.provider.NotePad/notes"); - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = "modified DESC"; - - /** - * The title of the note - *

Type: TEXT

- */ - public static final String TITLE = "title"; - - /** - * The note itself - *

Type: TEXT

- */ - public static final String NOTE = "note"; - - /** - * The timestamp for when the note was created - *

Type: INTEGER (long)

- */ - public static final String CREATED_DATE = "created"; - - /** - * The timestamp for when the note was last modified - *

Type: INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified"; - } -}