Creating the Location Editor Activity

In this section, you will create an editor for the location field of the Friends database. You are going to make this Activity slightly different from the NameEditor Activity. Therefore, the code will be different and follow a slightly unfamiliar process.

If you explored the Google demo NotePad, you should have noticed that the "notes" editor is a white screen with a dynamically drawn line on it that repeats itself as needed. This effect is performed using a custom View. You are going to use this same custom View for the LocationEditor.

location_editor.xml

The first step is to create location_editor.xml and LocationEditor.java files for the layout and code, respectively. The layout file should contain a call to the custom View layout. The full layout is as follows:

<?xml version="1.0" encoding="utf-8"?>

<view xmlns:android="http://schemas.android.com/apk/res/android"

class="android_programmers_guide.FindAFriend.LocationEditor$MyEditText"

android:id="@+id/location"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:background="#ffffff"

android:padding="10dip"

android:scrollbars="vertical"

android:fadingEdge="vertical" />

The LocationEditor will also contain a menu system that will allow the user to discard, delete, or revert any changes they make. This will be a pretty complex Activity. Therefore, it is best to start at the beginning, the imports section of the LocationEditor.java.

LocationEditor.java

Take a look at the following imports for this Activity, many of which deal with drawing the custom View on the screen:

import android.app.Activity;

import android.content.ComponentName;

import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.util.AttributeSet; import android.view.Menu; import android.widget.EditText; import java.util.Map;

Next, set up your Activity's main class outline. There are a number of variables that you need to define for use throughout the LocationEditor:

public class LocationEditor extends Activity {

private static final String TAG = "Friends";

private static final int FRIEND_INDEX = 1; private static final int NAME_INDEX = 2; private static final int MODIFIED_INDEX = 3;

private static final String[] PROJECTION = new String[] { Friends.Friend._ID, // 0 Friends.Friend.LOCATION, // 1 Friends.Friend.NAME, // 2 Friends.Friend.MODIFIED_DATE // 3

private static final String ORIGINAL_CONTENT = "origContent";

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;

private static final int STATE_EDIT = 0; private static final int STATE_INSERT = 1;

private int mState; private boolean mNoteOnly = false; private Uri mURI; private Cursor mCursor;

private EditText mText; private String mOriginalContent;

Having performed the tasks in the previous sections of this chapter, the variable definitions here should be rather self-explanatory.

The next piece of code shows a subclass that you need to create. This subclass will draw to the screen the EditText that will be used for the LocationEditor. You are breaking this out so that you can call it as needed from the Activity. Keep in mind that you will dynamically draw a new EditText on the screen as is needed by the user. Pay special attention to the onDraw class that you need to override.

public static class MyEditText extends EditText { private Rect mRect; private Paint mPaint;

public MyEditText(Context context, AttributeSet attrs, Map params) { super(context, attrs, params);

mRect = new Rect(); mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(0xFF0000FF);

@Override protected void onDraw(Canvas canvas) {

int count = getLineCount(); Rect r = mRect; Paint paint = mPaint;

int baseline = getLineBounds(i, r);

canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);

super.onDraw(canvas);

Again, while this may look like a lot of code, there should be nothing foreign about it. This subclass simply draws a new EditText as needed to the screen.

Just as with the NameEditor, you will use the onResume( ) and onPause( ) methods to do your database work. Take a look at the code for each below:

protected void onResume() { super.onResume();

setTitle(getText(R.string.title_edit)); } else if (mState == STATE_INSERT) {

setTitle(getText(R.string.title_create));

String note = mCursor.getString(FRIEND_INDEX); mText.setTextKeepState(note);

if (mOriginalContent == null) { mOriginalContent = note;

setTitle(getText(R.string.error_title)); mText.setText(getText(R.string.error_message));

protected void onPause() { super.onPause();

String text = mText.getText().toString(); int length = text.length();

if (isFinishing() && (length == 0) && !mNoteOnly) { setResult(RESULT_CANCELED); deleteFriend(); } else {

mCursor.updateLong(MODIFIED_INDEX, System.currentTimeMillis());

String title = text.substring(0, Math.min(30, length));

int lastSpace = title.lastIndexOf(' '); if (lastSpace > 0) {

title = title.substring(0, lastSpace)

mCursor.updateString(NAME_INDEX, title);

mCursor.updateString(FRIEND_INDEX, text); managedCommitUpdates(mCursor);

Much like in the NameEditor, you read from the database during onResume( ) and write back to it during onPause( ). The one added feature that appears in LocationEditor as opposed to NameEditor is that you are also writing out the modified dates when you make a change.

Finally, you need two methods for canceling changes and deleting friends. These methods will be called from the menu system:

private final void cancelFriend() { if (mCursor != null) {

mCursor.updateString(FRIEND_INDEX, mOriginalContent); mCursor.commitUpdates(); mCursor.deactivate(); mCursor = null; } else if (mState == STATE_INSERT) { deleteFriend();

setResult(RESULT_CANCELED); finish();

private final void deleteFriend() { if (mCursor != null) { mText.setText(""); mCursor.deleteRow(); mCursor.deactivate();

mCursor = null;

Given that you learned about creating menu systems in Chapter 8, simply examine the full LocationEditor.java file to see how all of these methods and subclasses work together:

package android_programmers_guide.FindAFriend;

import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.util.AttributeSet; import android.view.Menu; import android.widget.EditText; import java.util.Map;

public class LocationEditor extends Activity {

private static final String TAG = "Friends";

private static final int FRIEND_INDEX = 1; private static final int NAME_INDEX = 2; private static final int MODIFIED_INDEX = 3;

private static final String[] PROJECTION = new String[] { Friends.Friend. ID, // 0 Friends.Friend.LOCATION, // 1 Friends.Friend.NAME, // 2 Friends.Friend.MODIFIED_DATE // 3

private static final String ORIGINAL_CONTENT = "origContent"

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;

private static final int STATE_EDIT = 0; private static final int STATE_INSERT = 1;

private int mState;

private boolean mNoteOnly = false;

private Uri mURI;

private Cursor mCursor;

private EditText mText;

private String mOriginalContent;

public static class MyEditText extends EditText { private Rect mRect; private Paint mPaint;

public MyEditText(Context context, AttributeSet attrs, Map params) { super(context, attrs, params);

mRect = new Rect(); mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(0xFF0000FF);

@Override protected void onDraw(Canvas canvas) {

int count = getLineCount(); Rect r = mRect; Paint paint = mPaint;

int baseline = getLineBounds(i, r);

canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);

super.onDraw(canvas);

@Override protected void onCreate(Bundle icicle) { super.onCreate(icicle);

final Intent intent = getIntent();

final String type = intent.resolveType(this);

final String action = intent.getAction(); if (action.equals(Intent.EDIT_ACTION)) { mState = STATE_EDIT; mURI = intent.getData();

} else if (action.equals(Intent.INSERT_ACTION)) { mState = STATE_INSERT;

mURI = getContentResolver().insert(intent.getData(), null); if (mURI == null) {

finish(); return;

setResult(RESULT_OK, mURI.toString());

setContentView(R.layout.location_editor);

mText = (EditText) findViewById(R.id.location);

mCursor = managedQuery(mURI, PROJECTION, null, null);

mOriginalContent = icicle.getString(ORIGINAL_CONTENT);

@Override protected void onResume() { super.onResume();

setTitle(getText(R.string.title_edit));

setTitle(getText(R.string.title_create));

String note = mCursor.getString(FRIEND_INDEX);

mText.setTextKeepState(note);

if (mOriginalContent == null) { mOriginalContent = note;

setTitle(getText(R.string.error_title));

mText.setText(getText(R.string.error_message));

@Override protected void onFreeze(Bundle outState) {

outState.putString(ORIGINAL_CONTENT, mOriginalContent);

@Override protected void onPause() { super.onPause();

String text = mText.getText().toString(); int length = text.length();

if (isFinishing() && (length == 0) && !mNoteOnly) { setResult(RESULT_CANCELED); deleteFriend(); } else {

mCursor.updateLong(MODIFIED_INDEX, System.currentTimeMillis());

String title = text.substring(0, Math.min(30, length));

int lastSpace = title.lastIndexOf(' '); if (lastSpace > 0) {

title = title.substring(0, lastSpace);

mCursor.updateString(NAME_INDEX, title);

mCursor.updateString(FRIEND_INDEX, text);

managedCommitUpdates(mCursor);

@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu);

menu.add(0, REVERT_ID, R.string.menu_revert).setShortcut('0',

menu.add(0, DELETE_ID,

menu.add(0, DISCARD_ID, R.string.menu_discard).setShortcut('ΓΌ'/

Intent intent = new Intent(null, getIntent().getData());

intent.addCategory(Intent.ALTERNATIVE_CATEGORY);

menu.addIntentOptions(

Menu.ALTERNATIVE, 0, new ComponentName(this, LocationEditor.class), null, intent, 0, null);

return true;

@Override public boolean onOptionsItemSelected(Menu.Item item) { switch (item.getId()) { case DELETE_ID:

deleteFriend(); finish(); break; case DISCARD_ID:

cancelFriend(); break; case REVERT_ID:

cancelFriend(); break;

return super.onOptionsItemSelected(item);

private final void cancelFriend() { if (mCursor != null) {

mCursor.updateString(FRIEND_INDEX, mOriginalContent); mCursor.commitUpdates(); mCursor.deactivate(); mCursor = null; } else if (mState == STATE_INSERT) { deleteFriend();

setResult(RESULT_CANCELED); finish();

private final void deleteFriend() { if (mCursor != null) { mText.setText("");

mCursor.deleteRow(); mCursor.deactivate(); mCursor = null;

In the next section, you will create the Activity that will draw your Google Maps Overlay. The FriendsMap activity will read the full recordset of friends from the Friends database and write each to the Overlay.

0 0

Post a comment