Note.java

    /*
     * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
     *
     * 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 net.micode.notes.model;
    import android.content.ContentProviderOperation;
    import android.content.ContentProviderResult;
    import android.content.ContentUris;
    import android.content.ContentValues;
    import android.content.Context;
    import android.content.OperationApplicationException;
    import android.net.Uri;
    import android.os.RemoteException;
    import android.util.Log;

    import net.micode.notes.data.Notes;
    import net.micode.notes.data.Notes.CallNote;
    import net.micode.notes.data.Notes.DataColumns;
    import net.micode.notes.data.Notes.NoteColumns;
    import net.micode.notes.data.Notes.TextNote;

    import java.util.ArrayList;

    public class Note {
        private ContentValues mNoteDiffValues;
        private NoteData mNoteData;
        private static final String TAG = "Note";
        /**
         * Create a new note id for adding a new note to databases
         */
        public static synchronized long getNewNoteId(Context context, long folderId) {
            // Create a new note in the database
            ContentValues values = new ContentValues();
            long createdTime = System.currentTimeMillis();
            values.put(NoteColumns.CREATED_DATE, createdTime);
            values.put(NoteColumns.MODIFIED_DATE, createdTime);
            values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
            values.put(NoteColumns.LOCAL_MODIFIED, 1);
            values.put(NoteColumns.PARENT_ID, folderId);//将数据写入数据库表格
            Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
            //ContentResolver()主要是实现外部应用对ContentProvider中的数据
            //进行添加、删除、修改和查询操作
            long noteId = 0;
            try {
                noteId = Long.valueOf(uri.getPathSegments().get(1));
            } catch (NumberFormatException e) {
                Log.e(TAG, "Get note id error :" + e.toString());
                noteId = 0;
            }//try-catch异常处理
            if (noteId == -1) {
                throw new IllegalStateException("Wrong note id:" + noteId);
            }
            return noteId;
        }

        public Note() {
            mNoteDiffValues = new ContentValues();
            mNoteData = new NoteData();
        }

        public void setNoteValue(String key, String value) {
            mNoteDiffValues.put(key, value);
            mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
            mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
        }

        public void setTextData(String key, String value) {
            mNoteData.setTextData(key, value);
        }

        public void setTextDataId(long id) {
            mNoteData.setTextDataId(id);
        }

        public long getTextDataId() {
            return mNoteData.mTextDataId;
        }

        public void setCallDataId(long id) {
            mNoteData.setCallDataId(id);
        }

        public void setCallData(String key, String value) {
            mNoteData.setCallData(key, value);
        }

        public boolean isLocalModified() {
            return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
        }

        public boolean syncNote(Context context, long noteId) {
            if (noteId <= 0) {
                throw new IllegalArgumentException("Wrong note id:" + noteId);
            }

            if (!isLocalModified()) {
                return true;
            }

            /**
             * In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and
             * {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the
             * note data info
             */
            if (context.getContentResolver().update(
                    ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
                    null) == 0) {
                Log.e(TAG, "Update note error, should not happen");
                // Do not return, fall through
            }
            mNoteDiffValues.clear();

            if (mNoteData.isLocalModified()
                    && (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
                return false;
            }

            return true;
        }

        private class NoteData {
            private long mTextDataId;

            private ContentValues mTextDataValues;

            private long mCallDataId;

            private ContentValues mCallDataValues;

            private static final String TAG = "NoteData";

            public NoteData() {
                mTextDataValues = new ContentValues();
                mCallDataValues = new ContentValues();
                mTextDataId = 0;
                mCallDataId = 0;
            }

            boolean isLocalModified() {
                return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
            }

            void setTextDataId(long id) {
                if(id <= 0) {
                    throw new IllegalArgumentException("Text data id should larger than 0");
                }
                mTextDataId = id;
            }

            void setCallDataId(long id) {
                if (id <= 0) {
                    throw new IllegalArgumentException("Call data id should larger than 0");
                }
                mCallDataId = id;
            }

            void setCallData(String key, String value) {
                mCallDataValues.put(key, value);
                mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
                mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
            }

            void setTextData(String key, String value) {
                mTextDataValues.put(key, value);
                mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
                mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
            }

            Uri pushIntoContentResolver(Context context, long noteId) {
                /**
                 * Check for safety
                 */
                if (noteId <= 0) {
                    throw new IllegalArgumentException("Wrong note id:" + noteId);
                }

                ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
                ContentProviderOperation.Builder builder = null;

                if(mTextDataValues.size() > 0) {
                    mTextDataValues.put(DataColumns.NOTE_ID, noteId);
                    if (mTextDataId == 0) {
                        mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
                        Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
                                mTextDataValues);
                        try {
                            setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
                        } catch (NumberFormatException e) {
                            Log.e(TAG, "Insert new text data fail with noteId" + noteId);
                            mTextDataValues.clear();
                            return null;
                        }
                    } else {
                        builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
                                Notes.CONTENT_DATA_URI, mTextDataId));
                        builder.withValues(mTextDataValues);
                        operationList.add(builder.build());
                    }
                    mTextDataValues.clear();
                }

                if(mCallDataValues.size() > 0) {
                    mCallDataValues.put(DataColumns.NOTE_ID, noteId);
                    if (mCallDataId == 0) {
                        mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
                        Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
                                mCallDataValues);
                        try {
                            setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
                        } catch (NumberFormatException e) {
                            Log.e(TAG, "Insert new call data fail with noteId" + noteId);
                            mCallDataValues.clear();
                            return null;
                        }
                    } else {
                        builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
                                Notes.CONTENT_DATA_URI, mCallDataId));
                        builder.withValues(mCallDataValues);
                        operationList.add(builder.build());
                    }
                    mCallDataValues.clear();
                }

                if (operationList.size() > 0) {
                    try {
                        ContentProviderResult[] results = context.getContentResolver().applyBatch(
                                Notes.AUTHORITY, operationList);
                        return (results == null || results.length == 0 || results[0] == null) ? null
                                : ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
                    } catch (RemoteException e) {
                        Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
                        return null;
                    } catch (OperationApplicationException e) {
                        Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
                        return null;
                    }
                }
                return null;
            }
        }
    }