diff options
| author | Scott Main <smain@google.com> | 2010-10-19 17:19:03 -0700 |
|---|---|---|
| committer | Scott Main <smain@google.com> | 2010-10-21 12:46:04 -0700 |
| commit | 875234d9405358569599a203678a36f042aa6489 (patch) | |
| tree | 14b8e697422902ae9ba7550a22546d677c85ca35 /samples/NotePad | |
| parent | 9bfa6f90b8c56ed7404c0c07a70e27a9fbad3c23 (diff) | |
| download | android_development-875234d9405358569599a203678a36f042aa6489.tar.gz android_development-875234d9405358569599a203678a36f042aa6489.tar.bz2 android_development-875234d9405358569599a203678a36f042aa6489.zip | |
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
Diffstat (limited to 'samples/NotePad')
34 files changed, 274 insertions, 307 deletions
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. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.android.notepad" -> + package="com.example.android.notepad" > + <application android:icon="@drawable/app_notes" - android:label="@string/app_name" - > + android:label="@string/app_name" > <provider android:name="NotePadProvider" - android:authorities="com.google.provider.NotePad" - /> + android:authorities="com.example.notepad.provider.NotePad" /> - <activity android:name="NotesList" android:label="@string/title_notes_list"> + <activity android:name="NotesList" + android:label="@string/title_notes_list"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> @@ -50,16 +49,13 @@ <activity android:name="NoteEditor" android:theme="@android:style/Theme.Light" - android:label="@string/title_note" - android:screenOrientation="sensor" - android:configChanges="keyboardHidden|orientation" - > + android:configChanges="keyboardHidden|orientation"> <!-- This filter says that we can view or edit the data of a single note --> <intent-filter android:label="@string/resolve_edit"> <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.EDIT" /> - <action android:name="com.android.notepad.action.EDIT_NOTE" /> + <action android:name="com.android.notes.action.EDIT_NOTE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.item/vnd.google.note" /> </intent-filter> @@ -77,6 +73,7 @@ <activity android:name="TitleEditor" android:label="@string/title_edit_title" android:theme="@android:style/Theme.Dialog" + android:icon="@drawable/ic_menu_edit" android:windowSoftInputMode="stateVisible"> <!-- This activity implements an alternative action that can be performed on notes: editing their title. It can be used as @@ -110,6 +107,6 @@ </application> - <uses-sdk android:targetSdkVersion="4" android:minSdkVersion="3"/> + <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="4"/> </manifest> diff --git a/samples/NotePad/res/drawable-hdpi-v6/app_notes.png b/samples/NotePad/res/drawable-hdpi-v6/app_notes.png Binary files differdeleted file mode 100644 index 34918237f..000000000 --- a/samples/NotePad/res/drawable-hdpi-v6/app_notes.png +++ /dev/null diff --git a/samples/NotePad/res/drawable-hdpi/app_notes.png b/samples/NotePad/res/drawable-hdpi/app_notes.png Binary files differindex 258d3d167..34918237f 100755..100644 --- a/samples/NotePad/res/drawable-hdpi/app_notes.png +++ b/samples/NotePad/res/drawable-hdpi/app_notes.png diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_compose.png b/samples/NotePad/res/drawable-hdpi/ic_menu_compose.png Binary files differnew file mode 100644 index 000000000..6ad379e22 --- /dev/null +++ b/samples/NotePad/res/drawable-hdpi/ic_menu_compose.png diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_delete.png b/samples/NotePad/res/drawable-hdpi/ic_menu_delete.png Binary files differnew file mode 100644 index 000000000..2aed26a1b --- /dev/null +++ b/samples/NotePad/res/drawable-hdpi/ic_menu_delete.png diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_discard.png b/samples/NotePad/res/drawable-hdpi/ic_menu_discard.png Binary files differnew file mode 100644 index 000000000..a54ea9d91 --- /dev/null +++ b/samples/NotePad/res/drawable-hdpi/ic_menu_discard.png diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_edit.png b/samples/NotePad/res/drawable-hdpi/ic_menu_edit.png Binary files differnew file mode 100644 index 000000000..602dd1041 --- /dev/null +++ b/samples/NotePad/res/drawable-hdpi/ic_menu_edit.png diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_revert.png b/samples/NotePad/res/drawable-hdpi/ic_menu_revert.png Binary files differnew file mode 100644 index 000000000..11860a4e1 --- /dev/null +++ b/samples/NotePad/res/drawable-hdpi/ic_menu_revert.png diff --git a/samples/NotePad/res/drawable-hdpi/ic_menu_save.png b/samples/NotePad/res/drawable-hdpi/ic_menu_save.png Binary files differnew file mode 100644 index 000000000..fc26c5d5f --- /dev/null +++ b/samples/NotePad/res/drawable-hdpi/ic_menu_save.png diff --git a/samples/NotePad/res/drawable-hdpi-v6/live_folder_notes.png b/samples/NotePad/res/drawable-hdpi/live_folder_notes.png Binary files differindex c6d26f5cb..c6d26f5cb 100644 --- a/samples/NotePad/res/drawable-hdpi-v6/live_folder_notes.png +++ b/samples/NotePad/res/drawable-hdpi/live_folder_notes.png diff --git a/samples/NotePad/res/drawable-ldpi-v6/app_notes.png b/samples/NotePad/res/drawable-ldpi/app_notes.png Binary files differindex 8432ce63b..8432ce63b 100644 --- a/samples/NotePad/res/drawable-ldpi-v6/app_notes.png +++ b/samples/NotePad/res/drawable-ldpi/app_notes.png diff --git a/samples/NotePad/res/drawable-ldpi-v6/live_folder_notes.png b/samples/NotePad/res/drawable-ldpi/live_folder_notes.png Binary files differindex d547cbf2c..d547cbf2c 100644 --- a/samples/NotePad/res/drawable-ldpi-v6/live_folder_notes.png +++ b/samples/NotePad/res/drawable-ldpi/live_folder_notes.png diff --git a/samples/NotePad/res/drawable-mdpi/app_notes.png b/samples/NotePad/res/drawable-mdpi/app_notes.png Binary files differdeleted file mode 100644 index 0479138d1..000000000 --- a/samples/NotePad/res/drawable-mdpi/app_notes.png +++ /dev/null diff --git a/samples/NotePad/res/drawable-mdpi/live_folder_notes.png b/samples/NotePad/res/drawable-mdpi/live_folder_notes.png Binary files differdeleted file mode 100644 index ac54a49ed..000000000 --- a/samples/NotePad/res/drawable-mdpi/live_folder_notes.png +++ /dev/null diff --git a/samples/NotePad/res/drawable-mdpi-v6/app_notes.png b/samples/NotePad/res/drawable/app_notes.png Binary files differindex 81d1c22e1..81d1c22e1 100644 --- a/samples/NotePad/res/drawable-mdpi-v6/app_notes.png +++ b/samples/NotePad/res/drawable/app_notes.png diff --git a/samples/NotePad/res/drawable/ic_menu_compose.png b/samples/NotePad/res/drawable/ic_menu_compose.png Binary files differnew file mode 100644 index 000000000..1b4733e42 --- /dev/null +++ b/samples/NotePad/res/drawable/ic_menu_compose.png diff --git a/samples/NotePad/res/drawable/ic_menu_delete.png b/samples/NotePad/res/drawable/ic_menu_delete.png Binary files differnew file mode 100755 index 000000000..7d954943d --- /dev/null +++ b/samples/NotePad/res/drawable/ic_menu_delete.png diff --git a/samples/NotePad/res/drawable/ic_menu_discard.png b/samples/NotePad/res/drawable/ic_menu_discard.png Binary files differnew file mode 100644 index 000000000..78222ea8e --- /dev/null +++ b/samples/NotePad/res/drawable/ic_menu_discard.png diff --git a/samples/NotePad/res/drawable/ic_menu_edit.png b/samples/NotePad/res/drawable/ic_menu_edit.png Binary files differnew file mode 100755 index 000000000..41a9c2e20 --- /dev/null +++ b/samples/NotePad/res/drawable/ic_menu_edit.png diff --git a/samples/NotePad/res/drawable/ic_menu_revert.png b/samples/NotePad/res/drawable/ic_menu_revert.png Binary files differnew file mode 100644 index 000000000..e7e04f531 --- /dev/null +++ b/samples/NotePad/res/drawable/ic_menu_revert.png diff --git a/samples/NotePad/res/drawable/ic_menu_save.png b/samples/NotePad/res/drawable/ic_menu_save.png Binary files differnew file mode 100644 index 000000000..36d50b387 --- /dev/null +++ b/samples/NotePad/res/drawable/ic_menu_save.png diff --git a/samples/NotePad/res/drawable-mdpi-v6/live_folder_notes.png b/samples/NotePad/res/drawable/live_folder_notes.png Binary files differindex c565cd0d1..c565cd0d1 100644 --- a/samples/NotePad/res/drawable-mdpi-v6/live_folder_notes.png +++ b/samples/NotePad/res/drawable/live_folder_notes.png diff --git a/samples/NotePad/res/layout/note_editor.xml b/samples/NotePad/res/layout/note_editor.xml index d7da99ee8..f142c713d 100644 --- a/samples/NotePad/res/layout/note_editor.xml +++ b/samples/NotePad/res/layout/note_editor.xml @@ -13,17 +13,15 @@ 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:layout_width="fill_parent" + android:layout_height="fill_parent" android:background="@android:color/transparent" - android:padding="5dip" + android:padding="5dp" android:scrollbars="vertical" android:fadingEdge="vertical" android:gravity="top" android:textSize="22sp" - android:capitalize="sentences" -/> + 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 @@ <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" - android:layout_width="match_parent" + android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:textAppearance="?android:attr/textAppearanceLarge" android:gravity="center_vertical" diff --git a/samples/NotePad/res/menu/editor_options_menu.xml b/samples/NotePad/res/menu/editor_options_menu.xml new file mode 100644 index 000000000..b2d14ac86 --- /dev/null +++ b/samples/NotePad/res/menu/editor_options_menu.xml @@ -0,0 +1,20 @@ +<?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" /> + <group android:id="@+id/menu_group_edit"> + <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" /> + </group> + <group android:id="@+id/menu_group_insert"> + <item android:id="@+id/menu_discard" + android:icon="@drawable/ic_menu_discard" + android:title="@string/menu_discard" /> + </group> +</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 index 000000000..acc8edd63 --- /dev/null +++ b/samples/NotePad/res/menu/list_context_menu.xml @@ -0,0 +1,7 @@ +<?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_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 index 000000000..975455432 --- /dev/null +++ b/samples/NotePad/res/menu/list_options_menu.xml @@ -0,0 +1,8 @@ +<?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:alphabeticShortcut='a' + android:title="@string/menu_add" /> +</menu>
\ 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 @@ --> <resources> + <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">Create note</string> + <string name="title_edit">Edit: \"%1$s\"</string> + <string name="title_notes_list">Notes</string> + + <string name="menu_add">Add note</string> + <string name="menu_save">Save</string> <string name="menu_delete">Delete</string> - <string name="menu_insert">Add note</string> - <string name="menu_revert">Revert</string> + <string name="menu_open">Open</string> + <string name="menu_revert">Revert changes</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="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="resolve_title">Edit title</string> + + <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 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(); - - // 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); + String text = mText.getText().toString(); + int length = text.length(); - // 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: - deleteNote(); + case R.id.menu_save: + saveNote(); finish(); break; - case DISCARD_ID: - cancelNote(); + case R.id.menu_delete: + deleteNote(); + finish(); 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<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); + 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<String, String>(); - 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 - * <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)</P> - */ - public static final String CREATED_DATE = "created"; - - /** - * The timestamp for when the note was last modified - * <P>Type: INTEGER (long)</P> - */ - public static final String MODIFIED_DATE = "modified"; - } -} |
