OSDN Git Service

This is a manual merge of Ib7ea41079f3b268f3be1f86febdb1caed98bdd8e
authorScott Main <smain@google.com>
Mon, 29 Nov 2010 19:16:13 +0000 (11:16 -0800)
committerScott Main <smain@google.com>
Thu, 2 Dec 2010 20:09:38 +0000 (12:09 -0800)
Which includes the following:
        - 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.

Plus, this change adds Holo themes and items to the action bar.
And fix a bug in NoteEditor: the constants used for the column indexes caused the title
and note text to be saved incorrectly---removed them and instead perform column index
lookup on the notes cursor.

Change-Id: I6e7a693a35f5dc2da423982869dd871c4c171e5b

30 files changed:
samples/NotePad/AndroidManifest.xml
samples/NotePad/res/drawable-hdpi-v6/app_notes.png [deleted file]
samples/NotePad/res/drawable-hdpi/app_notes.png [changed mode: 0755->0644]
samples/NotePad/res/drawable-hdpi/ic_menu_compose.png [new file with mode: 0644]
samples/NotePad/res/drawable-hdpi/ic_menu_delete.png [new file with mode: 0644]
samples/NotePad/res/drawable-hdpi/ic_menu_edit.png [new file with mode: 0644]
samples/NotePad/res/drawable-hdpi/ic_menu_revert.png [new file with mode: 0644]
samples/NotePad/res/drawable-hdpi/ic_menu_save.png [new file with mode: 0644]
samples/NotePad/res/drawable-hdpi/live_folder_notes.png [moved from samples/NotePad/res/drawable-hdpi-v6/live_folder_notes.png with 100% similarity]
samples/NotePad/res/drawable-ldpi/app_notes.png [moved from samples/NotePad/res/drawable-ldpi-v6/app_notes.png with 100% similarity]
samples/NotePad/res/drawable-ldpi/live_folder_notes.png [moved from samples/NotePad/res/drawable-ldpi-v6/live_folder_notes.png with 100% similarity]
samples/NotePad/res/drawable-mdpi/app_notes.png [deleted file]
samples/NotePad/res/drawable-mdpi/live_folder_notes.png [deleted file]
samples/NotePad/res/drawable/app_notes.png [moved from samples/NotePad/res/drawable-mdpi-v6/app_notes.png with 100% similarity]
samples/NotePad/res/drawable/ic_menu_compose.png [new file with mode: 0644]
samples/NotePad/res/drawable/ic_menu_delete.png [new file with mode: 0755]
samples/NotePad/res/drawable/ic_menu_edit.png [new file with mode: 0755]
samples/NotePad/res/drawable/ic_menu_revert.png [new file with mode: 0644]
samples/NotePad/res/drawable/ic_menu_save.png [new file with mode: 0644]
samples/NotePad/res/drawable/live_folder_notes.png [moved from samples/NotePad/res/drawable-mdpi-v6/live_folder_notes.png with 100% similarity]
samples/NotePad/res/layout/note_editor.xml
samples/NotePad/res/layout/noteslist_item.xml
samples/NotePad/res/layout/title_editor.xml
samples/NotePad/res/menu/editor_options_menu.xml [new file with mode: 0644]
samples/NotePad/res/menu/list_context_menu.xml [new file with mode: 0644]
samples/NotePad/res/menu/list_options_menu.xml [new file with mode: 0644]
samples/NotePad/res/values/strings.xml
samples/NotePad/src/com/example/android/notepad/NoteEditor.java
samples/NotePad/src/com/example/android/notepad/NotesList.java
samples/NotePad/src/com/example/android/notepad/TitleEditor.java

index 2e0d85a..ddf4818 100644 (file)
@@ -22,8 +22,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.android.notepad" >
 
-    <uses-sdk android:targetSdkVersion="4" android:minSdkVersion="3"/>
-
+    <uses-sdk android:minSdkVersion="Froyo" />
     <application android:icon="@drawable/app_notes"
         android:label="@string/app_name"
     >
@@ -53,8 +52,7 @@
         </activity>
 
         <activity android:name="NoteEditor"
-            android:theme="@android:style/Theme.Light"
-            android:label="@string/title_note"
+            android:theme="@android:style/Theme.Light.Holo"
             android:screenOrientation="sensor"
             android:configChanges="keyboardHidden|orientation"
         >
@@ -83,7 +81,8 @@
 
         <activity android:name="TitleEditor"
             android:label="@string/title_edit_title"
-            android:theme="@android:style/Theme.Dialog"
+            android:icon="@drawable/ic_menu_edit"
+            android:theme="@android:style/Theme.Holo.Dialog"
             android:windowSoftInputMode="stateVisible">
             <!-- This activity implements an alternative action that can be
                  performed on notes: editing their title.  It can be used as
diff --git a/samples/NotePad/res/drawable-hdpi-v6/app_notes.png b/samples/NotePad/res/drawable-hdpi-v6/app_notes.png
deleted file mode 100644 (file)
index 3491823..0000000
Binary files a/samples/NotePad/res/drawable-hdpi-v6/app_notes.png and /dev/null differ
old mode 100755 (executable)
new mode 100644 (file)
index 258d3d1..3491823
Binary files a/samples/NotePad/res/drawable-hdpi/app_notes.png and b/samples/NotePad/res/drawable-hdpi/app_notes.png differ
diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_compose.png b/samples/NotePad/res/drawable-hdpi/ic_menu_compose.png
new file mode 100644 (file)
index 0000000..6ad379e
Binary files /dev/null and b/samples/NotePad/res/drawable-hdpi/ic_menu_compose.png differ
diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_delete.png b/samples/NotePad/res/drawable-hdpi/ic_menu_delete.png
new file mode 100644 (file)
index 0000000..2aed26a
Binary files /dev/null and b/samples/NotePad/res/drawable-hdpi/ic_menu_delete.png differ
diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_edit.png b/samples/NotePad/res/drawable-hdpi/ic_menu_edit.png
new file mode 100644 (file)
index 0000000..602dd10
Binary files /dev/null and b/samples/NotePad/res/drawable-hdpi/ic_menu_edit.png differ
diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_revert.png b/samples/NotePad/res/drawable-hdpi/ic_menu_revert.png
new file mode 100644 (file)
index 0000000..11860a4
Binary files /dev/null and b/samples/NotePad/res/drawable-hdpi/ic_menu_revert.png differ
diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_save.png b/samples/NotePad/res/drawable-hdpi/ic_menu_save.png
new file mode 100644 (file)
index 0000000..fc26c5d
Binary files /dev/null and b/samples/NotePad/res/drawable-hdpi/ic_menu_save.png differ
diff --git a/samples/NotePad/res/drawable-mdpi/app_notes.png b/samples/NotePad/res/drawable-mdpi/app_notes.png
deleted file mode 100644 (file)
index 0479138..0000000
Binary files a/samples/NotePad/res/drawable-mdpi/app_notes.png and /dev/null differ
diff --git a/samples/NotePad/res/drawable-mdpi/live_folder_notes.png b/samples/NotePad/res/drawable-mdpi/live_folder_notes.png
deleted file mode 100644 (file)
index ac54a49..0000000
Binary files a/samples/NotePad/res/drawable-mdpi/live_folder_notes.png and /dev/null differ
diff --git a/samples/NotePad/res/drawable/ic_menu_compose.png b/samples/NotePad/res/drawable/ic_menu_compose.png
new file mode 100644 (file)
index 0000000..1b4733e
Binary files /dev/null and b/samples/NotePad/res/drawable/ic_menu_compose.png differ
diff --git a/samples/NotePad/res/drawable/ic_menu_delete.png b/samples/NotePad/res/drawable/ic_menu_delete.png
new file mode 100755 (executable)
index 0000000..7d95494
Binary files /dev/null and b/samples/NotePad/res/drawable/ic_menu_delete.png differ
diff --git a/samples/NotePad/res/drawable/ic_menu_edit.png b/samples/NotePad/res/drawable/ic_menu_edit.png
new file mode 100755 (executable)
index 0000000..41a9c2e
Binary files /dev/null and b/samples/NotePad/res/drawable/ic_menu_edit.png differ
diff --git a/samples/NotePad/res/drawable/ic_menu_revert.png b/samples/NotePad/res/drawable/ic_menu_revert.png
new file mode 100644 (file)
index 0000000..e7e04f5
Binary files /dev/null and b/samples/NotePad/res/drawable/ic_menu_revert.png differ
diff --git a/samples/NotePad/res/drawable/ic_menu_save.png b/samples/NotePad/res/drawable/ic_menu_save.png
new file mode 100644 (file)
index 0000000..36d50b3
Binary files /dev/null and b/samples/NotePad/res/drawable/ic_menu_save.png differ
index d7da99e..552e105 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!-- Copyright (C) 2010 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.
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <view xmlns:android="http://schemas.android.com/apk/res/android"
     class="com.example.android.notepad.NoteEditor$LinedEditText"
     android:id="@+id/note"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@android:color/transparent"
-    android:padding="5dip"
+    android:padding="5dp"
     android:scrollbars="vertical"
     android:fadingEdge="vertical"
     android:gravity="top"
index e11c5ee..cafa9b1 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2006 The Android Open Source Project
+<!-- Copyright (C) 2010 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.
index 3593ec6..bbf38fc 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!-- Copyright (C) 2010 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.
@@ -24,7 +24,8 @@
                                          
     <EditText android:id="@+id/title" 
         android:maxLines="1" 
-        android:layout_marginTop="2dip"
+        android:layout_marginTop="2dp"
+        android:layout_marginBottom="15dp"
         android:layout_width="wrap_content"
        android:ems="25"
         android:layout_height="wrap_content" 
@@ -36,6 +37,7 @@
         android:layout_width="wrap_content" 
         android:layout_height="wrap_content" 
         android:layout_gravity="right"
-        android:text="@string/button_ok" />
+        android:text="@string/button_ok"
+        android:onClick="onClickOk" />
                
 </LinearLayout>
diff --git a/samples/NotePad/res/menu/editor_options_menu.xml b/samples/NotePad/res/menu/editor_options_menu.xml
new file mode 100644 (file)
index 0000000..ce385a6
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_save"
+          android:icon="@drawable/ic_menu_save"
+          android:alphabeticShortcut='s'
+          android:title="@string/menu_save"
+          android:showAsAction="always" />
+    <item android:id="@+id/menu_revert"
+          android:icon="@drawable/ic_menu_revert"
+          android:title="@string/menu_revert" />
+    <item android:id="@+id/menu_delete"
+          android:icon="@drawable/ic_menu_delete"
+          android:title="@string/menu_delete"
+          android:showAsAction="always" />
+</menu>
\ 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 (file)
index 0000000..71509c6
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/context_open"
+          android:title="@string/menu_open" />
+    <item android:id="@+id/context_copy"
+          android:title="@string/menu_copy" />
+    <item android:id="@+id/context_delete"
+          android:title="@string/menu_delete" />
+</menu>
\ 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 (file)
index 0000000..a60e6a4
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <!--  This is our one standard application action (creating a new note). -->
+    <item android:id="@+id/menu_add"
+          android:icon="@drawable/ic_menu_compose"
+          android:title="@string/menu_add"
+          android:alphabeticShortcut='a'
+          android:showAsAction="always" />
+    <!--  If there is currently data in the clipboard, this adds a PASTE menu item to the menu
+          so that the user can paste in the data.. -->
+    <item android:id="@+id/menu_paste"
+          android:icon="@drawable/ic_menu_compose"
+          android:title="@string/menu_paste"
+          android:alphabeticShortcut='p' />
+</menu>
\ No newline at end of file
index 43be4dd..26d23d0 100644 (file)
 -->
 
 <resources>
-    <string name="menu_copy">Copy</string>
+    <string name="app_name">NotePad</string>
+    <string name="live_folder_name">Notes</string>
+
+    <string name="title_edit_title">Note title:</string>
+    <string name="title_create">New note</string>
+    <string name="title_edit">Edit: %1$s</string>
+    <string name="title_notes_list">Notes</string>
+
+    <string name="menu_add">New note</string>
+    <string name="menu_save">Save</string>
     <string name="menu_delete">Delete</string>
-    <string name="menu_insert">Add note</string>
+    <string name="menu_open">Open</string>
+    <string name="menu_revert">Revert changes</string>
+    <string name="menu_copy">Copy</string>
     <string name="menu_paste">Paste</string>
-    <string name="menu_revert">Revert</string>
-    <string name="menu_discard">Discard</string>
+
+    <string name="button_ok">OK</string>
+    <string name="text_title">Title:</string>
 
     <string name="resolve_edit">Edit note</string>
-    <string name="resolve_title">Edit title</string>  
+    <string name="resolve_title">Edit title</string>
 
-    <string name="title_create">Create note</string>
-    <string name="title_edit">Edit note</string>
-       <string name="title_notes_list">Note pad</string>   
-       <string name="title_note">Note</string>  
-       <string name="title_edit_title">Note title:</string>  
-       
-       <string name="app_name">Note Pad</string>  
-       <string name="live_folder_name">Notes</string>
-       
-       <string name="button_ok">OK</string>  
-       
-       <string name="error_title">Error</string>
-       <string name="error_message">Error loading note</string>
-</resources>
+    <string name="error_title">Error</string>
+    <string name="error_message">Error loading note</string>
+    <string name="nothing_to_save">There is nothing to save</string>
+</resources>
\ No newline at end of file
index da85974..a3b8b38 100644 (file)
 
 package com.example.android.notepad;
 
-import com.example.android.notepad.NotePad;
-
 import android.app.Activity;
-import android.content.ClipboardManager;
 import android.content.ClipData;
+import android.content.ClipboardManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 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;
@@ -35,6 +34,7 @@ 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;
 
@@ -51,7 +51,7 @@ import android.widget.EditText;
  */
 public class NoteEditor extends Activity {
     // For logging and debugging purposes
-    private static final String TAG = "Notes";
+    private static final String TAG = "NoteEditor";
 
     /*
      * Creates a projection that returns the note ID and the note contents.
@@ -62,29 +62,17 @@ public class NoteEditor extends Activity {
             NotePad.Notes.COLUMN_NAME_TITLE,
             NotePad.Notes.COLUMN_NAME_NOTE
     };
-    // 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;
 
     // A label for the saved state of the activity
     private static final String ORIGINAL_CONTENT = "origContent";
 
-    // Menu item identifiers
-    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;
-
     // This Activity can be started by more than one action. Each action is represented
     // as a "state" constant
     private static final int STATE_EDIT = 0;
     private static final int STATE_INSERT = 1;
-    private static final int STATE_PASTE = 2;
 
     // Global mutable variables
     private int mState;
-    private boolean mNoteOnly = false;
     private Uri mUri;
     private Cursor mCursor;
     private EditText mText;
@@ -199,15 +187,6 @@ public class NoteEditor extends Activity {
             // set the result to be returned.
             setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));
 
-            // For a paste, initializes the data from clipboard.
-            if (Intent.ACTION_PASTE.equals(action)) {
-
-                // Does the paste
-                performPaste();
-                // Switches the state to PASTE. The title can not be modified.
-                mState = STATE_PASTE;
-            }
-
         // If the action was other than EDIT or INSERT:
         } else {
 
@@ -218,12 +197,6 @@ public class NoteEditor extends Activity {
             return;
         }
 
-        // Sets the layout for this Activity. See res/layout/note_editor.xml
-        setContentView(R.layout.note_editor);
-
-        // Gets a handle to the EditText in the the layout.
-        mText = (EditText) findViewById(R.id.note);
-
         /*
          * Using the URI passed in with the triggering Intent, gets the note or notes in
          * the provider.
@@ -240,6 +213,21 @@ public class NoteEditor extends Activity {
             null          // Use the default sort order (modification date, descending)
         );
 
+        // For a paste, initializes the data from clipboard.
+        // (Must be done after mCursor is initialized.)
+        if (Intent.ACTION_PASTE.equals(action)) {
+            // Does the paste
+            performPaste();
+            // Switches the state to EDIT so the title can be modified.
+            mState = STATE_EDIT;
+        }
+
+        // Sets the layout for this Activity. See res/layout/note_editor.xml
+        setContentView(R.layout.note_editor);
+
+        // Gets a handle to the EditText in the the layout.
+        mText = (EditText) findViewById(R.id.note);
+
         /*
          * If this Activity had stopped previously, its state was written the ORIGINAL_CONTENT
          * location in the saved Instance state. This gets the state.
@@ -266,6 +254,8 @@ public class NoteEditor extends Activity {
          * process. This tests that it's not null, since it should always contain data.
          */
         if (mCursor != null) {
+            // Requery in case something changed while paused (such as the title)
+            mCursor.requery();
 
             /* Moves to the first record. Always call moveToFirst() before accessing data in
              * a Cursor for the first time. The semantics of using a Cursor are that when it is
@@ -276,12 +266,14 @@ public class NoteEditor extends Activity {
 
             // Modifies the window title for the Activity according to the current Activity state.
             if (mState == STATE_EDIT) {
-
-                // Sets the title to Edit for edits
-                setTitle(getText(R.string.title_edit));
-
-            // Sets the title to "create" for inserts and pastes
-            } else if (mState == STATE_INSERT || mState == STATE_PASTE) {
+                // Set the title of the Activity to include the note title
+                int colTitleIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_TITLE);
+                String title = mCursor.getString(colTitleIndex);
+                Resources res = getResources();
+                String text = String.format(res.getString(R.string.title_edit), title);
+                setTitle(text);
+            // Sets the title to "create" for inserts
+            } else if (mState == STATE_INSERT) {
                 setTitle(getText(R.string.title_create));
             }
 
@@ -294,7 +286,8 @@ public class NoteEditor extends Activity {
 
             // Gets the note text from the Cursor and puts it in the TextView, but doesn't change
             // the text cursor's position.
-            String note = mCursor.getString(COLUMN_INDEX_NOTE);
+            int colNoteIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);
+            String note = mCursor.getString(colNoteIndex);
             mText.setTextKeepState(note);
 
             // Stores the original note text, to allow the user to revert changes.
@@ -361,7 +354,7 @@ public class NoteEditor extends Activity {
              * even if the note was being edited, the assumption being that the user wanted to
              * "clear out" (delete) the note.
              */
-            if (isFinishing() && (length == 0) && !mNoteOnly) {
+            if (isFinishing() && (length == 0)) {
                 setResult(RESULT_CANCELED);
                 deleteNote();
 
@@ -371,11 +364,13 @@ public class NoteEditor extends Activity {
                  * onCreate() inserted a new empty note into the provider, and it is this new note
                  * that is being edited.
                  */
-            } else {
-
+            } else if (mState == STATE_EDIT) {
                 // Creates a map to contain the new values for the columns
-                updateNote(text, null, !mNoteOnly);
-            }
+                updateNote(text, null);
+            } else if (mState == STATE_INSERT) {
+                updateNote(text, text);
+                mState = STATE_EDIT;
+          }
         }
     }
 
@@ -391,72 +386,38 @@ public class NoteEditor extends Activity {
      */
     @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);
 
-        // Builds the menus that are shown when editing. These are 'revert' to undo changes, and
-        // 'delete' to delete the note.
+        // Only add extra menu items for a saved note 
         if (mState == STATE_EDIT) {
-
-            // Adds the 'revert' menu item, and sets its shortcut to numeric 0, letter 'r' and its
-            // icon to the Android standard revert icon.
-            menu.add(0, REVERT_ID, 0, R.string.menu_revert)
-                    .setShortcut('0', 'r')
-                    .setIcon(android.R.drawable.ic_menu_revert);
-            if (!mNoteOnly) {
-
-                // Adds the 'delete' menu item, and sets its shortcut to numeric 1, letter 'd'
-                // and its icon to the Android standard delete icon
-                menu.add(0, DELETE_ID, 0, R.string.menu_delete)
-                        .setShortcut('1', 'd')
-                        .setIcon(android.R.drawable.ic_menu_delete);
-            }
-
-        // Builds the menus that are shown when inserting. The only option is 'Discard' to throw
-        // away the new note.
-        } else {
-            menu.add(0, DISCARD_ID, 0, R.string.menu_discard)
-                    .setShortcut('0', 'd')
-                    .setIcon(android.R.drawable.ic_menu_delete);
-        }
-
-        /*
-         * Appends menu items for any Activity declarations that implement an alternative action
-         * for this Activity's MIME type, one menu item for each Activity.
-         */
-        if (!mNoteOnly) {
-
-            // Makes a new Intent with the URI data passed to this Activity
-            Intent intent = new Intent(null, getIntent().getData());
-
-            // Adds the ALTERNATIVE category to the Intent.
+            // 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, mUri);
             intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
+            menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
+                    new ComponentName(this, NoteEditor.class), null, intent, 0, null);
+        }
 
-            /*
-             * Constructs a new ComponentName object that represents the current Activity.
-             */
-            ComponentName component = new ComponentName(
-                this,
-                NoteEditor.class);
+        return super.onCreateOptionsMenu(menu);
+    }
 
-            /*
-             * In the ALTERNATIVE menu group, adds an option for each Activity that is registered to
-             * handle this Activity's MIME type. The Intent describes what type of items should be
-             * added to the menu; in this case, Activity declarations with category ALTERNATIVE.
-             */
-            menu.addIntentOptions(
-                Menu.CATEGORY_ALTERNATIVE,  // The menu group to add the items to.
-                Menu.NONE,                  // No unique ID is needed.
-                Menu.NONE,                  // No ordering is needed.
-                component,                  // The current Activity object's component name
-                null,                       // No specific items need to be placed first.
-                intent,                     // The intent containing the type of items to add.
-                Menu.NONE,                  // No flags are necessary.
-                null                        // No need to generate an array of menu items.
-            );
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        // Check if note has changed and enable/disable the revert option
+        int colNoteIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);
+        String savedNote = mCursor.getString(colNoteIndex);
+        String currentNote = mText.getText().toString();
+        if (savedNote.equals(currentNote)) {
+            menu.findItem(R.id.menu_revert).setVisible(false);
+        } else {
+            menu.findItem(R.id.menu_revert).setVisible(true);
         }
-
-        // The method returns TRUE, so that further menu processing is not done.
-        return true;
+        return super.onPrepareOptionsMenu(menu);
     }
 
     /**
@@ -470,29 +431,21 @@ public class NoteEditor extends Activity {
      */
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-
-        // Chooses the action to perform
+        // Handle all of the possible menu actions.
         switch (item.getItemId()) {
-
-        // Deletes the note and close the Activity.
-        case DELETE_ID:
-        deleteNote();
-        finish();
-        break;
-
-        // Discards the new note.
-        case DISCARD_ID:
-        cancelNote();
-        break;
-
-        // Discards any changes to an edited note.
-        case REVERT_ID:
-        cancelNote();
-        break;
+        case R.id.menu_save:
+            String text = mText.getText().toString();
+            updateNote(text, null);
+            finish();
+            break;
+        case R.id.menu_delete:
+            deleteNote();
+            finish();
+            break;
+        case R.id.menu_revert:
+            cancelNote();
+            break;
         }
-
-        // Continues with processing the menu item. In effect, if the item was an alternative
-        // action, this invokes the Activity for that action.
         return super.onOptionsItemSelected(item);
     }
 
@@ -540,8 +493,10 @@ public class NoteEditor extends Activity {
                 // (moveToFirst() returns true), then this gets the note data from it.
                 if (orig != null) {
                     if (orig.moveToFirst()) {
-                        text = orig.getString(COLUMN_INDEX_NOTE);
-                        title = orig.getString(COLUMN_INDEX_TITLE);
+                        int colNoteIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_NOTE);
+                        int colTitleIndex = mCursor.getColumnIndex(NotePad.Notes.COLUMN_NAME_TITLE);
+                        text = orig.getString(colNoteIndex);
+                        title = orig.getString(colTitleIndex);
                     }
 
                     // Closes the cursor.
@@ -556,7 +511,7 @@ public class NoteEditor extends Activity {
             }
 
             // Updates the current note with the retrieved title and text.
-            updateNote(text, title, true);
+            updateNote(text, title);
         }
     }
 //END_INCLUDE(paste)
@@ -565,44 +520,40 @@ public class NoteEditor extends Activity {
      * Replaces the current note contents with the text and title provided as arguments.
      * @param text The new note contents to use.
      * @param title The new note title to use
-     * @param updateTitle <em>true</em> if the title should be updated. This also updates the
-     * modification timestamp to the current time.
      */
-    private final void updateNote(String text, String title, boolean updateTitle) {
+    private final void updateNote(String text, String title) {
 
         // Sets up a map to contain values to be updated in the provider.
         ContentValues values = new ContentValues();
-
-        // If updateTitle is true, sets the modification date/time stamp to now.
-        if (updateTitle) {
-            values.put(NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE, System.currentTimeMillis());
-
-            // If the action is to insert a new note, this creates an initial title for it.
-            if (mState == STATE_INSERT) {
-
-                // If no title was provided as an argument, create one from the note text.
-                if (title == null) {
-
-                    // Get the note's length
-                    int length = text.length();
-
-                    // Sets the title by getting a substring of the text that is 31 characters long
-                    // or the number of characters in the note plus one, whichever is smaller.
-                    title = text.substring(0, Math.min(30, length));
-
-                    // If the resulting length is more than 30 characters, chops off any
-                    // trailing spaces
-                    if (length > 30) {
-                        int lastSpace = title.lastIndexOf(' ');
-                        if (lastSpace > 0) {
-                            title = title.substring(0, lastSpace);
-                        }
+        values.put(NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE, System.currentTimeMillis());
+
+        // If the action is to insert a new note, this creates an initial title for it.
+        if (mState == STATE_INSERT) {
+
+            // If no title was provided as an argument, create one from the note text.
+            if (title == null) {
+  
+                // Get the note's length
+                int length = text.length();
+
+                // Sets the title by getting a substring of the text that is 31 characters long
+                // or the number of characters in the note plus one, whichever is smaller.
+                title = text.substring(0, Math.min(30, length));
+  
+                // If the resulting length is more than 30 characters, chops off any
+                // trailing spaces
+                if (length > 30) {
+                    int lastSpace = title.lastIndexOf(' ');
+                    if (lastSpace > 0) {
+                        title = title.substring(0, lastSpace);
                     }
                 }
-
-                // In the values map, sets the value of the title
-                values.put(NotePad.Notes.COLUMN_NAME_TITLE, title);
             }
+            // In the values map, sets the value of the title
+            values.put(NotePad.Notes.COLUMN_NAME_TITLE, title);
+        } else if (title != null) {
+            // In the values map, sets the value of the title
+            values.put(NotePad.Notes.COLUMN_NAME_TITLE, title);
         }
 
         // This puts the desired notes text into the map.
@@ -634,8 +585,6 @@ public class NoteEditor extends Activity {
      * newly created, or reverts to the original text of the note i
      */
     private final void cancelNote() {
-
-        // If
         if (mCursor != null) {
             if (mState == STATE_EDIT) {
                 // Put the original note text back into the database
index 6229dd2..8f0b2cb 100644 (file)
@@ -31,6 +31,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;
@@ -53,12 +54,6 @@ public class NotesList extends ListActivity {
     // For logging and debugging
     private static final String TAG = "NotesList";
 
-    // Menu item ids
-    public static final int MENU_ITEM_DELETE = Menu.FIRST;
-    public static final int MENU_ITEM_COPY = Menu.FIRST + 1;
-    public static final int MENU_ITEM_INSERT = Menu.FIRST + 2;
-    public static final int MENU_ITEM_PASTE = Menu.FIRST + 3;
-
     /**
      * The columns needed by the cursor adapter
      */
@@ -70,8 +65,6 @@ public class NotesList extends ListActivity {
     /** The index of the title column */
     private static final int COLUMN_INDEX_TITLE = 1;
 
-    private MenuItem mPasteItem;
-
     /**
      * onCreate is called when Android starts this Activity from scratch.
      */
@@ -159,70 +152,20 @@ public class NotesList extends ListActivity {
      */
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate menu from XML resource
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.list_options_menu, menu);
 
-        // The parent method creates the default method with the standard system items.
-        super.onCreateOptionsMenu(menu);
-
-        // Adds an Insert menu item
-        MenuItem menuItem = menu.add(
-            Menu.NONE,                    // No menu group.
-            MENU_ITEM_INSERT,             // Unique ID for this item.
-            Menu.NONE,                    // No order within the group.
-            R.string.menu_insert          // Displayed text for the menu item.
-        );
-
-        // Sets keyboard shortcuts for the menu item, either "3" or "a";
-        menuItem.setShortcut('3', 'a');
-
-        // Sets the icon for the menu item
-        menuItem.setIcon(android.R.drawable.ic_menu_add);
-
-        // If there is currently data in the clipboard, this adds a PASTE menu item to the menu
-        // so that the user can paste in the data.
-        mPasteItem = menu.add(
-                Menu.NONE,                // No menu group.
-                MENU_ITEM_PASTE,          // A unique ID for this item
-                Menu.NONE,                // No menu order
-                R.string.menu_paste       // The displayed text
-        ).setShortcut('4', 'p');          // Set the keyboard shortcuts for this new item.
-
-        // Generates any additional actions that can be performed on the
+        // 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.
-
-        /* Creates a new Intent with the same incoming data and no defined action.
-         * It also sets its category to ALTERNATIVE. This prepares the Intent as a place
-         * to group alternative options in the menu.
-         */
         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);
 
-        /* Creates a ComponentName from the current Context and this Activity object's
-         * class object.
-         */
-        ComponentName component = new ComponentName(this, NotesList.class);
-
-        /*
-         * Adds any other activities that want to be alternatives for this view. In effect,
-         * any application can add itself as an alternative on the options menu.
-         */
-        menu.addIntentOptions(
-            Menu.CATEGORY_ALTERNATIVE,   // Add the options to the Alternatives group
-            Menu.NONE,                   // Do not use a unique ID
-            Menu.NONE,                   // No need to order the options
-            component,                   // The ComponentName of the Activity making the request.
-                                         // This Activity is excluded from the list of alternatives.
-            null,                        // No specific items are listed first.
-            intent,                      // The Intent to resolve to, in effect, an Intent listing
-                                         // the alternatives
-            Menu.NONE,                   // no flags are needed
-            null                         // Since no specifics were used, so a menu item array is
-                                         // not needed.
-        );
-
-        // Returns true so that the menu is displayed.
-        return true;
+        return super.onCreateOptionsMenu(menu);
     }
 
     @Override
@@ -233,11 +176,13 @@ public class NotesList extends ListActivity {
         ClipboardManager clipboard = (ClipboardManager)
                 getSystemService(Context.CLIPBOARD_SERVICE);
 
+
+        MenuItem mPasteItem = menu.findItem(R.id.menu_paste);
+
         // If the clipboard contains an item, enables the Paste option on the menu.
         if (clipboard.hasPrimaryClip()) {
             mPasteItem.setEnabled(true);
         } else {
-
             // If the clipboard is empty, disables the menu's Paste option.
             mPasteItem.setEnabled(false);
         }
@@ -274,7 +219,6 @@ public class NotesList extends ListActivity {
              */
             intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
 
-
             /*
              * Add alternatives to the menu
              */
@@ -318,36 +262,26 @@ public class NotesList extends ListActivity {
      */
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-
-        // Gets the ID of the selected item
         switch (item.getItemId()) {
-
-        // If the menu item is Insert
-        case MENU_ITEM_INSERT:
-
-            /*
-             * Launches a new Activity using an Intent. The intent filter for the Activity
-             * has to have action ACTION_INSERT. No category is set, so DEFAULT is assumed.
-             * In effect, this starts the NoteEditor Activity in NotePad.
-             */
-            startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));
-            return true;
-
-        // If the menu item is Paste
-        case MENU_ITEM_PASTE:
-
-            /*
-             * Launches a new Activity using an Intent. The intent filter for the Activity
-             * has to have action ACTION_PASTE. No category is set, so DEFAULT is assumed.
-             * In effect, this starts the NoteEditor Activity in NotePad.
-             */
-            startActivity(new Intent(Intent.ACTION_PASTE, getIntent().getData()));
-            return true;
+        case R.id.menu_add:
+          /*
+           * Launches a new Activity using an Intent. The intent filter for the Activity
+           * has to have action ACTION_INSERT. No category is set, so DEFAULT is assumed.
+           * In effect, this starts the NoteEditor Activity in NotePad.
+           */
+           startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));
+           return true;
+        case R.id.menu_paste:
+          /*
+           * Launches a new Activity using an Intent. The intent filter for the Activity
+           * has to have action ACTION_PASTE. No category is set, so DEFAULT is assumed.
+           * In effect, this starts the NoteEditor Activity in NotePad.
+           */
+          startActivity(new Intent(Intent.ACTION_PASTE, getIntent().getData()));
+          return true;
+        default:
+            return super.onOptionsItemSelected(item);
         }
-
-        // If the menu item selected is not Insert or Paste, then this calls the regular
-        // processing to handle the item.
-        return super.onOptionsItemSelected(item);
     }
 
     /**
@@ -371,11 +305,9 @@ public class NotesList extends ListActivity {
 
         // Tries to get the position of the item in the ListView that was long-pressed.
         try {
-
             // Casts the incoming data object into the type for AdapterView objects.
             info = (AdapterView.AdapterContextMenuInfo) menuInfo;
         } catch (ClassCastException e) {
-
             // If the menu object can't be cast, logs an error.
             Log.e(TAG, "bad menuInfo", e);
             return;
@@ -392,29 +324,27 @@ public class NotesList extends ListActivity {
         // If the cursor is empty, then for some reason the adapter can't get the data from the
         // provider, so returns null to the caller.
         if (cursor == null) {
-
             // For some reason the requested item isn't available, do nothing
             return;
         }
 
+        // Inflate menu from XML resource
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.list_context_menu, menu);
+
         // Sets the menu header to be the title of the selected note.
         menu.setHeaderTitle(cursor.getString(COLUMN_INDEX_TITLE));
 
-        // Adds a menu item to copy the note to the context menu
-        menu.add(
-            Menu.NONE,          // No grouping is needed for this menu
-            MENU_ITEM_COPY,     // A unique ID for this menu item.
-            Menu.NONE,          // No ordering is necessary in this menu
-            R.string.menu_copy  // The resource ID for the string to display for this item.
-        );
-
-        // Adds a menu item to delete the note to the context menu
-        menu.add(
-            Menu.NONE,            // No grouping is needed for this menu
-            MENU_ITEM_DELETE,     // A unique ID for this menu item.
-            Menu.NONE,            // No ordering is necessary in this menu
-            R.string.menu_delete  // The resource ID for the string to display for this item.
-        );
+        // 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);
     }
 
     /**
@@ -429,7 +359,6 @@ public class NotesList extends ListActivity {
      */
     @Override
     public boolean onContextItemSelected(MenuItem item) {
-
         // The data from the menu item.
         AdapterView.AdapterContextMenuInfo info;
 
@@ -446,7 +375,6 @@ public class NotesList extends ListActivity {
          * note ID, to onContextItemSelected() via the item parameter.
          */
         try {
-
             // Casts the data object in the item into the type for AdapterView objects.
             info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
         } catch (ClassCastException e) {
@@ -457,58 +385,51 @@ public class NotesList extends ListActivity {
             // Triggers default processing of the menu item.
             return false;
         }
+        // Appends the selected note's ID to the URI sent with the incoming Intent.
+        Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), info.id);
 
         /*
-         * Gets the menu item's ID and compares it to known actions. The only actions that are
-         * implemented are COPY and DELETE (set in onCreateContextMenu()).
+         * Gets the menu item's ID and compares it to known actions.
          */
         switch (item.getItemId()) {
-
-            // Deletes the selected note
-            case MENU_ITEM_DELETE: {
-
-                // Appends the selected note's ID to the URI sent with the incoming Intent.
-                Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), info.id);
-
-                // Deletes the note from the provider by passing in a URI in note ID format.
-                // Please see the introductory note about performing provider operations on the
-                // UI thread.
-                getContentResolver().delete(
-                    noteUri,  // The URI of the provider
-                    null,     // No where clause is needed, since only a single note ID is being
-                              // passed in.
-                    null      // No where clause is used, so no where arguments are needed.
-                );
-
-                // Returns to the caller and skips further processing.
-                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;
 //BEGIN_INCLUDE(copy)
-            // Copies the selected note to the clipboard
-            case MENU_ITEM_COPY: {
-
-                // Gets a handle to the clipboard service.
-                ClipboardManager clipboard = (ClipboardManager)
-                        getSystemService(Context.CLIPBOARD_SERVICE);
-
-                // Appends the selected note's ID to the URI sent with the incoming Intent.
-                Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), info.id);
-
-                // Copies the notes URI to the clipboard. In effect, this copies the note itself
-                clipboard.setPrimaryClip(ClipData.newUri(   // new clipboard item holding a URI
-                        getContentResolver(),               // resolver to retrieve URI info
-                        "Note",                             // label for the clip
-                        null,                               // icon for the clip
-                        noteUri)                            // the URI
-                );
-
-                // Returns to the caller and skips further processing.
-                return true;
-            }
+        case R.id.context_copy:
+            // Gets a handle to the clipboard service.
+            ClipboardManager clipboard = (ClipboardManager)
+                    getSystemService(Context.CLIPBOARD_SERVICE);
+  
+            // Copies the notes URI to the clipboard. In effect, this copies the note itself
+            clipboard.setPrimaryClip(ClipData.newUri(   // new clipboard item holding a URI
+                    getContentResolver(),               // resolver to retrieve URI info
+                    "Note",                             // label for the clip
+                    null,                               // icon for the clip
+                    noteUri)                            // the URI
+            );
+  
+            // Returns to the caller and skips further processing.
+            return true;
 //END_INCLUDE(copy)
+        case R.id.context_delete:
+  
+            // Deletes the note from the provider by passing in a URI in note ID format.
+            // Please see the introductory note about performing provider operations on the
+            // UI thread.
+            getContentResolver().delete(
+                noteUri,  // The URI of the provider
+                null,     // No where clause is needed, since only a single note ID is being
+                          // passed in.
+                null      // No where clause is used, so no where arguments are needed.
+            );
+  
+            // Returns to the caller and skips further processing.
+            return true;
+        default:
+            return super.onContextItemSelected(item);
         }
-        return false;
     }
 
     /**
index b41a35c..5abe97b 100644 (file)
 
 package com.example.android.notepad;
 
-import com.example.android.notepad.NotePad;
-
 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;
 
 /**
@@ -36,7 +33,7 @@ import android.widget.EditText;
  * application should use the {@link android.content.AsyncQueryHandler}
  * or {@link android.os.AsyncTask} object to perform operations asynchronously on a separate thread.
  */
-public class TitleEditor extends Activity implements View.OnClickListener {
+public class TitleEditor extends Activity {
 
     /**
      * This is a special intent action that means "edit the title of a note".
@@ -95,11 +92,6 @@ public class TitleEditor extends Activity implements View.OnClickListener {
 
         // Gets the View ID for the EditText box
         mText = (EditText) this.findViewById(R.id.title);
-
-        // Sets up a listener for the OK button. Gets the Button by its ID, then sets its
-        // onClickListener to this Activity.
-        Button b = (Button) findViewById(R.id.ok);
-        b.setOnClickListener(this);
     }
 
     /**
@@ -169,16 +161,7 @@ public class TitleEditor extends Activity implements View.OnClickListener {
         }
     }
 
-    /**
-     * This method is called when the user clicks anywhere in the title text box.
-     *
-     * It calls finish(), which immediately triggers the onPause() method in this Activity. In
-     * turn, onPause() saves the text currently in the title text box to the note.
-     */
-    public void onClick(View v) {
-
-        // Calls finish to force the Activity to shut down. In the lifecycle, this forces a call to
-        // onPause(), which saves the work the user has done.
+    public void onClickOk(View v) {
         finish();
     }
 }