EMMA Coverage Report (generated Thu Oct 17 06:14:17 PDT 2013)
[all classes][com.example.android.notepad]

COVERAGE SUMMARY FOR SOURCE FILE [NoteEditor.java]

nameclass, %method, %block, %line, %
NoteEditor.java0%   (0/2)0%   (0/14)0%   (0/544)0%   (0/135)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class NoteEditor0%   (0/1)0%   (0/12)0%   (0/479)0%   (0/121)
<static initializer> 0%   (0/1)0%   (0/16)0%   (0/1)
NoteEditor (): void 0%   (0/1)0%   (0/3)0%   (0/2)
cancelNote (): void 0%   (0/1)0%   (0/43)0%   (0/12)
deleteNote (): void 0%   (0/1)0%   (0/22)0%   (0/6)
onCreate (Bundle): void 0%   (0/1)0%   (0/100)0%   (0/23)
onCreateOptionsMenu (Menu): boolean 0%   (0/1)0%   (0/38)0%   (0/6)
onOptionsItemSelected (MenuItem): boolean 0%   (0/1)0%   (0/19)0%   (0/9)
onPause (): void 0%   (0/1)0%   (0/27)0%   (0/8)
onPrepareOptionsMenu (Menu): boolean 0%   (0/1)0%   (0/51)0%   (0/12)
onResume (): void 0%   (0/1)0%   (0/76)0%   (0/19)
onSaveInstanceState (Bundle): void 0%   (0/1)0%   (0/6)0%   (0/2)
saveNote (): void 0%   (0/1)0%   (0/78)0%   (0/21)
     
class NoteEditor$LinedEditText0%   (0/1)0%   (0/2)0%   (0/65)0%   (0/14)
NoteEditor$LinedEditText (Context, AttributeSet): void 0%   (0/1)0%   (0/23)0%   (0/6)
onDraw (Canvas): void 0%   (0/1)0%   (0/42)0%   (0/8)

1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17package com.example.android.notepad;
18 
19import com.example.android.notepad.NotePad.NoteColumns;
20 
21import android.app.Activity;
22import android.content.ComponentName;
23import android.content.ContentValues;
24import android.content.Context;
25import android.content.Intent;
26import android.content.res.Resources;
27import android.database.Cursor;
28import android.graphics.Canvas;
29import android.graphics.Paint;
30import android.graphics.Rect;
31import android.net.Uri;
32import android.os.Bundle;
33import android.util.AttributeSet;
34import android.util.Log;
35import android.view.Menu;
36import android.view.MenuInflater;
37import android.view.MenuItem;
38import android.widget.EditText;
39import android.widget.Toast;
40 
41/**
42 * A generic activity for editing a note in a database.  This can be used
43 * either to simply view a note {@link Intent#ACTION_VIEW}, view and edit a note
44 * {@link Intent#ACTION_EDIT}, or create a new note {@link Intent#ACTION_INSERT}.  
45 */
46public class NoteEditor extends Activity {
47    private static final String TAG = "NoteEditor";
48 
49    /**
50     * Standard projection for the interesting columns of a normal note.
51     */
52    private static final String[] PROJECTION = new String[] {
53        NoteColumns._ID, // 0
54        NoteColumns.NOTE, // 1
55        NoteColumns.TITLE, // 2
56    };
57    /** The index of the note column */
58    private static final int COLUMN_INDEX_NOTE = 1;
59    /** The index of the title column */
60    private static final int COLUMN_INDEX_TITLE = 2;
61    
62    // This is our state data that is stored when freezing.
63    private static final String ORIGINAL_CONTENT = "origContent";
64 
65    // The different distinct states the activity can be run in.
66    private static final int STATE_EDIT = 0;
67    private static final int STATE_INSERT = 1;
68 
69    private int mState;
70    private Uri mUri;
71    private Cursor mCursor;
72    private EditText mText;
73    private String mOriginalContent;
74 
75    /**
76     * A custom EditText that draws lines between each line of text that is displayed.
77     */
78    public static class LinedEditText extends EditText {
79        private Rect mRect;
80        private Paint mPaint;
81 
82        // we need this constructor for LayoutInflater
83        public LinedEditText(Context context, AttributeSet attrs) {
84            super(context, attrs);
85            
86            mRect = new Rect();
87            mPaint = new Paint();
88            mPaint.setStyle(Paint.Style.STROKE);
89            mPaint.setColor(0x800000FF);
90        }
91        
92        @Override
93        protected void onDraw(Canvas canvas) {
94            int count = getLineCount();
95            Rect r = mRect;
96            Paint paint = mPaint;
97 
98            for (int i = 0; i < count; i++) {
99                int baseline = getLineBounds(i, r);
100 
101                canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
102            }
103 
104            super.onDraw(canvas);
105        }
106    }
107 
108    @Override
109    protected void onCreate(Bundle savedInstanceState) {
110        super.onCreate(savedInstanceState);
111 
112        final Intent intent = getIntent();
113 
114        // Do some setup based on the action being performed.
115        final String action = intent.getAction();
116        if (Intent.ACTION_EDIT.equals(action)) {
117            // Requested to edit: set that state, and the data being edited.
118            mState = STATE_EDIT;
119            mUri = intent.getData();
120        } else if (Intent.ACTION_INSERT.equals(action)) {
121            // Requested to insert: set that state, and create a new entry
122            // in the container.
123            mState = STATE_INSERT;
124            mUri = getContentResolver().insert(intent.getData(), null);
125 
126            // If we were unable to create a new note, then just finish
127            // this activity.  A RESULT_CANCELED will be sent back to the
128            // original activity if they requested a result.
129            if (mUri == null) {
130                Log.e(TAG, "Failed to insert new note into " + getIntent().getData());
131                finish();
132                return;
133            }
134 
135            // The new entry was created, so assume all will end well and
136            // set the result to be returned.
137            setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));
138 
139        } else {
140            // Whoops, unknown action!  Bail.
141            Log.e(TAG, "Unknown action, exiting");
142            finish();
143            return;
144        }
145 
146        // Set the layout for this activity.  You can find it in res/layout/note_editor.xml
147        setContentView(R.layout.note_editor);
148        
149        // The text view for our note, identified by its ID in the XML file.
150        mText = (EditText) findViewById(R.id.note);
151 
152        // Get the note!
153        mCursor = managedQuery(mUri, PROJECTION, null, null, null);
154 
155        // If an instance of this activity had previously stopped, we can
156        // get the original text it started with.
157        if (savedInstanceState != null) {
158            mOriginalContent = savedInstanceState.getString(ORIGINAL_CONTENT);
159        }
160    }
161 
162    @Override
163    protected void onResume() {
164        super.onResume();
165        // If we didn't have any trouble retrieving the data, it is now
166        // time to get at the stuff.
167        if (mCursor != null) {
168            // Requery in case something changed while paused (such as the title)
169            mCursor.requery();
170            // Make sure we are at the one and only row in the cursor.
171            mCursor.moveToFirst();
172 
173            // Modify our overall title depending on the mode we are running in.
174            if (mState == STATE_EDIT) {
175                // Set the title of the Activity to include the note title
176                String title = mCursor.getString(COLUMN_INDEX_TITLE);
177                Resources res = getResources();
178                String text = String.format(res.getString(R.string.title_edit), title);
179                setTitle(text);
180            } else if (mState == STATE_INSERT) {
181                setTitle(getText(R.string.title_create));
182            }
183 
184            // This is a little tricky: we may be resumed after previously being
185            // paused/stopped.  We want to put the new text in the text view,
186            // but leave the user where they were (retain the cursor position
187            // etc).  This version of setText does that for us.
188            String note = mCursor.getString(COLUMN_INDEX_NOTE);
189            mText.setTextKeepState(note);
190            
191            // If we hadn't previously retrieved the original text, do so
192            // now.  This allows the user to revert their changes.
193            if (mOriginalContent == null) {
194                mOriginalContent = note;
195            }
196 
197        } else {
198            setTitle(getText(R.string.error_title));
199            mText.setText(getText(R.string.error_message));
200        }
201    }
202 
203    @Override
204    protected void onSaveInstanceState(Bundle outState) {
205        // Save away the original text, so we still have it if the activity
206        // needs to be killed while paused.
207        outState.putString(ORIGINAL_CONTENT, mOriginalContent);
208    }
209 
210    @Override
211    protected void onPause() {
212        super.onPause();
213        // The user is going somewhere, so make sure changes are saved
214 
215        String text = mText.getText().toString();
216        int length = text.length();
217 
218        // If this activity is finished, and there is no text, then we
219        // simply delete the note entry.
220        // Note that we do this both for editing and inserting...  it
221        // would be reasonable to only do it when inserting.
222        if (isFinishing() && (length == 0) && mCursor != null) {
223            setResult(RESULT_CANCELED);
224            deleteNote();
225        } else {
226            saveNote();
227        }
228    }
229 
230    @Override
231    public boolean onCreateOptionsMenu(Menu menu) {
232        // Inflate menu from XML resource
233        MenuInflater inflater = getMenuInflater();
234        inflater.inflate(R.menu.editor_options_menu, menu);
235 
236        // Append to the
237        // menu items for any other activities that can do stuff with it
238        // as well.  This does a query on the system for any activities that
239        // implement the ALTERNATIVE_ACTION for our data, adding a menu item
240        // for each one that is found.
241        Intent intent = new Intent(null, getIntent().getData());
242        intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
243        menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
244                new ComponentName(this, NoteEditor.class), null, intent, 0, null);
245 
246        return super.onCreateOptionsMenu(menu);
247    }
248    
249    
250 
251    @Override
252    public boolean onPrepareOptionsMenu(Menu menu) {
253        if (mState == STATE_EDIT) {
254            menu.setGroupVisible(R.id.menu_group_edit, true);
255            menu.setGroupVisible(R.id.menu_group_insert, false);
256            
257            // Check if note has changed and enable/disable the revert option
258            String savedNote = mCursor.getString(COLUMN_INDEX_NOTE);
259            String currentNote = mText.getText().toString();
260            if (savedNote.equals(currentNote)) {
261                menu.findItem(R.id.menu_revert).setEnabled(false);
262            } else {
263                menu.findItem(R.id.menu_revert).setEnabled(true);
264            }
265        } else {
266            menu.setGroupVisible(R.id.menu_group_edit, false);
267            menu.setGroupVisible(R.id.menu_group_insert, true);
268        }
269        return super.onPrepareOptionsMenu(menu);
270    }
271 
272    @Override
273    public boolean onOptionsItemSelected(MenuItem item) {
274        // Handle all of the possible menu actions.
275        switch (item.getItemId()) {
276        case R.id.menu_save:
277            saveNote();
278            finish();
279            break;
280        case R.id.menu_delete:
281            deleteNote();
282            finish();
283            break;
284        case R.id.menu_revert:
285        case R.id.menu_discard:
286            cancelNote();
287            break;
288        }
289        return super.onOptionsItemSelected(item);
290        
291    }
292    
293    private final void saveNote() {
294        // Make sure their current
295        // changes are safely saved away in the provider.  We don't need
296        // to do this if only editing.
297        if (mCursor != null) {
298            // Get out updates into the provider.
299            ContentValues values = new ContentValues();
300 
301            // Bump the modification time to now.
302            values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
303 
304            String text = mText.getText().toString();
305            int length = text.length();
306            // If we are creating a new note, then we want to also create
307            // an initial title for it.
308            if (mState == STATE_INSERT) {
309                if (length == 0) {
310                    Toast.makeText(this, R.string.nothing_to_save, Toast.LENGTH_SHORT).show();
311                    return;
312                }
313                String title = text.substring(0, Math.min(30, length));
314                if (length > 30) {
315                    int lastSpace = title.lastIndexOf(' ');
316                    if (lastSpace > 0) {
317                        title = title.substring(0, lastSpace);
318                    }
319                }
320                values.put(NoteColumns.TITLE, title);
321            }
322 
323            // Write our text back into the provider.
324            values.put(NoteColumns.NOTE, text);
325 
326            // Commit all of our changes to persistent storage. When the update completes
327            // the content provider will notify the cursor of the change, which will
328            // cause the UI to be updated.
329            try {
330                getContentResolver().update(mUri, values, null, null);
331            } catch (NullPointerException e) {
332                Log.e(TAG, e.getMessage());
333            }
334            
335        }
336    }
337 
338    /**
339     * Take care of canceling work on a note.  Deletes the note if we
340     * had created it, otherwise reverts to the original text.
341     */
342    private final void cancelNote() {
343        if (mCursor != null) {
344            if (mState == STATE_EDIT) {
345                // Put the original note text back into the database
346                mCursor.close();
347                mCursor = null;
348                ContentValues values = new ContentValues();
349                values.put(NoteColumns.NOTE, mOriginalContent);
350                getContentResolver().update(mUri, values, null, null);
351            } else if (mState == STATE_INSERT) {
352                // We inserted an empty note, make sure to delete it
353                deleteNote();
354            }
355        }
356        setResult(RESULT_CANCELED);
357        finish();
358    }
359 
360    /**
361     * Take care of deleting a note.  Simply deletes the entry.
362     */
363    private final void deleteNote() {
364        if (mCursor != null) {
365            mCursor.close();
366            mCursor = null;
367            getContentResolver().delete(mUri, null, null);
368            mText.setText("");
369        }
370    }
371}

[all classes][com.example.android.notepad]
EMMA 2.0.5312 (C) Vladimir Roubtsov