This is a manual merge of Ib7ea41079f3b268f3be1f86febdb1caed98bdd8e
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
@@ -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
|
||||
|
||||
|
Before Width: | Height: | Size: 3.8 KiB |
BIN
samples/NotePad/res/drawable-hdpi/app_notes.png
Executable file → Normal file
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 3.8 KiB |
BIN
samples/NotePad/res/drawable-hdpi/ic_menu_compose.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
samples/NotePad/res/drawable-hdpi/ic_menu_delete.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
samples/NotePad/res/drawable-hdpi/ic_menu_edit.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
samples/NotePad/res/drawable-hdpi/ic_menu_revert.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
samples/NotePad/res/drawable-hdpi/ic_menu_save.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
BIN
samples/NotePad/res/drawable/ic_menu_compose.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
samples/NotePad/res/drawable/ic_menu_delete.png
Executable file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
samples/NotePad/res/drawable/ic_menu_edit.png
Executable file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
samples/NotePad/res/drawable/ic_menu_revert.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
samples/NotePad/res/drawable/ic_menu_save.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -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.
|
||||
@@ -13,14 +13,13 @@
|
||||
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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
15
samples/NotePad/res/menu/editor_options_menu.xml
Normal file
@@ -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>
|
||||
9
samples/NotePad/res/menu/list_context_menu.xml
Normal file
@@ -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>
|
||||
15
samples/NotePad/res/menu/list_options_menu.xml
Normal file
@@ -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>
|
||||
@@ -15,27 +15,29 @@
|
||||
-->
|
||||
|
||||
<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="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>
|
||||
<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>
|
||||
@@ -16,16 +16,15 @@
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* Constructs a new ComponentName object that represents the current Activity.
|
||||
*/
|
||||
ComponentName component = new ComponentName(
|
||||
this,
|
||||
NoteEditor.class);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
);
|
||||
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
|
||||
new ComponentName(this, NoteEditor.class), null, intent, 0, null);
|
||||
}
|
||||
|
||||
// The method returns TRUE, so that further menu processing is not done.
|
||||
return true;
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
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();
|
||||
values.put(NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE, System.currentTimeMillis());
|
||||
|
||||
// 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 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) {
|
||||
|
||||
// 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();
|
||||
|
||||
// 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));
|
||||
|
||||
// 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);
|
||||
}
|
||||
// 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
|
||||
|
||||
@@ -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: {
|
||||
case R.id.context_copy:
|
||||
// Gets a handle to the clipboard service.
|
||||
ClipboardManager clipboard = (ClipboardManager)
|
||||
getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
|
||||
// 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
|
||||
);
|
||||
|
||||
// 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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,15 +16,12 @@
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||