From 36caf1261d204ff4fddbc084296a92a7fab3d4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=AE=B6=E5=84=92?= <2494326140@qq.com> Date: Thu, 15 Jun 2023 19:49:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=8E=9F=E6=9D=A5=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/CJR_codereading/data/Contact.java | 73 -- doc/CJR_codereading/data/Notes.java | 279 ----- .../data/NotesDatabaseHelper.java | 362 ------ doc/CJR_codereading/data/NotesProvider.java | 305 ----- doc/CJR_codereading/model/Note.java | 253 ---- doc/CJR_codereading/model/WorkingNote.java | 368 ------ doc/CJR_codereading/tool/BackupUtils.java | 344 ------ doc/CJR_codereading/tool/DataUtils.java | 295 ----- .../tool/GTaskStringUtils.java | 113 -- doc/CJR_codereading/tool/ResourceParser.java | 181 --- .../widget/NoteWidgetProvider.java | 132 -- .../widget/NoteWidgetProvider_2x.java | 47 - .../widget/NoteWidgetProvider_4x.java | 46 - .../ui/AlarmAlertActivity.java | 207 ---- doc/cyw.readcode.ui/ui/AlarmInitReceiver.java | 71 -- doc/cyw.readcode.ui/ui/AlarmReceiver.java | 34 - doc/cyw.readcode.ui/ui/DateTimePicker.java | 504 -------- .../ui/DateTimePickerDialog.java | 96 -- doc/cyw.readcode.ui/ui/DropdownMenu.java | 65 - .../ui/FoldersListAdapter.java | 87 -- doc/cyw.readcode.ui/ui/NoteEditActivity.java | 1083 ----------------- doc/cyw.readcode.ui/ui/NoteEditText.java | 286 ----- doc/cyw.readcode.ui/ui/NoteItemData.java | 230 ---- doc/cyw.readcode.ui/ui/NotesListActivity.java | 1018 ---------------- doc/cyw.readcode.ui/ui/NotesListAdapter.java | 273 ----- doc/cyw.readcode.ui/ui/NotesListItem.java | 132 -- .../ui/NotesPreferenceActivity.java | 530 -------- doc/data/MetaData.java | 88 -- doc/data/Node.java | 104 -- doc/data/SqlData.java | 198 --- doc/data/SqlNote.java | 527 -------- doc/data/Task.java | 361 ------ doc/data/TaskList.java | 357 ------ doc/remote/GTaskASyncTask.java | 123 -- doc/remote/GTaskClient.java | 662 ---------- doc/remote/GTaskManager.java | 800 ------------ doc/remote/GTaskSyncService.java | 128 -- doc/remote/软件 (D).lnk | Bin 515 -> 0 bytes ...米便签开源代码的泛读报告.docx | Bin 370669 -> 0 bytes doc/插入图片用例描述文档.txt | 23 - doc/登录功能用例描述文档.txt | 18 - 41 files changed, 10803 deletions(-) delete mode 100644 doc/CJR_codereading/data/Contact.java delete mode 100644 doc/CJR_codereading/data/Notes.java delete mode 100644 doc/CJR_codereading/data/NotesDatabaseHelper.java delete mode 100644 doc/CJR_codereading/data/NotesProvider.java delete mode 100644 doc/CJR_codereading/model/Note.java delete mode 100644 doc/CJR_codereading/model/WorkingNote.java delete mode 100644 doc/CJR_codereading/tool/BackupUtils.java delete mode 100644 doc/CJR_codereading/tool/DataUtils.java delete mode 100644 doc/CJR_codereading/tool/GTaskStringUtils.java delete mode 100644 doc/CJR_codereading/tool/ResourceParser.java delete mode 100644 doc/CJR_codereading/widget/NoteWidgetProvider.java delete mode 100644 doc/CJR_codereading/widget/NoteWidgetProvider_2x.java delete mode 100644 doc/CJR_codereading/widget/NoteWidgetProvider_4x.java delete mode 100644 doc/cyw.readcode.ui/ui/AlarmAlertActivity.java delete mode 100644 doc/cyw.readcode.ui/ui/AlarmInitReceiver.java delete mode 100644 doc/cyw.readcode.ui/ui/AlarmReceiver.java delete mode 100644 doc/cyw.readcode.ui/ui/DateTimePicker.java delete mode 100644 doc/cyw.readcode.ui/ui/DateTimePickerDialog.java delete mode 100644 doc/cyw.readcode.ui/ui/DropdownMenu.java delete mode 100644 doc/cyw.readcode.ui/ui/FoldersListAdapter.java delete mode 100644 doc/cyw.readcode.ui/ui/NoteEditActivity.java delete mode 100644 doc/cyw.readcode.ui/ui/NoteEditText.java delete mode 100644 doc/cyw.readcode.ui/ui/NoteItemData.java delete mode 100644 doc/cyw.readcode.ui/ui/NotesListActivity.java delete mode 100644 doc/cyw.readcode.ui/ui/NotesListAdapter.java delete mode 100644 doc/cyw.readcode.ui/ui/NotesListItem.java delete mode 100644 doc/cyw.readcode.ui/ui/NotesPreferenceActivity.java delete mode 100644 doc/data/MetaData.java delete mode 100644 doc/data/Node.java delete mode 100644 doc/data/SqlData.java delete mode 100644 doc/data/SqlNote.java delete mode 100644 doc/data/Task.java delete mode 100644 doc/data/TaskList.java delete mode 100644 doc/remote/GTaskASyncTask.java delete mode 100644 doc/remote/GTaskClient.java delete mode 100644 doc/remote/GTaskManager.java delete mode 100644 doc/remote/GTaskSyncService.java delete mode 100644 doc/remote/软件 (D).lnk delete mode 100644 doc/小米便签开源代码的泛读报告.docx delete mode 100644 doc/插入图片用例描述文档.txt delete mode 100644 doc/登录功能用例描述文档.txt diff --git a/doc/CJR_codereading/data/Contact.java b/doc/CJR_codereading/data/Contact.java deleted file mode 100644 index d97ac5d..0000000 --- a/doc/CJR_codereading/data/Contact.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.data; - -import android.content.Context; -import android.database.Cursor; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.Data; -import android.telephony.PhoneNumberUtils; -import android.util.Log; - -import java.util.HashMap; - -public class Contact { - private static HashMap sContactCache; - private static final String TAG = "Contact"; - - private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER - + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" - + " AND " + Data.RAW_CONTACT_ID + " IN " - + "(SELECT raw_contact_id " - + " FROM phone_lookup" - + " WHERE min_match = '+')"; - - public static String getContact(Context context, String phoneNumber) { - if(sContactCache == null) { - sContactCache = new HashMap(); - } - - if(sContactCache.containsKey(phoneNumber)) { - return sContactCache.get(phoneNumber); - } - - String selection = CALLER_ID_SELECTION.replace("+", - PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); - Cursor cursor = context.getContentResolver().query( - Data.CONTENT_URI, - new String [] { Phone.DISPLAY_NAME }, - selection, - new String[] { phoneNumber }, - null); - - if (cursor != null && cursor.moveToFirst()) { - try { - String name = cursor.getString(0); - sContactCache.put(phoneNumber, name); - return name; - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, " Cursor get string error " + e.toString()); - return null; - } finally { - cursor.close(); - } - } else { - Log.d(TAG, "No contact matched with number:" + phoneNumber); - return null; - } - } -} diff --git a/doc/CJR_codereading/data/Notes.java b/doc/CJR_codereading/data/Notes.java deleted file mode 100644 index f240604..0000000 --- a/doc/CJR_codereading/data/Notes.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * 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.data; - -import android.net.Uri; -public class Notes { - public static final String AUTHORITY = "micode_notes"; - public static final String TAG = "Notes"; - public static final int TYPE_NOTE = 0; - public static final int TYPE_FOLDER = 1; - public static final int TYPE_SYSTEM = 2; - - /** - * Following IDs are system folders' identifiers - * {@link Notes#ID_ROOT_FOLDER } is default folder - * {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder - * {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records - */ - public static final int ID_ROOT_FOLDER = 0; - public static final int ID_TEMPARAY_FOLDER = -1; - public static final int ID_CALL_RECORD_FOLDER = -2; - public static final int ID_TRASH_FOLER = -3; - - public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; - public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; - public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; - public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; - public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; - public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; - - public static final int TYPE_WIDGET_INVALIDE = -1; - public static final int TYPE_WIDGET_2X = 0; - public static final int TYPE_WIDGET_4X = 1; - - public static class DataConstants { - public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; - public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; - } - - /** - * Uri to query all notes and folders - */ - public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); - - /** - * Uri to query data - */ - public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); - - public interface NoteColumns { - /** - * The unique ID for a row - *

Type: INTEGER (long)

- */ - public static final String ID = "_id"; - - /** - * The parent's id for note or folder - *

Type: INTEGER (long)

- */ - public static final String PARENT_ID = "parent_id"; - - /** - * Created data for note or folder - *

Type: INTEGER (long)

- */ - public static final String CREATED_DATE = "created_date"; - - /** - * Latest modified date - *

Type: INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; - - - /** - * Alert date - *

Type: INTEGER (long)

- */ - public static final String ALERTED_DATE = "alert_date"; - - /** - * Folder's name or text content of note - *

Type: TEXT

- */ - public static final String SNIPPET = "snippet"; - - /** - * Note's widget id - *

Type: INTEGER (long)

- */ - public static final String WIDGET_ID = "widget_id"; - - /** - * Note's widget type - *

Type: INTEGER (long)

- */ - public static final String WIDGET_TYPE = "widget_type"; - - /** - * Note's background color's id - *

Type: INTEGER (long)

- */ - public static final String BG_COLOR_ID = "bg_color_id"; - - /** - * For text note, it doesn't has attachment, for multi-media - * note, it has at least one attachment - *

Type: INTEGER

- */ - public static final String HAS_ATTACHMENT = "has_attachment"; - - /** - * Folder's count of notes - *

Type: INTEGER (long)

- */ - public static final String NOTES_COUNT = "notes_count"; - - /** - * The file type: folder or note - *

Type: INTEGER

- */ - public static final String TYPE = "type"; - - /** - * The last sync id - *

Type: INTEGER (long)

- */ - public static final String SYNC_ID = "sync_id"; - - /** - * Sign to indicate local modified or not - *

Type: INTEGER

- */ - public static final String LOCAL_MODIFIED = "local_modified"; - - /** - * Original parent id before moving into temporary folder - *

Type : INTEGER

- */ - public static final String ORIGIN_PARENT_ID = "origin_parent_id"; - - /** - * The gtask id - *

Type : TEXT

- */ - public static final String GTASK_ID = "gtask_id"; - - /** - * The version code - *

Type : INTEGER (long)

- */ - public static final String VERSION = "version"; - } - - public interface DataColumns { - /** - * The unique ID for a row - *

Type: INTEGER (long)

- */ - public static final String ID = "_id"; - - /** - * The MIME type of the item represented by this row. - *

Type: Text

- */ - public static final String MIME_TYPE = "mime_type"; - - /** - * The reference id to note that this data belongs to - *

Type: INTEGER (long)

- */ - public static final String NOTE_ID = "note_id"; - - /** - * Created data for note or folder - *

Type: INTEGER (long)

- */ - public static final String CREATED_DATE = "created_date"; - - /** - * Latest modified date - *

Type: INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; - - /** - * Data's content - *

Type: TEXT

- */ - public static final String CONTENT = "content"; - - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * integer data type - *

Type: INTEGER

- */ - public static final String DATA1 = "data1"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * integer data type - *

Type: INTEGER

- */ - public static final String DATA2 = "data2"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

- */ - public static final String DATA3 = "data3"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

- */ - public static final String DATA4 = "data4"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

- */ - public static final String DATA5 = "data5"; - } - - public static final class TextNote implements DataColumns { - /** - * Mode to indicate the text in check list mode or not - *

Type: Integer 1:check list mode 0: normal mode

- */ - public static final String MODE = DATA1; - - public static final int MODE_CHECK_LIST = 1; - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; - - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; - - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); - } - - public static final class CallNote implements DataColumns { - /** - * Call date for this record - *

Type: INTEGER (long)

- */ - public static final String CALL_DATE = DATA1; - - /** - * Phone number for this record - *

Type: TEXT

- */ - public static final String PHONE_NUMBER = DATA3; - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; - - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; - - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); - } -} diff --git a/doc/CJR_codereading/data/NotesDatabaseHelper.java b/doc/CJR_codereading/data/NotesDatabaseHelper.java deleted file mode 100644 index ffe5d57..0000000 --- a/doc/CJR_codereading/data/NotesDatabaseHelper.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * 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.data; - -import android.content.ContentValues; -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; - -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; - - -public class NotesDatabaseHelper extends SQLiteOpenHelper { - private static final String DB_NAME = "note.db"; - - private static final int DB_VERSION = 4; - - public interface TABLE { - public static final String NOTE = "note"; - - public static final String DATA = "data"; - } - - private static final String TAG = "NotesDatabaseHelper"; - - private static NotesDatabaseHelper mInstance; - - private static final String CREATE_NOTE_TABLE_SQL = - "CREATE TABLE " + TABLE.NOTE + "(" + - NoteColumns.ID + " INTEGER PRIMARY KEY," + - NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + - NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + - ")"; - - private static final String CREATE_DATA_TABLE_SQL = - "CREATE TABLE " + TABLE.DATA + "(" + - DataColumns.ID + " INTEGER PRIMARY KEY," + - DataColumns.MIME_TYPE + " TEXT NOT NULL," + - DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA1 + " INTEGER," + - DataColumns.DATA2 + " INTEGER," + - DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + - ")"; - - private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = - "CREATE INDEX IF NOT EXISTS note_id_index ON " + - TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; - - /** - * Increase folder's note count when move note to the folder - */ - private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER increase_folder_count_on_update "+ - " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; - - /** - * Decrease folder's note count when move note from folder - */ - private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER decrease_folder_count_on_update " + - " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + - " END"; - - /** - * Increase folder's note count when insert new note to the folder - */ - private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = - "CREATE TRIGGER increase_folder_count_on_insert " + - " AFTER INSERT ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; - - /** - * Decrease folder's note count when delete note from the folder - */ - private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = - "CREATE TRIGGER decrease_folder_count_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0;" + - " END"; - - /** - * Update note's content when insert data with type {@link DataConstants#NOTE} - */ - private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = - "CREATE TRIGGER update_note_content_on_insert " + - " AFTER INSERT ON " + TABLE.DATA + - " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; - - /** - * Update note's content when data with {@link DataConstants#NOTE} type has changed - */ - private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER update_note_content_on_update " + - " AFTER UPDATE ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; - - /** - * Update note's content when data with {@link DataConstants#NOTE} type has deleted - */ - private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = - "CREATE TRIGGER update_note_content_on_delete " + - " AFTER delete ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=''" + - " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + - " END"; - - /** - * Delete datas belong to note which has been deleted - */ - private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = - "CREATE TRIGGER delete_data_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN" + - " DELETE FROM " + TABLE.DATA + - " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + - " END"; - - /** - * Delete notes belong to folder which has been deleted - */ - private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = - "CREATE TRIGGER folder_delete_notes_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN" + - " DELETE FROM " + TABLE.NOTE + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; - - /** - * Move notes belong to folder which has been moved to trash folder - */ - private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = - "CREATE TRIGGER folder_move_notes_on_trash " + - " AFTER UPDATE ON " + TABLE.NOTE + - " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; - - public NotesDatabaseHelper(Context context) { - super(context, DB_NAME, null, DB_VERSION); - } - - public void createNoteTable(SQLiteDatabase db) { - db.execSQL(CREATE_NOTE_TABLE_SQL); - reCreateNoteTableTriggers(db); - createSystemFolder(db); - Log.d(TAG, "note table has been created"); - } - - private void reCreateNoteTableTriggers(SQLiteDatabase db) { - db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert"); - db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); - - db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); - db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); - db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER); - db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER); - db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); - db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); - db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); - } - - private void createSystemFolder(SQLiteDatabase db) { - ContentValues values = new ContentValues(); - - /** - * call record foler for call notes - */ - values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); - - /** - * root folder which is default folder - */ - values.clear(); - values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); - - /** - * temporary folder which is used for moving note - */ - values.clear(); - values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); - - /** - * create trash folder - */ - values.clear(); - values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); - } - - public void createDataTable(SQLiteDatabase db) { - db.execSQL(CREATE_DATA_TABLE_SQL); - reCreateDataTableTriggers(db); - db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); - Log.d(TAG, "data table has been created"); - } - - private void reCreateDataTableTriggers(SQLiteDatabase db) { - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); - - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); - } - - static synchronized NotesDatabaseHelper getInstance(Context context) { - if (mInstance == null) { - mInstance = new NotesDatabaseHelper(context); - } - return mInstance; - } - - @Override - public void onCreate(SQLiteDatabase db) { - createNoteTable(db); - createDataTable(db); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - boolean reCreateTriggers = false; - boolean skipV2 = false; - - if (oldVersion == 1) { - upgradeToV2(db); - skipV2 = true; // this upgrade including the upgrade from v2 to v3 - oldVersion++; - } - - if (oldVersion == 2 && !skipV2) { - upgradeToV3(db); - reCreateTriggers = true; - oldVersion++; - } - - if (oldVersion == 3) { - upgradeToV4(db); - oldVersion++; - } - - if (reCreateTriggers) { - reCreateNoteTableTriggers(db); - reCreateDataTableTriggers(db); - } - - if (oldVersion != newVersion) { - throw new IllegalStateException("Upgrade notes database to version " + newVersion - + "fails"); - } - } - - private void upgradeToV2(SQLiteDatabase db) { - db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); - db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); - createNoteTable(db); - createDataTable(db); - } - - private void upgradeToV3(SQLiteDatabase db) { - // drop unused triggers - db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update"); - // add a column for gtask id - db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID - + " TEXT NOT NULL DEFAULT ''"); - // add a trash system folder - ContentValues values = new ContentValues(); - values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); - } - - private void upgradeToV4(SQLiteDatabase db) { - db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION - + " INTEGER NOT NULL DEFAULT 0"); - } -} diff --git a/doc/CJR_codereading/data/NotesProvider.java b/doc/CJR_codereading/data/NotesProvider.java deleted file mode 100644 index edb0a60..0000000 --- a/doc/CJR_codereading/data/NotesProvider.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * 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.data; - - -import android.app.SearchManager; -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Intent; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.text.TextUtils; -import android.util.Log; - -import net.micode.notes.R; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.data.NotesDatabaseHelper.TABLE; - - -public class NotesProvider extends ContentProvider { - private static final UriMatcher mMatcher; - - private NotesDatabaseHelper mHelper; - - private static final String TAG = "NotesProvider"; - - private static final int URI_NOTE = 1; - private static final int URI_NOTE_ITEM = 2; - private static final int URI_DATA = 3; - private static final int URI_DATA_ITEM = 4; - - private static final int URI_SEARCH = 5; - private static final int URI_SEARCH_SUGGEST = 6; - - static { - mMatcher = new UriMatcher(UriMatcher.NO_MATCH); - mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); - mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); - mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); - mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); - mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); - mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); - mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); - } - - /** - * x'0A' represents the '\n' character in sqlite. For title and content in the search result, - * we will trim '\n' and white space in order to show more information. - */ - private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," - + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," - + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," - + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," - + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," - + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," - + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; - - private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION - + " FROM " + TABLE.NOTE - + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" - + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER - + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; - - @Override - public boolean onCreate() { - mHelper = NotesDatabaseHelper.getInstance(getContext()); - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - Cursor c = null; - SQLiteDatabase db = mHelper.getReadableDatabase(); - String id = null; - switch (mMatcher.match(uri)) { - case URI_NOTE: - c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, - sortOrder); - break; - case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); - c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id - + parseSelection(selection), selectionArgs, null, null, sortOrder); - break; - case URI_DATA: - c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, - sortOrder); - break; - case URI_DATA_ITEM: - id = uri.getPathSegments().get(1); - c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id - + parseSelection(selection), selectionArgs, null, null, sortOrder); - break; - case URI_SEARCH: - case URI_SEARCH_SUGGEST: - if (sortOrder != null || projection != null) { - throw new IllegalArgumentException( - "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); - } - - String searchString = null; - if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { - if (uri.getPathSegments().size() > 1) { - searchString = uri.getPathSegments().get(1); - } - } else { - searchString = uri.getQueryParameter("pattern"); - } - - if (TextUtils.isEmpty(searchString)) { - return null; - } - - try { - searchString = String.format("%%%s%%", searchString); - c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, - new String[] { searchString }); - } catch (IllegalStateException ex) { - Log.e(TAG, "got exception: " + ex.toString()); - } - break; - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - if (c != null) { - c.setNotificationUri(getContext().getContentResolver(), uri); - } - return c; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - SQLiteDatabase db = mHelper.getWritableDatabase(); - long dataId = 0, noteId = 0, insertedId = 0; - switch (mMatcher.match(uri)) { - case URI_NOTE: - insertedId = noteId = db.insert(TABLE.NOTE, null, values); - break; - case URI_DATA: - if (values.containsKey(DataColumns.NOTE_ID)) { - noteId = values.getAsLong(DataColumns.NOTE_ID); - } else { - Log.d(TAG, "Wrong data format without note id:" + values.toString()); - } - insertedId = dataId = db.insert(TABLE.DATA, null, values); - break; - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - // Notify the note uri - if (noteId > 0) { - getContext().getContentResolver().notifyChange( - ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); - } - - // Notify the data uri - if (dataId > 0) { - getContext().getContentResolver().notifyChange( - ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); - } - - return ContentUris.withAppendedId(uri, insertedId); - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - int count = 0; - String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); - boolean deleteData = false; - switch (mMatcher.match(uri)) { - case URI_NOTE: - selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; - count = db.delete(TABLE.NOTE, selection, selectionArgs); - break; - case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); - /** - * ID that smaller than 0 is system folder which is not allowed to - * trash - */ - long noteId = Long.valueOf(id); - if (noteId <= 0) { - break; - } - count = db.delete(TABLE.NOTE, - NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); - break; - case URI_DATA: - count = db.delete(TABLE.DATA, selection, selectionArgs); - deleteData = true; - break; - case URI_DATA_ITEM: - id = uri.getPathSegments().get(1); - count = db.delete(TABLE.DATA, - DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); - deleteData = true; - break; - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - if (count > 0) { - if (deleteData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); - } - getContext().getContentResolver().notifyChange(uri, null); - } - return count; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - int count = 0; - String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); - boolean updateData = false; - switch (mMatcher.match(uri)) { - case URI_NOTE: - increaseNoteVersion(-1, selection, selectionArgs); - count = db.update(TABLE.NOTE, values, selection, selectionArgs); - break; - case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); - increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); - count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id - + parseSelection(selection), selectionArgs); - break; - case URI_DATA: - count = db.update(TABLE.DATA, values, selection, selectionArgs); - updateData = true; - break; - case URI_DATA_ITEM: - id = uri.getPathSegments().get(1); - count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id - + parseSelection(selection), selectionArgs); - updateData = true; - break; - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - - if (count > 0) { - if (updateData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); - } - getContext().getContentResolver().notifyChange(uri, null); - } - return count; - } - - private String parseSelection(String selection) { - return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); - } - - private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { - StringBuilder sql = new StringBuilder(120); - sql.append("UPDATE "); - sql.append(TABLE.NOTE); - sql.append(" SET "); - sql.append(NoteColumns.VERSION); - sql.append("=" + NoteColumns.VERSION + "+1 "); - - if (id > 0 || !TextUtils.isEmpty(selection)) { - sql.append(" WHERE "); - } - if (id > 0) { - sql.append(NoteColumns.ID + "=" + String.valueOf(id)); - } - if (!TextUtils.isEmpty(selection)) { - String selectString = id > 0 ? parseSelection(selection) : selection; - for (String args : selectionArgs) { - selectString = selectString.replaceFirst("\\?", args); - } - sql.append(selectString); - } - - mHelper.getWritableDatabase().execSQL(sql.toString()); - } - - @Override - public String getType(Uri uri) { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/doc/CJR_codereading/model/Note.java b/doc/CJR_codereading/model/Note.java deleted file mode 100644 index 6706cf6..0000000 --- a/doc/CJR_codereading/model/Note.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * 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); - - 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; - } - 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 operationList = new ArrayList(); - 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; - } - } -} diff --git a/doc/CJR_codereading/model/WorkingNote.java b/doc/CJR_codereading/model/WorkingNote.java deleted file mode 100644 index be081e4..0000000 --- a/doc/CJR_codereading/model/WorkingNote.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * 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.appwidget.AppWidgetManager; -import android.content.ContentUris; -import android.content.Context; -import android.database.Cursor; -import android.text.TextUtils; -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.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.data.Notes.TextNote; -import net.micode.notes.tool.ResourceParser.NoteBgResources; - - -public class WorkingNote { - // Note for the working note - private Note mNote; - // Note Id - private long mNoteId; - // Note content - private String mContent; - // Note mode - private int mMode; - - private long mAlertDate; - - private long mModifiedDate; - - private int mBgColorId; - - private int mWidgetId; - - private int mWidgetType; - - private long mFolderId; - - private Context mContext; - - private static final String TAG = "WorkingNote"; - - private boolean mIsDeleted; - - private NoteSettingChangedListener mNoteSettingStatusListener; - - public static final String[] DATA_PROJECTION = new String[] { - DataColumns.ID, - DataColumns.CONTENT, - DataColumns.MIME_TYPE, - DataColumns.DATA1, - DataColumns.DATA2, - DataColumns.DATA3, - DataColumns.DATA4, - }; - - public static final String[] NOTE_PROJECTION = new String[] { - NoteColumns.PARENT_ID, - NoteColumns.ALERTED_DATE, - NoteColumns.BG_COLOR_ID, - NoteColumns.WIDGET_ID, - NoteColumns.WIDGET_TYPE, - NoteColumns.MODIFIED_DATE - }; - - private static final int DATA_ID_COLUMN = 0; - - private static final int DATA_CONTENT_COLUMN = 1; - - private static final int DATA_MIME_TYPE_COLUMN = 2; - - private static final int DATA_MODE_COLUMN = 3; - - private static final int NOTE_PARENT_ID_COLUMN = 0; - - private static final int NOTE_ALERTED_DATE_COLUMN = 1; - - private static final int NOTE_BG_COLOR_ID_COLUMN = 2; - - private static final int NOTE_WIDGET_ID_COLUMN = 3; - - private static final int NOTE_WIDGET_TYPE_COLUMN = 4; - - private static final int NOTE_MODIFIED_DATE_COLUMN = 5; - - // New note construct - private WorkingNote(Context context, long folderId) { - mContext = context; - mAlertDate = 0; - mModifiedDate = System.currentTimeMillis(); - mFolderId = folderId; - mNote = new Note(); - mNoteId = 0; - mIsDeleted = false; - mMode = 0; - mWidgetType = Notes.TYPE_WIDGET_INVALIDE; - } - - // Existing note construct - private WorkingNote(Context context, long noteId, long folderId) { - mContext = context; - mNoteId = noteId; - mFolderId = folderId; - mIsDeleted = false; - mNote = new Note(); - loadNote(); - } - - private void loadNote() { - Cursor cursor = mContext.getContentResolver().query( - ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, - null, null); - - if (cursor != null) { - if (cursor.moveToFirst()) { - mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); - mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); - mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); - mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); - mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); - mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); - } - cursor.close(); - } else { - Log.e(TAG, "No note with id:" + mNoteId); - throw new IllegalArgumentException("Unable to find note with id " + mNoteId); - } - loadNoteData(); - } - - private void loadNoteData() { - Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, - DataColumns.NOTE_ID + "=?", new String[] { - String.valueOf(mNoteId) - }, null); - - if (cursor != null) { - if (cursor.moveToFirst()) { - do { - String type = cursor.getString(DATA_MIME_TYPE_COLUMN); - if (DataConstants.NOTE.equals(type)) { - mContent = cursor.getString(DATA_CONTENT_COLUMN); - mMode = cursor.getInt(DATA_MODE_COLUMN); - mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN)); - } else if (DataConstants.CALL_NOTE.equals(type)) { - mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); - } else { - Log.d(TAG, "Wrong note type with type:" + type); - } - } while (cursor.moveToNext()); - } - cursor.close(); - } else { - Log.e(TAG, "No data with id:" + mNoteId); - throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); - } - } - - public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, - int widgetType, int defaultBgColorId) { - WorkingNote note = new WorkingNote(context, folderId); - note.setBgColorId(defaultBgColorId); - note.setWidgetId(widgetId); - note.setWidgetType(widgetType); - return note; - } - - public static WorkingNote load(Context context, long id) { - return new WorkingNote(context, id, 0); - } - - public synchronized boolean saveNote() { - if (isWorthSaving()) { - if (!existInDatabase()) { - if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { - Log.e(TAG, "Create new note fail with id:" + mNoteId); - return false; - } - } - - mNote.syncNote(mContext, mNoteId); - - /** - * Update widget content if there exist any widget of this note - */ - if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID - && mWidgetType != Notes.TYPE_WIDGET_INVALIDE - && mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onWidgetChanged(); - } - return true; - } else { - return false; - } - } - - public boolean existInDatabase() { - return mNoteId > 0; - } - - private boolean isWorthSaving() { - if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) - || (existInDatabase() && !mNote.isLocalModified())) { - return false; - } else { - return true; - } - } - - public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { - mNoteSettingStatusListener = l; - } - - public void setAlertDate(long date, boolean set) { - if (date != mAlertDate) { - mAlertDate = date; - mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate)); - } - if (mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onClockAlertChanged(date, set); - } - } - - public void markDeleted(boolean mark) { - mIsDeleted = mark; - if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID - && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onWidgetChanged(); - } - } - - public void setBgColorId(int id) { - if (id != mBgColorId) { - mBgColorId = id; - if (mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onBackgroundColorChanged(); - } - mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); - } - } - - public void setCheckListMode(int mode) { - if (mMode != mode) { - if (mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode); - } - mMode = mode; - mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); - } - } - - public void setWidgetType(int type) { - if (type != mWidgetType) { - mWidgetType = type; - mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); - } - } - - public void setWidgetId(int id) { - if (id != mWidgetId) { - mWidgetId = id; - mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); - } - } - - public void setWorkingText(String text) { - if (!TextUtils.equals(mContent, text)) { - mContent = text; - mNote.setTextData(DataColumns.CONTENT, mContent); - } - } - - public void convertToCallNote(String phoneNumber, long callDate) { - mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); - mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); - mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER)); - } - - public boolean hasClockAlert() { - return (mAlertDate > 0 ? true : false); - } - - public String getContent() { - return mContent; - } - - public long getAlertDate() { - return mAlertDate; - } - - public long getModifiedDate() { - return mModifiedDate; - } - - public int getBgColorResId() { - return NoteBgResources.getNoteBgResource(mBgColorId); - } - - public int getBgColorId() { - return mBgColorId; - } - - public int getTitleBgResId() { - return NoteBgResources.getNoteTitleBgResource(mBgColorId); - } - - public int getCheckListMode() { - return mMode; - } - - public long getNoteId() { - return mNoteId; - } - - public long getFolderId() { - return mFolderId; - } - - public int getWidgetId() { - return mWidgetId; - } - - public int getWidgetType() { - return mWidgetType; - } - - public interface NoteSettingChangedListener { - /** - * Called when the background color of current note has just changed - */ - void onBackgroundColorChanged(); - - /** - * Called when user set clock - */ - void onClockAlertChanged(long date, boolean set); - - /** - * Call when user create note from widget - */ - void onWidgetChanged(); - - /** - * Call when switch between check list mode and normal mode - * @param oldMode is previous mode before change - * @param newMode is new mode - */ - void onCheckListModeChanged(int oldMode, int newMode); - } -} diff --git a/doc/CJR_codereading/tool/BackupUtils.java b/doc/CJR_codereading/tool/BackupUtils.java deleted file mode 100644 index 39f6ec4..0000000 --- a/doc/CJR_codereading/tool/BackupUtils.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * 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.tool; - -import android.content.Context; -import android.database.Cursor; -import android.os.Environment; -import android.text.TextUtils; -import android.text.format.DateFormat; -import android.util.Log; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; - - -public class BackupUtils { - private static final String TAG = "BackupUtils"; - // Singleton stuff - private static BackupUtils sInstance; - - public static synchronized BackupUtils getInstance(Context context) { - if (sInstance == null) { - sInstance = new BackupUtils(context); - } - return sInstance; - } - - /** - * Following states are signs to represents backup or restore - * status - */ - // Currently, the sdcard is not mounted - public static final int STATE_SD_CARD_UNMOUONTED = 0; - // The backup file not exist - public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; - // The data is not well formated, may be changed by other programs - public static final int STATE_DATA_DESTROIED = 2; - // Some run-time exception which causes restore or backup fails - public static final int STATE_SYSTEM_ERROR = 3; - // Backup or restore success - public static final int STATE_SUCCESS = 4; - - private TextExport mTextExport; - - private BackupUtils(Context context) { - mTextExport = new TextExport(context); - } - - private static boolean externalStorageAvailable() { - return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); - } - - public int exportToText() { - return mTextExport.exportToText(); - } - - public String getExportedTextFileName() { - return mTextExport.mFileName; - } - - public String getExportedTextFileDir() { - return mTextExport.mFileDirectory; - } - - private static class TextExport { - private static final String[] NOTE_PROJECTION = { - NoteColumns.ID, - NoteColumns.MODIFIED_DATE, - NoteColumns.SNIPPET, - NoteColumns.TYPE - }; - - private static final int NOTE_COLUMN_ID = 0; - - private static final int NOTE_COLUMN_MODIFIED_DATE = 1; - - private static final int NOTE_COLUMN_SNIPPET = 2; - - private static final String[] DATA_PROJECTION = { - DataColumns.CONTENT, - DataColumns.MIME_TYPE, - DataColumns.DATA1, - DataColumns.DATA2, - DataColumns.DATA3, - DataColumns.DATA4, - }; - - private static final int DATA_COLUMN_CONTENT = 0; - - private static final int DATA_COLUMN_MIME_TYPE = 1; - - private static final int DATA_COLUMN_CALL_DATE = 2; - - private static final int DATA_COLUMN_PHONE_NUMBER = 4; - - private final String [] TEXT_FORMAT; - private static final int FORMAT_FOLDER_NAME = 0; - private static final int FORMAT_NOTE_DATE = 1; - private static final int FORMAT_NOTE_CONTENT = 2; - - private Context mContext; - private String mFileName; - private String mFileDirectory; - - public TextExport(Context context) { - TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); - mContext = context; - mFileName = ""; - mFileDirectory = ""; - } - - private String getFormat(int id) { - return TEXT_FORMAT[id]; - } - - /** - * Export the folder identified by folder id to text - */ - private void exportFolderToText(String folderId, PrintStream ps) { - // Query notes belong to this folder - Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, - NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { - folderId - }, null); - - if (notesCursor != null) { - if (notesCursor.moveToFirst()) { - do { - // Print note's last modified date - ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( - mContext.getString(R.string.format_datetime_mdhm), - notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); - // Query data belong to this note - String noteId = notesCursor.getString(NOTE_COLUMN_ID); - exportNoteToText(noteId, ps); - } while (notesCursor.moveToNext()); - } - notesCursor.close(); - } - } - - /** - * Export note identified by id to a print stream - */ - private void exportNoteToText(String noteId, PrintStream ps) { - Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, - DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { - noteId - }, null); - - if (dataCursor != null) { - if (dataCursor.moveToFirst()) { - do { - String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); - if (DataConstants.CALL_NOTE.equals(mimeType)) { - // Print phone number - String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER); - long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE); - String location = dataCursor.getString(DATA_COLUMN_CONTENT); - - if (!TextUtils.isEmpty(phoneNumber)) { - ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), - phoneNumber)); - } - // Print call date - ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat - .format(mContext.getString(R.string.format_datetime_mdhm), - callDate))); - // Print call attachment location - if (!TextUtils.isEmpty(location)) { - ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), - location)); - } - } else if (DataConstants.NOTE.equals(mimeType)) { - String content = dataCursor.getString(DATA_COLUMN_CONTENT); - if (!TextUtils.isEmpty(content)) { - ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), - content)); - } - } - } while (dataCursor.moveToNext()); - } - dataCursor.close(); - } - // print a line separator between note - try { - ps.write(new byte[] { - Character.LINE_SEPARATOR, Character.LETTER_NUMBER - }); - } catch (IOException e) { - Log.e(TAG, e.toString()); - } - } - - /** - * Note will be exported as text which is user readable - */ - public int exportToText() { - if (!externalStorageAvailable()) { - Log.d(TAG, "Media was not mounted"); - return STATE_SD_CARD_UNMOUONTED; - } - - PrintStream ps = getExportToTextPrintStream(); - if (ps == null) { - Log.e(TAG, "get print stream error"); - return STATE_SYSTEM_ERROR; - } - // First export folder and its notes - Cursor folderCursor = mContext.getContentResolver().query( - Notes.CONTENT_NOTE_URI, - NOTE_PROJECTION, - "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " - + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR " - + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null); - - if (folderCursor != null) { - if (folderCursor.moveToFirst()) { - do { - // Print folder's name - String folderName = ""; - if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) { - folderName = mContext.getString(R.string.call_record_folder_name); - } else { - folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET); - } - if (!TextUtils.isEmpty(folderName)) { - ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName)); - } - String folderId = folderCursor.getString(NOTE_COLUMN_ID); - exportFolderToText(folderId, ps); - } while (folderCursor.moveToNext()); - } - folderCursor.close(); - } - - // Export notes in root's folder - Cursor noteCursor = mContext.getContentResolver().query( - Notes.CONTENT_NOTE_URI, - NOTE_PROJECTION, - NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID - + "=0", null, null); - - if (noteCursor != null) { - if (noteCursor.moveToFirst()) { - do { - ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( - mContext.getString(R.string.format_datetime_mdhm), - noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); - // Query data belong to this note - String noteId = noteCursor.getString(NOTE_COLUMN_ID); - exportNoteToText(noteId, ps); - } while (noteCursor.moveToNext()); - } - noteCursor.close(); - } - ps.close(); - - return STATE_SUCCESS; - } - - /** - * Get a print stream pointed to the file {@generateExportedTextFile} - */ - private PrintStream getExportToTextPrintStream() { - File file = generateFileMountedOnSDcard(mContext, R.string.file_path, - R.string.file_name_txt_format); - if (file == null) { - Log.e(TAG, "create file to exported failed"); - return null; - } - mFileName = file.getName(); - mFileDirectory = mContext.getString(R.string.file_path); - PrintStream ps = null; - try { - FileOutputStream fos = new FileOutputStream(file); - ps = new PrintStream(fos); - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; - } catch (NullPointerException e) { - e.printStackTrace(); - return null; - } - return ps; - } - } - - /** - * Generate the text file to store imported data - */ - private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { - StringBuilder sb = new StringBuilder(); - sb.append(Environment.getExternalStorageDirectory()); - sb.append(context.getString(filePathResId)); - File filedir = new File(sb.toString()); - sb.append(context.getString( - fileNameFormatResId, - DateFormat.format(context.getString(R.string.format_date_ymd), - System.currentTimeMillis()))); - File file = new File(sb.toString()); - - try { - if (!filedir.exists()) { - filedir.mkdir(); - } - if (!file.exists()) { - file.createNewFile(); - } - return file; - } catch (SecurityException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - - return null; - } -} - - diff --git a/doc/CJR_codereading/tool/DataUtils.java b/doc/CJR_codereading/tool/DataUtils.java deleted file mode 100644 index 2a14982..0000000 --- a/doc/CJR_codereading/tool/DataUtils.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * 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.tool; - -import android.content.ContentProviderOperation; -import android.content.ContentProviderResult; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.OperationApplicationException; -import android.database.Cursor; -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.NoteColumns; -import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; - -import java.util.ArrayList; -import java.util.HashSet; - - -public class DataUtils { - public static final String TAG = "DataUtils"; - public static boolean batchDeleteNotes(ContentResolver resolver, HashSet ids) { - if (ids == null) { - Log.d(TAG, "the ids is null"); - return true; - } - if (ids.size() == 0) { - Log.d(TAG, "no id is in the hashset"); - return true; - } - - ArrayList operationList = new ArrayList(); - for (long id : ids) { - if(id == Notes.ID_ROOT_FOLDER) { - Log.e(TAG, "Don't delete system folder root"); - continue; - } - ContentProviderOperation.Builder builder = ContentProviderOperation - .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); - operationList.add(builder.build()); - } - try { - ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); - if (results == null || results.length == 0 || results[0] == null) { - Log.d(TAG, "delete notes failed, ids:" + ids.toString()); - return false; - } - return true; - } catch (RemoteException e) { - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - } catch (OperationApplicationException e) { - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - } - return false; - } - - public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) { - ContentValues values = new ContentValues(); - values.put(NoteColumns.PARENT_ID, desFolderId); - values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); - values.put(NoteColumns.LOCAL_MODIFIED, 1); - resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); - } - - public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids, - long folderId) { - if (ids == null) { - Log.d(TAG, "the ids is null"); - return true; - } - - ArrayList operationList = new ArrayList(); - for (long id : ids) { - ContentProviderOperation.Builder builder = ContentProviderOperation - .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); - builder.withValue(NoteColumns.PARENT_ID, folderId); - builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); - operationList.add(builder.build()); - } - - try { - ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); - if (results == null || results.length == 0 || results[0] == null) { - Log.d(TAG, "delete notes failed, ids:" + ids.toString()); - return false; - } - return true; - } catch (RemoteException e) { - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - } catch (OperationApplicationException e) { - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - } - return false; - } - - /** - * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}} - */ - public static int getUserFolderCount(ContentResolver resolver) { - Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI, - new String[] { "COUNT(*)" }, - NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", - new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, - null); - - int count = 0; - if(cursor != null) { - if(cursor.moveToFirst()) { - try { - count = cursor.getInt(0); - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, "get folder count failed:" + e.toString()); - } finally { - cursor.close(); - } - } - } - return count; - } - - public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { - Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), - null, - NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, - new String [] {String.valueOf(type)}, - null); - - boolean exist = false; - if (cursor != null) { - if (cursor.getCount() > 0) { - exist = true; - } - cursor.close(); - } - return exist; - } - - public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { - Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), - null, null, null, null); - - boolean exist = false; - if (cursor != null) { - if (cursor.getCount() > 0) { - exist = true; - } - cursor.close(); - } - return exist; - } - - public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { - Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), - null, null, null, null); - - boolean exist = false; - if (cursor != null) { - if (cursor.getCount() > 0) { - exist = true; - } - cursor.close(); - } - return exist; - } - - public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { - Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, - NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + - " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + - " AND " + NoteColumns.SNIPPET + "=?", - new String[] { name }, null); - boolean exist = false; - if(cursor != null) { - if(cursor.getCount() > 0) { - exist = true; - } - cursor.close(); - } - return exist; - } - - public static HashSet getFolderNoteWidget(ContentResolver resolver, long folderId) { - Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, - new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, - NoteColumns.PARENT_ID + "=?", - new String[] { String.valueOf(folderId) }, - null); - - HashSet set = null; - if (c != null) { - if (c.moveToFirst()) { - set = new HashSet(); - do { - try { - AppWidgetAttribute widget = new AppWidgetAttribute(); - widget.widgetId = c.getInt(0); - widget.widgetType = c.getInt(1); - set.add(widget); - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, e.toString()); - } - } while (c.moveToNext()); - } - c.close(); - } - return set; - } - - public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { - Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, - new String [] { CallNote.PHONE_NUMBER }, - CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", - new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }, - null); - - if (cursor != null && cursor.moveToFirst()) { - try { - return cursor.getString(0); - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, "Get call number fails " + e.toString()); - } finally { - cursor.close(); - } - } - return ""; - } - - public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { - Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, - new String [] { CallNote.NOTE_ID }, - CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" - + CallNote.PHONE_NUMBER + ",?)", - new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, - null); - - if (cursor != null) { - if (cursor.moveToFirst()) { - try { - return cursor.getLong(0); - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, "Get call note id fails " + e.toString()); - } - } - cursor.close(); - } - return 0; - } - - public static String getSnippetById(ContentResolver resolver, long noteId) { - Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, - new String [] { NoteColumns.SNIPPET }, - NoteColumns.ID + "=?", - new String [] { String.valueOf(noteId)}, - null); - - if (cursor != null) { - String snippet = ""; - if (cursor.moveToFirst()) { - snippet = cursor.getString(0); - } - cursor.close(); - return snippet; - } - throw new IllegalArgumentException("Note is not found with id: " + noteId); - } - - public static String getFormattedSnippet(String snippet) { - if (snippet != null) { - snippet = snippet.trim(); - int index = snippet.indexOf('\n'); - if (index != -1) { - snippet = snippet.substring(0, index); - } - } - return snippet; - } -} diff --git a/doc/CJR_codereading/tool/GTaskStringUtils.java b/doc/CJR_codereading/tool/GTaskStringUtils.java deleted file mode 100644 index 666b729..0000000 --- a/doc/CJR_codereading/tool/GTaskStringUtils.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.tool; - -public class GTaskStringUtils { - - public final static String GTASK_JSON_ACTION_ID = "action_id"; - - public final static String GTASK_JSON_ACTION_LIST = "action_list"; - - public final static String GTASK_JSON_ACTION_TYPE = "action_type"; - - public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create"; - - public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all"; - - public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move"; - - public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update"; - - public final static String GTASK_JSON_CREATOR_ID = "creator_id"; - - public final static String GTASK_JSON_CHILD_ENTITY = "child_entity"; - - public final static String GTASK_JSON_CLIENT_VERSION = "client_version"; - - public final static String GTASK_JSON_COMPLETED = "completed"; - - public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id"; - - public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id"; - - public final static String GTASK_JSON_DELETED = "deleted"; - - public final static String GTASK_JSON_DEST_LIST = "dest_list"; - - public final static String GTASK_JSON_DEST_PARENT = "dest_parent"; - - public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type"; - - public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta"; - - public final static String GTASK_JSON_ENTITY_TYPE = "entity_type"; - - public final static String GTASK_JSON_GET_DELETED = "get_deleted"; - - public final static String GTASK_JSON_ID = "id"; - - public final static String GTASK_JSON_INDEX = "index"; - - public final static String GTASK_JSON_LAST_MODIFIED = "last_modified"; - - public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point"; - - public final static String GTASK_JSON_LIST_ID = "list_id"; - - public final static String GTASK_JSON_LISTS = "lists"; - - public final static String GTASK_JSON_NAME = "name"; - - public final static String GTASK_JSON_NEW_ID = "new_id"; - - public final static String GTASK_JSON_NOTES = "notes"; - - public final static String GTASK_JSON_PARENT_ID = "parent_id"; - - public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id"; - - public final static String GTASK_JSON_RESULTS = "results"; - - public final static String GTASK_JSON_SOURCE_LIST = "source_list"; - - public final static String GTASK_JSON_TASKS = "tasks"; - - public final static String GTASK_JSON_TYPE = "type"; - - public final static String GTASK_JSON_TYPE_GROUP = "GROUP"; - - public final static String GTASK_JSON_TYPE_TASK = "TASK"; - - public final static String GTASK_JSON_USER = "user"; - - public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]"; - - public final static String FOLDER_DEFAULT = "Default"; - - public final static String FOLDER_CALL_NOTE = "Call_Note"; - - public final static String FOLDER_META = "METADATA"; - - public final static String META_HEAD_GTASK_ID = "meta_gid"; - - public final static String META_HEAD_NOTE = "meta_note"; - - public final static String META_HEAD_DATA = "meta_data"; - - public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE"; - -} diff --git a/doc/CJR_codereading/tool/ResourceParser.java b/doc/CJR_codereading/tool/ResourceParser.java deleted file mode 100644 index 1ad3ad6..0000000 --- a/doc/CJR_codereading/tool/ResourceParser.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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.tool; - -import android.content.Context; -import android.preference.PreferenceManager; - -import net.micode.notes.R; -import net.micode.notes.ui.NotesPreferenceActivity; - -public class ResourceParser { - - public static final int YELLOW = 0; - public static final int BLUE = 1; - public static final int WHITE = 2; - public static final int GREEN = 3; - public static final int RED = 4; - - public static final int BG_DEFAULT_COLOR = YELLOW; - - public static final int TEXT_SMALL = 0; - public static final int TEXT_MEDIUM = 1; - public static final int TEXT_LARGE = 2; - public static final int TEXT_SUPER = 3; - - public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM; - - public static class NoteBgResources { - private final static int [] BG_EDIT_RESOURCES = new int [] { - R.drawable.edit_yellow, - R.drawable.edit_blue, - R.drawable.edit_white, - R.drawable.edit_green, - R.drawable.edit_red - }; - - private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] { - R.drawable.edit_title_yellow, - R.drawable.edit_title_blue, - R.drawable.edit_title_white, - R.drawable.edit_title_green, - R.drawable.edit_title_red - }; - - public static int getNoteBgResource(int id) { - return BG_EDIT_RESOURCES[id]; - } - - public static int getNoteTitleBgResource(int id) { - return BG_EDIT_TITLE_RESOURCES[id]; - } - } - - public static int getDefaultBgId(Context context) { - if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( - NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { - return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length); - } else { - return BG_DEFAULT_COLOR; - } - } - - public static class NoteItemBgResources { - private final static int [] BG_FIRST_RESOURCES = new int [] { - R.drawable.list_yellow_up, - R.drawable.list_blue_up, - R.drawable.list_white_up, - R.drawable.list_green_up, - R.drawable.list_red_up - }; - - private final static int [] BG_NORMAL_RESOURCES = new int [] { - R.drawable.list_yellow_middle, - R.drawable.list_blue_middle, - R.drawable.list_white_middle, - R.drawable.list_green_middle, - R.drawable.list_red_middle - }; - - private final static int [] BG_LAST_RESOURCES = new int [] { - R.drawable.list_yellow_down, - R.drawable.list_blue_down, - R.drawable.list_white_down, - R.drawable.list_green_down, - R.drawable.list_red_down, - }; - - private final static int [] BG_SINGLE_RESOURCES = new int [] { - R.drawable.list_yellow_single, - R.drawable.list_blue_single, - R.drawable.list_white_single, - R.drawable.list_green_single, - R.drawable.list_red_single - }; - - public static int getNoteBgFirstRes(int id) { - return BG_FIRST_RESOURCES[id]; - } - - public static int getNoteBgLastRes(int id) { - return BG_LAST_RESOURCES[id]; - } - - public static int getNoteBgSingleRes(int id) { - return BG_SINGLE_RESOURCES[id]; - } - - public static int getNoteBgNormalRes(int id) { - return BG_NORMAL_RESOURCES[id]; - } - - public static int getFolderBgRes() { - return R.drawable.list_folder; - } - } - - public static class WidgetBgResources { - private final static int [] BG_2X_RESOURCES = new int [] { - R.drawable.widget_2x_yellow, - R.drawable.widget_2x_blue, - R.drawable.widget_2x_white, - R.drawable.widget_2x_green, - R.drawable.widget_2x_red, - }; - - public static int getWidget2xBgResource(int id) { - return BG_2X_RESOURCES[id]; - } - - private final static int [] BG_4X_RESOURCES = new int [] { - R.drawable.widget_4x_yellow, - R.drawable.widget_4x_blue, - R.drawable.widget_4x_white, - R.drawable.widget_4x_green, - R.drawable.widget_4x_red - }; - - public static int getWidget4xBgResource(int id) { - return BG_4X_RESOURCES[id]; - } - } - - public static class TextAppearanceResources { - private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] { - R.style.TextAppearanceNormal, - R.style.TextAppearanceMedium, - R.style.TextAppearanceLarge, - R.style.TextAppearanceSuper - }; - - public static int getTexAppearanceResource(int id) { - /** - * HACKME: Fix bug of store the resource id in shared preference. - * The id may larger than the length of resources, in this case, - * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} - */ - if (id >= TEXTAPPEARANCE_RESOURCES.length) { - return BG_DEFAULT_FONT_SIZE; - } - return TEXTAPPEARANCE_RESOURCES[id]; - } - - public static int getResourcesSize() { - return TEXTAPPEARANCE_RESOURCES.length; - } - } -} diff --git a/doc/CJR_codereading/widget/NoteWidgetProvider.java b/doc/CJR_codereading/widget/NoteWidgetProvider.java deleted file mode 100644 index ec6f819..0000000 --- a/doc/CJR_codereading/widget/NoteWidgetProvider.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.widget; -import android.app.PendingIntent; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.util.Log; -import android.widget.RemoteViews; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.tool.ResourceParser; -import net.micode.notes.ui.NoteEditActivity; -import net.micode.notes.ui.NotesListActivity; - -public abstract class NoteWidgetProvider extends AppWidgetProvider { - public static final String [] PROJECTION = new String [] { - NoteColumns.ID, - NoteColumns.BG_COLOR_ID, - NoteColumns.SNIPPET - }; - - public static final int COLUMN_ID = 0; - public static final int COLUMN_BG_COLOR_ID = 1; - public static final int COLUMN_SNIPPET = 2; - - private static final String TAG = "NoteWidgetProvider"; - - @Override - public void onDeleted(Context context, int[] appWidgetIds) { - ContentValues values = new ContentValues(); - values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); - for (int i = 0; i < appWidgetIds.length; i++) { - context.getContentResolver().update(Notes.CONTENT_NOTE_URI, - values, - NoteColumns.WIDGET_ID + "=?", - new String[] { String.valueOf(appWidgetIds[i])}); - } - } - - private Cursor getNoteWidgetInfo(Context context, int widgetId) { - return context.getContentResolver().query(Notes.CONTENT_NOTE_URI, - PROJECTION, - NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?", - new String[] { String.valueOf(widgetId), String.valueOf(Notes.ID_TRASH_FOLER) }, - null); - } - - protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - update(context, appWidgetManager, appWidgetIds, false); - } - - private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, - boolean privacyMode) { - for (int i = 0; i < appWidgetIds.length; i++) { - if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) { - int bgId = ResourceParser.getDefaultBgId(context); - String snippet = ""; - Intent intent = new Intent(context, NoteEditActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]); - intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType()); - - Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]); - if (c != null && c.moveToFirst()) { - if (c.getCount() > 1) { - Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]); - c.close(); - return; - } - snippet = c.getString(COLUMN_SNIPPET); - bgId = c.getInt(COLUMN_BG_COLOR_ID); - intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID)); - intent.setAction(Intent.ACTION_VIEW); - } else { - snippet = context.getResources().getString(R.string.widget_havenot_content); - intent.setAction(Intent.ACTION_INSERT_OR_EDIT); - } - - if (c != null) { - c.close(); - } - - RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId()); - rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId)); - intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId); - /** - * Generate the pending intent to start host for the widget - */ - PendingIntent pendingIntent = null; - if (privacyMode) { - rv.setTextViewText(R.id.widget_text, - context.getString(R.string.widget_under_visit_mode)); - pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent( - context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); - } else { - rv.setTextViewText(R.id.widget_text, snippet); - pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent, - PendingIntent.FLAG_UPDATE_CURRENT); - } - - rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent); - appWidgetManager.updateAppWidget(appWidgetIds[i], rv); - } - } - } - - protected abstract int getBgResourceId(int bgId); - - protected abstract int getLayoutId(); - - protected abstract int getWidgetType(); -} diff --git a/doc/CJR_codereading/widget/NoteWidgetProvider_2x.java b/doc/CJR_codereading/widget/NoteWidgetProvider_2x.java deleted file mode 100644 index adcb2f7..0000000 --- a/doc/CJR_codereading/widget/NoteWidgetProvider_2x.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.widget; - -import android.appwidget.AppWidgetManager; -import android.content.Context; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.tool.ResourceParser; - - -public class NoteWidgetProvider_2x extends NoteWidgetProvider { - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - super.update(context, appWidgetManager, appWidgetIds); - } - - @Override - protected int getLayoutId() { - return R.layout.widget_2x; - } - - @Override - protected int getBgResourceId(int bgId) { - return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId); - } - - @Override - protected int getWidgetType() { - return Notes.TYPE_WIDGET_2X; - } -} diff --git a/doc/CJR_codereading/widget/NoteWidgetProvider_4x.java b/doc/CJR_codereading/widget/NoteWidgetProvider_4x.java deleted file mode 100644 index c12a02e..0000000 --- a/doc/CJR_codereading/widget/NoteWidgetProvider_4x.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.widget; - -import android.appwidget.AppWidgetManager; -import android.content.Context; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.tool.ResourceParser; - - -public class NoteWidgetProvider_4x extends NoteWidgetProvider { - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - super.update(context, appWidgetManager, appWidgetIds); - } - - protected int getLayoutId() { - return R.layout.widget_4x; - } - - @Override - protected int getBgResourceId(int bgId) { - return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId); - } - - @Override - protected int getWidgetType() { - return Notes.TYPE_WIDGET_4X; - } -} diff --git a/doc/cyw.readcode.ui/ui/AlarmAlertActivity.java b/doc/cyw.readcode.ui/ui/AlarmAlertActivity.java deleted file mode 100644 index e9fdb28..0000000 --- a/doc/cyw.readcode.ui/ui/AlarmAlertActivity.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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.ui; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.DialogInterface.OnDismissListener; -import android.content.Intent; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.media.RingtoneManager; -import android.net.Uri; -import android.os.Bundle; -import android.os.PowerManager; -import android.provider.Settings; -import android.view.Window; -import android.view.WindowManager; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.tool.DataUtils; - -import java.io.IOException; - -public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { - private long mNoteId; //文本在数据库存储中的ID号 - private String mSnippet; //闹钟提示时出现的文本片段 - private static final int SNIPPET_PREW_MAX_LEN = 60; - MediaPlayer mPlayer; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - //Bundle类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的 - //onsaveInstanceState方法是用来保存Activity的状态的 - //能从onCreate的参数savedInsanceState中获得状态数据 - requestWindowFeature(Window.FEATURE_NO_TITLE); - //界面显示——无标题 - - final Window win = getWindow(); - win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); - - if (!isScreenOn()) { - win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON - //保持窗体点亮 - | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON - //将窗体点亮 - | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON - //允许窗体点亮时锁屏 - | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); - }//在手机锁屏后如果到了闹钟提示时间,点亮屏幕 - - Intent intent = getIntent(); - - try { - mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); - mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); - //根据ID从数据库中获取标签的内容; - //getContentResolver()是实现数据共享,实例存储。 - mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, - SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info) - : mSnippet; - //判断标签片段是否达到符合长度 - } catch (IllegalArgumentException e) { - e.printStackTrace(); - return; - } - /* - try - { - // 代码区 - } - catch(Exception e) - { - // 异常处理 - } - 代码区如果有错误,就会返回所写异常的处理。*/ - mPlayer = new MediaPlayer(); - if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { - showActionDialog(); - //弹出对话框 - playAlarmSound(); - //闹钟提示音激发 - } else { - finish(); - //完成闹钟动作 - } - } - - private boolean isScreenOn() { - //判断屏幕是否锁屏,调用系统函数判断,最后返回值是布尔类型 - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - return pm.isScreenOn(); - } - - private void playAlarmSound() { - //闹钟提示音激发 - Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); - //调用系统的铃声管理URI,得到闹钟提示音 - int silentModeStreams = Settings.System.getInt(getContentResolver(), - Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); - - if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { - mPlayer.setAudioStreamType(silentModeStreams); - } else { - mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); - } - try { - mPlayer.setDataSource(this, url); - //方法:setDataSource(Context context, Uri uri) - //解释:无返回值,设置多媒体数据来源【根据 Uri】 - mPlayer.prepare(); - //准备同步 - mPlayer.setLooping(true); - //设置是否循环播放 - mPlayer.start(); - //开始播放 - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - //e.printStackTrace()函数功能是抛出异常, 还将显示出更深的调用信息 - //System.out.println(e),这个方法打印出异常,并且输出在哪里出现的异常 - } catch (SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalStateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - private void showActionDialog() { - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - //AlertDialog的构造方法全部是Protected的 - //所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。 - //要创建一个AlertDialog,就要用到AlertDialog.Builder中的create()方法 - //如这里的dialog就是新建了一个AlertDialog - dialog.setTitle(R.string.app_name); - //为对话框设置标题 - dialog.setMessage(mSnippet); - //为对话框设置内容 - dialog.setPositiveButton(R.string.notealert_ok, this); - //给对话框添加"Yes"按钮 - if (isScreenOn()) { - dialog.setNegativeButton(R.string.notealert_enter, this); - }//对话框添加"No"按钮 - dialog.show().setOnDismissListener(this); - } - - public void onClick(DialogInterface dialog, int which) { - switch (which) { - //用which来选择click后下一步的操作 - case DialogInterface.BUTTON_NEGATIVE: - //这是取消操作 - Intent intent = new Intent(this, NoteEditActivity.class); - //实现两个类间的数据传输 - intent.setAction(Intent.ACTION_VIEW); - //设置动作属性 - intent.putExtra(Intent.EXTRA_UID, mNoteId); - //实现key-value对 - //EXTRA_UID为key;mNoteId为键 - startActivity(intent); - //开始动作 - break; - default: - //这是确定操作 - break; - } - } - - public void onDismiss(DialogInterface dialog) { - //忽略 - stopAlarmSound(); - //停止闹钟声音 - finish(); - //完成该动作 - } - - private void stopAlarmSound() { - if (mPlayer != null) { - mPlayer.stop(); - //停止播放 - mPlayer.release(); - //释放MediaPlayer对象 - mPlayer = null; - } - } -} diff --git a/doc/cyw.readcode.ui/ui/AlarmInitReceiver.java b/doc/cyw.readcode.ui/ui/AlarmInitReceiver.java deleted file mode 100644 index 7f03f69..0000000 --- a/doc/cyw.readcode.ui/ui/AlarmInitReceiver.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.ui; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.ContentUris; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; - -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.NoteColumns; - - -public class AlarmInitReceiver extends BroadcastReceiver { - - private static final String [] PROJECTION = new String [] { - NoteColumns.ID, - NoteColumns.ALERTED_DATE - }; - //对数据库的操作,调用标签ID和闹钟时间 - private static final int COLUMN_ID = 0; - private static final int COLUMN_ALERTED_DATE = 1; - - @Override - public void onReceive(Context context, Intent intent) { - long currentDate = System.currentTimeMillis(); - //System.currentTimeMillis()产生一个当前的毫秒 - //这个毫秒其实就是自1970年1月1日0时起的毫秒数 - Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI, - PROJECTION, - NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE, - new String[] { String.valueOf(currentDate) }, - //将long变量currentDate转化为字符串 - null); - - if (c != null) { - if (c.moveToFirst()) { - do { - long alertDate = c.getLong(COLUMN_ALERTED_DATE); - Intent sender = new Intent(context, AlarmReceiver.class); - sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); - PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); - AlarmManager alermManager = (AlarmManager) context - .getSystemService(Context.ALARM_SERVICE); - alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); - } while (c.moveToNext()); - } - c.close(); - } - //然而通过网上查找资料发现,对于闹钟机制的启动,通常需要上面的几个步骤 - //如新建Intent、PendingIntent以及AlarmManager等 - //这里就是根据数据库里的闹钟时间创建一个闹钟机制 - } -} diff --git a/doc/cyw.readcode.ui/ui/AlarmReceiver.java b/doc/cyw.readcode.ui/ui/AlarmReceiver.java deleted file mode 100644 index 8d7492d..0000000 --- a/doc/cyw.readcode.ui/ui/AlarmReceiver.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.ui; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -public class AlarmReceiver extends BroadcastReceiver {//类:闹钟消息接收器,从BroadcastReceiver类继承而来 - @Override - public void onReceive(Context context, Intent intent) { - intent.setClass(context, AlarmAlertActivity.class); - //启动AlarmAlertActivity - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - //activity要存在于activity的栈中,而非activity的途径启动activity时必然不存在一个activity的栈 - //所以要新起一个栈装入启动的activity - context.startActivity(intent); - } -} -//这是实现alarm这个功能最接近用户层的包,基于上面的两个包, \ No newline at end of file diff --git a/doc/cyw.readcode.ui/ui/DateTimePicker.java b/doc/cyw.readcode.ui/ui/DateTimePicker.java deleted file mode 100644 index 11a8469..0000000 --- a/doc/cyw.readcode.ui/ui/DateTimePicker.java +++ /dev/null @@ -1,504 +0,0 @@ -/* - * 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.ui; - -import java.text.DateFormatSymbols; -import java.util.Calendar; - -import net.micode.notes.R; - - -import android.content.Context; -import android.text.format.DateFormat; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.NumberPicker; - -public class DateTimePicker extends FrameLayout {//FrameLayout是布局模板之一 - //所有的子元素全部在屏幕的右上方 - - private static final boolean DEFAULT_ENABLE_STATE = true; - - private static final int HOURS_IN_HALF_DAY = 12; - private static final int HOURS_IN_ALL_DAY = 24; - private static final int DAYS_IN_ALL_WEEK = 7; - private static final int DATE_SPINNER_MIN_VAL = 0; - private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1; - private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0; - private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23; - private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1; - private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12; - private static final int MINUT_SPINNER_MIN_VAL = 0; - private static final int MINUT_SPINNER_MAX_VAL = 59; - private static final int AMPM_SPINNER_MIN_VAL = 0; - private static final int AMPM_SPINNER_MAX_VAL = 1; - //初始化控件 - private final NumberPicker mDateSpinner; - private final NumberPicker mHourSpinner; - private final NumberPicker mMinuteSpinner; - private final NumberPicker mAmPmSpinner; - //NumberPicker是数字选择器 - //这里定义的四个变量全部是在设置闹钟时需要选择的变量(如日期、时、分、上午或者下午) - - private Calendar mDate; - //定义了Calendar类型的变量mDate,用于操作时间 - private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; - - private boolean mIsAm; - - private boolean mIs24HourView; - - private boolean mIsEnabled = DEFAULT_ENABLE_STATE; - - private boolean mInitialising; - - private OnDateTimeChangedListener mOnDateTimeChangedListener; - - private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() { - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal); - updateDateControl(); - onDateTimeChanged(); - } - };//OnValueChangeListener,这是时间改变监听器,这里主要是对日期的监听 - //将现在日期的值传递给mDate;updateDateControl是同步操作 - - private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() { - //这里是对 小时(Hour) 的监听 - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - boolean isDateChanged = false; - Calendar cal = Calendar.getInstance(); - //声明一个Calendar的变量cal,便于后续的操作 - if (!mIs24HourView) { - if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) { - cal.setTimeInMillis(mDate.getTimeInMillis()); - cal.add(Calendar.DAY_OF_YEAR, 1); - isDateChanged = true; - //这里是对于12小时制时,晚上11点和12点交替时对日期的更改 - } else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) { - cal.setTimeInMillis(mDate.getTimeInMillis()); - cal.add(Calendar.DAY_OF_YEAR, -1); - isDateChanged = true; - }//这里是对于12小时制时,凌晨11点和12点交替时对日期的更改 - if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY || - oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) { - mIsAm = !mIsAm; - updateAmPmControl(); - }//这里是对于12小时制时,中午11点和12点交替时对AM和PM的更改 - } else { - if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) { - cal.setTimeInMillis(mDate.getTimeInMillis()); - cal.add(Calendar.DAY_OF_YEAR, 1); - isDateChanged = true; - //这里是对于24小时制时,晚上11点和12点交替时对日期的更改 - } else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) { - cal.setTimeInMillis(mDate.getTimeInMillis()); - cal.add(Calendar.DAY_OF_YEAR, -1); - isDateChanged = true; - } - }//这里是对于12小时制时,凌晨11点和12点交替时对日期的更改 - int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY); - //通过数字选择器对newHour的赋值 - mDate.set(Calendar.HOUR_OF_DAY, newHour); - //通过set函数将新的Hour值传给mDate - onDateTimeChanged(); - if (isDateChanged) { - setCurrentYear(cal.get(Calendar.YEAR)); - setCurrentMonth(cal.get(Calendar.MONTH)); - setCurrentDay(cal.get(Calendar.DAY_OF_MONTH)); - } - } - }; - - private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() { - @Override - //这里是对 分钟(Minute)改变的监听 - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - int minValue = mMinuteSpinner.getMinValue(); - int maxValue = mMinuteSpinner.getMaxValue(); - int offset = 0; - //设置offset,作为小时改变的一个记录数据 - if (oldVal == maxValue && newVal == minValue) { - offset += 1; - } else if (oldVal == minValue && newVal == maxValue) { - offset -= 1; - }//如果原值为59,新值为0,则offset加1 - //如果原值为0,新值为59,则offset减1 - if (offset != 0) { - mDate.add(Calendar.HOUR_OF_DAY, offset); - mHourSpinner.setValue(getCurrentHour()); - updateDateControl(); - int newHour = getCurrentHourOfDay(); - if (newHour >= HOURS_IN_HALF_DAY) { - mIsAm = false; - updateAmPmControl(); - } else { - mIsAm = true; - updateAmPmControl(); - } - } - mDate.set(Calendar.MINUTE, newVal); - onDateTimeChanged(); - } - }; - - private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() { - //对AM和PM的监听 - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - mIsAm = !mIsAm; - if (mIsAm) { - mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY); - } else { - mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY); - } - updateAmPmControl(); - onDateTimeChanged(); - } - }; - - public interface OnDateTimeChangedListener { - void onDateTimeChanged(DateTimePicker view, int year, int month, - int dayOfMonth, int hourOfDay, int minute); - }//接口:日期变化监听器 - - public DateTimePicker(Context context) { - this(context, System.currentTimeMillis()); - } -//方法:实例化时间日期选择器 - public DateTimePicker(Context context, long date) { - this(context, date, DateFormat.is24HourFormat(context)); - }//通过对数据库的访问,获取当前的系统时间 - - public DateTimePicker(Context context, long date, boolean is24HourView) { - super(context);//获取系统时间 - mDate = Calendar.getInstance(); - mInitialising = true; - mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY; - inflate(context, R.layout.datetime_picker, this); - //如果当前Activity里用到别的layout,比如对话框layout - //还要设置这个layout上的其他组件的内容,就必须用inflate()方法先将对话框的layout找出来 - //然后再用findViewById()找到它上面的其它组件 - mDateSpinner = (NumberPicker) findViewById(R.id.date); - mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL); - mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL); - mDateSpinner.setOnValueChangedListener(mOnDateChangedListener); - - mHourSpinner = (NumberPicker) findViewById(R.id.hour); - mHourSpinner.setOnValueChangedListener(mOnHourChangedListener); - mMinuteSpinner = (NumberPicker) findViewById(R.id.minute); - mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL); - mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL); - mMinuteSpinner.setOnLongPressUpdateInterval(100); - mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener); - - String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings(); - mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm); - mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL); - mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL); - mAmPmSpinner.setDisplayedValues(stringsForAmPm); - mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener); - - // update controls to initial state - updateDateControl(); - updateHourControl(); - updateAmPmControl(); - - set24HourView(is24HourView); - - // set to current time - setCurrentDate(date); - - setEnabled(isEnabled()); - - // set the content descriptions - mInitialising = false; - } - - @Override - public void setEnabled(boolean enabled) {//方法:将转轮设置为使能状态 - if (mIsEnabled == enabled) { - return; - } - super.setEnabled(enabled); - mDateSpinner.setEnabled(enabled);//语句:分别对四个分部件设置使能 - mMinuteSpinner.setEnabled(enabled); - mHourSpinner.setEnabled(enabled); - mAmPmSpinner.setEnabled(enabled); - mIsEnabled = enabled;//修改标志变量 - } - - @Override - public boolean isEnabled() { - return mIsEnabled; - }//函数:判断当前的时间日期选择器是否处于启用的的状态 - - /** - * Get the current date in millis - * - * @return the current date in millis - */ - public long getCurrentDateInTimeMillis() { - return mDate.getTimeInMillis(); - } -//实现函数——得到当前的秒数 - /** - * Set the current date - * - * @param date The current date in millis - */ - public void setCurrentDate(long date) { - Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(date); - setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), - cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)); - }//实现函数功能——设置当前的时间,参数是date - - /** - * Set the current date - * - * @param year The current year - * @param month The current month - * @param dayOfMonth The current dayOfMonth - * @param hourOfDay The current hourOfDay - * @param minute The current minute - */ - public void setCurrentDate(int year, int month, - int dayOfMonth, int hourOfDay, int minute) { - setCurrentYear(year); - setCurrentMonth(month); - setCurrentDay(dayOfMonth); - setCurrentHour(hourOfDay); - setCurrentMinute(minute); - }//实现函数功能——设置当前的时间,参数是各详细的变量 - - /** - * Get current year - * - * @return The current year - */ - //下面是得到year、month、day等值 - public int getCurrentYear() { - return mDate.get(Calendar.YEAR); - } - - /** - * Set current year - * - * @param year The current year - */ - public void setCurrentYear(int year) { - if (!mInitialising && year == getCurrentYear()) { - return; - } - mDate.set(Calendar.YEAR, year); - updateDateControl(); - onDateTimeChanged(); - } - - /** - * Get current month in the year - * - * @return The current month in the year - */ - public int getCurrentMonth() { - return mDate.get(Calendar.MONTH); - } - - /** - * Set current month in the year - * - * @param month The month in the year - */ - public void setCurrentMonth(int month) { - if (!mInitialising && month == getCurrentMonth()) { - return; - } - mDate.set(Calendar.MONTH, month); - updateDateControl(); - onDateTimeChanged(); - } - - /** - * Get current day of the month - * - * @return The day of the month - */ - public int getCurrentDay() { - return mDate.get(Calendar.DAY_OF_MONTH); - } - - /** - * Set current day of the month - * - * @param dayOfMonth The day of the month - */ - public void setCurrentDay(int dayOfMonth) { - if (!mInitialising && dayOfMonth == getCurrentDay()) { - return; - } - mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); - updateDateControl(); - onDateTimeChanged(); - } - - /** - * Get current hour in 24 hour mode, in the range (0~23) - * @return The current hour in 24 hour mode - */ - public int getCurrentHourOfDay() { - return mDate.get(Calendar.HOUR_OF_DAY); - } - - private int getCurrentHour() { - if (mIs24HourView){ - return getCurrentHourOfDay(); - } else { - int hour = getCurrentHourOfDay(); - if (hour > HOURS_IN_HALF_DAY) { - return hour - HOURS_IN_HALF_DAY; - } else { - return hour == 0 ? HOURS_IN_HALF_DAY : hour; - } - } - } - - /** - * Set current hour in 24 hour mode, in the range (0~23) - * - * @param hourOfDay - */ - public void setCurrentHour(int hourOfDay) { - if (!mInitialising && hourOfDay == getCurrentHourOfDay()) { - return; - } - mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); - if (!mIs24HourView) { - if (hourOfDay >= HOURS_IN_HALF_DAY) { - mIsAm = false; - if (hourOfDay > HOURS_IN_HALF_DAY) { - hourOfDay -= HOURS_IN_HALF_DAY; - } - } else { - mIsAm = true; - if (hourOfDay == 0) { - hourOfDay = HOURS_IN_HALF_DAY; - } - } - updateAmPmControl(); - } - mHourSpinner.setValue(hourOfDay); - onDateTimeChanged(); - } - - /** - * Get currentMinute - * - * @return The Current Minute - */ - public int getCurrentMinute() { - return mDate.get(Calendar.MINUTE); - } - - /** - * Set current minute - */ - public void setCurrentMinute(int minute) { - if (!mInitialising && minute == getCurrentMinute()) { - return; - } - mMinuteSpinner.setValue(minute); - mDate.set(Calendar.MINUTE, minute); - onDateTimeChanged(); - } - - /** - * @return true if this is in 24 hour view else false. - */ - public boolean is24HourView () { - return mIs24HourView; - } - - /** - * Set whether in 24 hour or AM/PM mode. - * - * @param is24HourView True for 24 hour mode. False for AM/PM mode. - */ - public void set24HourView(boolean is24HourView) {//函数:设置24小时下的视图 - if (mIs24HourView == is24HourView) { - return; - } - mIs24HourView = is24HourView; - mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE);// 语句:如果为12小时视图则显示上下午选择 - int hour = getCurrentHourOfDay(); - updateHourControl(); - setCurrentHour(hour); - updateAmPmControl(); - } - - private void updateDateControl() { - Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(mDate.getTimeInMillis()); - cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1); - mDateSpinner.setDisplayedValues(null); - for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) { - cal.add(Calendar.DAY_OF_YEAR, 1); - mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal); - } - mDateSpinner.setDisplayedValues(mDateDisplayValues); - mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); - mDateSpinner.invalidate(); - }// 对于星期几的算法 - - private void updateAmPmControl() { - if (mIs24HourView) { - mAmPmSpinner.setVisibility(View.GONE); - } else { - int index = mIsAm ? Calendar.AM : Calendar.PM; - mAmPmSpinner.setValue(index); - mAmPmSpinner.setVisibility(View.VISIBLE); - }// 对于上下午操作的算法 - } - - private void updateHourControl() { - if (mIs24HourView) { - mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW); - mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW); - } else { - mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW); - mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW); - }// 对与小时的算法 - } - - /** - * Set the callback that indicates the 'Set' button has been pressed. - * @param callback the callback, if null will do nothing - */ - public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) { - //函数:根据参数设置时间日期监听器 - mOnDateTimeChangedListener = callback; - } - - private void onDateTimeChanged() {//函数:监听日期时间的变化 - if (mOnDateTimeChangedListener != null) { - mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(), - getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute()); - } - } -} diff --git a/doc/cyw.readcode.ui/ui/DateTimePickerDialog.java b/doc/cyw.readcode.ui/ui/DateTimePickerDialog.java deleted file mode 100644 index b35a4cf..0000000 --- a/doc/cyw.readcode.ui/ui/DateTimePickerDialog.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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.ui; - -import java.util.Calendar; - -import net.micode.notes.R; -import net.micode.notes.ui.DateTimePicker; -import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.text.format.DateFormat; -import android.text.format.DateUtils; - -public class DateTimePickerDialog extends AlertDialog implements OnClickListener { - - private Calendar mDate = Calendar.getInstance(); - //创建一个Calendar类型的变量 mDate,方便时间的操作 - private boolean mIs24HourView; - private OnDateTimeSetListener mOnDateTimeSetListener; - //声明一个时间日期滚动选择控件 mOnDateTimeSetListener - private DateTimePicker mDateTimePicker; - //DateTimePicker控件,控件一般用于让用户可以从日期列表中选择单个值。 - //运行时,单击控件边上的下拉箭头,会显示为两个部分:一个下拉列表,一个用于选择日期的 - public interface OnDateTimeSetListener { - //设置一个接口当时期时间设置时进行的操作 - void OnDateTimeSet(AlertDialog dialog, long date); - } - - public DateTimePickerDialog(Context context, long date) { - //对该界面对话框的实例化 - super(context); - //对数据库的操作 - mDateTimePicker = new DateTimePicker(context); - setView(mDateTimePicker);//添加一个子视图 - mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() { - public void onDateTimeChanged(DateTimePicker view, int year, int month, - int dayOfMonth, int hourOfDay, int minute) { - mDate.set(Calendar.YEAR, year); - mDate.set(Calendar.MONTH, month); - mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); - mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); - mDate.set(Calendar.MINUTE, minute);//将视图中的各选项设置为系统当前时间 - updateTitle(mDate.getTimeInMillis()); - } - }); - mDate.setTimeInMillis(date);//得到系统时间 - mDate.set(Calendar.SECOND, 0);//将秒数设置为0 - mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); - setButton(context.getString(R.string.datetime_dialog_ok), this); - setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);//设置按钮 - set24HourView(DateFormat.is24HourFormat(this.getContext()));//时间标准化打印 - updateTitle(mDate.getTimeInMillis()); - }//将时间日期滚动选择控件实例化 - - public void set24HourView(boolean is24HourView) { - mIs24HourView = is24HourView; - } - - public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { - mOnDateTimeSetListener = callBack; - }//将时间日期滚动选择控件实例化 - - private void updateTitle(long date) { - int flag = - DateUtils.FORMAT_SHOW_YEAR | - DateUtils.FORMAT_SHOW_DATE | - DateUtils.FORMAT_SHOW_TIME; - flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR; - setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); - }//android开发中常见日期管理工具类(API)——DateUtils:按照上下午显示时间 - - public void onClick(DialogInterface arg0, int arg1) { - if (mOnDateTimeSetListener != null) { - mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); - } - }//第一个参数arg0是接收到点击事件的对话框 - //第二个参数arg1是该对话框上的按钮 -} \ No newline at end of file diff --git a/doc/cyw.readcode.ui/ui/DropdownMenu.java b/doc/cyw.readcode.ui/ui/DropdownMenu.java deleted file mode 100644 index 0c4b307..0000000 --- a/doc/cyw.readcode.ui/ui/DropdownMenu.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.PopupMenu; -import android.widget.PopupMenu.OnMenuItemClickListener; - -import net.micode.notes.R; - -public class DropdownMenu { - private Button mButton; - private PopupMenu mPopupMenu; - //声明一个下拉菜单 - private Menu mMenu; - - public DropdownMenu(Context context, Button button, int menuId) { - mButton = button; - mButton.setBackgroundResource(R.drawable.dropdown_icon); - //设置这个view的背景 - mPopupMenu = new PopupMenu(context, mButton); - mMenu = mPopupMenu.getMenu(); - mPopupMenu.getMenuInflater().inflate(menuId, mMenu); - //MenuInflater是用来实例化Menu目录下的Menu布局文件 - //根据ID来确认menu的内容选项 - mButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mPopupMenu.show(); - } - }); - } - - public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) { - if (mPopupMenu != null) { - mPopupMenu.setOnMenuItemClickListener(listener); - }//设置菜单的监听 - } - - public MenuItem findItem(int id) { - return mMenu.findItem(id); - }//对于菜单选项的初始化,根据索引搜索菜单需要的选项 - - public void setTitle(CharSequence title) { - mButton.setText(title); - }//布局文件,设置标题 -} \ No newline at end of file diff --git a/doc/cyw.readcode.ui/ui/FoldersListAdapter.java b/doc/cyw.readcode.ui/ui/FoldersListAdapter.java deleted file mode 100644 index 2c5853d..0000000 --- a/doc/cyw.readcode.ui/ui/FoldersListAdapter.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.database.Cursor; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CursorAdapter; -import android.widget.LinearLayout; -import android.widget.TextView; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.NoteColumns; - - -public class FoldersListAdapter extends CursorAdapter { - //CursorAdapter是Cursor和ListView的接口 - //FoldersListAdapter继承了CursorAdapter的类 - //主要作用是便签数据库和用户的交互 - //这里就是用folder(文件夹)的形式展现给用户 - public static final String [] PROJECTION = { - NoteColumns.ID, - NoteColumns.SNIPPET - };//调用数据库中便签的ID和片段 - - public static final int ID_COLUMN = 0; - public static final int NAME_COLUMN = 1; - - public FoldersListAdapter(Context context, Cursor c) { - super(context, c); - // TODO Auto-generated constructor stub - }//数据库操作 - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - //ViewGroup是容器 - return new FolderListItem(context); - }//创建一个文件夹,对于各文件夹中子标签的初始化 - - @Override - public void bindView(View view, Context context, Cursor cursor) { - if (view instanceof FolderListItem) { - String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context - .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); - ((FolderListItem) view).bind(folderName); - } - }//将各个布局文件绑定起来 - - public String getFolderName(Context context, int position) { - Cursor cursor = (Cursor) getItem(position); - return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context - .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); - }//根据数据库中标签的ID得到标签的各项内容 - - private class FolderListItem extends LinearLayout { - private TextView mName; - - public FolderListItem(Context context) { - super(context); - //操作数据库 - inflate(context, R.layout.folder_list_item, this); - //根据布局文件的名字等信息将其找出来 - mName = (TextView) findViewById(R.id.tv_folder_name); - } - - public void bind(String name) { - mName.setText(name);//设置名字 - } - } - -} \ No newline at end of file diff --git a/doc/cyw.readcode.ui/ui/NoteEditActivity.java b/doc/cyw.readcode.ui/ui/NoteEditActivity.java deleted file mode 100644 index 9bbbb97..0000000 --- a/doc/cyw.readcode.ui/ui/NoteEditActivity.java +++ /dev/null @@ -1,1083 +0,0 @@ -/* - * 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.ui; - -import android.app.Activity; -import android.app.AlarmManager; -import android.app.AlertDialog; -import android.app.PendingIntent; -import android.app.SearchManager; -import android.appwidget.AppWidgetManager; -import android.content.ContentUris; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Paint; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.text.style.BackgroundColorSpan; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.WindowManager; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.TextNote; -import net.micode.notes.model.WorkingNote; -import net.micode.notes.model.WorkingNote.NoteSettingChangedListener; -import net.micode.notes.tool.DataUtils; -import net.micode.notes.tool.ResourceParser; -import net.micode.notes.tool.ResourceParser.TextAppearanceResources; -import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener; -import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener; -import net.micode.notes.widget.NoteWidgetProvider_2x; -import net.micode.notes.widget.NoteWidgetProvider_4x; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - -public class NoteEditActivity extends Activity implements OnClickListener, - NoteSettingChangedListener, OnTextViewChangeListener { - //该类主要是针对标签的编辑 - //继承了系统内部许多和监听有关的类 - private class HeadViewHolder { - public TextView tvModified; - - public ImageView ivAlertIcon; - - public TextView tvAlertDate; - - public ImageView ibSetBgColor; - } - //使用Map实现数据存储 - private static final Map sBgSelectorBtnsMap = new HashMap(); - static { - sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); - sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED); - sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE); - sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN); - sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE); - //put函数是将指定值和指定键相连 - } - - private static final Map sBgSelectorSelectionMap = new HashMap(); - static { - sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select); - sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select); - sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select); - sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select); - sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); - //put函数是将指定值和指定键相连 - } - - private static final Map sFontSizeBtnsMap = new HashMap(); - static { - sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE); - sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL); - sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM); - sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER); - //put函数是将指定值和指定键相连 - } - - private static final Map sFontSelectorSelectionMap = new HashMap(); - static { - sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select); - sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select); - sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select); - sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); - //put函数是将指定值和指定键相连 - } - - private static final String TAG = "NoteEditActivity"; - - private HeadViewHolder mNoteHeaderHolder; - - private View mHeadViewPanel; - //私有化一个界面操作mHeadViewPanel,对表头的操作 - private View mNoteBgColorSelector; - //私有化一个界面操作mNoteBgColorSelector,对背景颜色的操作 - private View mFontSizeSelector; - //私有化一个界面操作mFontSizeSelector,对标签字体的操作 - private EditText mNoteEditor; - //声明编辑控件,对文本操作 - private View mNoteEditorPanel; - //私有化一个界面操作mNoteEditorPanel,文本编辑的控制板 - //private WorkingNote mWorkingNote; - public WorkingNote mWorkingNote; - //对模板WorkingNote的初始化 - private SharedPreferences mSharedPrefs; - //私有化SharedPreferences的数据存储方式 - //它的本质是基于XML文件存储key-value键值对数据 - private int mFontSizeId; - //用于操作字体的大小 - private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; - - private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; - - public static final String TAG_CHECKED = String.valueOf('\u221A'); - public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); - - private LinearLayout mEditTextList; - //线性布局 - private String mUserQuery; - private Pattern mPattern; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - this.setContentView(R.layout.note_edit); - //对数据库的访问操作 - if (savedInstanceState == null && !initActivityState(getIntent())) { - finish(); - return; - } - initResources(); - } - - /** - * Current activity may be killed when the memory is low. Once it is killed, for another time - * user load this activity, we should restore the former state - */ - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID)); - if (!initActivityState(intent)) { - finish(); - return; - } - Log.d(TAG, "Restoring from killed activity"); - }//为防止内存不足时程序的终止,在这里有一个保存现场的函数 - } - - private boolean initActivityState(Intent intent) { - /** - * If the user specified the {@link Intent#ACTION_VIEW} but not provided with id, - * then jump to the NotesListActivity - */ - mWorkingNote = null; - if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { - long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); - mUserQuery = ""; - //如果用户实例化标签时,系统并未给出标签ID - /** - * Starting from the searched result - */ - //根据键值查找ID - if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) { - noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); - mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); - } - //如果ID在数据库中未找到 - if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { - Intent jump = new Intent(this, NotesListActivity.class); - startActivity(jump); - //程序将跳转到上面声明的intent——jump - showToast(R.string.error_note_not_exist); - finish(); - return false; - } - //ID在数据库中找到 - else { - mWorkingNote = WorkingNote.load(this, noteId); - if (mWorkingNote == null) { - Log.e(TAG, "load note failed with note id" + noteId); - //打印出红色的错误信息 - finish(); - return false; - } - } - //setSoftInputMode——软键盘输入模式 - getWindow().setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN - | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - } else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { - // intent.getAction() - // 大多用于broadcast发送广播时给机制(intent)设置一个action,就是一个字符串 - // 用户可以通过receive(接受)intent,通过 getAction得到的字符串,来决定做什么 - long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); - int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID); - int widgetType = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, - Notes.TYPE_WIDGET_INVALIDE); - int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, - ResourceParser.getDefaultBgId(this)); - // intent.getInt(Long、String)Extra是对各变量的语法分析 - // Parse call-record note - String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); - long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0); - if (callDate != 0 && phoneNumber != null) { - if (TextUtils.isEmpty(phoneNumber)) { - Log.w(TAG, "The call record number is null"); - } - long noteId = 0; - if ((noteId = DataUtils.getNoteIdByPhoneNumberAndCallDate(getContentResolver(), - phoneNumber, callDate)) > 0) { - mWorkingNote = WorkingNote.load(this, noteId); - if (mWorkingNote == null) { - Log.e(TAG, "load call note failed with note id" + noteId); - finish(); - return false; - } - //将电话号码与手机的号码簿相关 - } else { - mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, - widgetType, bgResId); - mWorkingNote.convertToCallNote(phoneNumber, callDate); - // - } - } else { - mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType, - bgResId); - }//创建一个新的WorkingNote - - getWindow().setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE - | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - } else { - Log.e(TAG, "Intent not specified action, should not support"); - finish(); - return false; - } - mWorkingNote.setOnSettingStatusChangedListener(this); - return true; - } - - @Override - protected void onResume() { - super.onResume(); - initNoteScreen(); - } - - private void initNoteScreen() { - //对界面的初始化操作 - mNoteEditor.setTextAppearance(this, TextAppearanceResources - .getTexAppearanceResource(mFontSizeId)); - //设置外观 - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - switchToListMode(mWorkingNote.getContent()); - } else { - mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); - mNoteEditor.setSelection(mNoteEditor.getText().length()); - } - for (Integer id : sBgSelectorSelectionMap.keySet()) { - findViewById(sBgSelectorSelectionMap.get(id)).setVisibility(View.GONE); - } - mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); - mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); - - mNoteHeaderHolder.tvModified.setText(DateUtils.formatDateTime(this, - mWorkingNote.getModifiedDate(), DateUtils.FORMAT_SHOW_DATE - | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME - | DateUtils.FORMAT_SHOW_YEAR)); - - /** - * TODO: Add the menu for setting alert. Currently disable it because the DateTimePicker - * is not ready - */ - showAlertHeader(); - } - //设置闹钟的显示 - private void showAlertHeader() { - if (mWorkingNote.hasClockAlert()) { - long time = System.currentTimeMillis(); - if (time > mWorkingNote.getAlertDate()) { - mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired); - } - //如果系统时间大于了闹钟设置的时间,那么闹钟失效 - else { - mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( - mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); - } - mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE); - mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); - //显示闹钟开启的图标 - } else { - mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE); - mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE); - }; - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - initActivityState(intent); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - /** - * For new note without note id, we should firstly save it to - * generate a id. If the editing note is not worth saving, there - * is no id which is equivalent to create new note - */ - if (!mWorkingNote.existInDatabase()) { - saveNote(); - } - //在创建一个新的标签时,先在数据库中匹配 - //如果不存在,那么先在数据库中存储 - outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); - Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); - } - - @Override - //MotionEvent是对屏幕触控的传递机制 - public boolean dispatchTouchEvent(MotionEvent ev) { - if (mNoteBgColorSelector.getVisibility() == View.VISIBLE - && !inRangeOfView(mNoteBgColorSelector, ev)) { - mNoteBgColorSelector.setVisibility(View.GONE); - return true; - }//颜色选择器在屏幕上可见 - - if (mFontSizeSelector.getVisibility() == View.VISIBLE - && !inRangeOfView(mFontSizeSelector, ev)) { - mFontSizeSelector.setVisibility(View.GONE); - return true; - }//字体大小选择器在屏幕上可见 - return super.dispatchTouchEvent(ev); - } - //对屏幕触控的坐标进行操作 - private boolean inRangeOfView(View view, MotionEvent ev) { - int []location = new int[2]; - view.getLocationOnScreen(location); - int x = location[0]; - int y = location[1]; - if (ev.getX() < x - || ev.getX() > (x + view.getWidth()) - || ev.getY() < y - || ev.getY() > (y + view.getHeight())) - //如果触控的位置超出了给定的范围,返回false - { - return false; - } - return true; - } - - private void initResources() { - mHeadViewPanel = findViewById(R.id.note_title); - mNoteHeaderHolder = new HeadViewHolder(); - mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date); - mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon); - mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date); - mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color); - mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this); - mNoteEditor = (EditText) findViewById(R.id.note_edit_view); - mNoteEditorPanel = findViewById(R.id.sv_note_edit); - mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector); - for (int id : sBgSelectorBtnsMap.keySet()) { - ImageView iv = (ImageView) findViewById(id); - iv.setOnClickListener(this); - }//对标签各项属性内容的初始化 - - mFontSizeSelector = findViewById(R.id.font_size_selector); - for (int id : sFontSizeBtnsMap.keySet()) { - View view = findViewById(id); - view.setOnClickListener(this); - };//对字体大小的选择 - mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE); - /** - * HACKME: Fix bug of store the resource id in shared preference. - * The id may larger than the length of resources, in this case, - * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} - */ - if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) { - mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; - } - mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); - } - - @Override - protected void onPause() { - super.onPause(); - if(saveNote()) { - Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length()); - } - clearSettingState(); - } - //和桌面小工具的同步 - private void updateWidget() { - Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); - if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { - intent.setClass(this, NoteWidgetProvider_2x.class); - } else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) { - intent.setClass(this, NoteWidgetProvider_4x.class); - } else { - Log.e(TAG, "Unspported widget type"); - return; - } - - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { - mWorkingNote.getWidgetId() - }); - - sendBroadcast(intent); - setResult(RESULT_OK, intent); - } - - public void onClick(View v) { - int id = v.getId(); - if (id == R.id.btn_set_bg_color) { - mNoteBgColorSelector.setVisibility(View.VISIBLE); - findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - - View.VISIBLE); - } else if (sBgSelectorBtnsMap.containsKey(id)) { - findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - View.GONE); - mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); - mNoteBgColorSelector.setVisibility(View.GONE); - } else if (sFontSizeBtnsMap.containsKey(id)) { - findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); - mFontSizeId = sFontSizeBtnsMap.get(id); - mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit(); - findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - getWorkingText(); - switchToListMode(mWorkingNote.getContent()); - } else { - mNoteEditor.setTextAppearance(this, - TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); - } - mFontSizeSelector.setVisibility(View.GONE); - } - }//************************存在问题 - - @Override - public void onBackPressed() { - if(clearSettingState()) { - return; - } - - saveNote(); - super.onBackPressed(); - } - - private boolean clearSettingState() { - if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) { - mNoteBgColorSelector.setVisibility(View.GONE); - return true; - } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { - mFontSizeSelector.setVisibility(View.GONE); - return true; - } - return false; - } - - public void onBackgroundColorChanged() { - findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - View.VISIBLE); - mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); - mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); - } - - @Override - //对选择菜单的准备 - public boolean onPrepareOptionsMenu(Menu menu) { - if (isFinishing()) { - return true; - } - clearSettingState(); - menu.clear(); - if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) { - getMenuInflater().inflate(R.menu.call_note_edit, menu); - // MenuInflater是用来实例化Menu目录下的Menu布局文件的 - } else { - getMenuInflater().inflate(R.menu.note_edit, menu); - } - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_normal_mode); - } else { - menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode); - } - if (mWorkingNote.hasClockAlert()) { - menu.findItem(R.id.menu_alert).setVisible(false); - } else { - menu.findItem(R.id.menu_delete_remind).setVisible(false); - } - return true; - } - - @Override - /* - * 函数功能:动态改变菜单选项内容 - * 函数实现:如下注释 - */ - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - //根据菜单的id来编剧相关项目 - case R.id.menu_new_note: - //创建一个新的便签 - createNewNote(); - break; - case R.id.menu_delete: - //删除便签 - AlertDialog.Builder builder = new AlertDialog.Builder(this); - //创建关于删除操作的对话框 - builder.setTitle(getString(R.string.alert_title_delete)); - // 设置标签的标题为alert_title_delete - builder.setIcon(android.R.drawable.ic_dialog_alert); - //设置对话框图标 - builder.setMessage(getString(R.string.alert_message_delete_note)); - //设置对话框内容 - builder.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - //建立按键监听器 - public void onClick(DialogInterface dialog, int which) { - //点击所触发事件 - deleteCurrentNote(); - // 删除单签便签 - finish(); - } - }); - //添加“YES”按钮 - builder.setNegativeButton(android.R.string.cancel, null); - //添加“NO”的按钮 - builder.show(); - //显示对话框 - break; - case R.id.menu_font_size: - //字体大小的编辑 - mFontSizeSelector.setVisibility(View.VISIBLE); - // 将字体选择器置为可见 - findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); - // 通过id找到相应的大小 - break; - case R.id.menu_list_mode: - //选择列表模式 - mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ? - TextNote.MODE_CHECK_LIST : 0); - break; - case R.id.menu_share: - //菜单共享 - getWorkingText(); - sendTo(this, mWorkingNote.getContent()); - // 用sendto函数将运行文本发送到遍历的本文内 - break; - case R.id.menu_send_to_desktop: - //发送到桌面 - sendToDesktop(); - break; - case R.id.menu_alert: - //创建提醒器 - setReminder(); - break; - case R.id.menu_delete_remind: - //删除日期提醒 - mWorkingNote.setAlertDate(0, false); - break; - default: - break; - } - return true; - } - - /* - * 函数功能:建立事件提醒器 - * 函数实现:如下注释 - */ - private void setReminder() { - DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis()); - // 建立修改时间日期的对话框 - d.setOnDateTimeSetListener(new OnDateTimeSetListener() { - public void OnDateTimeSet(AlertDialog dialog, long date) { - mWorkingNote.setAlertDate(date , true); - //选择提醒的日期 - } - }); - //建立时间日期的监听器 - d.show(); - //显示对话框 - } - - /** - * Share note to apps that support {@link Intent#ACTION_SEND} action - * and {@text/plain} type - */ - /* - * 函数功能:共享便签 - * 函数实现:如下注释 - */ - private void sendTo(Context context, String info) { - Intent intent = new Intent(Intent.ACTION_SEND); - //建立intent链接选项 - intent.putExtra(Intent.EXTRA_TEXT, info); - //将需要传递的便签信息放入text文件中 - intent.setType("text/plain"); - //编辑连接器的类型 - context.startActivity(intent); - //在acti中进行链接 - } - - /* - * 函数功能:创建一个新的便签 - * 函数实现:如下注释 - */ - private void createNewNote() { - // Firstly, save current editing notes - //保存当前便签 - saveNote(); - - // For safety, start a new NoteEditActivity - finish(); - Intent intent = new Intent(this, NoteEditActivity.class); - //设置链接器 - intent.setAction(Intent.ACTION_INSERT_OR_EDIT); - //该活动定义为创建或编辑 - intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); - //将运行便签的id添加到INTENT_EXTRA_FOLDER_ID标记中 - startActivity(intent); - //开始activity并链接 - } - - /* - * 函数功能:删除当前便签 - * 函数实现:如下注释 - */ - private void deleteCurrentNote() { - if (mWorkingNote.existInDatabase()) { - //假如当前运行的便签内存有数据 - HashSet ids = new HashSet(); - long id = mWorkingNote.getNoteId(); - if (id != Notes.ID_ROOT_FOLDER) { - ids.add(id); - //如果不是头文件夹建立一个hash表把便签id存起来 - } else { - Log.d(TAG, "Wrong note id, should not happen"); - //否则报错 - } - if (!isSyncMode()) { - //在非同步模式情况下 - //删除操作 - if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) { - Log.e(TAG, "Delete Note error"); - } - } else { - //同步模式 - //移动至垃圾文件夹的操作 - if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) { - Log.e(TAG, "Move notes to trash folder error, should not happens"); - } - } - } - mWorkingNote.markDeleted(true); - //将这些标签的删除标记置为true - } - - /* - * 函数功能:判断是否为同步模式 - * 函数实现:直接看NotesPreferenceActivity中同步名称是否为空 - */ - private boolean isSyncMode() { - return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; - } - - /* - * 函数功能:设置提醒时间 - * 函数实现:如下注释 - */ - public void onClockAlertChanged(long date, boolean set) { - /** - * User could set clock to an unsaved note, so before setting the - * alert clock, we should save the note first - */ - if (!mWorkingNote.existInDatabase()) { - //首先保存已有的便签 - saveNote(); - } - if (mWorkingNote.getNoteId() > 0) { - Intent intent = new Intent(this, AlarmReceiver.class); - intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId())); - //若有有运行的便签就是建立一个链接器将标签id都存在uri中 - PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); - AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); - //设置提醒管理器 - showAlertHeader(); - if(!set) { - alarmManager.cancel(pendingIntent); - } else { - alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); - } - //如果用户设置了时间,就通过提醒管理器设置一个监听事项 - } else { - /** - * There is the condition that user has input nothing (the note is - * not worthy saving), we have no note id, remind the user that he - * should input something - */ - //没有运行的便签就报错 - Log.e(TAG, "Clock alert setting error"); - showToast(R.string.error_note_empty_for_clock); - } - } - - /* - * 函数功能:Widget发生改变的所触发的事件 - */ - public void onWidgetChanged() { - updateWidget();//更新Widget - } - - /* - * 函数功能: 删除编辑文本框所触发的事件 - * 函数实现:如下注释 - */ - public void onEditTextDelete(int index, String text) { - int childCount = mEditTextList.getChildCount(); - if (childCount == 1) { - return; - } - //没有编辑框的话直接返回 - for (int i = index + 1; i < childCount; i++) { - ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) - .setIndex(i - 1); - //通过id把编辑框存在便签编辑框中 - } - - mEditTextList.removeViewAt(index); - //删除特定位置的视图 - NoteEditText edit = null; - if(index == 0) { - edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( - R.id.et_edit_text); - } else { - edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById( - R.id.et_edit_text); - } - //通过id把编辑框存在空的NoteEditText中 - int length = edit.length(); - edit.append(text); - edit.requestFocus();//请求优先完成该此 编辑 - edit.setSelection(length);//定位到length位置处的条目 - } - - /* - * 函数功能:进入编辑文本框所触发的事件 - * 函数实现:如下注释 - */ - public void onEditTextEnter(int index, String text) { - /** - * Should not happen, check for debug - */ - if(index > mEditTextList.getChildCount()) { - Log.e(TAG, "Index out of mEditTextList boundrary, should not happen"); - //越界把偶偶 - } - - View view = getListItem(text, index); - mEditTextList.addView(view, index); - //建立一个新的视图并添加到编辑文本框内 - NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); - edit.requestFocus();//请求优先操作 - edit.setSelection(0);//定位到起始位置 - for (int i = index + 1; i < mEditTextList.getChildCount(); i++) { - ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) - .setIndex(i); - //遍历子文本框并设置对应对下标 - } - } - - /* - * 函数功能:切换至列表模式 - * 函数实现:如下注释 - */ - private void switchToListMode(String text) { - mEditTextList.removeAllViews(); - String[] items = text.split("\n"); - int index = 0; - //清空所有视图,初始化下标 - for (String item : items) { - if(!TextUtils.isEmpty(item)) { - mEditTextList.addView(getListItem(item, index)); - index++; - //遍历所有文本单元并添加到文本框中 - } - } - mEditTextList.addView(getListItem("", index)); - mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus(); - //优先请求此操作 - - mNoteEditor.setVisibility(View.GONE); - //便签编辑器不可见 - mEditTextList.setVisibility(View.VISIBLE); - //将文本编辑框置为可见 - } - - /* - * 函数功能:获取高亮效果的反馈情况 - * 函数实现:如下注释 - */ - private Spannable getHighlightQueryResult(String fullText, String userQuery) { - SpannableString spannable = new SpannableString(fullText == null ? "" : fullText); - //新建一个效果选项 - if (!TextUtils.isEmpty(userQuery)) { - mPattern = Pattern.compile(userQuery); - //将用户的询问进行解析 - Matcher m = mPattern.matcher(fullText); - //建立一个状态机检查Pattern并进行匹配 - int start = 0; - while (m.find(start)) { - spannable.setSpan( - new BackgroundColorSpan(this.getResources().getColor( - R.color.user_query_highlight)), m.start(), m.end(), - Spannable.SPAN_INCLUSIVE_EXCLUSIVE); - //设置背景颜色 - start = m.end(); - //跟新起始位置 - } - } - return spannable; - } - - /* - * 函数功能:获取列表项 - * 函数实现:如下注释 - */ - private View getListItem(String item, int index) { - View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); - //创建一个视图 - final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); - edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); - //创建一个文本编辑框并设置可见性 - CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); - cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); - } else { - edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); - } - } - }); - //建立一个打钩框并设置监听器 - - if (item.startsWith(TAG_CHECKED)) { - //选择勾选 - cb.setChecked(true); - edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); - item = item.substring(TAG_CHECKED.length(), item.length()).trim(); - } else if (item.startsWith(TAG_UNCHECKED)) { - //选择不勾选 - cb.setChecked(false); - edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); - item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); - } - - edit.setOnTextViewChangeListener(this); - edit.setIndex(index); - edit.setText(getHighlightQueryResult(item, mUserQuery)); - //运行编辑框的监听器对该行为作出反应,并设置下标及文本内容 - return view; - } - - /* - * 函数功能:便签内容发生改变所 触发的事件 - * 函数实现:如下注释 - */ - public void onTextChange(int index, boolean hasText) { - if (index >= mEditTextList.getChildCount()) { - Log.e(TAG, "Wrong index, should not happen"); - return; - //越界报错 - } - if(hasText) { - mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE); - } else { - mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE); - } - //如果内容不为空则将其子编辑框可见性置为可见,否则不可见 - } - - /* - * 函数功能:检查模式和列表模式的切换 - * 函数实现:如下注释 - */ - public void onCheckListModeChanged(int oldMode, int newMode) { - if (newMode == TextNote.MODE_CHECK_LIST) { - switchToListMode(mNoteEditor.getText().toString()); - //检查模式切换到列表模式 - } else { - if (!getWorkingText()) { - mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", - "")); - } - //若是获取到文本就改变其检查标记 - mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); - mEditTextList.setVisibility(View.GONE); - mNoteEditor.setVisibility(View.VISIBLE); - //修改文本编辑器的内容和可见性 - } - } - - /* - * 函数功能:设置勾选选项表并返回是否勾选的标记 - * 函数实现:如下注释 - */ - private boolean getWorkingText() { - boolean hasChecked = false; - //初始化check标记 - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - // 若模式为CHECK_LIST - StringBuilder sb = new StringBuilder(); - //创建可变字符串 - for (int i = 0; i < mEditTextList.getChildCount(); i++) { - View view = mEditTextList.getChildAt(i); - //遍历所有子编辑框的视图 - NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); - if (!TextUtils.isEmpty(edit.getText())) { - //若文本不为空 - if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { - //该选项框已打钩 - sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); - hasChecked = true; - //扩展字符串为已打钩并把标记置true - } else { - sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n"); - //扩展字符串添加未打钩 - } - } - } - mWorkingNote.setWorkingText(sb.toString()); - //利用编辑好的字符串设置运行便签的内容 - } else { - mWorkingNote.setWorkingText(mNoteEditor.getText().toString()); - // 若不是该模式直接用编辑器中的内容设置运行中标签的内容 - } - return hasChecked; - } - - /* - * 函数功能:保存便签 - * 函数实现:如下注释 - */ - private boolean saveNote() { - getWorkingText(); - boolean saved = mWorkingNote.saveNote(); - //运行 getWorkingText()之后保存 - if (saved) { - /** - * There are two modes from List view to edit view, open one note, - * create/edit a node. Opening node requires to the original - * position in the list when back from edit view, while creating a - * new node requires to the top of the list. This code - * {@link #RESULT_OK} is used to identify the create/edit state - */ - //如英文注释所说链接RESULT_OK是为了识别保存的2种情况,一是创建后保存,二是修改后保存 - setResult(RESULT_OK); - } - return saved; - } - - /* - * 函数功能:将便签发送至桌面 - * 函数实现:如下注释 - */ - private void sendToDesktop() { - /** - * Before send message to home, we should make sure that current - * editing note is exists in databases. So, for new note, firstly - * save it - */ - if (!mWorkingNote.existInDatabase()) { - saveNote(); - //若不存在数据也就是新的标签就保存起来先 - } - - if (mWorkingNote.getNoteId() > 0) { - //若是有内容 - Intent sender = new Intent(); - Intent shortcutIntent = new Intent(this, NoteEditActivity.class); - //建立发送到桌面的连接器 - shortcutIntent.setAction(Intent.ACTION_VIEW); - //链接为一个视图 - shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId()); - sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - sender.putExtra(Intent.EXTRA_SHORTCUT_NAME, - makeShortcutIconTitle(mWorkingNote.getContent())); - sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, - Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app)); - sender.putExtra("duplicate", true); - //将便签的相关信息都添加到要发送的文件里 - sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); - //设置sneder的行为是发送 - showToast(R.string.info_note_enter_desktop); - sendBroadcast(sender); - //显示到桌面 - } else { - /** - * There is the condition that user has input nothing (the note is - * not worthy saving), we have no note id, remind the user that he - * should input something - */ - Log.e(TAG, "Send to desktop error"); - showToast(R.string.error_note_empty_for_send_to_desktop); - //空便签直接报错 - } - } - - /* - * 函数功能:编辑小图标的标题 - * 函数实现:如下注释 - */ - private String makeShortcutIconTitle(String content) { - content = content.replace(TAG_CHECKED, ""); - content = content.replace(TAG_UNCHECKED, ""); - return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, - SHORTCUT_ICON_TITLE_MAX_LEN) : content; - //直接设置为content中的内容并返回,有勾选和未勾选2种 - } - - /* - * 函数功能:显示提示的视图 - * 函数实现:根据下标显示对应的提示 - */ - private void showToast(int resId) { - showToast(resId, Toast.LENGTH_SHORT); - } - - /* - * 函数功能:持续显示提示的视图 - * 函数实现:根据下标和持续的时间(duration)编辑提示视图并显示 - */ - private void showToast(int resId, int duration) { - Toast.makeText(this, resId, duration).show(); - } -} diff --git a/doc/cyw.readcode.ui/ui/NoteEditText.java b/doc/cyw.readcode.ui/ui/NoteEditText.java deleted file mode 100644 index 334ebd6..0000000 --- a/doc/cyw.readcode.ui/ui/NoteEditText.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.graphics.Rect; -import android.text.Layout; -import android.text.Selection; -import android.text.Spanned; -import android.text.TextUtils; -import android.text.style.URLSpan; -import android.util.AttributeSet; -import android.util.Log; -import android.view.ContextMenu; -import android.view.KeyEvent; -import android.view.MenuItem; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.MotionEvent; -import android.widget.EditText; - -import net.micode.notes.R; - -import java.util.HashMap; -import java.util.Map; - -//继承edittext,设置便签设置文本框 -public class NoteEditText extends EditText { - private static final String TAG = "NoteEditText"; - private int mIndex; - private int mSelectionStartBeforeDelete; - - private static final String SCHEME_TEL = "tel:" ; - private static final String SCHEME_HTTP = "http:" ; - private static final String SCHEME_EMAIL = "mailto:" ; - - ///建立一个字符和整数的hash表,用于链接电话,网站,还有邮箱 - private static final Map sSchemaActionResMap = new HashMap(); - static { - sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); - sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web); - sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email); - } - - /** - * Call by the {@link NoteEditActivity} to delete or add edit text - */ - //在NoteEditActivity中删除或添加文本的操作,可以看做是一个文本是否被变的标记,英文注释已说明的很清楚 - public interface OnTextViewChangeListener { - /** - * Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens - * and the text is null - */ - //处理删除按键时的操作 - void onEditTextDelete(int index, String text); - - /** - * Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER} - * happen - */ - //处理进入按键时的操作 - void onEditTextEnter(int index, String text); - - /** - * Hide or show item option when text change - */ - void onTextChange(int index, boolean hasText); - } - - private OnTextViewChangeListener mOnTextViewChangeListener; - - //根据context设置文本 - public NoteEditText(Context context) { - super(context, null);//用super引用父类变量 - mIndex = 0; - } - - //设置当前光标 - public void setIndex(int index) { - mIndex = index; - } - - //初始化文本修改标记 - public void setOnTextViewChangeListener(OnTextViewChangeListener listener) { - mOnTextViewChangeListener = listener; - } - - //AttributeSet 百度了一下是自定义空控件属性,用于维护便签动态变化的属性 - //初始化便签 - public NoteEditText(Context context, AttributeSet attrs) { - super(context, attrs, android.R.attr.editTextStyle); - } - - // 根据defstyle自动初始化 - public NoteEditText(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - // TODO Auto-generated construct or stub - } - - @Override - //view里的函数,处理手机屏幕的所有事件 - /*参数event为手机屏幕触摸事件封装类的对象,其中封装了该事件的所有信息, - 例如触摸的位置、触摸的类型以及触摸的时间等。该对象会在用户触摸手机屏幕时被创建。*/ - public boolean onTouchEvent(MotionEvent event) { - switch (event.getAction()) { - //重写了需要处理屏幕被按下的事件 - case MotionEvent.ACTION_DOWN: - //跟新当前坐标值 - int x = (int) event.getX(); - int y = (int) event.getY(); - x -= getTotalPaddingLeft(); - y -= getTotalPaddingTop(); - x += getScrollX(); - y += getScrollY(); - - //用布局控件layout根据x,y的新值设置新的位置 - Layout layout = getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - //更新光标新的位置 - Selection.setSelection(getText(), off); - break; - } - - return super.onTouchEvent(event); - } - - @Override - /* - * 函数功能:处理用户按下一个键盘按键时会触发 的事件 - * 实现过程:如下注释 - */ - public boolean onKeyDown(int keyCode, KeyEvent event) { - switch (keyCode) { - //根据按键的 Unicode 编码值来处理 - case KeyEvent.KEYCODE_ENTER: - //“进入”按键 - if (mOnTextViewChangeListener != null) { - return false; - } - break; - case KeyEvent.KEYCODE_DEL: - //“删除”按键 - mSelectionStartBeforeDelete = getSelectionStart(); - break; - default: - break; - } - //继续执行父类的其他点击事件 - return super.onKeyDown(keyCode, event); - } - - @Override - /* - * 函数功能:处理用户松开一个键盘按键时会触发 的事件 - * 实现方式:如下注释 - */ - public boolean onKeyUp(int keyCode, KeyEvent event) { - switch(keyCode) { - //根据按键的 Unicode 编码值来处理,有删除和进入2种操作 - case KeyEvent.KEYCODE_DEL: - if (mOnTextViewChangeListener != null) { - //若是被修改过 - if (0 == mSelectionStartBeforeDelete && mIndex != 0) { - //若之前有被修改并且文档不为空 - mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); - //利用上文OnTextViewChangeListener对KEYCODE_DEL按键情况的删除函数进行删除 - return true; - } - } else { - Log.d(TAG, "OnTextViewChangeListener was not seted"); - //其他情况报错,文档的改动监听器并没有建立 - } - break; - case KeyEvent.KEYCODE_ENTER: - //同上也是分为监听器是否建立2种情况 - if (mOnTextViewChangeListener != null) { - int selectionStart = getSelectionStart(); - //获取当前位置 - String text = getText().subSequence(selectionStart, length()).toString(); - //获取当前文本 - setText(getText().subSequence(0, selectionStart)); - //根据获取的文本设置当前文本 - mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); - //当{@link KeyEvent#KEYCODE_ENTER}添加新文本 - } else { - Log.d(TAG, "OnTextViewChangeListener was not seted"); - //其他情况报错,文档的改动监听器并没有建立 - } - break; - default: - break; - } - //继续执行父类的其他按键弹起的事件 - return super.onKeyUp(keyCode, event); - } - - @Override - /* - * 函数功能:当焦点发生变化时,会自动调用该方法来处理焦点改变的事件 - * 实现方式:如下注释 - * 参数:focused表示触发该事件的View是否获得了焦点,当该控件获得焦点时,Focused等于true,否则等于false。 - direction表示焦点移动的方向,用数值表示 - Rect:表示在触发事件的View的坐标系中,前一个获得焦点的矩形区域,即表示焦点是从哪里来的。如果不可用则为null - */ - protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { - if (mOnTextViewChangeListener != null) { - //若监听器已经建立 - if (!focused && TextUtils.isEmpty(getText())) { - //获取到焦点并且文本不为空 - mOnTextViewChangeListener.onTextChange(mIndex, false); - //mOnTextViewChangeListener子函数,置false隐藏事件选项 - } else { - mOnTextViewChangeListener.onTextChange(mIndex, true); - //mOnTextViewChangeListener子函数,置true显示事件选项 - } - } - //继续执行父类的其他焦点变化的事件 - super.onFocusChanged(focused, direction, previouslyFocusedRect); - } - - @Override - /* - * 函数功能:生成上下文菜单 - * 函数实现:如下注释 - */ - protected void onCreateContextMenu(ContextMenu menu) { - if (getText() instanceof Spanned) { - //有文本存在 - int selStart = getSelectionStart(); - int selEnd = getSelectionEnd(); - //获取文本开始和结尾位置 - - int min = Math.min(selStart, selEnd); - int max = Math.max(selStart, selEnd); - //获取开始到结尾的最大值和最小值 - - final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class); - //设置url的信息的范围值 - if (urls.length == 1) { - int defaultResId = 0; - for(String schema: sSchemaActionResMap.keySet()) { - //获取计划表中所有的key值 - if(urls[0].getURL().indexOf(schema) >= 0) { - //若url可以添加则在添加后将defaultResId置为key所映射的值 - defaultResId = sSchemaActionResMap.get(schema); - break; - } - } - - if (defaultResId == 0) { - //defaultResId == 0则说明url并没有添加任何东西,所以置为连接其他SchemaActionResMap的值 - defaultResId = R.string.note_link_other; - } - - //建立菜单 - menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener( - new OnMenuItemClickListener() { - //新建按键监听器 - public boolean onMenuItemClick(MenuItem item) { - // goto a new intent - urls[0].onClick(NoteEditText.this); - //根据相应的文本设置菜单的按键 - return true; - } - }); - } - } - //继续执行父类的其他菜单创建的事件 - super.onCreateContextMenu(menu); - } -} diff --git a/doc/cyw.readcode.ui/ui/NoteItemData.java b/doc/cyw.readcode.ui/ui/NoteItemData.java deleted file mode 100644 index ff52c1f..0000000 --- a/doc/cyw.readcode.ui/ui/NoteItemData.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.database.Cursor; -import android.text.TextUtils; - -import net.micode.notes.data.Contact; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.tool.DataUtils; - - -public class NoteItemData { - static final String [] PROJECTION = new String [] { - NoteColumns.ID, - NoteColumns.ALERTED_DATE, - NoteColumns.BG_COLOR_ID, - NoteColumns.CREATED_DATE, - NoteColumns.HAS_ATTACHMENT, - NoteColumns.MODIFIED_DATE, - NoteColumns.NOTES_COUNT, - NoteColumns.PARENT_ID, - NoteColumns.SNIPPET, - NoteColumns.TYPE, - NoteColumns.WIDGET_ID, - NoteColumns.WIDGET_TYPE, - }; - //常量标记和数据就不一一标记了,意义翻译基本就知道 - private static final int ID_COLUMN = 0; - private static final int ALERTED_DATE_COLUMN = 1; - private static final int BG_COLOR_ID_COLUMN = 2; - private static final int CREATED_DATE_COLUMN = 3; - private static final int HAS_ATTACHMENT_COLUMN = 4; - private static final int MODIFIED_DATE_COLUMN = 5; - private static final int NOTES_COUNT_COLUMN = 6; - private static final int PARENT_ID_COLUMN = 7; - private static final int SNIPPET_COLUMN = 8; - private static final int TYPE_COLUMN = 9; - private static final int WIDGET_ID_COLUMN = 10; - private static final int WIDGET_TYPE_COLUMN = 11; - - private long mId; - private long mAlertDate; - private int mBgColorId; - private long mCreatedDate; - private boolean mHasAttachment; - private long mModifiedDate; - private int mNotesCount; - private long mParentId; - private String mSnippet; - private int mType; - private int mWidgetId; - private int mWidgetType; - private String mName; - private String mPhoneNumber; - - private boolean mIsLastItem; - private boolean mIsFirstItem; - private boolean mIsOnlyOneItem; - private boolean mIsOneNoteFollowingFolder; - private boolean mIsMultiNotesFollowingFolder; - //初始化NoteItemData,主要利用光标cursor获取的东西 - public NoteItemData(Context context, Cursor cursor) { - //getxxx为转换格式 - mId = cursor.getLong(ID_COLUMN); - mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); - mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN); - mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN); - mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0) ? true : false; - mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN); - mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN); - mParentId = cursor.getLong(PARENT_ID_COLUMN); - mSnippet = cursor.getString(SNIPPET_COLUMN); - mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace( - NoteEditActivity.TAG_UNCHECKED, ""); - mType = cursor.getInt(TYPE_COLUMN); - mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); - mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); - - //初始化电话号码的信息 - mPhoneNumber = ""; - if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { - mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); - if (!TextUtils.isEmpty(mPhoneNumber)) {//mphonenumber里有符合字符串,则用contart功能连接 - mName = Contact.getContact(context, mPhoneNumber); - if (mName == null) { - mName = mPhoneNumber; - } - } - } - - if (mName == null) { - mName = ""; - } - checkPostion(cursor); - } - ///根据鼠标的位置设置标记,和位置 - private void checkPostion(Cursor cursor) { - //初始化几个标记,cursor具体功能笔记中已提到,不一一叙述 - mIsLastItem = cursor.isLast() ? true : false; - mIsFirstItem = cursor.isFirst() ? true : false; - mIsOnlyOneItem = (cursor.getCount() == 1); - //初始化“多重子文件”“单一子文件”2个标记 - mIsMultiNotesFollowingFolder = false; - mIsOneNoteFollowingFolder = false; - - //主要是设置上诉2标记 - if (mType == Notes.TYPE_NOTE && !mIsFirstItem) {//若是note格式并且不是第一个元素 - int position = cursor.getPosition(); - if (cursor.moveToPrevious()) {//获取光标位置后看上一行 - if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER - || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) {//若光标满足系统或note格式 - if (cursor.getCount() > (position + 1)) { - mIsMultiNotesFollowingFolder = true;//若是数据行数大于但前位置+1则设置成正确 - } else { - mIsOneNoteFollowingFolder = true;//否则单一文件夹标记为true - } - } - if (!cursor.moveToNext()) {//若不能再往下走则报错 - throw new IllegalStateException("cursor move to previous but can't move back"); - } - } - } - } - ///下面的代码的作用均是声明获取属性的方法,下面一系列函数都是返回状态值等,用于判断状态 - public boolean isOneFollowingFolder() { - return mIsOneNoteFollowingFolder; - } - - public boolean isMultiFollowingFolder() { - return mIsMultiNotesFollowingFolder; - } - - public boolean isLast() { - return mIsLastItem; - } - - public String getCallName() { - return mName; - } - - public boolean isFirst() { - return mIsFirstItem; - } - - public boolean isSingle() { - return mIsOnlyOneItem; - } - - public long getId() { - return mId; - } - - public long getAlertDate() { - return mAlertDate; - } - - public long getCreatedDate() { - return mCreatedDate; - } - - public boolean hasAttachment() { - return mHasAttachment; - } - - public long getModifiedDate() { - return mModifiedDate; - } - - public int getBgColorId() { - return mBgColorId; - } - - public long getParentId() { - return mParentId; - } - - public int getNotesCount() { - return mNotesCount; - } - - public long getFolderId () { - return mParentId; - } - - public int getType() { - return mType; - } - - public int getWidgetType() { - return mWidgetType; - } - - public int getWidgetId() { - return mWidgetId; - } - - public String getSnippet() { - return mSnippet; - } - - public boolean hasAlert() { - return (mAlertDate > 0); - } - - //若数据父id为保存至文件夹模式的id且满足电话号码单元不为空,则isCallRecord为true - public boolean isCallRecord() { - return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber)); - } - - public static int getNoteType(Cursor cursor) {//获得便签的类型 - return cursor.getInt(TYPE_COLUMN); - } -} \ No newline at end of file diff --git a/doc/cyw.readcode.ui/ui/NotesListActivity.java b/doc/cyw.readcode.ui/ui/NotesListActivity.java deleted file mode 100644 index 9992129..0000000 --- a/doc/cyw.readcode.ui/ui/NotesListActivity.java +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * 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.ui; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.appwidget.AppWidgetManager; -import android.content.AsyncQueryHandler; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.os.AsyncTask; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.util.Log; -import android.view.ActionMode; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.Display; -import android.view.HapticFeedbackConstants; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnCreateContextMenuListener; -import android.view.View.OnTouchListener; -import android.view.inputmethod.InputMethodManager; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.AdapterView.OnItemLongClickListener; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ListView; -import android.widget.PopupMenu; -import android.widget.TextView; -import android.widget.Toast; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.gtask.remote.GTaskSyncService; -import net.micode.notes.model.WorkingNote; -import net.micode.notes.tool.BackupUtils; -import net.micode.notes.tool.DataUtils; -import net.micode.notes.tool.ResourceParser; -import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; -import net.micode.notes.widget.NoteWidgetProvider_2x; -import net.micode.notes.widget.NoteWidgetProvider_4x; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashSet; -//主界面,一进入就是这个界面 -/** - * @author k - * - */ -public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { //没有用特定的标签加注释。。。感觉没有什么用 - private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; - - private static final int FOLDER_LIST_QUERY_TOKEN = 1; - - private static final int MENU_FOLDER_DELETE = 0; - - private static final int MENU_FOLDER_VIEW = 1; - - private static final int MENU_FOLDER_CHANGE_NAME = 2; - - private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; //单行超过80个字符 - - private enum ListEditState { - NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER - }; - - private ListEditState mState; - - private BackgroundQueryHandler mBackgroundQueryHandler; - - private NotesListAdapter mNotesListAdapter; - - private ListView mNotesListView; - - private Button mAddNewNote; - - private boolean mDispatch; - - private int mOriginY; - - private int mDispatchY; - - private TextView mTitleBar; - - private long mCurrentFolderId; - - private ContentResolver mContentResolver; - - private ModeCallback mModeCallBack; - - private static final String TAG = "NotesListActivity"; - - public static final int NOTES_LISTVIEW_SCROLL_RATE = 30; - - private NoteItemData mFocusNoteDataItem; - - private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?"; - - private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>" - + Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" + " OR (" - + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " - + NoteColumns.NOTES_COUNT + ">0)"; - - private final static int REQUEST_CODE_OPEN_NODE = 102; - private final static int REQUEST_CODE_NEW_NODE = 103; - - @Override - // 创建类 - protected void onCreate(final Bundle savedInstanceState) { //需要是final类型 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。 - // final类不能被继承,没有子类,final类中的方法默认是final的。 - //final方法不能被子类的方法覆盖,但可以被继承。 - //final成员变量表示常量,只能被赋值一次,赋值后值不再改变。 - //final不能用于修饰构造方法。 - super.onCreate(savedInstanceState); // 调用父类的onCreate函数 - setContentView(R.layout.note_list); - initResources(); - - /** - * Insert an introduction when user firstly use this application - */ - setAppInfoFromRawRes(); - } - - @Override - // 返回一些子模块完成的数据交给主Activity处理 - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - // 结果值 和 要求值 符合要求 - if (resultCode == RESULT_OK - && (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) { - mNotesListAdapter.changeCursor(null); - } else { - super.onActivityResult(requestCode, resultCode, data); - // 调用 Activity 的onActivityResult() - } - } - - private void setAppInfoFromRawRes() { - // Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。 - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) { - StringBuilder sb = new StringBuilder(); - InputStream in = null; - try { - // 把资源文件放到应用程序的/raw/raw下,那么就可以在应用中使用getResources获取资源后, - // 以openRawResource方法(不带后缀的资源文件名)打开这个文件。 - in = getResources().openRawResource(R.raw.introduction); - if (in != null) { - InputStreamReader isr = new InputStreamReader(in); - BufferedReader br = new BufferedReader(isr); - char [] buf = new char[1024]; // 自行定义的数值,使用者不知道有什么意义 - int len = 0; - while ((len = br.read(buf)) > 0) { - sb.append(buf, 0, len); - } - } else { - Log.e(TAG, "Read introduction file error"); - return; - } - } catch (IOException e) { - e.printStackTrace(); - return; - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - // 创建空的WorkingNote - WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER, - AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE, - ResourceParser.RED); - note.setWorkingText(sb.toString()); - if (note.saveNote()) { - // 更新保存note的信息 - sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); - } else { - Log.e(TAG, "Save introduction note error"); - return; - } - } - } - - @Override - protected void onStart() { - super.onStart(); - startAsyncNotesListQuery(); - } - - // 初始化资源 - private void initResources() { - mContentResolver = this.getContentResolver(); // 获取应用程序的数据,得到类似数据表的东西 - mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); - mCurrentFolderId = Notes.ID_ROOT_FOLDER; - - // findViewById 是安卓编程的定位函数,主要是引用.R文件里的引用名 - mNotesListView = (ListView) findViewById(R.id.notes_list); // 绑定XML中的ListView,作为Item的容器 - mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null), - null, false); - mNotesListView.setOnItemClickListener(new OnListItemClickListener()); - mNotesListView.setOnItemLongClickListener(this); - mNotesListAdapter = new NotesListAdapter(this); - mNotesListView.setAdapter(mNotesListAdapter); - mAddNewNote = (Button) findViewById(R.id.btn_new_note);// 在activity中要获取该按钮 - mAddNewNote.setOnClickListener(this); - mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener()); - mDispatch = false; - mDispatchY = 0; - mOriginY = 0; - mTitleBar = (TextView) findViewById(R.id.tv_title_bar); - mState = ListEditState.NOTE_LIST; - mModeCallBack = new ModeCallback(); - } - - // 继承自ListView.MultiChoiceModeListener 和 OnMenuItemClickListener - private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { - private DropdownMenu mDropDownMenu; - private ActionMode mActionMode; - private MenuItem mMoveMenu; - - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - getMenuInflater().inflate(R.menu.note_list_options, menu); - menu.findItem(R.id.delete).setOnMenuItemClickListener(this); - mMoveMenu = menu.findItem(R.id.move); - if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER - || DataUtils.getUserFolderCount(mContentResolver) == 0) { - mMoveMenu.setVisible(false); - } else { - mMoveMenu.setVisible(true); - mMoveMenu.setOnMenuItemClickListener(this); - } - mActionMode = mode; - mNotesListAdapter.setChoiceMode(true); - mNotesListView.setLongClickable(false); - mAddNewNote.setVisibility(View.GONE); - - View customView = LayoutInflater.from(NotesListActivity.this).inflate( - R.layout.note_list_dropdown_menu, null); - mode.setCustomView(customView); - mDropDownMenu = new DropdownMenu(NotesListActivity.this, - (Button) customView.findViewById(R.id.selection_menu), - R.menu.note_list_dropdown); - mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){ - public boolean onMenuItemClick(final MenuItem item) { - mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected()); - updateMenu(); - return true; - } - - }); - return true; - } - - // 更新菜单 - private void updateMenu() { - int selectedCount = mNotesListAdapter.getSelectedCount(); - // Update dropdown menu - String format = getResources().getString(R.string.menu_select_title, selectedCount); - mDropDownMenu.setTitle(format); // 更改标题 - MenuItem item = mDropDownMenu.findItem(R.id.action_select_all); - if (item != null) { - if (mNotesListAdapter.isAllSelected()) { - item.setChecked(true); - item.setTitle(R.string.menu_deselect_all); - } else { - item.setChecked(false); - item.setTitle(R.string.menu_select_all); - } - } - } - - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - // TODO Auto-generated method stub - return false; - } - - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - // TODO Auto-generated method stub - return false; - } - - public void onDestroyActionMode(ActionMode mode) { - mNotesListAdapter.setChoiceMode(false); - mNotesListView.setLongClickable(true); - mAddNewNote.setVisibility(View.VISIBLE); - } - - public void finishActionMode() { - mActionMode.finish(); - } - - public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { - mNotesListAdapter.setCheckedItem(position, checked); - updateMenu(); - } - - public boolean onMenuItemClick(MenuItem item) { - if (mNotesListAdapter.getSelectedCount() == 0) { - Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none), - Toast.LENGTH_SHORT).show(); - return true; - } - - switch (item.getItemId()) { - case R.id.delete: - AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); - builder.setTitle(getString(R.string.alert_title_delete)); - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setMessage(getString(R.string.alert_message_delete_notes, - mNotesListAdapter.getSelectedCount())); - builder.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int which) { - batchDelete(); - } - }); - builder.setNegativeButton(android.R.string.cancel, null); - builder.show(); - break; - case R.id.move: - startQueryDestinationFolders(); - break; - default: - return false; - } - return true; - } - } - - private class NewNoteOnTouchListener implements OnTouchListener { - - public boolean onTouch(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: { - Display display = getWindowManager().getDefaultDisplay(); - int screenHeight = display.getHeight(); - int newNoteViewHeight = mAddNewNote.getHeight(); - int start = screenHeight - newNoteViewHeight; - int eventY = start + (int) event.getY(); - /** - * Minus TitleBar's height - */ - if (mState == ListEditState.SUB_FOLDER) { - eventY -= mTitleBar.getHeight(); - start -= mTitleBar.getHeight(); - } - /** - * HACKME:When click the transparent part of "New Note" button, dispatch - * the event to the list view behind this button. The transparent part of - * "New Note" button could be expressed by formula y=-0.12x+94锛圲nit:pixel锛� - * and the line top of the button. The coordinate based on left of the "New - * Note" button. The 94 represents maximum height of the transparent part. - * Notice that, if the background of the button changes, the formula should - * also change. This is very bad, just for the UI designer's strong requirement. - */ - if (event.getY() < (event.getX() * (-0.12) + 94)) { - View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1 - - mNotesListView.getFooterViewsCount()); - if (view != null && view.getBottom() > start - && (view.getTop() < (start + 94))) { - mOriginY = (int) event.getY(); - mDispatchY = eventY; - event.setLocation(event.getX(), mDispatchY); - mDispatch = true; - return mNotesListView.dispatchTouchEvent(event); - } - } - break; - } - case MotionEvent.ACTION_MOVE: { - if (mDispatch) { - mDispatchY += (int) event.getY() - mOriginY; - event.setLocation(event.getX(), mDispatchY); - return mNotesListView.dispatchTouchEvent(event); - } - break; - } - default: { - if (mDispatch) { - event.setLocation(event.getX(), mDispatchY); - mDispatch = false; - return mNotesListView.dispatchTouchEvent(event); - } - break; - } - } - return false; - } - - }; - - private void startAsyncNotesListQuery() { - String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION - : NORMAL_SELECTION; - mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null, - Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[] { - String.valueOf(mCurrentFolderId) - }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); - } - - private final class BackgroundQueryHandler extends AsyncQueryHandler { - public BackgroundQueryHandler(ContentResolver contentResolver) { - super(contentResolver); - } - - @Override - protected void onQueryComplete(int token, Object cookie, Cursor cursor) { - switch (token) { - case FOLDER_NOTE_LIST_QUERY_TOKEN: - mNotesListAdapter.changeCursor(cursor); - break; - case FOLDER_LIST_QUERY_TOKEN: - if (cursor != null && cursor.getCount() > 0) { - showFolderListMenu(cursor); - } else { - Log.e(TAG, "Query folder failed"); - } - break; - default: - return; - } - } - } - - private void showFolderListMenu(Cursor cursor) { - AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); - builder.setTitle(R.string.menu_title_select_folder); - final FoldersListAdapter adapter = new FoldersListAdapter(this, cursor); - builder.setAdapter(adapter, new DialogInterface.OnClickListener() { - - public void onClick(DialogInterface dialog, int which) { - DataUtils.batchMoveToFolder(mContentResolver, - mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which)); - Toast.makeText( - NotesListActivity.this, - getString(R.string.format_move_notes_to_folder, - mNotesListAdapter.getSelectedCount(), - adapter.getFolderName(NotesListActivity.this, which)), - Toast.LENGTH_SHORT).show(); - mModeCallBack.finishActionMode(); - } - }); - builder.show(); - } - - private void createNewNote() { - Intent intent = new Intent(this, NoteEditActivity.class); - intent.setAction(Intent.ACTION_INSERT_OR_EDIT); - intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId); - this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE); - } - - private void batchDelete() { - new AsyncTask>() { - protected HashSet doInBackground(Void... unused) { - HashSet widgets = mNotesListAdapter.getSelectedWidget(); - if (!isSyncMode()) { - // if not synced, delete notes directly - if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter - .getSelectedItemIds())) { - } else { - Log.e(TAG, "Delete notes error, should not happens"); - } - } else { - // in sync mode, we'll move the deleted note into the trash - // folder - if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter - .getSelectedItemIds(), Notes.ID_TRASH_FOLER)) { - Log.e(TAG, "Move notes to trash folder error, should not happens"); - } - } - return widgets; - } - - @Override - protected void onPostExecute(HashSet widgets) { - if (widgets != null) { - for (AppWidgetAttribute widget : widgets) { - if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID - && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) { - updateWidget(widget.widgetId, widget.widgetType); - } - } - } - mModeCallBack.finishActionMode(); - } - }.execute(); - } - - private void deleteFolder(long folderId) { - if (folderId == Notes.ID_ROOT_FOLDER) { - Log.e(TAG, "Wrong folder id, should not happen " + folderId); - return; - } - - HashSet ids = new HashSet(); - ids.add(folderId); - HashSet widgets = DataUtils.getFolderNoteWidget(mContentResolver, - folderId); - if (!isSyncMode()) { - // if not synced, delete folder directly - DataUtils.batchDeleteNotes(mContentResolver, ids); - } else { - // in sync mode, we'll move the deleted folder into the trash folder - DataUtils.batchMoveToFolder(mContentResolver, ids, Notes.ID_TRASH_FOLER); - } - if (widgets != null) { - for (AppWidgetAttribute widget : widgets) { - if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID - && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) { - updateWidget(widget.widgetId, widget.widgetType); - } - } - } - } - - private void openNode(NoteItemData data) { - Intent intent = new Intent(this, NoteEditActivity.class); - intent.setAction(Intent.ACTION_VIEW); - intent.putExtra(Intent.EXTRA_UID, data.getId()); - this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE); - } - - private void openFolder(NoteItemData data) { - mCurrentFolderId = data.getId(); - startAsyncNotesListQuery(); - if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { - mState = ListEditState.CALL_RECORD_FOLDER; - mAddNewNote.setVisibility(View.GONE); - } else { - mState = ListEditState.SUB_FOLDER; - } - if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { - mTitleBar.setText(R.string.call_record_folder_name); - } else { - mTitleBar.setText(data.getSnippet()); - } - mTitleBar.setVisibility(View.VISIBLE); - } - - public void onClick(View v) { - switch (v.getId()) { - case R.id.btn_new_note: - createNewNote(); - break; - default: - break; - } - } - - private void showSoftInput() { - InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - if (inputMethodManager != null) { - inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); - } - } - - private void hideSoftInput(View view) { - InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - - private void showCreateOrModifyFolderDialog(final boolean create) { - final AlertDialog.Builder builder = new AlertDialog.Builder(this); - View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null); - final EditText etName = (EditText) view.findViewById(R.id.et_foler_name); - showSoftInput(); - if (!create) { - if (mFocusNoteDataItem != null) { - etName.setText(mFocusNoteDataItem.getSnippet()); - builder.setTitle(getString(R.string.menu_folder_change_name)); - } else { - Log.e(TAG, "The long click data item is null"); - return; - } - } else { - etName.setText(""); - builder.setTitle(this.getString(R.string.menu_create_folder)); - } - - builder.setPositiveButton(android.R.string.ok, null); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - hideSoftInput(etName); - } - }); - - final Dialog dialog = builder.setView(view).show(); - final Button positive = (Button)dialog.findViewById(android.R.id.button1); - positive.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - hideSoftInput(etName); - String name = etName.getText().toString(); - if (DataUtils.checkVisibleFolderName(mContentResolver, name)) { - Toast.makeText(NotesListActivity.this, getString(R.string.folder_exist, name), - Toast.LENGTH_LONG).show(); - etName.setSelection(0, etName.length()); - return; - } - if (!create) { - if (!TextUtils.isEmpty(name)) { - ContentValues values = new ContentValues(); - values.put(NoteColumns.SNIPPET, name); - values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); - values.put(NoteColumns.LOCAL_MODIFIED, 1); - mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID - + "=?", new String[] { - String.valueOf(mFocusNoteDataItem.getId()) - }); - } - } else if (!TextUtils.isEmpty(name)) { - ContentValues values = new ContentValues(); - values.put(NoteColumns.SNIPPET, name); - values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); - mContentResolver.insert(Notes.CONTENT_NOTE_URI, values); - } - dialog.dismiss(); - } - }); - - if (TextUtils.isEmpty(etName.getText())) { - positive.setEnabled(false); - } - /** - * When the name edit text is null, disable the positive button - */ - etName.addTextChangedListener(new TextWatcher() { - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // TODO Auto-generated method stub - - } - - public void onTextChanged(CharSequence s, int start, int before, int count) { - if (TextUtils.isEmpty(etName.getText())) { - positive.setEnabled(false); - } else { - positive.setEnabled(true); - } - } - - public void afterTextChanged(Editable s) { - // TODO Auto-generated method stub - - } - }); - } - - /* (non-Javadoc) - * @see android.app.Activity#onBackPressed() - * 按返回键时根据情况更改类中的数据 - */ - @Override - public void onBackPressed() { switch (mState) { - case SUB_FOLDER: - mCurrentFolderId = Notes.ID_ROOT_FOLDER; - mState = ListEditState.NOTE_LIST; - startAsyncNotesListQuery(); - mTitleBar.setVisibility(View.GONE); - break; - case CALL_RECORD_FOLDER: - mCurrentFolderId = Notes.ID_ROOT_FOLDER; - mState = ListEditState.NOTE_LIST; - mAddNewNote.setVisibility(View.VISIBLE); - mTitleBar.setVisibility(View.GONE); - startAsyncNotesListQuery(); - break; - case NOTE_LIST: - super.onBackPressed(); - break; - default: - break; - } - } - - /** - * @param appWidgetId - * @param appWidgetType - * 根据不同类型的widget更新插件,通过intent传送数据 - */ - private void updateWidget(int appWidgetId, int appWidgetType) { - Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); - if (appWidgetType == Notes.TYPE_WIDGET_2X) { - intent.setClass(this, NoteWidgetProvider_2x.class); - } else if (appWidgetType == Notes.TYPE_WIDGET_4X) { - intent.setClass(this, NoteWidgetProvider_4x.class); - } else { - Log.e(TAG, "Unspported widget type"); - return; - } - - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { - appWidgetId - }); - - sendBroadcast(intent); - setResult(RESULT_OK, intent); - } - - /** - * 声明监听器,建立菜单,包括名称,视图,删除操作,更改名称操作; - */ - private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() { - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - if (mFocusNoteDataItem != null) { - menu.setHeaderTitle(mFocusNoteDataItem.getSnippet()); - menu.add(0, MENU_FOLDER_VIEW, 0, R.string.menu_folder_view); - menu.add(0, MENU_FOLDER_DELETE, 0, R.string.menu_folder_delete); - menu.add(0, MENU_FOLDER_CHANGE_NAME, 0, R.string.menu_folder_change_name); - } - } - }; - - @Override - public void onContextMenuClosed(Menu menu) { - if (mNotesListView != null) { - mNotesListView.setOnCreateContextMenuListener(null); - } - super.onContextMenuClosed(menu); - } - - /* (non-Javadoc) - * @see android.app.Activity#onContextItemSelected(android.view.MenuItem) - * 针对menu中不同的选择进行不同的处理,里面详细注释 - */ - @Override - public boolean onContextItemSelected(MenuItem item) { - if (mFocusNoteDataItem == null) { - Log.e(TAG, "The long click data item is null"); - return false; - } - switch (item.getItemId()) { - case MENU_FOLDER_VIEW: - openFolder(mFocusNoteDataItem);//打开对应文件 - break; - case MENU_FOLDER_DELETE: - AlertDialog.Builder builder = new AlertDialog.Builder(this);//设置确认是否删除的对话框 - builder.setTitle(getString(R.string.alert_title_delete)); - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setMessage(getString(R.string.alert_message_delete_folder)); - builder.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - deleteFolder(mFocusNoteDataItem.getId()); - } - }); - builder.setNegativeButton(android.R.string.cancel, null); - builder.show();//显示对话框 - break; - case MENU_FOLDER_CHANGE_NAME: - showCreateOrModifyFolderDialog(false); - break; - default: - break; - } - - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.clear(); - if (mState == ListEditState.NOTE_LIST) { - getMenuInflater().inflate(R.menu.note_list, menu); - // set sync or sync_cancel - menu.findItem(R.id.menu_sync).setTitle( - GTaskSyncService.isSyncing() ? R.string.menu_sync_cancel : R.string.menu_sync); - } else if (mState == ListEditState.SUB_FOLDER) { - getMenuInflater().inflate(R.menu.sub_folder, menu); - } else if (mState == ListEditState.CALL_RECORD_FOLDER) { - getMenuInflater().inflate(R.menu.call_record_folder, menu); - } else { - Log.e(TAG, "Wrong state:" + mState); - } - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_new_folder: { - showCreateOrModifyFolderDialog(true); - break; - } - case R.id.menu_export_text: { - exportNoteToText(); - break; - } - case R.id.menu_sync: { - if (isSyncMode()) { - if (TextUtils.equals(item.getTitle(), getString(R.string.menu_sync))) { - GTaskSyncService.startSync(this); - } else { - GTaskSyncService.cancelSync(this); - } - } else { - startPreferenceActivity(); - } - break; - } - case R.id.menu_setting: { - startPreferenceActivity(); - break; - } - case R.id.menu_new_note: { - createNewNote(); - break; - } - case R.id.menu_search: - onSearchRequested(); - break; - default: - break; - } - return true; - } - - /* (non-Javadoc) - * @see android.app.Activity#onSearchRequested() - * 直接调用startSearch函数 - */ - @Override - public boolean onSearchRequested() { - startSearch(null, false, null /* appData */, false); - return true; - } - - /** - * 函数功能:实现将便签导出到文本功能 - */ - private void exportNoteToText() { - final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this); - new AsyncTask() { - - @Override - protected Integer doInBackground(Void... unused) { - return backup.exportToText(); - } - - @Override - protected void onPostExecute(Integer result) { - if (result == BackupUtils.STATE_SD_CARD_UNMOUONTED) { - AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); - builder.setTitle(NotesListActivity.this - .getString(R.string.failed_sdcard_export)); - builder.setMessage(NotesListActivity.this - .getString(R.string.error_sdcard_unmounted)); - builder.setPositiveButton(android.R.string.ok, null); - builder.show(); - } else if (result == BackupUtils.STATE_SUCCESS) { - AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); - builder.setTitle(NotesListActivity.this - .getString(R.string.success_sdcard_export)); - builder.setMessage(NotesListActivity.this.getString( - R.string.format_exported_file_location, backup - .getExportedTextFileName(), backup.getExportedTextFileDir())); - builder.setPositiveButton(android.R.string.ok, null); - builder.show(); - } else if (result == BackupUtils.STATE_SYSTEM_ERROR) { - AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); - builder.setTitle(NotesListActivity.this - .getString(R.string.failed_sdcard_export)); - builder.setMessage(NotesListActivity.this - .getString(R.string.error_sdcard_export)); - builder.setPositiveButton(android.R.string.ok, null); - builder.show(); - } - } - - }.execute(); - } - - /** - * @return - * 功能:判断是否正在同步 - */ - private boolean isSyncMode() { - return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; - } - - /** - * 功能:跳转到PreferenceActivity界面 - */ - private void startPreferenceActivity() { - Activity from = getParent() != null ? getParent() : this; - Intent intent = new Intent(from, NotesPreferenceActivity.class); - from.startActivityIfNeeded(intent, -1); - } - - /** - * @author k - * 函数功能:实现对便签列表项的点击事件(短按) - */ - private class OnListItemClickListener implements OnItemClickListener { - - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (view instanceof NotesListItem) { - NoteItemData item = ((NotesListItem) view).getItemData(); - if (mNotesListAdapter.isInChoiceMode()) { - if (item.getType() == Notes.TYPE_NOTE) { - position = position - mNotesListView.getHeaderViewsCount(); - mModeCallBack.onItemCheckedStateChanged(null, position, id, - !mNotesListAdapter.isSelectedItem(position)); - } - return; - } - - switch (mState) { - case NOTE_LIST: - if (item.getType() == Notes.TYPE_FOLDER - || item.getType() == Notes.TYPE_SYSTEM) { - openFolder(item); - } else if (item.getType() == Notes.TYPE_NOTE) { - openNode(item); - } else { - Log.e(TAG, "Wrong note type in NOTE_LIST"); - } - break; - case SUB_FOLDER: - case CALL_RECORD_FOLDER: - if (item.getType() == Notes.TYPE_NOTE) { - openNode(item); - } else { - Log.e(TAG, "Wrong note type in SUB_FOLDER"); - } - break; - default: - break; - } - } - } - - } - - /** - * 查询目标文件 - */ - private void startQueryDestinationFolders() { - String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?"; - selection = (mState == ListEditState.NOTE_LIST) ? selection: - "(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")"; - - mBackgroundQueryHandler.startQuery(FOLDER_LIST_QUERY_TOKEN, - null, - Notes.CONTENT_NOTE_URI, - FoldersListAdapter.PROJECTION, - selection, - new String[] { - String.valueOf(Notes.TYPE_FOLDER), - String.valueOf(Notes.ID_TRASH_FOLER), - String.valueOf(mCurrentFolderId) - }, - NoteColumns.MODIFIED_DATE + " DESC"); - } - - /* (non-Javadoc) - * @see android.widget.AdapterView.OnItemLongClickListener#onItemLongClick(android.widget.AdapterView, android.view.View, int, long) - * 长按某一项时进行的操作 - * 如果长按的是便签,则通过ActionMode菜单实现;如果长按的是文件夹,则通过ContextMenu菜单实现; - * 具体ActionMOde菜单和ContextMenu菜单的详细见精度笔记 - */ - public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {// 函数:实现长按项目的点击事件。如果长按的是便签,则通过ActionMode菜单实现;如果长按的是文件夹,则通过ContextMenu菜单实现。 - if (view instanceof NotesListItem) { - mFocusNoteDataItem = ((NotesListItem) view).getItemData(); - if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) { - if (mNotesListView.startActionMode(mModeCallBack) != null) { - mModeCallBack.onItemCheckedStateChanged(null, position, id, true); - mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - } else { - Log.e(TAG, "startActionMode fails"); - } - } else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) { - mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener); - } - } - return false; - } -} \ No newline at end of file diff --git a/doc/cyw.readcode.ui/ui/NotesListAdapter.java b/doc/cyw.readcode.ui/ui/NotesListAdapter.java deleted file mode 100644 index 5c5d3ee..0000000 --- a/doc/cyw.readcode.ui/ui/NotesListAdapter.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.database.Cursor; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CursorAdapter; - - -import net.micode.notes.data.Notes; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; - - -/* - * 功能:直译为便签表连接器,继承了CursorAdapter,它为cursor和ListView提供了连接的桥梁。 - * 所以NotesListAdapter实现的是鼠标和编辑便签链接的桥梁 - */ -public class NotesListAdapter extends CursorAdapter { - private static final String TAG = "NotesListAdapter"; - private Context mContext; - private HashMap mSelectedIndex; - private int mNotesCount; //便签数 - private boolean mChoiceMode; //选择模式标记 - - /* - * 桌面widget的属性,包括编号和类型 - */ - public static class AppWidgetAttribute { - public int widgetId; - public int widgetType; - }; - - /* - * 函数功能:初始化便签链接器 - * 函数实现:根据传进来的内容设置相关变量 - */ - public NotesListAdapter(Context context) { - super(context, null); //父类对象置空 - mSelectedIndex = new HashMap(); //新建选项下标的hash表 - mContext = context; - mNotesCount = 0; - } - - @Override - /* - * 函数功能:新建一个视图来存储光标所指向的数据 - * 函数实现:使用兄弟类NotesListItem新建一个项目选项 - */ - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return new NotesListItem(context); - } - - /* - * 函数功能:将已经存在的视图和鼠标指向的数据进行捆绑 - * 函数实现:如下注释 - */ - @Override - public void bindView(View view, Context context, Cursor cursor) { - if (view instanceof NotesListItem) { - //若view是NotesListItem的一个实例 - NoteItemData itemData = new NoteItemData(context, cursor); - ((NotesListItem) view).bind(context, itemData, mChoiceMode, - isSelectedItem(cursor.getPosition())); - //则新建一个项目选项并且用bind跟将view和鼠标,内容,便签数据捆绑在一起 - } - } - - /* - * 函数功能:设置勾选框 - * 函数实现:如下注释 - */ - public void setCheckedItem(final int position, final boolean checked) { - mSelectedIndex.put(position, checked); - //根据定位和是否勾选设置下标 - notifyDataSetChanged(); - //在修改后刷新activity - } - - /* - * 函数功能:判断单选按钮是否勾选 - */ - public boolean isInChoiceMode() { - return mChoiceMode; - } - - /* - * 函数功能:设置单项选项框 - * 函数实现:重置下标并且根据参数mode设置选项 - */ - public void setChoiceMode(boolean mode) { - mSelectedIndex.clear(); - mChoiceMode = mode; - } - - /* - * 函数功能:选择全部选项 - * 函数实现:如下注释 - */ - public void selectAll(boolean checked) { - Cursor cursor = getCursor(); - //获取光标位置 - for (int i = 0; i < getCount(); i++) { - if (cursor.moveToPosition(i)) { - if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) { - setCheckedItem(i, checked); - } - } - } - //遍历所有光标可用的位置在判断为便签类型之后勾选单项框 - } - - /* - * 函数功能:建立选择项的下标列表 - * 函数实现:如下注释 - */ - public HashSet getSelectedItemIds() { - HashSet itemSet = new HashSet(); - //建立hash表 - for (Integer position : mSelectedIndex.keySet()) { - //遍历所有的关键 - if (mSelectedIndex.get(position) == true) { - //若光标位置可用 - Long id = getItemId(position); - if (id == Notes.ID_ROOT_FOLDER) { - //原文件不需要添加 - Log.d(TAG, "Wrong item id, should not happen"); - } else { - itemSet.add(id); - } - //则将id该下标假如选项集合中 - - } - } - - return itemSet; - } - - /* - * 函数功能:建立桌面Widget的选项表 - * 函数实现:如下注释 - */ - public HashSet getSelectedWidget() { - HashSet itemSet = new HashSet(); - for (Integer position : mSelectedIndex.keySet()) { - if (mSelectedIndex.get(position) == true) { - Cursor c = (Cursor) getItem(position); - //以上4句和getSelectedItemIds一样,不再重复 - if (c != null) { - //光标位置可用的话就建立新的Widget属性并编辑下标和类型,最后添加到选项集中 - AppWidgetAttribute widget = new AppWidgetAttribute(); - NoteItemData item = new NoteItemData(mContext, c); - widget.widgetId = item.getWidgetId(); - widget.widgetType = item.getWidgetType(); - itemSet.add(widget); - /** - * Don't close cursor here, only the adapter could close it - */ - } else { - Log.e(TAG, "Invalid cursor"); - return null; - } - } - } - return itemSet; - } - - /* - * 函数功能:获取选项个数 - * 函数实现:如下注释 - */ - public int getSelectedCount() { - Collection values = mSelectedIndex.values(); - //首先获取选项下标的值 - if (null == values) { - return 0; - } - Iterator iter = values.iterator(); - //初始化叠加器 - int count = 0; - while (iter.hasNext()) { - if (true == iter.next()) { - //若value值为真计数+1 - count++; - } - } - return count; - } - - /* - * 函数功能:判断是否全部选中 - * 函数实现:如下注释 - */ - public boolean isAllSelected() { - int checkedCount = getSelectedCount(); - return (checkedCount != 0 && checkedCount == mNotesCount); - //获取选项数看是否等于便签的个数 - } - - /* - * 函数功能:判断是否为选项表 - * 函数实现:通过传递的下标来确定 - */ - public boolean isSelectedItem(final int position) { - if (null == mSelectedIndex.get(position)) { - return false; - } - return mSelectedIndex.get(position); - } - - @Override - /* - * 函数功能:在activity内容发生局部变动的时候回调该函数计算便签的数量 - * 函数实现:如下注释 - */ - protected void onContentChanged() { - super.onContentChanged(); - //执行基类函数 - calcNotesCount(); - } - - @Override - /* - * 函数功能:在activity光标发生局部变动的时候回调该函数计算便签的数量 - */ - public void changeCursor(Cursor cursor) { - super.changeCursor(cursor); - //执行基类函数 - calcNotesCount(); - } - - /* - * 函数功能:计算便签数量 - * - */ - private void calcNotesCount() { - mNotesCount = 0; - for (int i = 0; i < getCount(); i++) { - //获取总数同时遍历 - Cursor c = (Cursor) getItem(i); - if (c != null) { - if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) { - mNotesCount++; - //若该位置不为空并且文本类型为便签就+1 - } - } else { - Log.e(TAG, "Invalid cursor"); - return; - } - //否则报错 - } - } -} diff --git a/doc/cyw.readcode.ui/ui/NotesListItem.java b/doc/cyw.readcode.ui/ui/NotesListItem.java deleted file mode 100644 index b89acf7..0000000 --- a/doc/cyw.readcode.ui/ui/NotesListItem.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.text.format.DateUtils; -import android.view.View; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.tool.DataUtils; -import net.micode.notes.tool.ResourceParser.NoteItemBgResources; - - -//创建便签列表项目选项 -public class NotesListItem extends LinearLayout { - private ImageView mAlert;//闹钟图片 - private TextView mTitle; //标题 - private TextView mTime; //时间 - private TextView mCallName; // - private NoteItemData mItemData; //标签数据 - private CheckBox mCheckBox; //打钩框 - - /*初始化基本信息*/ - public NotesListItem(Context context) { - super(context); //super()它的主要作用是调整调用父类构造函数的顺序 - inflate(context, R.layout.note_item, this);//Inflate可用于将一个xml中定义的布局控件找出来,这里的xml是r。layout - //findViewById用于从contentView中查找指定ID的View,转换出来的形式根据需要而定; - mAlert = (ImageView) findViewById(R.id.iv_alert_icon); - mTitle = (TextView) findViewById(R.id.tv_title); - mTime = (TextView) findViewById(R.id.tv_time); - mCallName = (TextView) findViewById(R.id.tv_name); - mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); - } - ///根据data的属性对各个控件的属性的控制,主要是可见性Visibility,内容setText,格式setTextAppearance - public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) { - if (choiceMode && data.getType() == Notes.TYPE_NOTE) { - mCheckBox.setVisibility(View.VISIBLE); ///设置可见行为可见 - mCheckBox.setChecked(checked); ///格子打钩 - } else { - mCheckBox.setVisibility(View.GONE); - } - - mItemData = data; - ///设置控件属性,一共三种情况,由data的id和父id是否与保存到文件夹的id一致来决定 - if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { - mCallName.setVisibility(View.GONE); - mAlert.setVisibility(View.VISIBLE); - //设置该textview的style - mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); - //settext为设置内容 - mTitle.setText(context.getString(R.string.call_record_folder_name) - + context.getString(R.string.format_folder_files_count, data.getNotesCount())); - mAlert.setImageResource(R.drawable.call_record); - } else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) { - mCallName.setVisibility(View.VISIBLE); - mCallName.setText(data.getCallName()); - mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem); - mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); - ///关于闹钟的设置 - if (data.hasAlert()) { - mAlert.setImageResource(R.drawable.clock);//图片来源的设置 - mAlert.setVisibility(View.VISIBLE); - } else { - mAlert.setVisibility(View.GONE); - } - } else { - mCallName.setVisibility(View.GONE); - mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); - ///设置title格式 - if (data.getType() == Notes.TYPE_FOLDER) { - mTitle.setText(data.getSnippet() - + context.getString(R.string.format_folder_files_count, - data.getNotesCount())); - mAlert.setVisibility(View.GONE); - } else { - mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); - if (data.hasAlert()) { - mAlert.setImageResource(R.drawable.clock);///设置图片来源 - mAlert.setVisibility(View.VISIBLE); - } else { - mAlert.setVisibility(View.GONE); - } - } - } - ///设置内容,获取相关时间,从data里编辑的日期中获取 - mTime. setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); - - setBackground(data); - } - //根据data的文件属性来设置背景 - private void setBackground(NoteItemData data) { - int id = data.getBgColorId(); - //,若是note型文件,则4种情况,对于4种不同情况的背景来源 - if (data.getType() == Notes.TYPE_NOTE) { - //单个数据并且只有一个子文件夹 - if (data.isSingle() || data.isOneFollowingFolder()) { - setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); - } else if (data.isLast()) {//是最后一个数据 - setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id)); - } else if (data.isFirst() || data.isMultiFollowingFolder()) {//是一个数据并有多个子文件夹 - setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); - } else { - setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); - } - } else { - //若不是note直接调用文件夹的背景来源 - setBackgroundResource(NoteItemBgResources.getFolderBgRes()); - } - } - public NoteItemData getItemData() { - return mItemData; - }//返回当前便签的数据信息 -} diff --git a/doc/cyw.readcode.ui/ui/NotesPreferenceActivity.java b/doc/cyw.readcode.ui/ui/NotesPreferenceActivity.java deleted file mode 100644 index 75cfd3d..0000000 --- a/doc/cyw.readcode.ui/ui/NotesPreferenceActivity.java +++ /dev/null @@ -1,530 +0,0 @@ -/* - * 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.ui; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.ActionBar; -import android.app.AlertDialog; -import android.content.BroadcastReceiver; -import android.content.ContentValues; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceActivity; -import android.preference.PreferenceCategory; -import android.text.TextUtils; -import android.text.format.DateFormat; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; -import android.widget.Toast; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.gtask.remote.GTaskSyncService; - -/* - *该类功能:NotesPreferenceActivity,在小米便签中主要实现的是对背景颜色和字体大小的数据储存。 - * 继承了PreferenceActivity主要功能为对系统信息和配置进行自动保存的Activity - */ -public class NotesPreferenceActivity extends PreferenceActivity { - public static final String PREFERENCE_NAME = "notes_preferences"; - //优先名 - public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name"; - //同步账号 - public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time"; - //同步时间 - public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear"; - - private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key"; - //同步密码 - private static final String AUTHORITIES_FILTER_KEY = "authorities"; - //本地密码 - private PreferenceCategory mAccountCategory; - //账户分组 - private GTaskReceiver mReceiver; - //同步任务接收器 - private Account[] mOriAccounts; - //账户 - private boolean mHasAddedAccount; - //账户的hash标记 - - @Override - /* - *函数功能:创建一个activity,在函数里要完成所有的正常静态设置 - *参数:Bundle icicle:存放了 activity 当前的状态 - *函数实现:如下注释 - */ - protected void onCreate(Bundle icicle) { - //先执行父类的创建函数 - super.onCreate(icicle); - - /* using the app icon for navigation */ - getActionBar().setDisplayHomeAsUpEnabled(true); - //给左上角图标的左边加上一个返回的图标 - - addPreferencesFromResource(R.xml.preferences); - //添加xml来源并显示 xml - mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY); - //根据同步账户关键码来初始化分组 - mReceiver = new GTaskReceiver(); - IntentFilter filter = new IntentFilter(); - filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME); - registerReceiver(mReceiver, filter); - //初始化同步组件 - - mOriAccounts = null; - View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null); - //获取listvivew,ListView的作用:用于列出所有选择 - getListView().addHeaderView(header, null, true); - //在listview组件上方添加其他组件 - } - - @Override - /* - * 函数功能:activity交互功能的实现,用于接受用户的输入 - * 函数实现:如下注释 - */ - protected void onResume() { - //先执行父类 的交互实现 - super.onResume(); - - // need to set sync account automatically if user has added a new - // account - if (mHasAddedAccount) { - //若用户新加了账户则自动设置同步账户 - Account[] accounts = getGoogleAccounts(); - //获取google同步账户 - if (mOriAccounts != null && accounts.length > mOriAccounts.length) { - //若原账户不为空且当前账户有增加 - for (Account accountNew : accounts) { - boolean found = false; - for (Account accountOld : mOriAccounts) { - if (TextUtils.equals(accountOld.name, accountNew.name)) { - //更新账户 - found = true; - break; - } - } - if (!found) { - setSyncAccount(accountNew.name); - //若是没有找到旧的账户,那么同步账号中就只添加新账户 - break; - } - } - } - } - - refreshUI(); - //刷新标签界面 - } - - @Override - /* - * 函数功能:销毁一个activity - * 函数实现:如下注释 - */ - protected void onDestroy() { - if (mReceiver != null) { - unregisterReceiver(mReceiver); - //注销接收器 - } - super.onDestroy(); - //执行父类的销毁动作 - } - - /* - * 函数功能:重新设置账户信息 - * 函数实现:如下注释 - */ - private void loadAccountPreference() { - mAccountCategory.removeAll(); - //销毁所有的分组 - Preference accountPref = new Preference(this); - //建立首选项 - final String defaultAccount = getSyncAccountName(this); - accountPref.setTitle(getString(R.string.preferences_account_title)); - accountPref.setSummary(getString(R.string.preferences_account_summary)); - //设置首选项的大标题和小标题 - accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - //建立监听器 - if (!GTaskSyncService.isSyncing()) { - if (TextUtils.isEmpty(defaultAccount)) { - // the first time to set account - //若是第一次建立账户显示选择账户提示对话框 - showSelectAccountAlertDialog(); - } else { - // if the account has already been set, we need to promp - // user about the risk - //若是已经建立则显示修改对话框并进行修改操作 - showChangeAccountConfirmAlertDialog(); - } - } else { - //若在没有同步的情况下,则在toast中显示不能修改 - Toast.makeText(NotesPreferenceActivity.this, - R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT) - .show(); - } - return true; - } - }); - - //根据新建首选项编辑新的账户分组 - mAccountCategory.addPreference(accountPref); - } - - /* - *函数功能:设置按键的状态和最后同步的时间 - *函数实现:如下注释 - */ - private void loadSyncButton() { - Button syncButton = (Button) findViewById(R.id.preference_sync_button); - TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview); - //获取同步按钮控件和最终同步时间的的窗口 - // set button state - //设置按钮的状态 - if (GTaskSyncService.isSyncing()) { - //若是在同步状态下 - syncButton.setText(getString(R.string.preferences_button_sync_cancel)); - syncButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - GTaskSyncService.cancelSync(NotesPreferenceActivity.this); - } - }); - //设置按钮显示的文本为“取消同步”以及监听器 - } else { - syncButton.setText(getString(R.string.preferences_button_sync_immediately)); - syncButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - GTaskSyncService.startSync(NotesPreferenceActivity.this); - } - }); - //若是不同步则设置按钮显示的文本为“立即同步”以及对应监听器 - } - syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); - //设置按键可用还是不可用 - - // set last sync time - // 设置最终同步时间 - if (GTaskSyncService.isSyncing()) { - //若是在同步的情况下 - lastSyncTimeView.setText(GTaskSyncService.getProgressString()); - lastSyncTimeView.setVisibility(View.VISIBLE); - // 根据当前同步服务器设置时间显示框的文本以及可见性 - } else { - //若是非同步情况 - long lastSyncTime = getLastSyncTime(this); - if (lastSyncTime != 0) { - lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time, - DateFormat.format(getString(R.string.preferences_last_sync_time_format), - lastSyncTime))); - lastSyncTimeView.setVisibility(View.VISIBLE); - //则根据最后同步时间的信息来编辑时间显示框的文本内容和可见性 - } else { - //若时间为空直接设置为不可见状态 - lastSyncTimeView.setVisibility(View.GONE); - } - } - } - /* - *函数功能:刷新标签界面 - *函数实现:调用上文设置账号和设置按键两个函数来实现 - */ - private void refreshUI() { - loadAccountPreference(); - loadSyncButton(); - } - - /* - * 函数功能:显示账户选择的对话框并进行账户的设置 - * 函数实现:如下注释 - */ - private void showSelectAccountAlertDialog() { - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); - //创建一个新的对话框 - - View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); - TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); - titleTextView.setText(getString(R.string.preferences_dialog_select_account_title)); - TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); - subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips)); - //设置标题以及子标题的内容 - dialogBuilder.setCustomTitle(titleView); - dialogBuilder.setPositiveButton(null, null); - //设置对话框的自定义标题,建立一个YES的按钮 - Account[] accounts = getGoogleAccounts(); - String defAccount = getSyncAccountName(this); - //获取同步账户信息 - mOriAccounts = accounts; - mHasAddedAccount = false; - - if (accounts.length > 0) { - //若账户不为空 - CharSequence[] items = new CharSequence[accounts.length]; - final CharSequence[] itemMapping = items; - int checkedItem = -1; - int index = 0; - for (Account account : accounts) { - if (TextUtils.equals(account.name, defAccount)) { - checkedItem = index; - //在账户列表中查询到所需账户 - } - items[index++] = account.name; - } - dialogBuilder.setSingleChoiceItems(items, checkedItem, - //在对话框建立一个单选的复选框 - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - setSyncAccount(itemMapping[which].toString()); - dialog.dismiss(); - //取消对话框 - refreshUI(); - } - //设置点击后执行的事件,包括检录新同步账户和刷新标签界面 - }); - //建立对话框网络版的监听器 - } - - View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null); - dialogBuilder.setView(addAccountView); - //给新加账户对话框设置自定义样式 - - final AlertDialog dialog = dialogBuilder.show(); - //显示对话框 - addAccountView.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - mHasAddedAccount = true; - //将新加账户的hash置true - Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); - //建立网络建立组件 - intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] { - "gmail-ls" - }); - startActivityForResult(intent, -1); - //跳回上一个选项 - dialog.dismiss(); - } - }); - //建立新加账户对话框的监听器 - } - - /* - * 函数功能:显示账户选择对话框和相关账户操作 - * 函数实现:如下注释 - */ - private void showChangeAccountConfirmAlertDialog() { - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); - //创建一个新的对话框 - View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); - TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); - titleTextView.setText(getString(R.string.preferences_dialog_change_account_title, - getSyncAccountName(this))); - TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); - subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg)); - //根据同步修改的账户信息设置标题以及子标题的内容 - dialogBuilder.setCustomTitle(titleView); - //设置对话框的自定义标题 - CharSequence[] menuItemArray = new CharSequence[] { - getString(R.string.preferences_menu_change_account), - getString(R.string.preferences_menu_remove_account), - getString(R.string.preferences_menu_cancel) - }; - //定义一些标记字符串 - dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() { - //设置对话框要显示的一个list,用于显示几个命令时,即change,remove,cancel - public void onClick(DialogInterface dialog, int which) { - //按键功能,由which来决定 - if (which == 0) { - //进入账户选择对话框 - showSelectAccountAlertDialog(); - } else if (which == 1) { - //删除账户并且跟新便签界面 - removeSyncAccount(); - refreshUI(); - } - } - }); - dialogBuilder.show(); - //显示对话框 - } - - /* - *函数功能:获取谷歌账户 - *函数实现:通过账户管理器直接获取 - */ - private Account[] getGoogleAccounts() { - AccountManager accountManager = AccountManager.get(this); - return accountManager.getAccountsByType("com.google"); - } - - /* - * 函数功能:设置同步账户 - * 函数实现:如下注释: - */ - private void setSyncAccount(String account) { - if (!getSyncAccountName(this).equals(account)) { - //假如该账号不在同步账号列表中 - SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - //编辑共享的首选项 - if (account != null) { - editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account); - } else { - editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); - } - //将该账号加入到首选项中 - - editor.commit(); - //提交修改的数据 - - - setLastSyncTime(this, 0); - //将最后同步时间清零 - - // clean up local gtask related info - new Thread(new Runnable() { - public void run() { - ContentValues values = new ContentValues(); - values.put(NoteColumns.GTASK_ID, ""); - values.put(NoteColumns.SYNC_ID, 0); - getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); - } - }).start(); - //重置当地同步任务的信息 - - Toast.makeText(NotesPreferenceActivity.this, - getString(R.string.preferences_toast_success_set_accout, account), - Toast.LENGTH_SHORT).show(); - //将toast的文本信息置为“设置账户成功”并显示出来 - } - } - /* - * 函数功能:删除同步账户 - * 函数实现:如下注释: - */ - private void removeSyncAccount() { - SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - //设置共享首选项 - - if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) { - editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME); - //假如当前首选项中有账户就删除 - } - if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) { - editor.remove(PREFERENCE_LAST_SYNC_TIME); - //删除当前首选项中有账户时间 - } - editor.commit(); - //提交更新后的数据 - - // clean up local gtask related info - new Thread(new Runnable() { - public void run() { - ContentValues values = new ContentValues(); - values.put(NoteColumns.GTASK_ID, ""); - values.put(NoteColumns.SYNC_ID, 0); - getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); - } - }).start(); - //重置当地同步任务的信息 - } - - /* - * 函数功能:获取同步账户名称 - * 函数实现:通过共享的首选项里的信息直接获取 - */ - public static String getSyncAccountName(Context context) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, - Context.MODE_PRIVATE); - return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); - } - - /* - * 函数功能:设置最终同步的时间 - * 函数实现:如下注释 - */ - public static void setLastSyncTime(Context context, long time) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, - Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - // 从共享首选项中找到相关账户并获取其编辑器 - editor.putLong(PREFERENCE_LAST_SYNC_TIME, time); - editor.commit(); - //编辑最终同步时间并提交更新 - } - /* - * 函数功能:获取最终同步时间 - * 函数实现:通过共享的首选项里的信息直接获取 - */ - public static long getLastSyncTime(Context context) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, - Context.MODE_PRIVATE); - return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); - } - - /* - * 函数功能:接受同步信息 - * 函数实现:继承BroadcastReceiver - */ - private class GTaskReceiver extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - refreshUI(); - if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) { - //获取随广播而来的Intent中的同步服务的数据 - TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview); - syncStatus.setText(intent - .getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG)); - //通过获取的数据在设置系统的状态 - } - - } - } - - /* - * 函数功能:处理菜单的选项 - * 函数实现:如下注释 - * 参数:MenuItem菜单选项 - */ - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - //根据选项的id选择,这里只有一个主页 - case android.R.id.home: - Intent intent = new Intent(this, NotesListActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - //在主页情况下在创建连接组件intent,发出清空的信号并开始一个相应的activity - default: - return false; - } - } -} - diff --git a/doc/data/MetaData.java b/doc/data/MetaData.java deleted file mode 100644 index e591aee..0000000 --- a/doc/data/MetaData.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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.gtask.data; - -import android.database.Cursor; -import android.util.Log; - -import net.micode.notes.tool.GTaskStringUtils; - -import org.json.JSONException; -import org.json.JSONObject; - - -//创建继承自Task的类 -public class MetaData extends Task { - private final static String TAG = MetaData.class.getSimpleName();//调用getSimpleName()函数 - - private String mRelatedGid = null;//初始化mRelatedGid为null - //函数:设置meta,用put方法将gid传给GTaskStringUtils.META_HEAD_GTASK_ID,用catch来在出现错误时报错 - public void setMeta(String gid, JSONObject metaInfo) { - try { - metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); - } catch (JSONException e) { - Log.e(TAG, "failed to put related gid");//catch异常处理 - } - setNotes(metaInfo.toString()); - setName(GTaskStringUtils.META_NOTE_NAME); - } - //获取相关的gid - public String getRelatedGid() { - return mRelatedGid; - } - - //函数判断getNotes()是否为空,并返回 - @Override - public boolean isWorthSaving() { - return getNotes() != null; - } - - //调用父类Task中的setContentByRemoteJSON ()函数,使用远程json数据对象设置元数据内容 - @Override - public void setContentByRemoteJSON(JSONObject js) { - super.setContentByRemoteJSON(js); - if (getNotes() != null) { - try { - JSONObject metaInfo = new JSONObject(getNotes().trim()); - mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); - } catch (JSONException e) { - Log.w(TAG, "failed to get related gid"); - mRelatedGid = null; - } - } - } - - //函数:函数覆盖,将错误抛出 - @Override - public void setContentByLocalJSON(JSONObject js) { - // this function should not be called - throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); - } - - //函数:从元数据库中获得本地JSON对象,并抛出错误 - @Override - public JSONObject getLocalJSONFromContent() { - throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); - } - - //函数:获取同步动作状态,并抛出错误 - @Override - public int getSyncAction(Cursor c) { - throw new IllegalAccessError("MetaData:getSyncAction should not be called"); - } - -} diff --git a/doc/data/Node.java b/doc/data/Node.java deleted file mode 100644 index 3bb770a..0000000 --- a/doc/data/Node.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.gtask.data; //包名,依赖关系 - -import android.database.Cursor; //引用cursor,此公用接口提供对数据库查询返回的结果集的随机读写访问。 - -import org.json.JSONObject;//引用 JSONObject,一组可修改的名称/值映射集。 - -public abstract class Node { - public static final int SYNC_ACTION_NONE = 0; - - public static final int SYNC_ACTION_ADD_REMOTE = 1;//需要在远程云端增加内容 - - public static final int SYNC_ACTION_ADD_LOCAL = 2;//需要在本地增加内容 - - public static final int SYNC_ACTION_DEL_REMOTE = 3; //需要在远程云端删除内容 - - public static final int SYNC_ACTION_DEL_LOCAL = 4;//需要在本地删除内容 - - public static final int SYNC_ACTION_UPDATE_REMOTE = 5;//需要将本地内容更新到远程云端 - - public static final int SYNC_ACTION_UPDATE_LOCAL = 6;//需要将远程云端内容更新到本地 - - public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; //同步出现冲突 - - public static final int SYNC_ACTION_ERROR = 8;//同步出现错误 - - private String mGid; //记录最后一次修改时间 - - private String mName;//bool类型,表明表征是否被删除 - - private long mLastModified;//记录最后一次修改时间 - - private boolean mDeleted;//判断 表征是否被删除 - - //构造函数,进行初始化,界面没有,名字为空,最后一次修改时间为0(没有修改),表征是否删除。 - public Node() { - mGid = null; - mName = ""; - mLastModified = 0; - mDeleted = false; - } - - // 创建JSONObject对象,创建操作和更新操作,形参是操作号 - public abstract JSONObject getCreateAction(int actionId); - - public abstract JSONObject getUpdateAction(int actionId);//获取需要更新活动的ID - - public abstract void setContentByRemoteJSON(JSONObject js);//都是JSONObject和Curson中的一些操作,主要是创建相应的对象进行远端和本地同步操作 - - public abstract void setContentByLocalJSON(JSONObject js);//声明JSONObject对象抽象类,从本地JSON中同步设置目录 - - - public abstract JSONObject getLocalJSONFromContent();//声明JSONObject对象抽象类,从目录中获取本地JSON - - public abstract int getSyncAction(Cursor c);//声明int抽象类,获取同步行为代号 - - public void setGid(String gid) { - this.mGid = gid; - } //对构造函数中的对象进行赋值或者获取对象的具体内容将gid赋给mGid,以下均为Node函数参数的输入与赋值 - - public void setName(String name) { - this.mName = name; - } //设置名字 - - public void setLastModified(long lastModified) { - this.mLastModified = lastModified; - }//时间标识 - - public void setDeleted(boolean deleted) { - this.mDeleted = deleted; - }//删除标识 - - public String getGid() { - return this.mGid; - }//返回git - - public String getName() { - return this.mName; - }//返回mname - - public long getLastModified() { - return this.mLastModified; - }//获取时间标识 - - public boolean getDeleted() { - return this.mDeleted; - }//获取删除标识 - -} diff --git a/doc/data/SqlData.java b/doc/data/SqlData.java deleted file mode 100644 index 0c04274..0000000 --- a/doc/data/SqlData.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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.gtask.data; - -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.util.Log; - -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.data.NotesDatabaseHelper.TABLE; -import net.micode.notes.gtask.exception.ActionFailureException; - -import org.json.JSONException; -import org.json.JSONObject; - - -public class SqlData { - //得到类的简写名称存入字符串TAG中 - private static final String TAG = SqlData.class.getSimpleName();//调用getSimpleName ()函数 - - private static final int INVALID_ID = -99999;//为mDataId置初始值-99999 - - //来自Notes类中定义的DataColumn中的一些常量 - // 集合了interface DataColumns中所有SF常量 - public static final String[] PROJECTION_DATA = new String[] { - DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, - DataColumns.DATA3 - }; - //以下五个变量作为sql表中5列的编号 - public static final int DATA_ID_COLUMN = 0; - - public static final int DATA_MIME_TYPE_COLUMN = 1; - - public static final int DATA_CONTENT_COLUMN = 2; - - public static final int DATA_CONTENT_DATA_1_COLUMN = 3; - - public static final int DATA_CONTENT_DATA_3_COLUMN = 4; - - private ContentResolver mContentResolver; - //判断是否直接用Content生成,是为true,否则为false - private boolean mIsCreate; - - private long mDataId; - - private String mDataMimeType; - - private String mDataContent; - - private long mDataContentData1; - - private String mDataContentData3; - - private ContentValues mDiffDataValues; - - public SqlData(Context context) { - mContentResolver = context.getContentResolver();//mContentResolver用于获取ContentProvider提供的数据 - mIsCreate = true; - mDataId = INVALID_ID; - mDataMimeType = DataConstants.NOTE; - mDataContent = ""; - mDataContentData1 = 0; - mDataContentData3 = ""; - mDiffDataValues = new ContentValues(); - } - /* - * 功能描述:构造函数,初始化数据 - * 参数注解:mContentResolver用于获取ContentProvider提供的数据 - * 参数注解: mIsCreate表征当前数据是用哪种方式创建(两种构造函数的参数不同) - */ - public SqlData(Context context, Cursor c) { - mContentResolver = context.getContentResolver(); - mIsCreate = false; - loadFromCursor(c); - mDiffDataValues = new ContentValues(); - } - //从光标处加载数据 - private void loadFromCursor(Cursor c) { - mDataId = c.getLong(DATA_ID_COLUMN); - mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); - mDataContent = c.getString(DATA_CONTENT_COLUMN); - mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); - mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); - } - //功能描述:设置用于共享的数据,并提供异常抛出与处理机制 - public void setContent(JSONObject js) throws JSONException { - //JSONObject对象中有DataColumns.ID这一项,则设置,否则设为INVALID_ID - long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; - if (mIsCreate || mDataId != dataId) { - mDiffDataValues.put(DataColumns.ID, dataId); - } - mDataId = dataId; - - String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE) - : DataConstants.NOTE; - if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { - mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType); - } - mDataMimeType = dataMimeType; - - String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; - if (mIsCreate || !mDataContent.equals(dataContent)) { - mDiffDataValues.put(DataColumns.CONTENT, dataContent); - } - mDataContent = dataContent; - - long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; - if (mIsCreate || mDataContentData1 != dataContentData1) { - mDiffDataValues.put(DataColumns.DATA1, dataContentData1); - } - mDataContentData1 = dataContentData1; - - String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; - if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { - mDiffDataValues.put(DataColumns.DATA3, dataContentData3); - } - mDataContentData3 = dataContentData3; - } - //功能描述:获取共享的数据内容,并提供异常抛出与处理机制 - public JSONObject getContent() throws JSONException { - if (mIsCreate) { - Log.e(TAG, "it seems that we haven't created this in database yet"); - return null; - } - //创建JSONObject对象。并将相关数据放入其中,并返回 - JSONObject js = new JSONObject(); - js.put(DataColumns.ID, mDataId); - js.put(DataColumns.MIME_TYPE, mDataMimeType); - js.put(DataColumns.CONTENT, mDataContent); - js.put(DataColumns.DATA1, mDataContentData1); - js.put(DataColumns.DATA3, mDataContentData3); - return js; - } - //commit函数用于把当前造作所做的修改保存到数据库 - public void commit(long noteId, boolean validateVersion, long version) { - - if (mIsCreate) { - if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { - mDiffDataValues.remove(DataColumns.ID); - } - - mDiffDataValues.put(DataColumns.NOTE_ID, noteId); - Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); - try { - mDataId = Long.valueOf(uri.getPathSegments().get(1)); - } catch (NumberFormatException e) { - Log.e(TAG, "Get note id error :" + e.toString()); - throw new ActionFailureException("create note failed"); - } - } else { - if (mDiffDataValues.size() > 0) { - int result = 0; - if (!validateVersion) { - result = mContentResolver.update(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); - } else { - result = mContentResolver.update(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, - " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE - + " WHERE " + NoteColumns.VERSION + "=?)", new String[] { - String.valueOf(noteId), String.valueOf(version) - }); - } - if (result == 0) { - Log.w(TAG, "there is no update. maybe user updates note when syncing"); - } - } - } - - mDiffDataValues.clear(); - mIsCreate = false; - } - //获取当前id - public long getId() { - return mDataId; - } -} diff --git a/doc/data/SqlNote.java b/doc/data/SqlNote.java deleted file mode 100644 index 36854e7..0000000 --- a/doc/data/SqlNote.java +++ /dev/null @@ -1,527 +0,0 @@ -/* - * 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.gtask.data; - -import android.appwidget.AppWidgetManager; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.util.Log; - -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.gtask.exception.ActionFailureException; -import net.micode.notes.tool.GTaskStringUtils; -import net.micode.notes.tool.ResourceParser; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; - - -public class SqlNote { - //调用getSimpleName(),类名简称存入TAG - private static final String TAG = SqlNote.class.getSimpleName(); - - private static final int INVALID_ID = -99999; - - public static final String[] PROJECTION_NOTE = new String[] { - NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID, - NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE, - NoteColumns.NOTES_COUNT, NoteColumns.PARENT_ID, NoteColumns.SNIPPET, NoteColumns.TYPE, - NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.SYNC_ID, - NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID, - NoteColumns.VERSION - }; - - public static final int ID_COLUMN = 0; - - public static final int ALERTED_DATE_COLUMN = 1; - - public static final int BG_COLOR_ID_COLUMN = 2; - - public static final int CREATED_DATE_COLUMN = 3; - - public static final int HAS_ATTACHMENT_COLUMN = 4; - - public static final int MODIFIED_DATE_COLUMN = 5; - - public static final int NOTES_COUNT_COLUMN = 6; - - public static final int PARENT_ID_COLUMN = 7; - - public static final int SNIPPET_COLUMN = 8; - - public static final int TYPE_COLUMN = 9; - - public static final int WIDGET_ID_COLUMN = 10; - - public static final int WIDGET_TYPE_COLUMN = 11; - - public static final int SYNC_ID_COLUMN = 12; - - public static final int LOCAL_MODIFIED_COLUMN = 13; - - public static final int ORIGIN_PARENT_ID_COLUMN = 14; - - public static final int GTASK_ID_COLUMN = 15; - - public static final int VERSION_COLUMN = 16; - - private Context mContext; - - private ContentResolver mContentResolver; - - private boolean mIsCreate; - - private long mId; - - private long mAlertDate; - - private int mBgColorId; - - private long mCreatedDate; - - private int mHasAttachment; - - private long mModifiedDate; - - private long mParentId; - - private String mSnippet; - - private int mType; - - private int mWidgetId; - - private int mWidgetType; - - private long mOriginParent; - - private long mVersion; - - private ContentValues mDiffNoteValues; - - private ArrayList mDataList; - - //构造函数只有context,对所有的变量进行初始化 - public SqlNote(Context context) { - mContext = context; - mContentResolver = context.getContentResolver(); - mIsCreate = true; - mId = INVALID_ID; - mAlertDate = 0; - mBgColorId = ResourceParser.getDefaultBgId(context); - mCreatedDate = System.currentTimeMillis();//调用系统函数获得创建时间 - mHasAttachment = 0; - mModifiedDate = System.currentTimeMillis();//最后一次修改时间初始化为创建时间 - mParentId = 0; - mSnippet = ""; - mType = Notes.TYPE_NOTE; - mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; - mWidgetType = Notes.TYPE_WIDGET_INVALIDE; - mOriginParent = 0; - mVersion = 0; - mDiffNoteValues = new ContentValues(); - mDataList = new ArrayList(); - } - - //构造函数有context和一个数据库的cursor,多数变量通过cursor指向的一条记录直接进行初始化 - public SqlNote(Context context, Cursor c) { - mContext = context; - mContentResolver = context.getContentResolver(); - mIsCreate = false; - loadFromCursor(c); - mDataList = new ArrayList(); - // - if (mType == Notes.TYPE_NOTE) - loadDataContent(); - mDiffNoteValues = new ContentValues(); - } - - - // mIsCreate用于标示构造方式 - public SqlNote(Context context, long id) { - mContext = context; - mContentResolver = context.getContentResolver(); - mIsCreate = false; - loadFromCursor(id); - mDataList = new ArrayList(); - if (mType == Notes.TYPE_NOTE) - loadDataContent(); - mDiffNoteValues = new ContentValues(); - - } - - //功能描述:通过id从光标处加载数据 - - private void loadFromCursor(long id) { - Cursor c = null; - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", - new String[] { - String.valueOf(id) - }, null);//通过id获得对应的ContentResolver中的cursor - if (c != null) { - c.moveToNext(); - loadFromCursor(c);//然后加载数据进行初始化,这样函数 - //SqlNote(Context context, long id)与SqlNote(Context context, long id)的实现方式基本相同 - } else { - Log.w(TAG, "loadFromCursor: cursor = null"); - } - } finally { - if (c != null) - c.close(); - } - } - - // 功能描述:通过游标从光标处加载数据 - private void loadFromCursor(Cursor c) { - //直接从一条记录中的获得以下变量的初始值 - mId = c.getLong(ID_COLUMN); - mAlertDate = c.getLong(ALERTED_DATE_COLUMN); - mBgColorId = c.getInt(BG_COLOR_ID_COLUMN); - mCreatedDate = c.getLong(CREATED_DATE_COLUMN); - mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN); - mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN); - mParentId = c.getLong(PARENT_ID_COLUMN); - mSnippet = c.getString(SNIPPET_COLUMN); - mType = c.getInt(TYPE_COLUMN); - mWidgetId = c.getInt(WIDGET_ID_COLUMN); - mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); - mVersion = c.getLong(VERSION_COLUMN); - } - - // 功能描述:通过content机制获取共享数据并加载到数据库当前游标 - private void loadDataContent() { - Cursor c = null; - mDataList.clear(); - try { - c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, - "(note_id=?)", new String[] { - String.valueOf(mId) - }, null); - if (c != null) { - if (c.getCount() == 0) { - Log.w(TAG, "it seems that the note has not data"); - return; - } - while (c.moveToNext()) { - SqlData data = new SqlData(mContext, c); - mDataList.add(data); - } - } else { - Log.w(TAG, "loadDataContent: cursor = null"); - } - } finally { - if (c != null) - c.close(); - } - } - - // 功能描述:设置通过content机制用于共享的数据信息 - public boolean setContent(JSONObject js) { - try { - JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { - Log.w(TAG, "cannot set system folder"); - } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { - // for folder we can only update the snnipet and type - String snippet = note.has(NoteColumns.SNIPPET) ? note - .getString(NoteColumns.SNIPPET) : ""; - if (mIsCreate || !mSnippet.equals(snippet)) { - mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); - } - mSnippet = snippet; - - int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) - : Notes.TYPE_NOTE; - if (mIsCreate || mType != type) { - mDiffNoteValues.put(NoteColumns.TYPE, type); - } - mType = type; - } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { - JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID; - if (mIsCreate || mId != id) { - mDiffNoteValues.put(NoteColumns.ID, id); - } - mId = id; - - long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note - .getLong(NoteColumns.ALERTED_DATE) : 0; - if (mIsCreate || mAlertDate != alertDate) { - mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate); - } - mAlertDate = alertDate; - - int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note - .getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext); - if (mIsCreate || mBgColorId != bgColorId) { - mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId); - } - mBgColorId = bgColorId; - long createDate = note.has(NoteColumns.CREATED_DATE) ? note - .getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis(); - if (mIsCreate || mCreatedDate != createDate) { - mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate); - } - mCreatedDate = createDate; - - int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note - .getInt(NoteColumns.HAS_ATTACHMENT) : 0; - if (mIsCreate || mHasAttachment != hasAttachment) { - mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment); - } - mHasAttachment = hasAttachment; - - long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note - .getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis(); - if (mIsCreate || mModifiedDate != modifiedDate) { - mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate); - } - mModifiedDate = modifiedDate; - - long parentId = note.has(NoteColumns.PARENT_ID) ? note - .getLong(NoteColumns.PARENT_ID) : 0; - if (mIsCreate || mParentId != parentId) { - mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId); - } - mParentId = parentId; - - String snippet = note.has(NoteColumns.SNIPPET) ? note - .getString(NoteColumns.SNIPPET) : ""; - if (mIsCreate || !mSnippet.equals(snippet)) { - mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); - } - mSnippet = snippet; - - int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) - : Notes.TYPE_NOTE; - if (mIsCreate || mType != type) { - mDiffNoteValues.put(NoteColumns.TYPE, type); - } - mType = type; - - int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID) - : AppWidgetManager.INVALID_APPWIDGET_ID; - if (mIsCreate || mWidgetId != widgetId) { - mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId); - } - mWidgetId = widgetId; - - int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note - .getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE; - if (mIsCreate || mWidgetType != widgetType) { - mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType); - } - mWidgetType = widgetType; - - long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note - .getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; - if (mIsCreate || mOriginParent != originParent) { - mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent); - } - mOriginParent = originParent; - - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - SqlData sqlData = null; - if (data.has(DataColumns.ID)) { - long dataId = data.getLong(DataColumns.ID); - for (SqlData temp : mDataList) { - if (dataId == temp.getId()) { - sqlData = temp; - } - } - } - - if (sqlData == null) { - sqlData = new SqlData(mContext); - mDataList.add(sqlData); - } - - sqlData.setContent(data); - } - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - return false; - } - return true; - } - - // 功能描述:获取content机制提供的数据并加载到note中 - public JSONObject getContent() { - try { - JSONObject js = new JSONObject(); - - if (mIsCreate) { - Log.e(TAG, "it seems that we haven't created this in database yet"); - return null; - } - - JSONObject note = new JSONObject(); - if (mType == Notes.TYPE_NOTE) {//类型为note时 - note.put(NoteColumns.ID, mId); - note.put(NoteColumns.ALERTED_DATE, mAlertDate); - note.put(NoteColumns.BG_COLOR_ID, mBgColorId); - note.put(NoteColumns.CREATED_DATE, mCreatedDate); - note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment); - note.put(NoteColumns.MODIFIED_DATE, mModifiedDate); - note.put(NoteColumns.PARENT_ID, mParentId); - note.put(NoteColumns.SNIPPET, mSnippet); - note.put(NoteColumns.TYPE, mType); - note.put(NoteColumns.WIDGET_ID, mWidgetId); - note.put(NoteColumns.WIDGET_TYPE, mWidgetType); - note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent); - js.put(GTaskStringUtils.META_HEAD_NOTE, note); - - JSONArray dataArray = new JSONArray(); - for (SqlData sqlData : mDataList) { - JSONObject data = sqlData.getContent(); - if (data != null) { - dataArray.put(data); - } - } - js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); - } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {//类型为文件夹或者 - note.put(NoteColumns.ID, mId); - note.put(NoteColumns.TYPE, mType); - note.put(NoteColumns.SNIPPET, mSnippet); - js.put(GTaskStringUtils.META_HEAD_NOTE, note); - } - - return js; - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - } - return null; - } - - // 功能描述:给当前id设置父id - public void setParentId(long id) { - mParentId = id; - mDiffNoteValues.put(NoteColumns.PARENT_ID, id); - } - - //功能描述:给当前id设置Gtaskid - public void setGtaskId(String gid) { - mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); - } - - // 功能描述:给当前id设置同步id - public void setSyncId(long syncId) { - mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); - } - - // 功能描述:初始化本地修改,即撤销所有当前修改 - public void resetLocalModified() { - mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); - } - - // 功能描述:获得当前id - public long getId() { - return mId; - } - - //获得当前id的父id - public long getParentId() { - return mParentId; - } - - //获取小片段即用于显示的部分便签内容 - public String getSnippet() { - return mSnippet; - } - - //判断是否为便签类型 - public boolean isNoteType() { - return mType == Notes.TYPE_NOTE; - } - - //commit函数用于把当前造作所做的修改保存到数据库 - public void commit(boolean validateVersion) { - if (mIsCreate) { - if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { - mDiffNoteValues.remove(NoteColumns.ID); - } - - Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues); - try { - mId = Long.valueOf(uri.getPathSegments().get(1)); - } catch (NumberFormatException e) { - Log.e(TAG, "Get note id error :" + e.toString()); - throw new ActionFailureException("create note failed"); - } - if (mId == 0) { - throw new IllegalStateException("Create thread id failed"); - } - - if (mType == Notes.TYPE_NOTE) { - for (SqlData sqlData : mDataList) {//直接使用sqldata中的实现 - sqlData.commit(mId, false, -1); - } - } - } else { - if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) { - Log.e(TAG, "No such note"); - throw new IllegalStateException("Try to update note with invalid id"); - } - if (mDiffNoteValues.size() > 0) { - mVersion ++; - int result = 0; - if (!validateVersion) { //构造字符串 - result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" - + NoteColumns.ID + "=?)", new String[] { - String.valueOf(mId) - }); - } else { - result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" - + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", - new String[] { - String.valueOf(mId), String.valueOf(mVersion) - }); - } - if (result == 0) { - Log.w(TAG, "there is no update. maybe user updates note when syncing"); - } - } - - if (mType == Notes.TYPE_NOTE) { - for (SqlData sqlData : mDataList) { - sqlData.commit(mId, validateVersion, mVersion); - } - } - } - - // refresh local info - loadFromCursor(mId); - if (mType == Notes.TYPE_NOTE) - loadDataContent(); - - mDiffNoteValues.clear(); - mIsCreate = false; - } -} \ No newline at end of file diff --git a/doc/data/Task.java b/doc/data/Task.java deleted file mode 100644 index 14edea4..0000000 --- a/doc/data/Task.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * 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.gtask.data; - -import android.database.Cursor; -import android.text.TextUtils; -import android.util.Log; - -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.gtask.exception.ActionFailureException; -import net.micode.notes.tool.GTaskStringUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - - -public class Task extends Node { - private static final String TAG = Task.class.getSimpleName(); - // 任务是否已完成 - private boolean mCompleted; - - // 与任务关联的备注 - private String mNotes; - - // 与任务关联的元信息 - private JSONObject mMetaInfo; - - // 在列表中位于该任务前面的任务 - private Task mPriorSibling; - - // 该任务所属的父任务列表 - private TaskList mParent; - - //创建一个新的空任务的构造函数 - public Task() { - super(); - mCompleted = false; - mNotes = null; - mPriorSibling = null; - mParent = null; - mMetaInfo = null; - } - - //从JSON对象创建任务的构造函数 - //如果JSON对象不符合预期的格式,则抛出异常。 - public Task(JSONObject jsonObject) throws JSONException { - super(jsonObject); - mCompleted = jsonObject.getBoolean(GTaskStringUtils.STATUS); - mNotes = jsonObject.optString(GTaskStringUtils.NOTES); - mMetaInfo = jsonObject.optJSONObject(GTaskStringUtils.META_DATA); - } - - public JSONObject getCreateAction(int actionId) { - JSONObject js = new JSONObject(); - - try { - // action_id 操作ID - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - - // index 任务在父任务列表中的位置 - js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this)); - - // entity_delta 任务实体信息 - JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务名称 - entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); // 创建者ID - entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, - GTaskStringUtils.GTASK_JSON_TYPE_TASK); // 实体类型为任务 - if (getNotes() != null) { - entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); // 关联的备注信息 - } - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - - // parent_id 父任务列表ID - js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid()); - - // dest_parent_type 目标父实体类型 - js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE, - GTaskStringUtils.GTASK_JSON_TYPE_GROUP); - - // list_id 任务列表ID - js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid()); - - // prior_sibling_id 前置任务ID - if (mPriorSibling != null) { - js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid()); - } - - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to generate task-create jsonobject"); - } - - return js; - } - - public JSONObject getUpdateAction(int actionId) { - JSONObject js = new JSONObject(); - - try { - // action_id 操作ID - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - - // id 任务ID - js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - - // entity_delta 任务实体信息 - JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务名称 - if (getNotes() != null) { - entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); // 关联的备注信息 - } - entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); // 是否被删除 - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to generate task-update jsonobject"); - } - - return js; - } - - public void setContentByRemoteJSON(JSONObject js) { - if (js != null) { - try { - // id - if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { - setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); - } - - // last_modified 最近修改时间 - if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { - setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); - } - - // name 任务名称 - if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { - setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); - } - - // notes 关联的备注信息 - if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) { - setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); - } - - // deleted 是否被删除 - if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) { - setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); - } - - // completed 是否已完成 - if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) { - setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED)); - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to get task content from jsonobject"); - } - } - - } - //将本地存储的JSON对象中的内容设置到任务对象中。 - public void setContentByLocalJSON(JSONObject js) { - if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) - || !js.has(GTaskStringUtils.META_HEAD_DATA)) { - Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); - } - - try { - JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - - if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) { - Log.e(TAG, "invalid type"); - return; - } - - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { - setName(data.getString(DataColumns.CONTENT)); // 设置任务名称为备注内容 - break; - } - } - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - } - } - //从任务对象中获取本地存储的JSON对象。 - public JSONObject getLocalJSONFromContent() { - String name = getName(); - try { - if (mMetaInfo == null) { - // 从Web创建的新任务 - if (name == null) { - Log.w(TAG, "the note seems to be an empty one"); - return null; - } - - JSONObject js = new JSONObject(); - JSONObject note = new JSONObject(); - JSONArray dataArray = new JSONArray(); - JSONObject data = new JSONObject(); - data.put(DataColumns.CONTENT, name); - dataArray.put(data); - js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); - note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); - js.put(GTaskStringUtils.META_HEAD_NOTE, note); - return js; - } else { - // 已同步的任务 - JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { - data.put(DataColumns.CONTENT, getName()); // 更新备注内容为任务名称 - break; - } - } - - note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); - return mMetaInfo; - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - return null; - } - } - - public void setMetaInfo(MetaData metaData) { - if (metaData != null && metaData.getNotes() != null) { - try { - mMetaInfo = new JSONObject(metaData.getNotes()); - } catch (JSONException e) { - Log.w(TAG, e.toString()); - mMetaInfo = null; - } - } - } - //根据传入的Cursor对象获取同步任务的操作类型。 - public int getSyncAction(Cursor c) { - try { - JSONObject noteInfo = null; - if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) { - noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - } - - if (noteInfo == null) { - Log.w(TAG, "it seems that note meta has been deleted"); - return SYNC_ACTION_UPDATE_REMOTE; - } - - if (!noteInfo.has(NoteColumns.ID)) { - Log.w(TAG, "remote note id seems to be deleted"); - return SYNC_ACTION_UPDATE_LOCAL; - } - - // 验证笔记ID是否匹配 - if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) { - Log.w(TAG, "note id doesn't match"); - return SYNC_ACTION_UPDATE_LOCAL; - } - - if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // 本地没有更新 - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // 双方都没有更新 - return SYNC_ACTION_NONE; - } else { - // 应用远程更新到本地 - return SYNC_ACTION_UPDATE_LOCAL; - } - } else { - // 验证gtask id是否匹配 - if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { - Log.e(TAG, "gtask id doesn't match"); - return SYNC_ACTION_ERROR; - } - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // 仅有本地修改 - return SYNC_ACTION_UPDATE_REMOTE; - } else { - // 本地和远程都有修改 - return SYNC_ACTION_UPDATE_CONFLICT; - } - } - } catch (Exception e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - } - - return SYNC_ACTION_ERROR; - } - //判断是否值得保存。 - // 如果有元数据、名称或笔记内容,则返回true,否则返回false - public boolean isWorthSaving() { - return mMetaInfo != null || (getName() != null && getName().trim().length() > 0) - || (getNotes() != null && getNotes().trim().length() > 0); - } - //设置任务是否已完成 - public void setCompleted(boolean completed) { - this.mCompleted = completed; - } - //设置笔记内容 - public void setNotes(String notes) { - this.mNotes = notes; - } - //设置前一个同级任务。 - public void setPriorSibling(Task priorSibling) { - this.mPriorSibling = priorSibling; - } - //设置所属任务列表 - public void setParent(TaskList parent) { - this.mParent = parent; - } - // 获取任务是否已完成 - public boolean getCompleted() { - return this.mCompleted; - } - //获取笔记内容 - public String getNotes() { - return this.mNotes; - } - //获取前一个同级任务。 - public Task getPriorSibling() { - return this.mPriorSibling; - } - //获取所属任务列表 - public TaskList getParent() { - return this.mParent; - } - -} diff --git a/doc/data/TaskList.java b/doc/data/TaskList.java deleted file mode 100644 index 81ac4d8..0000000 --- a/doc/data/TaskList.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * 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.gtask.data; - -import android.database.Cursor; -import android.util.Log; - -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.gtask.exception.ActionFailureException; -import net.micode.notes.tool.GTaskStringUtils; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; - - -public class TaskList extends Node { - private static final String TAG = TaskList.class.getSimpleName();//tag标记 - - private int mIndex;//当前TaskList的指针 - - private ArrayList mChildren;//类中主要的保存数据的单元,用来实现一个以Task为元素的ArrayList - - public TaskList() { - super(); - mChildren = new ArrayList(); - mIndex = 1; - } - - // 生成并返回一个包含了一定数据的JSONObject实体 - public JSONObject getCreateAction(int actionId) { - JSONObject js = new JSONObject(); - - try { - // action_type - js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); - - // action_id - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - - // index - js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); - - // entity_delta - JSONObject entity = new JSONObject();//entity实体 - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); - entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, - GTaskStringUtils.GTASK_JSON_TYPE_GROUP); - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to generate tasklist-create jsonobject"); - } - - return js; - } - - //生成并返回一个包含了一定数据的JSONObject实体 - public JSONObject getUpdateAction(int actionId) { - JSONObject js = new JSONObject(); - - try { - // action_type - js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - - // action_id - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - - // id - js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - - // entity_delta - JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to generate tasklist-update jsonobject"); - } - - return js; - } - - public void setContentByRemoteJSON(JSONObject js) { - if (js != null) { - try { - // id - if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { - setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); - } - - // last_modified - if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { - setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); - } - - // name - if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { - setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); - } - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("fail to get tasklist content from jsonobject"); - } - } - } - - public void setContentByLocalJSON(JSONObject js) { - if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { - Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); - } - - try { - JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - - if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { - String name = folder.getString(NoteColumns.SNIPPET); - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name); - } else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { - if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT); - else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_CALL_NOTE); - else - Log.e(TAG, "invalid system folder"); - } else { - Log.e(TAG, "error type"); - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - } - } - - public JSONObject getLocalJSONFromContent() { - try { - JSONObject js = new JSONObject(); - JSONObject folder = new JSONObject(); - - String folderName = getName(); - if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)) - folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(), - folderName.length()); - folder.put(NoteColumns.SNIPPET, folderName); - if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT) - || folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE)) - folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - else - folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); - - js.put(GTaskStringUtils.META_HEAD_NOTE, folder); - - return js; - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - return null; - } - } - - public int getSyncAction(Cursor c) { - try { - if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // there is no local update - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // no update both side - return SYNC_ACTION_NONE; - } else { - // apply remote to local - return SYNC_ACTION_UPDATE_LOCAL; - } - } else { - // validate gtask id - if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { - Log.e(TAG, "gtask id doesn't match"); - return SYNC_ACTION_ERROR; - } - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // local modification only - return SYNC_ACTION_UPDATE_REMOTE; - } else { - // for folder conflicts, just apply local modification - return SYNC_ACTION_UPDATE_REMOTE; - } - } - } catch (Exception e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - } - - return SYNC_ACTION_ERROR; - } - - //获得TaskList的大小,即mChildren的大小 - public int getChildTaskCount() { - return mChildren.size(); - } - - //在当前任务表末尾添加新的任务 - public boolean addChildTask(Task task) { - boolean ret = false; - if (task != null && !mChildren.contains(task)) { - ret = mChildren.add(task); - if (ret) { - // need to set prior sibling and parent - task.setPriorSibling(mChildren.isEmpty() ? null : mChildren - .get(mChildren.size() - 1)); - task.setParent(this); - //每一次ArrayList的变化都要紧跟相关Task中PriorSibling - - } - } - return ret; - } - - //在当前任务表的指定位置添加新的任务 - public boolean addChildTask(Task task, int index) { - if (index < 0 || index > mChildren.size()) { - Log.e(TAG, "add child task: invalid index"); - return false; - } - - int pos = mChildren.indexOf(task); - if (task != null && pos == -1) { - mChildren.add(index, task); - - // update the task list - Task preTask = null; - Task afterTask = null; - if (index != 0) - preTask = mChildren.get(index - 1); - if (index != mChildren.size() - 1) - afterTask = mChildren.get(index + 1); - - task.setPriorSibling(preTask); - if (afterTask != null) - afterTask.setPriorSibling(task); - } - - return true; - } - - //删除TaskList中的一个Task - public boolean removeChildTask(Task task) { - boolean ret = false; - int index = mChildren.indexOf(task); - if (index != -1) { - ret = mChildren.remove(task); - - if (ret) { - // reset prior sibling and parent - task.setPriorSibling(null); - task.setParent(null); - - // update the task list - if (index != mChildren.size()) { - mChildren.get(index).setPriorSibling( - index == 0 ? null : mChildren.get(index - 1)); - } - } - } - return ret; - } - - //将当前TaskList中含有的某个Task移到index位置 - public boolean moveChildTask(Task task, int index) { - - if (index < 0 || index >= mChildren.size()) { - Log.e(TAG, "move child task: invalid index"); - return false; - } - - int pos = mChildren.indexOf(task); - if (pos == -1) { - Log.e(TAG, "move child task: the task should in the list"); - return false; - } - - if (pos == index) - return true; - return (removeChildTask(task) && addChildTask(task, index)); - //利用已实现好的功能完成当下功能; - } - - //功能:按gid寻找Task - public Task findChildTaskByGid(String gid) { - for (int i = 0; i < mChildren.size(); i++) { - Task t = mChildren.get(i); - if (t.getGid().equals(gid)) { - return t; - } - } - return null; - } - - //返回指定Task的index - public int getChildTaskIndex(Task task) { - return mChildren.indexOf(task); - } - - //返回指定index的Task - public Task getChildTaskByIndex(int index) { - if (index < 0 || index >= mChildren.size()) { - Log.e(TAG, "getTaskByIndex: invalid index"); - return null; - } - return mChildren.get(index); - } - - //返回指定gid的Task - public Task getChilTaskByGid(String gid) { - for (Task task : mChildren) {//一种常见的ArrayList的遍历方法(四种,见精读笔记) - if (task.getGid().equals(gid)) - return task; - } - return null; - } - - public ArrayList getChildTaskList() { - return this.mChildren; - } - - public void setIndex(int index) { - this.mIndex = index; - } - - public int getIndex() { - return this.mIndex; - } -} \ No newline at end of file diff --git a/doc/remote/GTaskASyncTask.java b/doc/remote/GTaskASyncTask.java deleted file mode 100644 index d7bd6da..0000000 --- a/doc/remote/GTaskASyncTask.java +++ /dev/null @@ -1,123 +0,0 @@ - -/* - * 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.gtask.remote; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.os.AsyncTask; - -import net.micode.notes.R;//引入android自动生成的R类 -import net.micode.notes.ui.NotesListActivity; -import net.micode.notes.ui.NotesPreferenceActivity; - -//类:扩展于AysyncTask类,是用来处理GTask的异步任务的类 -public class GTaskASyncTask extends AsyncTask { - - private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; - - public interface OnCompleteListener {//通过interface实现多个接口,接口为OnCompleteListener,用来初始化异步的功能 - void onComplete(); - } - - private Context mContext; - - private NotificationManager mNotifiManager; - - private GTaskManager mTaskManager; - //函数: GTaskASyncTask类的构造函数 - private OnCompleteListener mOnCompleteListener; - - public GTaskASyncTask(Context context, OnCompleteListener listener) { - mContext = context; - mOnCompleteListener = listener; - mNotifiManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); - mTaskManager = GTaskManager.getInstance(); - } - //方法:中断同步操作 - public void cancelSync() { - mTaskManager.cancelSync(); - } - //方法: 提交后台进度,并调用onProgressUpdate方法来更新进度条 - public void publishProgess(String message) { - publishProgress(new String[] { - message - }); - } - //方法:显示通知消息,在这里主要用于向用户通知同步的进程 - private void showNotification(int tickerId, String content) { - Notification notification = new Notification(R.drawable.notification, mContext - .getString(tickerId), System.currentTimeMillis()); - notification.defaults = Notification.DEFAULT_LIGHTS; - notification.flags = Notification.FLAG_AUTO_CANCEL; - PendingIntent pendingIntent; - if (tickerId != R.string.ticker_success) { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesPreferenceActivity.class), 0); - - } else { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesListActivity.class), 0); - } - /*notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, - pendingIntent);*/ - mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); - } - //方法:异步执行后台线程将要完成的任务 - @Override - protected Integer doInBackground(Void... unused) { - publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity - .getSyncAccountName(mContext))); - return mTaskManager.sync(mContext, this); - } - //方法:在调用publishProgress时,该方法被执行,并将进度信息更新到UI组件中 - @Override - protected void onProgressUpdate(String... progress) { - showNotification(R.string.ticker_syncing, progress[0]); - if (mContext instanceof GTaskSyncService) { - ((GTaskSyncService) mContext).sendBroadcast(progress[0]); - } - } - //方法: 在dolnBackground执行完成后,该方法会被UI线程调用,将后台的计算结果传递到UI进程,并在界面上展示出来 - @Override - protected void onPostExecute(Integer result) { - if (result == GTaskManager.STATE_SUCCESS) { - showNotification(R.string.ticker_success, mContext.getString( - R.string.success_sync_account, mTaskManager.getSyncAccount())); - NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); - } else if (result == GTaskManager.STATE_NETWORK_ERROR) { - showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network)); - } else if (result == GTaskManager.STATE_INTERNAL_ERROR) { - showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); - } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { - showNotification(R.string.ticker_cancel, mContext - .getString(R.string.error_sync_cancelled)); - } - if (mOnCompleteListener != null) { - new Thread(new Runnable() { - - public void run() { - mOnCompleteListener.onComplete(); - } - }).start(); - } - } -} diff --git a/doc/remote/GTaskClient.java b/doc/remote/GTaskClient.java deleted file mode 100644 index c9c8bf6..0000000 --- a/doc/remote/GTaskClient.java +++ /dev/null @@ -1,662 +0,0 @@ - /* - * 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.gtask.remote; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerFuture; -import android.app.Activity; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.Log; - -import net.micode.notes.gtask.data.Node; -import net.micode.notes.gtask.data.Task; -import net.micode.notes.gtask.data.TaskList; -import net.micode.notes.gtask.exception.ActionFailureException; -import net.micode.notes.gtask.exception.NetworkFailureException; -import net.micode.notes.tool.GTaskStringUtils; -import net.micode.notes.ui.NotesPreferenceActivity; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.cookie.Cookie; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.LinkedList; -import java.util.List; -import java.util.zip.GZIPInputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - - - public class GTaskClient { - private static final String TAG = GTaskClient.class.getSimpleName(); - - private static final String GTASK_URL = "https://mail.google.com/tasks/"; - - private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; - - private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; - - private static GTaskClient mInstance = null; - - private DefaultHttpClient mHttpClient; - - private String mGetUrl; - - private String mPostUrl; - - private long mClientVersion; - - private boolean mLoggedin; - - private long mLastLoginTime; - - private int mActionId; - - private Account mAccount; - - private JSONArray mUpdateArray; - - private GTaskClient() { - mHttpClient = null; - mGetUrl = GTASK_GET_URL; - mPostUrl = GTASK_POST_URL; - mClientVersion = -1; - mLoggedin = false; - mLastLoginTime = 0; - mActionId = 1; - mAccount = null; - mUpdateArray = null; - } - - /*用来获取的实例化对象 - * 使用 getInstance() - * 返回mInstance这个实例化对象 - */ - public static synchronized GTaskClient getInstance() { - if (mInstance == null) { - mInstance = new GTaskClient(); - } - return mInstance; - } - - //用来实现登录操作的函数,传入Activity - public boolean login(Activity activity) { - // we suppose that the cookie would expire after 5 minutes - // then we need to re-login - //判断距离最后一次登录操作是否超过5分钟 - final long interval = 1000 * 60 * 5; - if (mLastLoginTime + interval < System.currentTimeMillis()) { - mLoggedin = false; - } - - // need to re-login after account switch 重新登录操作 - if (mLoggedin - && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity - .getSyncAccountName(activity))) { - mLoggedin = false; - } - - //如果没超过时间,则不需要重新登录 - if (mLoggedin) { - Log.d(TAG, "already logged in"); - return true; - } - - mLastLoginTime = System.currentTimeMillis();//更新最后登录时间,改为系统当前的时间 - String authToken = loginGoogleAccount(activity, false);//判断是否登录到谷歌账户 - if (authToken == null) { - Log.e(TAG, "login google account failed"); - return false; - } - - // login with custom domain if necessary - //尝试使用用户自己的域名登录 - if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() //将用户账号名改为统一格式(小写)后判断是否为一个谷歌账号地址 - .endsWith("googlemail.com"))) { - StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); - int index = mAccount.name.indexOf('@') + 1; - String suffix = mAccount.name.substring(index); - url.append(suffix + "/"); - mGetUrl = url.toString() + "ig"; //设置用户对应的getUrl - mPostUrl = url.toString() + "r/ig"; //设置用户对应的postUrl - - if (tryToLoginGtask(activity, authToken)) { - mLoggedin = true; - } - } - - // try to login with google official url - //如果用户账户无法登录,则使用谷歌官方的URI进行登录 - if (!mLoggedin) { - mGetUrl = GTASK_GET_URL; - mPostUrl = GTASK_POST_URL; - if (!tryToLoginGtask(activity, authToken)) { - return false; - } - } - - mLoggedin = true; - return true; - } - - //具体实现登录谷歌账户 - - private String loginGoogleAccount(Activity activity, boolean invalidateToken) { - String authToken; //令牌,是登录操作保证安全性的一个方法 - AccountManager accountManager = AccountManager.get(activity);//AccountManager这个类给用户提供了集中注册账号的接口 - Account[] accounts = accountManager.getAccountsByType("com.google");//获取全部以com.google结尾的account - - if (accounts.length == 0) { - Log.e(TAG, "there is no available google account"); - return null; - } - - String accountName = NotesPreferenceActivity.getSyncAccountName(activity); - Account account = null; - //遍历获得的accounts信息,寻找已经记录过的账户信息 - for (Account a : accounts) { - if (a.name.equals(accountName)) { - account = a; - break; - } - } - if (account != null) { - mAccount = account; - } else { - Log.e(TAG, "unable to get an account with the same name in the settings"); - return null; - } - - // get the token now - //获取选中账号的令牌 - AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, - "goanna_mobile", null, activity, null, null); - try { - Bundle authTokenBundle = accountManagerFuture.getResult(); - authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); - //如果是invalidateToken,那么需要调用invalidateAuthToken(String, String)方法废除这个无效token - if (invalidateToken) { - accountManager.invalidateAuthToken("com.google", authToken); - loginGoogleAccount(activity, false); - } - } catch (Exception e) { - Log.e(TAG, "get auth token failed"); - authToken = null; - } - - return authToken; - } - - //尝试登陆Gtask,这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法 - private boolean tryToLoginGtask(Activity activity, String authToken) { - if (!loginGtask(authToken)) { - // maybe the auth token is out of authTokedate, now let's invalidate the - // token and try again - //删除过一个无效的authToken,申请一个新的后再次尝试登陆 - authToken = loginGoogleAccount(activity, true); - if (authToken == null) { - Log.e(TAG, "login google account failed"); - return false; - } - - if (!loginGtask(authToken)) { - Log.e(TAG, "login gtask failed"); - return false; - } - } - return true; - } - - //实现登录GTask的具体操作 - private boolean loginGtask(String authToken) { - int timeoutConnection = 10000; - int timeoutSocket = 15000; //socket是一种通信连接实现数据的交换的端口 - HttpParams httpParameters = new BasicHttpParams(); //实例化一个新的HTTP参数类 - HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);//设置连接超时时间 - HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);//设置设置端口超时时间 - mHttpClient = new DefaultHttpClient(httpParameters); - BasicCookieStore localBasicCookieStore = new BasicCookieStore(); //设置本地cookie - mHttpClient.setCookieStore(localBasicCookieStore); - HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); - - // login gtask - try { - String loginUrl = mGetUrl + "?auth=" + authToken; //设置登录的url - HttpGet httpGet = new HttpGet(loginUrl); //通过登录的uri实例化网页上资源的查找 - HttpResponse response = null; - response = mHttpClient.execute(httpGet); - - // get the cookie now - //获取CookieStore里存放的cookie,看如果存有“GTL(不知道什么意思)”,则说明有验证成功的有效的cookie - List cookies = mHttpClient.getCookieStore().getCookies(); - boolean hasAuthCookie = false; - for (Cookie cookie : cookies) { - if (cookie.getName().contains("GTL")) { - hasAuthCookie = true; - } - } - if (!hasAuthCookie) { - Log.w(TAG, "it seems that there is no auth cookie"); - } - - // get the client version - //获取client的内容,具体操作是在返回的Content中截取从_setup(开始到)}中间的字符串内容,也就是gtask_url的内容 - String resString = getResponseContent(response.getEntity()); - String jsBegin = "_setup("; - String jsEnd = ")}"; - int begin = resString.indexOf(jsBegin); - int end = resString.lastIndexOf(jsEnd); - String jsString = null; - if (begin != -1 && end != -1 && begin < end) { - jsString = resString.substring(begin + jsBegin.length(), end); - } - JSONObject js = new JSONObject(jsString); - mClientVersion = js.getLong("v"); - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - return false; - } catch (Exception e) { - // simply catch all exceptions - Log.e(TAG, "httpget gtask_url failed"); - return false; - } - - return true; - } - - private int getActionId() { - return mActionId++; - } - - /*实例化创建一个用于向网络传输数据的对象 - * 使用HttpPost类 - * 返回一个httpPost实例化对象,但里面还没有内容 - */ - private HttpPost createHttpPost() { - HttpPost httpPost = new HttpPost(mPostUrl); - httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); - httpPost.setHeader("AT", "1"); - return httpPost; - } - - /*通过URL获取响应后返回的数据,也就是网络上的数据和资源 - * 使用getContentEncoding()获取网络上的资源和数据 - * 返回值就是获取到的资源 - */ - private String getResponseContent(HttpEntity entity) throws IOException { - String contentEncoding = null; - if (entity.getContentEncoding() != null) {//通过URL得到HttpEntity对象,如果不为空则使用getContent()方法创建一个流将数据从网络都过来 - contentEncoding = entity.getContentEncoding().getValue(); - Log.d(TAG, "encoding: " + contentEncoding); - } - - InputStream input = entity.getContent(); - if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {//GZIP是使用DEFLATE进行压缩数据的另一个压缩库 - input = new GZIPInputStream(entity.getContent()); - } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {//DEFLATE是一个无专利的压缩算法,它可以实现无损数据压缩 - Inflater inflater = new Inflater(true); - input = new InflaterInputStream(entity.getContent(), inflater); - } - - try { - InputStreamReader isr = new InputStreamReader(input); - BufferedReader br = new BufferedReader(isr);//是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了时候,再读入内存,是为了提供读的效率而设计的 - StringBuilder sb = new StringBuilder(); - - while (true) { - String buff = br.readLine(); - if (buff == null) { - return sb.toString(); - } - sb = sb.append(buff); - } - } finally { - input.close(); - } - } - - /*通过JSON发送请求 - * 请求的具体内容在json的实例化对象js中然后传入 - * 利用UrlEncodedFormEntity entity和httpPost.setEntity(entity)方法把js中的内容放置到httpPost中 - * 执行请求后使用getResponseContent方法得到返回的数据和资源 - * 将资源再次放入json后返回 - */ - private JSONObject postRequest(JSONObject js) throws NetworkFailureException { - if (!mLoggedin) {//未登录 - Log.e(TAG, "please login first"); - throw new ActionFailureException("not logged in"); - } - - //实例化一个httpPost的对象用来向服务器传输数据,在这里就是发送请求,而请求的内容在js里 - HttpPost httpPost = createHttpPost(); - try { - LinkedList list = new LinkedList(); - list.add(new BasicNameValuePair("r", js.toString())); - UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); //UrlEncodedFormEntity()的形式比较单一,是普通的键值对 - httpPost.setEntity(entity); - - // execute the post - //执行这个请求 - HttpResponse response = mHttpClient.execute(httpPost); - String jsString = getResponseContent(response.getEntity()); - return new JSONObject(jsString); - - } catch (ClientProtocolException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("postRequest failed"); - } catch (IOException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("postRequest failed"); - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("unable to convert response content to jsonobject"); - } catch (Exception e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("error occurs when posting request"); - } - } - - /*创建单个任务 - * 传入参数是一个.gtask.data.Task包里Task类的对象 - * 利用json获取Task里的内容,并且创建相应的jsPost - * 利用postRequest得到任务的返回信息 - * 使用task.setGid设置task的new_ID - */ - public void createTask(Task task) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - - // action_list - actionList.put(task.getCreateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // post - JSONObject jsResponse = postRequest(jsPost); - JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( - GTaskStringUtils.GTASK_JSON_RESULTS).get(0); - task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("create task: handing jsonobject failed"); - } - } - - /* - * 创建一个任务列表,与createTask几乎一样,区别就是最后设置的是tasklist的gid - */ - public void createTaskList(TaskList tasklist) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - - // action_list - actionList.put(tasklist.getCreateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - // post - JSONObject jsResponse = postRequest(jsPost); - JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( - GTaskStringUtils.GTASK_JSON_RESULTS).get(0); - tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("create tasklist: handing jsonobject failed"); - } - } - - /* - * 同步更新操作 - * 使用JSONObject进行数据存储,使用jsPost.put,Put的信息包括UpdateArray和ClientVersion - * 使用postRequest发送这个jspost,进行处理 - */ - public void commitUpdate() throws NetworkFailureException { - if (mUpdateArray != null) { - try { - JSONObject jsPost = new JSONObject(); - - // action_list - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); - - // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - postRequest(jsPost); - mUpdateArray = null; - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("commit update: handing jsonobject failed"); - } - } - } - - /* - * 添加更新的事项 - * 调用commitUpdate()实现 - */ - public void addUpdateNode(Node node) throws NetworkFailureException { - if (node != null) { - // too many update items may result in an error - // set max to 10 items - if (mUpdateArray != null && mUpdateArray.length() > 10) { - commitUpdate(); - } - - if (mUpdateArray == null) - mUpdateArray = new JSONArray(); - mUpdateArray.put(node.getUpdateAction(getActionId())); - } - } - - /* - * 移动task,比如讲task移动到不同的task列表中去 - * 通过getGid获取task所属列表的gid - * 通过JSONObject.put(String name, Object value)函数设置移动后的task的相关属性值,从而达到移动的目的 - * 最后还是通过postRequest进行更新后的发送 - */ - public void moveTask(Task task, TaskList preParent, TaskList curParent) - throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); - - // action_list - action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); - action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); - action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); - if (preParent == curParent && task.getPriorSibling() != null) { - // put prioring_sibing_id only if moving within the tasklist and - // it is not the first one - //设置优先级ID,只有当移动是发生在文件中 - action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); - } - action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); //设置移动前所属列表 - action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); //设置当前所属列表 - if (preParent != curParent) { - // put the dest_list only if moving between tasklists - action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); - } - actionList.put(action); - //最后将ACTION_LIST加入到jsPost中 - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - postRequest(jsPost); - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("move task: handing jsonobject failed"); - } - } - - /* - * 删除操作节点 - * 还是利用JSON - * 删除过后使用postRequest发送删除后的结果 - */ - public void deleteNode(Node node) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - - // action_list - node.setDeleted(true); - actionList.put(node.getUpdateAction(getActionId())); //这里会获取到删除操作的ID,加入到actionLiast中 - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - postRequest(jsPost); - mUpdateArray = null; - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("delete node: handing jsonobject failed"); - } - } - - /* - * 获取任务列表 - * 首先通过GetURI使用getResponseContent从网上获取数据 - * 然后筛选出"_setup("到)}的部分,并且从中获取GTASK_JSON_LISTS的内容返回 - */ - public JSONArray getTaskLists() throws NetworkFailureException { - if (!mLoggedin) { - Log.e(TAG, "please login first"); - throw new ActionFailureException("not logged in"); - } - - try { - HttpGet httpGet = new HttpGet(mGetUrl); - HttpResponse response = null; - response = mHttpClient.execute(httpGet); - - // get the task list - //筛选工作,把筛选出的字符串放入jsString - String resString = getResponseContent(response.getEntity()); - String jsBegin = "_setup("; - String jsEnd = ")}"; - int begin = resString.indexOf(jsBegin); - int end = resString.lastIndexOf(jsEnd); - String jsString = null; - if (begin != -1 && end != -1 && begin < end) { - jsString = resString.substring(begin + jsBegin.length(), end); - } - JSONObject js = new JSONObject(jsString); - //获取GTASK_JSON_LISTS - return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); - } catch (ClientProtocolException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("gettasklists: httpget failed"); - } catch (IOException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("gettasklists: httpget failed"); - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("get task lists: handing jasonobject failed"); - } - } - - /* - * 通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务 - */ - public JSONArray getTaskList(String listGid) throws NetworkFailureException { - commitUpdate(); - try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); - - // action_list - action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); - action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); - action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); //这里设置为传入的listGid - action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); - actionList.put(action); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - JSONObject jsResponse = postRequest(jsPost); - return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("get task list: handing jsonobject failed"); - } - } - - public Account getSyncAccount() { - return mAccount; - } - - //重置更新的内容 - public void resetUpdateArray() { - mUpdateArray = null; - } - } \ No newline at end of file diff --git a/doc/remote/GTaskManager.java b/doc/remote/GTaskManager.java deleted file mode 100644 index d2b4082..0000000 --- a/doc/remote/GTaskManager.java +++ /dev/null @@ -1,800 +0,0 @@ -/* - * 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.gtask.remote; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.util.Log; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.gtask.data.MetaData; -import net.micode.notes.gtask.data.Node; -import net.micode.notes.gtask.data.SqlNote; -import net.micode.notes.gtask.data.Task; -import net.micode.notes.gtask.data.TaskList; -import net.micode.notes.gtask.exception.ActionFailureException; -import net.micode.notes.gtask.exception.NetworkFailureException; -import net.micode.notes.tool.DataUtils; -import net.micode.notes.tool.GTaskStringUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; - - -public class GTaskManager { - private static final String TAG = GTaskManager.class.getSimpleName(); - - public static final int STATE_SUCCESS = 0; - - public static final int STATE_NETWORK_ERROR = 1; - - public static final int STATE_INTERNAL_ERROR = 2; - - public static final int STATE_SYNC_IN_PROGRESS = 3; - - public static final int STATE_SYNC_CANCELLED = 4; - - private static GTaskManager mInstance = null; - - private Activity mActivity; - - private Context mContext; - - private ContentResolver mContentResolver; - - private boolean mSyncing; - - private boolean mCancelled; - - private HashMap mGTaskListHashMap; - - private HashMap mGTaskHashMap; - - private HashMap mMetaHashMap; - - private TaskList mMetaList; - - private HashSet mLocalDeleteIdMap; - - private HashMap mGidToNid; - - private HashMap mNidToGid; - - private GTaskManager() { - mSyncing = false; - mCancelled = false; - mGTaskListHashMap = new HashMap(); - mGTaskHashMap = new HashMap(); - mMetaHashMap = new HashMap(); - mMetaList = null; - mLocalDeleteIdMap = new HashSet(); - mGidToNid = new HashMap(); - mNidToGid = new HashMap(); - } - - public static synchronized GTaskManager getInstance() { - if (mInstance == null) { - mInstance = new GTaskManager(); - } - return mInstance; - } - - public synchronized void setActivityContext(Activity activity) { - // used for getting authtoken - mActivity = activity; - } - - public int sync(Context context, GTaskASyncTask asyncTask) { - if (mSyncing) { - Log.d(TAG, "Sync is in progress"); - return STATE_SYNC_IN_PROGRESS; - } - mContext = context; - mContentResolver = mContext.getContentResolver(); - mSyncing = true; - mCancelled = false; - mGTaskListHashMap.clear(); - mGTaskHashMap.clear(); - mMetaHashMap.clear(); - mLocalDeleteIdMap.clear(); - mGidToNid.clear(); - mNidToGid.clear(); - - try { - GTaskClient client = GTaskClient.getInstance(); - client.resetUpdateArray(); - - // login google task - if (!mCancelled) { - if (!client.login(mActivity)) { - throw new NetworkFailureException("login google task failed"); - } - } - - // get the task list from google - asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); - initGTaskList(); - - // do content sync work - asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); - syncContent(); - } catch (NetworkFailureException e) { - Log.e(TAG, e.toString()); - return STATE_NETWORK_ERROR; - } catch (ActionFailureException e) { - Log.e(TAG, e.toString()); - return STATE_INTERNAL_ERROR; - } catch (Exception e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - return STATE_INTERNAL_ERROR; - } finally { - mGTaskListHashMap.clear(); - mGTaskHashMap.clear(); - mMetaHashMap.clear(); - mLocalDeleteIdMap.clear(); - mGidToNid.clear(); - mNidToGid.clear(); - mSyncing = false; - } - - return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; - } - - private void initGTaskList() throws NetworkFailureException { - if (mCancelled) - return; - GTaskClient client = GTaskClient.getInstance(); - try { - JSONArray jsTaskLists = client.getTaskLists(); - - // init meta list first - mMetaList = null; - for (int i = 0; i < jsTaskLists.length(); i++) { - JSONObject object = jsTaskLists.getJSONObject(i); - String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); - String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); - - if (name - .equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { - mMetaList = new TaskList(); - mMetaList.setContentByRemoteJSON(object); - - // load meta data - JSONArray jsMetas = client.getTaskList(gid); - for (int j = 0; j < jsMetas.length(); j++) { - object = (JSONObject) jsMetas.getJSONObject(j); - MetaData metaData = new MetaData(); - metaData.setContentByRemoteJSON(object); - if (metaData.isWorthSaving()) { - mMetaList.addChildTask(metaData); - if (metaData.getGid() != null) { - mMetaHashMap.put(metaData.getRelatedGid(), metaData); - } - } - } - } - } - - // create meta list if not existed - if (mMetaList == null) { - mMetaList = new TaskList(); - mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META); - GTaskClient.getInstance().createTaskList(mMetaList); - } - - // init task list - for (int i = 0; i < jsTaskLists.length(); i++) { - JSONObject object = jsTaskLists.getJSONObject(i); - String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); - String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); - - if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX) - && !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META)) { - TaskList tasklist = new TaskList(); - tasklist.setContentByRemoteJSON(object); - mGTaskListHashMap.put(gid, tasklist); - mGTaskHashMap.put(gid, tasklist); - - // load tasks - JSONArray jsTasks = client.getTaskList(gid); - for (int j = 0; j < jsTasks.length(); j++) { - object = (JSONObject) jsTasks.getJSONObject(j); - gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); - Task task = new Task(); - task.setContentByRemoteJSON(object); - if (task.isWorthSaving()) { - task.setMetaInfo(mMetaHashMap.get(gid)); - tasklist.addChildTask(task); - mGTaskHashMap.put(gid, task); - } - } - } - } - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("initGTaskList: handing JSONObject failed"); - } - } - - private void syncContent() throws NetworkFailureException { - int syncType; - Cursor c = null; - String gid; - Node node; - - mLocalDeleteIdMap.clear(); - - if (mCancelled) { - return; - } - - // for local deleted note - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type<>? AND parent_id=?)", new String[] { - String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) - }, null); - if (c != null) { - while (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c); - } - - mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); - } - } else { - Log.w(TAG, "failed to query trash folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // sync folder first - syncFolder(); - - // for note existing in database - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type=? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); - if (c != null) { - while (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); - mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); - syncType = node.getSyncAction(c); - } else { - if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add - syncType = Node.SYNC_ACTION_ADD_REMOTE; - } else { - // remote delete - syncType = Node.SYNC_ACTION_DEL_LOCAL; - } - } - doContentSync(syncType, node, c); - } - } else { - Log.w(TAG, "failed to query existing note in database"); - } - - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // go through remaining items - Iterator> iter = mGTaskHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - node = entry.getValue(); - doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); - } - - // mCancelled can be set by another thread, so we neet to check one by - // one - // clear local delete table - if (!mCancelled) { - if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { - throw new ActionFailureException("failed to batch-delete local deleted notes"); - } - } - - // refresh local sync id - if (!mCancelled) { - GTaskClient.getInstance().commitUpdate(); - refreshLocalSyncId(); - } - - } - - private void syncFolder() throws NetworkFailureException { - Cursor c = null; - String gid; - Node node; - int syncType; - - if (mCancelled) { - return; - } - - // for root folder - try { - c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, - Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); - if (c != null) { - c.moveToNext(); - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER); - mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid); - // for system folder, only update remote name if necessary - if (!node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) - doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); - } else { - doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); - } - } else { - Log.w(TAG, "failed to query root folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // for call-note folder - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", - new String[] { - String.valueOf(Notes.ID_CALL_RECORD_FOLDER) - }, null); - if (c != null) { - if (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER); - mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid); - // for system folder, only update remote name if - // necessary - if (!node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_CALL_NOTE)) - doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); - } else { - doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); - } - } - } else { - Log.w(TAG, "failed to query call note folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // for local existing folders - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type=? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); - if (c != null) { - while (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); - mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); - syncType = node.getSyncAction(c); - } else { - if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add - syncType = Node.SYNC_ACTION_ADD_REMOTE; - } else { - // remote delete - syncType = Node.SYNC_ACTION_DEL_LOCAL; - } - } - doContentSync(syncType, node, c); - } - } else { - Log.w(TAG, "failed to query existing folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - - // for remote add folders - Iterator> iter = mGTaskListHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - gid = entry.getKey(); - node = entry.getValue(); - if (mGTaskHashMap.containsKey(gid)) { - mGTaskHashMap.remove(gid); - doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); - } - } - - if (!mCancelled) - GTaskClient.getInstance().commitUpdate(); - } - - private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; - } - - MetaData meta; - switch (syncType) { - case Node.SYNC_ACTION_ADD_LOCAL: - addLocalNode(node); - break; - case Node.SYNC_ACTION_ADD_REMOTE: - addRemoteNode(node, c); - break; - case Node.SYNC_ACTION_DEL_LOCAL: - meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN)); - if (meta != null) { - GTaskClient.getInstance().deleteNode(meta); - } - mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); - break; - case Node.SYNC_ACTION_DEL_REMOTE: - meta = mMetaHashMap.get(node.getGid()); - if (meta != null) { - GTaskClient.getInstance().deleteNode(meta); - } - GTaskClient.getInstance().deleteNode(node); - break; - case Node.SYNC_ACTION_UPDATE_LOCAL: - updateLocalNode(node, c); - break; - case Node.SYNC_ACTION_UPDATE_REMOTE: - updateRemoteNode(node, c); - break; - case Node.SYNC_ACTION_UPDATE_CONFLICT: - // merging both modifications maybe a good idea - // right now just use local update simply - updateRemoteNode(node, c); - break; - case Node.SYNC_ACTION_NONE: - break; - case Node.SYNC_ACTION_ERROR: - default: - throw new ActionFailureException("unkown sync action type"); - } - } - - private void addLocalNode(Node node) throws NetworkFailureException { - if (mCancelled) { - return; - } - - SqlNote sqlNote; - if (node instanceof TaskList) { - if (node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) { - sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER); - } else if (node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { - sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER); - } else { - sqlNote = new SqlNote(mContext); - sqlNote.setContent(node.getLocalJSONFromContent()); - sqlNote.setParentId(Notes.ID_ROOT_FOLDER); - } - } else { - sqlNote = new SqlNote(mContext); - JSONObject js = node.getLocalJSONFromContent(); - try { - if (js.has(GTaskStringUtils.META_HEAD_NOTE)) { - JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - if (note.has(NoteColumns.ID)) { - long id = note.getLong(NoteColumns.ID); - if (DataUtils.existInNoteDatabase(mContentResolver, id)) { - // the id is not available, have to create a new one - note.remove(NoteColumns.ID); - } - } - } - - if (js.has(GTaskStringUtils.META_HEAD_DATA)) { - JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - if (data.has(DataColumns.ID)) { - long dataId = data.getLong(DataColumns.ID); - if (DataUtils.existInDataDatabase(mContentResolver, dataId)) { - // the data id is not available, have to create - // a new one - data.remove(DataColumns.ID); - } - } - } - - } - } catch (JSONException e) { - Log.w(TAG, e.toString()); - e.printStackTrace(); - } - sqlNote.setContent(js); - - Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); - if (parentId == null) { - Log.e(TAG, "cannot find task's parent id locally"); - throw new ActionFailureException("cannot add local node"); - } - sqlNote.setParentId(parentId.longValue()); - } - - // create the local node - sqlNote.setGtaskId(node.getGid()); - sqlNote.commit(false); - - // update gid-nid mapping - mGidToNid.put(node.getGid(), sqlNote.getId()); - mNidToGid.put(sqlNote.getId(), node.getGid()); - - // update meta - updateRemoteMeta(node.getGid(), sqlNote); - } - - private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; - } - - SqlNote sqlNote; - // update the note locally - sqlNote = new SqlNote(mContext, c); - sqlNote.setContent(node.getLocalJSONFromContent()); - - Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()) - : new Long(Notes.ID_ROOT_FOLDER); - if (parentId == null) { - Log.e(TAG, "cannot find task's parent id locally"); - throw new ActionFailureException("cannot update local node"); - } - sqlNote.setParentId(parentId.longValue()); - sqlNote.commit(true); - - // update meta info - updateRemoteMeta(node.getGid(), sqlNote); - } - - private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; - } - - SqlNote sqlNote = new SqlNote(mContext, c); - Node n; - - // update remotely - if (sqlNote.isNoteType()) { - Task task = new Task(); - task.setContentByLocalJSON(sqlNote.getContent()); - - String parentGid = mNidToGid.get(sqlNote.getParentId()); - if (parentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); - throw new ActionFailureException("cannot add remote task"); - } - mGTaskListHashMap.get(parentGid).addChildTask(task); - - GTaskClient.getInstance().createTask(task); - n = (Node) task; - - // add meta - updateRemoteMeta(task.getGid(), sqlNote); - } else { - TaskList tasklist = null; - - // we need to skip folder if it has already existed - String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX; - if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) - folderName += GTaskStringUtils.FOLDER_DEFAULT; - else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER) - folderName += GTaskStringUtils.FOLDER_CALL_NOTE; - else - folderName += sqlNote.getSnippet(); - - Iterator> iter = mGTaskListHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - String gid = entry.getKey(); - TaskList list = entry.getValue(); - - if (list.getName().equals(folderName)) { - tasklist = list; - if (mGTaskHashMap.containsKey(gid)) { - mGTaskHashMap.remove(gid); - } - break; - } - } - - // no match we can add now - if (tasklist == null) { - tasklist = new TaskList(); - tasklist.setContentByLocalJSON(sqlNote.getContent()); - GTaskClient.getInstance().createTaskList(tasklist); - mGTaskListHashMap.put(tasklist.getGid(), tasklist); - } - n = (Node) tasklist; - } - - // update local note - sqlNote.setGtaskId(n.getGid()); - sqlNote.commit(false); - sqlNote.resetLocalModified(); - sqlNote.commit(true); - - // gid-id mapping - mGidToNid.put(n.getGid(), sqlNote.getId()); - mNidToGid.put(sqlNote.getId(), n.getGid()); - } - - private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; - } - - SqlNote sqlNote = new SqlNote(mContext, c); - - // update remotely - node.setContentByLocalJSON(sqlNote.getContent()); - GTaskClient.getInstance().addUpdateNode(node); - - // update meta - updateRemoteMeta(node.getGid(), sqlNote); - - // move task if necessary - if (sqlNote.isNoteType()) { - Task task = (Task) node; - TaskList preParentList = task.getParent(); - - String curParentGid = mNidToGid.get(sqlNote.getParentId()); - if (curParentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); - throw new ActionFailureException("cannot update remote task"); - } - TaskList curParentList = mGTaskListHashMap.get(curParentGid); - - if (preParentList != curParentList) { - preParentList.removeChildTask(task); - curParentList.addChildTask(task); - GTaskClient.getInstance().moveTask(task, preParentList, curParentList); - } - } - - // clear local modified flag - sqlNote.resetLocalModified(); - sqlNote.commit(true); - } - - private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { - if (sqlNote != null && sqlNote.isNoteType()) { - MetaData metaData = mMetaHashMap.get(gid); - if (metaData != null) { - metaData.setMeta(gid, sqlNote.getContent()); - GTaskClient.getInstance().addUpdateNode(metaData); - } else { - metaData = new MetaData(); - metaData.setMeta(gid, sqlNote.getContent()); - mMetaList.addChildTask(metaData); - mMetaHashMap.put(gid, metaData); - GTaskClient.getInstance().createTask(metaData); - } - } - } - - private void refreshLocalSyncId() throws NetworkFailureException { - if (mCancelled) { - return; - } - - // get the latest gtask list - mGTaskHashMap.clear(); - mGTaskListHashMap.clear(); - mMetaHashMap.clear(); - initGTaskList(); - - Cursor c = null; - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type<>? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); - if (c != null) { - while (c.moveToNext()) { - String gid = c.getString(SqlNote.GTASK_ID_COLUMN); - Node node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - ContentValues values = new ContentValues(); - values.put(NoteColumns.SYNC_ID, node.getLastModified()); - mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, - c.getLong(SqlNote.ID_COLUMN)), values, null, null); - } else { - Log.e(TAG, "something is missed"); - throw new ActionFailureException( - "some local items don't have gid after sync"); - } - } - } else { - Log.w(TAG, "failed to query local note to refresh sync id"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - } - - public String getSyncAccount() { - return GTaskClient.getInstance().getSyncAccount().name; - } - - public void cancelSync() { - mCancelled = true; - } -} diff --git a/doc/remote/GTaskSyncService.java b/doc/remote/GTaskSyncService.java deleted file mode 100644 index cca36f7..0000000 --- a/doc/remote/GTaskSyncService.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.gtask.remote; - -import android.app.Activity; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; - -public class GTaskSyncService extends Service { - public final static String ACTION_STRING_NAME = "sync_action_type"; - - public final static int ACTION_START_SYNC = 0; - - public final static int ACTION_CANCEL_SYNC = 1; - - public final static int ACTION_INVALID = 2; - - public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service"; - - public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing"; - - public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg"; - - private static GTaskASyncTask mSyncTask = null; - - private static String mSyncProgress = ""; - - private void startSync() { - if (mSyncTask == null) { - mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { - public void onComplete() { - mSyncTask = null; - sendBroadcast(""); - stopSelf(); - } - }); - sendBroadcast(""); - mSyncTask.execute(); - } - } - - private void cancelSync() { - if (mSyncTask != null) { - mSyncTask.cancelSync(); - } - } - - @Override - public void onCreate() { - mSyncTask = null; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Bundle bundle = intent.getExtras(); - if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { - switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) { - case ACTION_START_SYNC: - startSync(); - break; - case ACTION_CANCEL_SYNC: - cancelSync(); - break; - default: - break; - } - return START_STICKY; - } - return super.onStartCommand(intent, flags, startId); - } - - @Override - public void onLowMemory() { - if (mSyncTask != null) { - mSyncTask.cancelSync(); - } - } - - public IBinder onBind(Intent intent) { - return null; - } - - public void sendBroadcast(String msg) { - mSyncProgress = msg; - Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); - intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); - intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); - sendBroadcast(intent); - } - - public static void startSync(Activity activity) { - GTaskManager.getInstance().setActivityContext(activity); - Intent intent = new Intent(activity, GTaskSyncService.class); - intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC); - activity.startService(intent); - } - - public static void cancelSync(Context context) { - Intent intent = new Intent(context, GTaskSyncService.class); - intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); - context.startService(intent); - } - - public static boolean isSyncing() { - return mSyncTask != null; - } - - public static String getProgressString() { - return mSyncProgress; - } -} diff --git a/doc/remote/软件 (D).lnk b/doc/remote/软件 (D).lnk deleted file mode 100644 index f353aa81d1b9d651b58e8b48448e7b3a02c4e104..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 515 zcmeZaU|?VrVFHp23S})9{68Scx9C-u;>N{gSLUeTuBCf7poY!B4mackRt=cAcH`(ArOOr zDG-YSF*6WXoYqto0MaMk?)k?6Hi(-+4+vv0$OMRv1rb0R1d6kDjSP&842%s73zLeA z7#w^~Z9h2wh12>&0gIOK>?loH;$nTw^R3`CmWE%^nVc1b zX`OU~@PidM%0OZu0P;7;EWGI1B&)3_)@x diff --git a/doc/小米便签开源代码的泛读报告.docx b/doc/小米便签开源代码的泛读报告.docx deleted file mode 100644 index 37ba7090a1b8e8ca021f1bd96a908219b5a5f974..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 370669 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

__YcCj0&pLnV8Gw2&ehQg%q+%8q_@>; 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

^Ye2c`ba5fclA}|a`^dj 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 -oOGf|FsSO*N-pw?liBn z?=52Io{CP6gH2wb_&|3h`_1-&&Yn=pE9e3qSE6%#hBbu0-pyY=K9tF78)#e-0<35d zNb(ZY-qMq@5A-tOk71pw+Sm;;H`sa$NLZi$ZirtHrGNdn{S50`V5pz$SwHU{JW3dR zb|Z2ZsOS{k3Uv23SDxFSq+5V5JY|jl@{|ngTRQs=Kz#o4@&B0R-_R_d@Cic-2xU%~ zbZKR+KjYr`k>4i{Jl)n@jrT`BoO--0czUtume*inCUM{-=v)@E+J zn0eEnuu`-BZS9dwU+&(!gYwgVPPx=VMMO(Z3zMANi8I74wu~=F&M%?piyNz9!xx^G z3PwM*AyP1#cE*A^(a^b#2V;xo9qyQ&*9_fN_8f{$Q0c{up1S0Sr(%QFaD$Wf*LVp| zVFQ|*BjbsI=V>1n-!yO#pFv(+k3}ysw@YUl;#<;c!Qtm*nzmDhqsZq~6nzGABC(~L zktWY=)Vq7#tka1&La^!3&z>*3KeoD( zTaa72Wg1R9j?Cn3ncwz};3lBw2RVBR8#v6&G?8JBTYaU@mkP5&0|cNRj<4O zM(;zWTK5q`S0G*(%*x{@$~k(EFiB)5jl$!$%wN}q2rDmSlZAPb`IvDEL|UJ(W{!`B zQ*1j0p}XBQQQ<9;JwLtT`ND>qa1e4!cw9y(opE!eA^O&FoNTpd`x&e2vANt1=e5Xf z)#EdaNS|}N2iVocyI=^svyv-vyr3FD(-z6w}IIsUZ`NVe|=j?(x1a(++G7|i_?4xkujL^n@cVx%$Jw; z)D=i)fw!sp4+8>xM-6)gduCyA!7M*~*Ypgc^gX*(qVXWRqD23vPhX(#iU{DWpm)${ z?ge-ZocjYWO)%Fhwvu}r9ro&|vOdUB2+yyx2jsu;D)+c(lJa@^?XTl1y{c$4|A@1% zzQ3es1i;;BP!x$5gLsNwLHDaPKq!%zM0d9fj-b26nT&YxWhJA&b;tIZ9OnA%7NwB` zV~rHPnXD@@QnMczzF&#?F$@~>No`Bz`R3&>+W99iL4|1|5hv-Bnat0Z;#W6)0Rq>) zzx$r;z^trR_8@(r`4&kb8CX3VHg?n$W>)RH7$pu{HmB(GnhJNyBo>*Ob3<#%bm&}t zno&0`l1U$~RfyiKT>Va@8-xRI---&~LPn~W#%$jU8a;PqAS^9LGK#$AjIBk|GBPVe zG(zU=m&>@`#B8^7dCV3{H=UJ%u7tVIV!EB5jG^5-khh>zm+)2fx;HD@TMvV}vNmsF zrfn-JfuwYF%Jnq7}|1kyaYj-uP1Tcf;t;Y?IoOGTBIm2)Zni7Cu-(}MYnS+*Yu8;Pf;?$&QcS}%#WcAx3*dJ?v>FW zi(yf|_ddtm`V|jj8`=mzhNSgr+b>Pm6< *3N}4b}ka1t~H>U459C#ezX$Ve9P{L zP&KkG(>g;b&}M6qfz7_5y;2?ObZ4ksJAl)GNqHS3KT^02VQwJ3@Mpqh638O-0ccWv z0r3)W*Z~L2Yo8#Vpm$9)YWAwavt!&wn%zr$ZvD0@k-4ZtzwE8V+J8K$*0H;O+&aGJ zi!$+E8Ij#Su@l6BihYoBJkKZTvheXaikMlF7x>ZBEjicW4xUtl4+6l(UYp>8MGc6T zA@lhdTik34Da~+Fw7jZ!KomMKsZ)jYpl6R}VSNjcxoN*rqa0F?352S-wpDJt&r1)g zJ%U7{^y|dpP~nq{Ex#S#b1d-av6PRzfubGp`+KxDlHF%1O=+9~&&@6f5?>~qy0<}x zbCF0{0W#=-istLGW!dbBf)bUmS)c8Wx{}3>*K=#<{YXLqR}l-xY3`=+VTq|XX$d63 z@_6W6T{GFafVqrhYFE;e$Edc$H9~Hh)2ZHBPn6eDNb&Bz4F_G)TF+T}=k!YS6Pp0K zE{$Tr@!{Abn(O7~x~7Yd;E=E8WMC~4Kz9~O^Ipka>Aq8bFs@z-Ao(znUGgt3U@K4^z&kpljscoztJPKv=+)n^BoK=mP%zF>z~6O^K$ zm__Wz3YifD6<*x;wmO-fRP+J$#3$0J?5PtP0a)JFA#XsM+3`w#*lVvZO7R43LVlu! zQuj++m3y-NGrGMsDNxQp=R~b3G@#}=%y?XE=RjxN1!knl@KZGZ0jrTa>wdmPr zDbwiifac?ej~&GX%A9G21sYmIq*0p_BN|W8m_ytQ!?WsIN#HCi<+8WelW{0$DPZGS zUeGu1qlDd8??E5%L(EAqANT8)kBS>!U3=TRVg2Kji_HBDv~nIdJBps5+yvOEcsoJ) zBNAFI%TaZZEqssgtD|zei&bo|p5*^}jZ&aSs77Z_`@dJl_*WaSTW@!x7pWUZ&KBE{ z9z1$AalWI*_H0>2eL;fHdld|@s0=)Qnol~(eIn^Aq zERs&UjDGJi(JrAmes;=;rPWjg@?Kq|*6d_H%Np>#2U%WRN-v-&<&C*euxcCcCV zaZ%r6q6E}Yq#0%0CGvx9ck3hU?n7 z58En4@QG2}_YGYH$mim|J$4t2Kl6A6Rm;CF?i7)Lfn8Q5Z9Q`3naFqyridA6Bzt2h zD5Ok|b0m}p!$(cV$e_z)x_NLubBVN$K{mZD8N!ss1ebF;UKEJ*g0lt_Dq>;6AH#J@+Vb>} zMz);mi4-23CFR~#hegz^_-Vk`M!Y`2_FC395;SmDx4(#2)cJ-;xg(|Y2^4(xjF84} zL^2cx!*xKND6Py^$#0|vUY@yYnq|)3+P~-fi0jI^vuQv=xgbcmc2rI=cd51|f$P35 zf39zf@5cSF3Qa_9#4 z$CAK$+$|(BE(6jLOjJhhK6AI5ulGkj=NYV#4H|AH3yp z-bG((;@!%)%CngvS?V^lxBX17TAaz=$?-m}ZUb+&4P zizbF_zdrz*MVYe$Oi@2a4Dbwl+AD$3S7L$_Lx!kY_F%yh??icsJM`g@Qx=jxE$Wq+ zn71&?dH^P!6B)@2nLp8uDXrocn@FQ z7>I=7Aba1T^j|!5+nz#GJoK!-p(|kSgg7_vhi-SeCm7uIhHJAkpJh#Ys6=h0X|ViW z-MPd-wA?||x?ALkH{UM5Ll4c9$|GJL(9jz#Prs?qK|%e}R5A9(vy{B`a9tcx`e=N7 zyc&405es!y-x}zj8?LgnwY6<|C_aU~P5eamU-wT+A(R=#z{yk@MYMIsk7!<0~j+%$ynLWC2|s&z?(*+SI+yO@5~UP>gzi zpf@_U?zk8t-#Qim(;k?dpjj^GE}Y8`=`3Z1sMR#SuWAT7J|_G$n13jn1&3cyb26qy z)y18Cxb)g126FNSP3~T4Hpv})?s=7J(Cx`h=$CA>-`O%pfM2-@PJy(H$ocQ}D2>>-|3HQgQlwzw~nJgSc#qc+PTGm zYIQs@`etAV?P(6F%3clEx8Um>{P_o*1JZn>!1@QnQ?*eVUkB+aQ%%1eINjA*)(|oQ zU~g`MQtnbJ@B>J(G}8`qkNZg1X}>>5ytdWfJUigE7#Zyw7D;Eg@6)0zcLy<3_6##r zdh{_n)-4rBfCIU^oMNbnH&@1B&9Vh9Oe`Q2C3h1Oi5HZk)`|xPf*0-6orVw* zNO#s%cLy){>Ka^~_VJU#`I!*IH)<{-Bf`}p`rcKqzPa(1+SRa0xE9;6(pZ=eJoBro zZH(PJ(Z9CnOH{z;g`n=vv6(z_ZDD4)h9ch3>w<6FWXDQ0<~LHmdRkYHUz&7!_98{m z+OF`hvn9-Deso|uKhX3=S}JVRFv3$y3=XV-(<~$p5Q3X-4pgHYVn%uEm&fBryB&gj zf8@MP_ zZT*dx^5FuX^L9`6)dt|t!V^D@`HxT(2I7ffh#&aFrxDp%tz+#og+0g|5l3qH*38GF zhV7%Ie%Wj#+4O2U)WUBM zH~T!Gf|w5Q-b&awxcaq#a-itKHTX5|-L0VL% z&;A_4w}IfjZ+w0{G1^ORmmj%AH>Q7Yy_~8MZEN3Qz^9)&v*P9$^u)cgLQvK|%S4G+ zY);)&JwzG`JE=4xujD5NmpS$;fVC_9I7HQ%d&j}?%WhGV(c51Nf|%}t{Zi#z1y_3P zpPg3?{WU{NBYhF92}zxO?T1@zG{Fxf=ZrqHfjI<9U^AZ+qNWebI2QI?uJW8@tG<49 zI*iD(hZcFsm|W}*wMXRm4$D^)>#EVz_-RUKgc40d55*jrcZ+zmb_Bl==KDFCG=iold^4H?d#$)>s@jLlT_!qL ziH#wrpI3jczcJJA!7~tfFGI@GPMsmJY|1P zsZiHFCSZHkqOVT6W6h!q`RxI`TLM@#P{OqNH}93`BO}Rx!4cO7B%R(#NT}f#wIQzI z%*ux|T_{@g`|+Rmq+C{$*rO)jOrA^W--Hm9`LlhY_Is-Wq7(@_SR_=K-_vem3oY&z_It(QGaqWFGcRnQ%%&u#~})$ulbH#Y=h z#8ej;$hKMfeGsvA)d_sFzf(>kc2GgO3RRROY-SeKP6IE5_!4?d)V|l(;?+PXaWG5~uN~bGq{d!4=2WJ-fQJ&Ebt3R`Ue|)9S z=~OquzL&=W&qk7Sos4k|QQ#yCxGT^9GjpkXHP2bgV{&cgqbDh8Nip@iD4Y-H8vsTh z6*UBY3q7`{ZT}P&eH>}=o!Y&aHT{(ff<{)Yz&o3HsjC4ua2_heKS^mWh zA^gU@%T_Iz8eYAuV>mnM-UF`$G__QcfTx~Q)uM4Edm+^9We15qcoZeiNIJmxkkPfX zPMNQkl@>&=9Qt+l-0VP|W|kA7Qo%8F*nWUdJE(hTvd-w#R(yb_;gZ0W)pLU7J&%t) z-1Cq3z6XFV(T@lh@m)(T>DwwxKb znQ~(N%|_!bN`Z>nXN##L*$du$c)fS=Lm@rx_UnQ;r3G87IkbE$&PqMSmFI9w7kdj45dOa-V8LIYk8kR`5yNwvsB{j@w1iyHH=uA7VEE9482kCRZ z7{5Ed9hmPw$Z22=1=4{aitjYJzCT3_@o>)okX!0CM`QCoJiP-@1@b%9plY$ev!Ea? zAUy-p!Ck=bUy^r-^^v3lY`cE60vvfjHRf!hJiJZcxgxKMpH#G&B!8)de`PSeuG+LI zISg3J^KWmn0X{dE@k{9h{p3z^Bs7y4%-w=6EGHrN^EksE%O@R#RVDHYBtIUmbvKXL z^Ck3*>>!qmtqhSG$y42VwUk7mc6>Ml|9oUvA>^u{zm#@{s6SX zPb(X2m%o4mvN#S)6DS8;f%b4@nX?^hZ(!2vz|v?rN!?+N)UIyynFN<=Kof}7&1Tshr5``RYL6#Dn{ zzzH#oiUAC|45p(5chr6_q1hB5CwNV4H=d#=)e%6|R((<<{++(0o~-Pv8^3(nXXWj) zm)2HbNj35|Tyae_vLj%ZdZ%VemFgNGU=IKa6P zVB2sae!76+Ja=i&gZ7yW=W`E+F@uX;aF~0yc2tO+N8oNM>Vj3Z}yDZmsvjevsq;iTt-j!t%vS#)q?r5 zn%DI3V<=D`)u90Nk`$(Sy9GU~j1FclYtB}#r_9y?3%*qNvua^iFkLs(0x(d@=9`-I zH*=5ELJL^YPb-4FGLx0kGyp_EB|)T8NAJNtcmRYWz&Ed`O<4Q9-=S9XtOwl_DTCAM zBhQbbi1%Mj_evpGGyZJBh!f54M+k zkj8l1MfID8L=rB4a>HvTgNGpwqxH_*+a2=1Lh&zHxJ&tSb;8p6$96pOJO0TSoXaH< z*Q1-nqs<6U0@O2u;GU6y(tV;CL1k(W>nLh&yB!Y419bm^|L71}QDFUNLm_v@!Q5Tw zwXe`-#pusBBcX!hzV32@qQ1QDnD}~Npq;wpw^yL{kwc<5%y6P7thpd5ls+a~5H>c@ z|8~X8Q`GHZbUJ^z!8l5$sS0vWb9Ho`esJG+>8%tjnSQc#;%8#dE<5;_m|%Jy0h>Lm zi!UnRBuU-Yv#=Jt=jV_KdtMjNTo&%>6C#X$^OAen)M}rZ*UaS7;NE(na{y>nA6aB0 zZE?0(^aJ~Z#X|>#uI#O&c&fI&E!v-S(4nZRe*c7>RN2FgyT6p>vcJ~#P4@9XsGQLq zp&VbJv>ICtqigK;S~_pG?#BrTi|gV|@aswYO67Mg=0YL`|QNGU=_zi7nBolhjE|5`Fc1ykM~#OvU{oZO;B&4ld1E9LAtr-<>W3h>egDnvLX}D_Wlu^`QnHVXBs9@ShWGnk z`5T^*{`{>b+fJCp@Iztdh@6h#qw_<2qTwA!F-mcIC?Cs6o?n1i6xp;l-7X-CxBQm; zsF_1(039Z3C^dck(QG5XR#8PUkl@20Ir=DYr1>qz-n+Nur@;mt$*yEmXA{>SD1IZ1 zP+*cgJj45f`!fS0Rl*!EB;oaIVd3eb^hY5TnjPVfz*LP|59Hyn(ek1pn0uQ(iQLaf z3X9lqC-CCz9=)IW7g2|Q@D1f3K_~qM)~oCGjtd3Cjaccn#VVCrIQ2P=?DGZ2_hWi_ zr(S02*LETO5UXOgRJeIYkYMO7SjRnRcvi68U(u$UcN{FlQ^);LDXy*$4!LVE6&aw7 z0%c=&LKugCECPUIv2|_sK(&>F?acPAmQDvGcUK(0n^fGz$B^gx>@@fQT$sa2{1GgK zq@N8VweSJiv}~LUyZqhjlrHY^QxbJT;%u zFDXJ;hh3R10z#u@1MZKQ01U{I57~>)Df$1DP`as)~4Mvy5K<-fNZ* zXC;SAyg*3gy_-s#X~Yd6n`oV@omaXqi9%_en>L`k;YWW*&hv^-_&~zr6@2@zMF!RX zcx$`D3h^JHk`SNbx;o`jhlUHzd%R1vx6P7wFqH&W{fr}1&@2BmhbK7#RHVKm!vKUR z6H-T`S3mR}A&oHxV>SxkMNKuCcKR`Cp}9F@yYK#?PN}xC8qJ9qLA;~qRPnvBHUobe zVRhHSQoRfeq||}zq|i;82)PJ)C8S_(%fk6BU64 zM2G>vzeH}n(DVrhgfy)CHv|MQKW1k?14;sO;T<{3PNMUlgd~^$E@1(>0{;9bO$uO) zzvy88Q26{q*z$Kt&4GWdk@>qW2cX`2uY#D%(0?iX`G>Y< zC&Bwq8lr!W<4>Kz-#hr5*607Zp&TQOCc(Ggl$1zq_9+v4mk6uNsg5iP>cv1|KFO^GjK0hn#pQ%_L^O=3U5 zSAnkT{|oKZf7e!TTUuIJtl8JRpDXykHH8n)Ee~lrn}tShAy!BAh@S`R{5A|~MLx$B zigwoumrZ1$u4U0&1VoibEaz!4j2ClZA_*$%I)`h4H(`NZ9^Mgs5#QF$Et?f^IWTcE zMs?9*946%Rk(RZLoSsNknMnNRrbYhO&~1ufTuDH;g6t+VBu5I;sH{#E44Z2~eu6h| z`S?_l<(?;ykt`7b{;~cyhuChGz+-q`KOri9nYa)1UFhdtVX4FFf=|6`X7*@3FMs~3 z@?x>8cvg~JAeg8;FsAH~I`8xD8BB7l2~r=4ygkV7Mn12hsd@1Zb4c_`mP9un6-ELW zTS4+Ukt&t4>#`!Ry)o-UqWFY^L+D~6!1|ZHpCN0TNR=@jtOBx)&D1EVm|R56#V+_1 zAgR&5iJxfb0Be{A_>x*CHZkGSuCJIPARVt>mR9Wm#5Dn{3QgidjC1HW0v(tbb!ST!7El+KWL-2<5omnzAA@l=c1}7_&WP0p1i2vd!p4VOF|b{WG*aPY^Z~e!R5l|ISlv(dL)Wn zNm&Nh1@j7Lb9sjdLX5vAx zsNpE|!vgMgUK%PZ#iUl8Qg#?tb+lX65Q5BUvW+~eVG0xl!k*ijR zjPm`he!(Dt8s8-B+m;JJm(H88w&X=R7qIQWv4e?K*lVtmo+&%LZnaJ|_z;6D)5W2gz$S^LOfSABx;K?*htqP-)#ylg# zTw*F{HY_tUHPKbfwZ#Fnmq_RCVW_EB%VP2BgP0ibdZd!piucxVGQ%qP+T zk73N4g%0a!SgjlAUC0K6AKA-;)yq=I%mQrIb5lU8(H~fXOdDi;vmYjHC-!VZhGXI< zHue35ty><5Gi%cfMZ_7fD=|~b{fXi|5!7z*Fx~z8qhMwbq;@e~730yf$&zdIQwpi=UoLtte)AkOs$Q zR)`Ln<$b=~k1%h%B_Wn}cici7DG3TcrFSDe)^+bpLxHT^dCy&o9e2=v<_n%-Zf?eS)uJzuC9u|5fWxv{aae|2V{3LkQs<+JZT;34SpaB^`Kg7H>_3u^@?nW>&V zIWjx{ci6M*A2<9@VX9=y?Rg_@Rf_dusI=<&=D^PFxscBL!-b@wXIeOOCi(m7FIhF?WqTRdW1KHHOSAx zZVi6~S9_V36ZoWCwqi6>YUhTsMHrj2Guz6dX+Wh#A!^;0_}k*XKa;65GLq)!Iy^4g z?Fz$7bYuNoB@Lhv*m)mAyQxJd^@e#%a-rGS`qGdLXwBu7G3ai)IKrd9>sW4oa_-2p zg&1GG@Ts-dpqa45{?p|1mj>e5R+>wx^F~Tub)qw>T21+Z2GGoc9^;ZhKjV^|aKKga zU**fKISH_@`)G%zEIb%-pf8C?8VD5M6YBvaI>b(VrMuZyw|4WhGP<@1_CEefn#|R@ zZLYz`j1L8oS7xqI%gl0{S2ioAC~N8~n)wn=gcl1jcTVC( z$uGY1t6}DD3=FUlqVH_wYDfAtGL*YN)sAgb&GKU+aHN@*m}ph7sL-d{T{`N0KjR52 z%}Jro;6+SjA;T}qn&wJp5=GS{nrZL$ZRT_)x~y+CId|R1T^F&d)3n!459A9ams)Ud zIBlmk%#_$>=afYd+g97A$7sTOOJCS$CyFoyX!CkV)wFPkA$o*97*AJU`DpN?b&2yD@+I#8&P!`)uJ)a9S%delwON68LTwtF z0IJOf>oc?$^m6R?J68M(Xx!_H?z4(KEHKX*C?}_)G5*Fq;Obrk$zVv3G-|jHvbU*1 zzqd(?D}EPf`)?N@D#g?d|Qi@U?fO z?b0O&3QVq4dG&OcO@&NB*matPeh}%NtTa;X;eVk{|JO+1W?N-O!i`AVGKUxCCh*R< zb)1UpaH#08T&3?-(K*#~&bUE8Q}xL2+bIAgt7EVF1xdrQEE{wX$mtc`d7WE7GX&c0 z(~W@};vwwrwK=@D7_Gqaz1eMl902%dmi{*Z{{cwegGky_>@X`C)u92Yg;m$Ym9=Bz zv-4cOpX#2q1TAi@4y)&i+KV_N6^NGM6I0nU3<%tLGwRee9`<&WQSn#w1e zvayVPrQ`QcR}EmgwZ%AGAT7&ZeC=Ib$o^{c8!v|C^LDrlM;5s{u?~={8Cs#8ZN99G z2sHl_jA=I7XxC|SfSpearIZ@EL~K@W&b-PG?5`4JtCFh?m>cnqnP}sw`ZRK6d|^+I z-{+C>j6~j>pH(G7y`DD#Wh0NTh&U4f{KI~(Ko)E%P5s-#&C==*j2!ekhSC3^?iAZB z-wn1}GJG$1WpDHBia$T-rQ;v_^w>KU_mCf&fqr(+;%j{Xdi9JThdcrN=+kK1eN}}@ z7iD+@P>;D`4YnFlO85ZO6}^3Rt00=&b}hiuYC(5He$JTY2m#9j&JO*&^S3^Wj}RuXpy1$qae5!CR2@XF zky=)4TUzoTsRbSxz+3R?_hNsQPlMy8;BIr-_^nXn3D!)S=KbsABL7@OzeBwj@81=; z@e+3!k`(vKJUVLX;>C;4Sf$@i2eOj^Kh|;&7T@zB!UGP|>7-;QIQ4BS+&+K7HRlw}R>L#QN%TgbxR;Z6b zQ73M#%MYx`=zKk)v~yzRpQmU33v&Qol*KH7URHHnbhdVE)5lZo*B7#(P5IY8FXU}F zgItP(VL@=jk3n+&VQtrD)4In2GWYdA z=L1N8lzs>FpqJqyP2|}bxLIymPQ>?!;jKYVH_TZSoECKz;`(Ifa{!%1a!P%697!ncEDpUpvUj=>xo=6 zs+xyP>h$cp+sSe(5D0|T-OJm5g2PiTu-ilI#;?^v{{)9pk{%egA`7fwo_}9Ae0UWQ zx|0(FQOf|<1N8gTya_bkWZ`7Nul1;vNBAM!h6Bj^Fkpvz%~GXJm>X<59Yn6*Q~u| zmT3!@j$nI4^T6-+$OZq&dI9rWT;vVwz1Vfb-IOlbz+@i+usf!AGqW7x7tYZQe*yFU;pR)~gxs#{uuTc2q zwa6O>emndNL)c;px1r%(dRii+P_SG@9INFS4rrMa8CzgBgCg~oPieOUfjSvbZL(}` zZU#=g-8Buq=vBfM08i-&w^ds3d_6%SDdjk8LN6?VDcd9;JgSQd#A|&P5hpCI+xJ@0p1yM+BRa7&RaYaK z-Ja{rZsI9^t@Ios!cY3caW5OL$pK4Yhb(1!PXRb4TOv;Btdw_hx9=K?k~buRcT0az^aB=>WGOfvFsj@( zbv-(0mao#?y*?Ito)Sr71YFfHJ+zM-gIeMe%P|w$1L}RelN|Y9?>fe{cWfPX&_lVJwEQc@4_ z^#GS^3>dEW#tzS2xEZn_Vp={2qh#Ep-8q`} zP!6zuwgxNp*g0RwV#j~7w$?yk_=DzSokWxe0s^{D^?$MVmSI(HUEA=oQIHS>q(f1W zMX0odq(v!>fPi#&he(L9Kt+)5l9XB~Eec3T_aX!Yq`T{#bD?hce(w8u@AvuMAK!6& zAIIT#gK)9dbKe!)^Yt1Jcfj2Co_dxYc7y_Jd>w)$Bql@sKao?DRS&$fU_k z2xKyLcPGw(?>i8P73AV*>U`LJBDERX_GV5!7B*mY8b+t>$DQxUl$Kr_*#9n!7HYcI z%7LJwhU;&3_A6L_h=N2My_|~eYQRz&i?_w(uRi6qx3mWl>&bkzd3a>GQ|IJl@jCJz zo5^6=5cpZZE&TSTruHA&vB9=zl2&#&owdI7tK)Br#qgG z1a}rNl;478RO;T|o{Oo~J>}!ruO%vIS0x&oX$I#|Q`-VUaTNx1@7o>yOWGq=`P)JN zJ`WRSz~YH{@^RReS)Z{K8HmD=8a3c*AB}GKVHC_@NUAkIs>npBR(Tkvkee^7Y zn5t7-Cd-Up?$vo`?aCxcYRFlYEU}8&vVdF>EtOx#@)R@kOrs(JLRKAgl9&Z``N4Lm zS2JKM@mWi`*q!m?(G<+mLZf=3^}a5g<0xp0SDZt|E~F6>)1J+5X%@2E>QPE#e1X#G zCYY(y%MZ#iB-89RlXp?)7i-xbwx==g@xo8G%Gs0$eXIl0^xt>R>|fXw$VO z<-_1|8h5<$%V7-9IA|y9j}8Uq6rOC zY`94wYm2czo$9=Y$$-s>(ZJ}JgU(%xhT}G|M50%!$)@b)SudXDC)r=^HJzNomA)tH z{9r41e|n6?YqxrQV3KwZGd=lSlaCeGlJVJYEvH&r>_bOYr+Lh{UhUpk5Le1RhIcv7 znnlRfhN@o)J$HLQM^k{eWGG4{F=YKN8CCE=n@WPV`FLYE^Lj+u;@0jQBW2s0d6hSX zu@5WM)k+L!m792Vv%vxj07B~D{k}-5PfWtjfcOI$(mZ@Fvk{7mfFBKcLO*X-dQJ}8 z@8AddE(okhe062zJGMxOdk%v?L;>JG<(muT@v0%xXoy2O44GJ-u7Pc#TJ5E4VRK#D zfh51vef=eB@~ObZvFX0PuZF$^(e8OCgCb^bU1Yi9*^T7)X@mQ>&zo(aM6m3gqdma8 zAqlogy+1k!Wprb_Eq@|;Sz;|n$fxNMcE4fcl++ca>_%)5olWK_b)AXHN!=^iyIuxU zT>Xa&#)i{Ann|D|!Gc+TGQH0STOumksD9T^V~p#rg3*q3we0|`3^Nz78QNcNPI}Xo zS>G+8?g;dNb5-19#s!R^WBq$a_fB(*bU%syWZ2LY?{fFfa!D$dRI7;*D&3t@NCgNG zqyZxZ3>9I0=;X57WCO^Tlh$uo8rRzl;bDmvDf__H)zuL+cX%X!;bwqp z1cLIKkF;Ln-D9wsHZMN@Xrg05$%RJaN{&Mc!(J7A|FGlCnS-_;yM<27f_7Uv?( z7{8-jE&CmasMz)w=JmIqPsmcK-S9QwHamex^Y3gnZ5F{O9bbDqP1K|DlR~mGQ}dA} zz?7lcS)TyGj8OeQMBl%g!3tsp-c!Vaef(>hG?91igm|4NuW_#%PK)n?pTs92`j zBt}bNK{(0NMEuKlK+e)RQy?} z`t5bx+oavQTC$IpV$-cfaqEA)+-oX7R;S zcIuppS2@WAw(b5Z-li->U!>0m2DNZA>x_oAYMqmA7U^DCyW+-Og0hxMa@a}hIL#4b zmYCL$G8)G5IFuHcwqTsOaU{YVk}Go!$;RSm;ekZV7Nl4w2w)dG%8(D<$E@`pe>9`A z?oN!%Pw!hKju3yu&(8DO`+cs<^lswZN2UO0D^X20yE~h>8E?0GH<26bUZIFDFW+8S>=BtX| z=(C*(THfg6yq5*GY92Et?KNteRiuX;gT~Qh{EV`jDOt>`?mbhh;cmZq$cgAX5M_vu znc`I=gl%nRsb3boeF;SQ1y*DA;1JF(*0n7L+!6uCi72<&%A-z&G?=`h_h`$C z1nnXm_lp!lZ`Sl18^`^N#+=vE6!oX7ZTVfdY=BAy5Z?cm0C=x4V3iOSHem};(r{RK z8o*5{Sga3*dRg&5`uXxQGBU8l2Nok=!axemVIE&LbFMEk#@&=1C~mA91F{P&<~Trx z%~u1i8UP9~Aau}e^D1i57-`p+(4Eca48BkjxKz|UptgORKyGkJjI5jPkBYCLQV1utfFse!E- z9O&4L@u&NUfPesWJV_TlXh&te1)1Mpz4@y^!lgKNvSH-Iq3x1c;)!u&7#|Z0=!+eo z4Zky_2dfL{^ybrnp}%xAS*zu{U&d$F7zJwei)>hjkrwA8V6)%{3AAp(_Wvym7+g?e zYbUtI)b3~&+q-VfL^lT^gK~z#=PwKVT?&Gw%7E2Xc~hL-8IS<=0Mm>h3loz?+xWr1 zWVtI1$A!(Up?{?_Lt3W04Di>rmgjZ>D2qU>T{!Sg@zoyd%Tj5fU{$`#?>e(XoQGH& zzasM$efGE=ekw4Z2&X2d$T0H1Goa9H@|D@F0`TFmClUHkrNdtheKMXG|4r0J*5sUS z-TUl)Q7@#BzG~n^46?SXY&_vuFAUl$V{@U=qAHv@TEvL3XFs9+%A3d-ZbnnUE;k8# z3XiH&vFx#D|^XxxxPM-bb8^r$Q2 zd-8NHW#pmm^x~*9dZBVn0V7?c-=MY}@=lR}JK&`UvhGhzBq2o{Bu9R7K7O_pVO#L! z-jAGL!AZ4He)Ge})~h#eM4?Tu)Fybpy=vN5aNT)rW~T7?Hw(@Ka8v&8PBs6!7w`{E zkvO#T^~r`fH;Ria+aOny2>ma4QG>_rYg*@EvqbGdm0DVC%>rpk8$fowiYk*}i3{z5 z{xr}5d;1UTo`3L+RA*sXNQ&Sg{~MrR84uz-hPLOm`DNG1!PQA{$_b%wl)LGdr>=Z% z;BViR!GF9xdV`qy2;yM9AQ30d{vY)K5Qv^P2RDT3`Tw*UM2uqXhd@dI9FD#T|KDf> zJYx9$ehPmb`&#%Q$^ZMY&t3BYb!rgDPRB3K-jxO)w$6zG+6lU{PmVxBX@~Q8f59aJ z)9%cna3JW>F2xZ3m$Nyoz?9_4Y~{C>9xpv8+j1d5%-sDMm*DgB)ouuk&#dQS)&;By zLarJ#61aU>CQ@&km6}+hKj)%|BhKD516iZ|V2vyuf}IFH!Ta5VM2?XZlT%Z7B)1YP zrb0U>n~asd8+YCxn>a4n@Gp7+-4q_5Is@PqO$CJYKmD2h3CUw){6D#85RwN8y%Plm zMZFrk?FeUzG6Mh2$p$dL6Z|~v;bRYr|KigG7VjTcP`{3otK+8CvpoV)ZVTVXU9ue4 zW_pA58pB@ZNHu9@x$x~u&tsMfjovODhC2im!Vo#aOi9v~LfIfU@2|8W4Z!E*zA0)Uvm z9U|cPke4_>wS^&eCoiF?sR`aD_LBoEEw2BLyY+lTuzG1%X#ZY$>J9xUwmx9(FzV7= zKJtMo-J!hNnue{(nx~l>;nCEEWkVte2hlHKJ>dFnt3q0+cokRW9iRPhWZvq!%Xov~ zFs7+Fh*^Arq84Qjm^3L5no4-ocMCat^ERSzmjy2KPb?Aa?=N-G>tWzBM);+3-mgbJt!x5HZ$#YXKT`X|23#;83=2K z4oEFPUGw}AyvQ=Tg@Exz}$;Ndzo7g*@IQ)s8T+D`y*VPxs?H_j*%IQ+p zihG-}U>znrU@859=Il(Aj49 zCeH^FG5Z3&ZV1Fw`~lKOS8Doz=y|sL$j96T8%)ZZJPcv{Y+$!0a8>fsF1tM$iKD5Y&-``CNYXh|9AxEdaGD62<1Dwy`+NodgU{0%n6o{TH}C zFZ&6f zhDjkI;QwuZ2qyi_r7qzz^GRs@7*a%YXzM zeGN!BE}sY$6k~{=7Zz!yoQ|+B$G7|{ zC>50KjYR>f`=6g0LR+k8%a1u@YKR{;2W=3!~F^MTurn$t>e=u0(YyI z{c8Q~O#EFf_w?is9|0lxpgo7}8_2gTdMAsj2#Irilld+qa8n+vn@M z4eZ+`+-L*CTSN4uh4O}Q({;OnC6T+}hSgScP+5fexzoxyrIRr(NR)Rno6u_Tb^DKR z4SUC8srZ>hTCyTF?!moaGxW70T47qkfMR-ohrm5tVX4NcpAGiYR6zg<=-Z zzai)r)`Cr51e$k-up0;&pD3zjNu3G98|I6pBR$^cYB5|l287o76Z*KDuz_`Zf9652 zHHy$4?m)ZJz51Tqg04ST*2S$f?ApKYsAfr&C`C(SvUOEwKKo=5ZPSuc>`wB@BDFs2 zaIU<@1+w^11}dc3EeaSeN>Hl_)C#%uRXxy1tB?M0HzB=wSjmEvO0|jnM~O7b_=O*9 z?fJr7p8YLYeks@UJKvrtb?L5~k_2^wFgo5@IJWG!-K($RF4?b3Kf;iqxzMYiboZiR&Qq5HKt;HLZPjwM}GFS#aq7qmukUi=9*&+E!jS(Cf zzMdAk2-=4&hsDEGpRr%}>?8M~JKRF*z89rwIz(|B}2B^ zyrA(-G;Br%5SVwH_QklZd`~HudMh=Vpy0^OW1IR^W zBtsVhFVrU62eMSy^pzIqcL$naS{MFK+vB%Zw09b*&YA?;kv3ws(@C|GX8)iW#)b|( z{lpRCE{ZSVaQ6zf_=vdc;QTD*s)L_(kWb-qKBguojdn7uNPMGMw^p`zJfYRn1{YSy zu&i}KCQlC*u}7D@=hvj{bZAW0Z@xQ$nxS>ai`Ggw*A413CeD4h@0PW-(YJ79bd$Q>|clftT1p`pw0*_`}e#%2Y~C&aEVz^Dnjbr;9t}` z;6(i(`2aGfE1f0Gh{eQsqjT_P>be-;mAUlp*tE9sPWGans*tPU#SJ4*=z5>(c9`+MJ+DR(Q(9!5+o{9=;EdGU21eV6aST2YMZ`sWjJF&hk7_T>WCh}Jupv^JC- z*#9Fvz>!wYk>Blpe%cRY(@p(wgQ}|$69&7d&ru9UO6&>E`t3itY}dGwecd$zFl-Qr zuMDLEVzVTJq#uos7QoUb(}?Tv0QnwWU-cT{G(CD?xhHhDrW&<<_H2peJ#c0-4bOJ) zsk)0+0Whd-ZeYxpon0Z2cRcJmFxG(L9S_C}2Uo0mjANeK)rx0+;>3x31X+rzy?xOF zDUUWd&;e2MN*kV2=>d@~{dcD)0Tf?xr@fuwb90@jEBj3%@6 zKy)?fRTMpa>p)mK{xu?$Rh91|T;M|yZJ_O%lC$$j6!bTMziB^PlKKZb<1MIIorSt% zvm8LW1l?Nz$bBVrB{G*oASA%M_1G0--v(qoneL%oZ7fp{He}=0AlM{1V?LNU>6lS4 z6`nN-$)`xLMpO_GVWFZJMxI!OI~rG(ZC!xl#X!?^OsGO5=^+!H&Y7(z0>Cd4Y`5hS z$)^|`S6re!NMKbNGsBApwJa*61i}6?CME_19{|pMIy*cq)@enQBKH113o8CDJ@edO z4BNQfGC(V(9C@^A4f@37O!QTKpc5;-926a+zAfjC`2p5_F9&E8M+;gG`>F6?F0Dbl zr)*nyB(2pctxb zBpBgO0U33bBV+fjdXSm)8@9+;^IoN+WyHItmjub5KjPjC{G10uO*t932@Z@^7<`gW zYoY?5jpAi21yRcEHw97gveG?<4rK*3`KcO*5V_0is1uq}u_ceS(5HXg@E`yBCH=8d z6vx&&-Dh86t*>8(d`8Ug?6_WL5ismhzF_KA5RYRyYJO{Hz^_7xL(z=rd-;3al^X~P zx}P+Z?6MRqf%CtaGFi627zc$%{B!usF`Ph|BHnUe8EkN;Z@sPCk{1TB%?G0QpL03% zbX`_?YjOkL>F%&BfL_O(4~~=2PSdEukX@Q#drER|zP|po8|^B`Pn>9n7;7Q7;*RSx zV}Y8C(~HAWULQCvs}$%s<7J%r#7sgv^BJ91WxB(EM$3GM+6d3Kc0W4a+Q!~KHT>E- zwcwF&7UG(p)kqK?a$wb4e<1yKQBpZ zN(6i<{_bI)B6gK3wYYO|%K@txn`ay8)?Vq0ofCi-{5al3zSmYaZ(W^C=ukQ5uqAW3TtX zv4L9y&7(HbQ*-j`b2@Hj^U=NPo)8f9LVhOQK2khl3bb5@0$*zp^SwDRF9J*8`WwjI z1$nx&GmIR}<^(V6)%c?8F-<^k@3#K(G-E@}%Ey@CyjjqjG;^O(l2&rWrQ!e_M`+&d zd&}W&D)FElE1>iP6C^~$P1xwi8feR&`w2J0azgeTwkL!@d}5+XNaQpTSzt_1zzc5) z4_te95*~NOphvPv5#5O8?|w~QLZ23k>zWzU+|6+39A1-FwwvvZ6x`c)ymWeoD#D^- ztP=O$cVLZ@1W`IHN%tyqmk=ax-1RCL&3ahE2^*z=xj}@Bpt|>~N>O{@zRc|&T*TKb z6YDNevbz^?x)*7&@f^!pzX$mq0-%w!RZk!x+J7XR8^|M>vw&253v@8`8!Eq9K;1XM zsqSU|I?9qqZxpjuVag`=ICBEb5cn8Z8NA0u&};|jk6wDUc)Y3=nJ&ZU(@lk&dZePgQZigpg8mU)kNbtl8=# zx>#QsWAf}N1f;trK-BauoQUd=26_bnT;0S|MXiwStD~*#CG*fho3x4RxoeqzlN4Kd zIY0k6Xdt!~(e_5oAM^0DwE_s+Hw#FZd!WClUSxRP;nW*ewXiw&#+H-p=ZJbpo7DQF z=bUV;i@~Yv(ooLuBRVYsO^yqW(F7}dfXD$A#=Xo3+kk5w{L;G!=yGWz-=$f4A~2HG zYb^oGJ%WXp#HqEq6Y~vyWU;RIomTu}Qwyhy^rj_8H;-Z@dj+QqOx+oO2M_+CS2av@ zYWZ&ZioBEwd`0hoX%ndCiQ0S^KBICi88dfb<5p*k^yZwunnbgxKEGgsRN4pm$iIy|NS>nL;9A^IXwXnHi4L&J2V{{n74J2%q>P~QdlHEJt+D-+}* z(=8}#t5NUl7fa7=dljR$Cs_st1`Nj=U45GoJP)J$Km!D*x@YO93KqE9wxxGkYnvy9 z_U719-B;i2zuqkc%9CL502zmHS8d)8BkzSSkQ(?%&jOzNJs%G9$xB2%O%W=4s<>vb zwPB$2PdM^lGK2vZd=`4j|MbZ(UW=$-een>Gp-rx4O1DntZ`k!U;|6*Gf7v^wXav<; z>3Q($sPKXJJT>d!Q8ktT|B0FZUD=Awz5eN$4|{b7NRG$UPvIea-T%e){-1B- zU!tl9koGUr{{L4hda*oD{E^>ss=^8|qM)NrXiIwA@#eKz;Cbicvpbo}sdsPw&b1WV zF=K>zW;@(AzM>%i=R@K>1T;5End8uK22*Z)X<)s_crpZ8vV>%}6J3k0fP*I$nV zjV=UlCX5q9)%WVIo43AlnZ?31lLE1uR;qi$Lo$%Pve_jEwYZKMBu^GM;_LwBxc#oN z;+S#rCr4Hysvv@(LuvR2JsnaH4x&&ALW<|l`_qi5+15A}8vy%D$Dg@Jnc+MN)6=C~ z2%OgZwtaYH06GhB4nsi9&bNEEU9tOo=xZO*3~7zfn}lL+^x5VMeYvw^7isT69J=?+ zgt5zDD{CNsi#3$WDIN%-pGe5HQpD@Zby8^QHJfX^$u6B7gmAAO=2Y%H1YeK6J(812 ziF-fM$R2_(xbCAa(1q0y5;vkRijB>RC7j}BcK-x<(*SI82uNE)R(*%)NRwr~BU!4H z(7qwsbjSMS;*F6oWww~Rz=eEBs(J5v#tv#Nw-!mkFX%i7>BK{{(NEQ=_r#XeCXG?R9{E z{Zxe@0#qzl$?`F29>~LOg!Cqf2}^}(cBoUmIPN;<+)YgU0lDQBHJcB!0g28~%_6jh z-VBu^!l{7n)6p50{g|4GGqvIfez`FdDkb?fQi|C1C}NqqA`m$s9}>nUVR~jTJh8yC zzlYo`F6|CViy+|)SC_lX_UYb*!*WuT+f_cPl2?+n1wwHikGc?b)$D3xpe$R@uK8R> z6(BIOa|Zg4`Y-DH&&tVB2A!*|-A!EL62qaat+gDDZ77cI=U*#j{Dy3zo(|d>P|9=f zjyjh5c>VI{a%C(U?Rrn|xP=Y28;6Das6PJ|g&Mo7tE;~ac3+8JTlUoJ13P`UPGGvN zJ!j@ikqsIr6^rYk6t{zeN;#vQb}|8B9A)c-J*Cr1kHzV5DjovuHQ^FKz<}*FzGoaR zIyW%ntcN_-epy2Nn~nX)*pol_x&N&U|DP{DacZaZTP1p);*R@TY^;nB<{jhE;Rh2# zyW?u@musnm4?+&i0?B(c;J4Zl%u2NvFP#n32JhN!2m~Ug+Xvw;;HTcp7C4+zDev?S zXA556*>#IfK3Zz8R|3Ue@LW|gFSFOZtQ4fvIo zC$B;^m<_-OmO1&tLACwxphXIc*~8HZ=Z0rBS4_W{2?1T!3>qRtsSs!BzF!Pr5}U8$ zxJ!j{sM?1h`GcHQx7rq7(5N29hCxSe1=s|{SMth+ScMJ5XrMR~nOkl(+qLry%saJn z8l+f-R$V|khSia&jZk^2At?TA{8~Uaq?xrD@%+5!eGDG6fM16e5IbwS0W+tfYNu!4 zu);B@j4TF3XB8ZmMYa0v!@|E#=`dNZEMSgQL@$EDG4?m=>!H!<4kWA1gdRzlAN|z> zlYl%S1;wf`Iqu7|zT^t1RQReN;6Y;xnvHM6s>!}tT*rSxI199iE|s@yrK5$enTIgU zptMM}FQ?n-INFUqayyEE5#jppL?KLBzP{!KjwR*CX{ZkSwp#jfmAr^6v_+Y>1ZIK3 z;nlfh$mrn0Pf)g2)fbkOiDRjAj-09~2=UXjL=7=0do+jWyTpcSfEwj2jwZJ$CYYL7 zr>BM;Czp+h{z@RSYM{oiPFpj#F>)*!2d>99sFWV3`%Sb`-Bv4i`A|m}mon0P@X%#> z!^!W3@LG>28MYr?sf=%jx>xwH_&!5+`%gLtTx$QDQ}$#7zFex5a#v?(h?MHl4w+Fe z-67Y;Sv#|jH;09XV7RzC4-HKn`$<)?dRp~>3-DJ1DY%T+Mxgp4IT z8cJBpxze%B={M*Z^1gX;K3@*=C!dnRhLBw{JLMsICVm=NwhF2PN7hMTQKok{GY3>w zLfY;SyeN_o0E`F-Q$i|Eb1085cD4o+ToG7g#KM5a3DEMK*Ai4z#7&7R*8r-4p-Fho z~cOF_*N z1GCisWN`}b{yKoDUe(YOCb$AhU^|q*7R^j|Y+hSdybO3Zdi0?QM%22caDWTI}@KPTi4 z1*D!G90c4~2EQZjLJeS|({TgZV1J*1B=9%H#LR?|f8z4F`OKB$q>7~p(HxibJ<{#x zx`Qli;)vJSC-^UuOECZHcU=0nOY~1t!9Udb|3RkRQP?e??fd<&q*e$P6Tb&k{oQ8g zZ)2+df4d-$SAQhce?NQwMn?i*2sqFGF`(=Jo4!i_OgD_(0iM8p?r6ss^MN(xLC?3V z+_9>mMF=KI$O}qZLZ{d~`&T8*e{{F8LVqxJ&i0S!@^324DXg{>wxdA<23x&gO@>?= zhW)|ZjtL{!q?Q4VVjfNYcM~*QgM!U(3D;4}W&;cUpigc4M_v|>t!-ctlN)CXNGSL8 zHI^1v_L_$xvbdkO*tpQ~zx<^z?fpOj2S#BjE!}rUpN^PDYEU?4PORe^j+QU><5$NE zDk0Kk4j59$(!!w@bwHxpI1xwKpSds13F|%7wdQ&)BMzmb<4ja4AxnYL3BP5T%_GAC z?0sr$b~RM9}>_SAWRY zaoZ?5;gX#%qZ~C*4k|E#Z`Q}+R1XyM*od|O)Cx|qr+Q!)xCnP}CotEJK3zA_le4M= zR7o<^u@3BT0G3M2mIOmV8DQ+xRP{;_&D50RyaMd!D4{vx=P%IYXX2F!VAp(x%jb!~ z^}P>1em>@ixQKrleh(GA87iL5E#>5UsVwJBF`M?VY$?S#j}A+m!8K1j#htDY>$*Uj zZ`4b^Mi&SKot;=g=SD&V7rNSYgzIn@7}QexoEbwt633%7YVBA1?9>3cAid`xkK_$F zUh8Aerhlz7@SURIx9?{I80^YJf|dSo3isu=x{m(oMmx@k2X%na>A{!^b^$2lfLDRO zd}EF2vu_1y4^dz^z@x-7T!-7i@RRFYfhMrTlGoti6=W!!)-& ziZTB}a|JDVi|W&5FC1M)dDO%iZ7R%r&8RCre3zQY&Q=oj`^-==POx-g#k{6O{a|Sb zUSI0592^aF#jUG-t1mVzlS5%})=S|Ije*r{ejqbU)7LzmbA}Qi!@1%A-kt zz%es*&t;plUO)W?j?43)J9sI=WpK~^B?GVeuQKq%T{XgX48JVG;N>8{q+Id&J8sXB z9(!1lgDrd!vj@=*ySoB^q~-`ZF=gyfGtDdF9u&ZHt53pquCLrY1*^L0R#vARHkNOc zAatg)%uZNB^KdmmMg!Kz%2i~T2g^rvEuXvmC&?HdKM8a~_5OO%WcE1nKykD4k zx*s+UW}G3xfHXrW=52catviq1cGA0|TxQkmhBQ^l%#n&#U9`@1-Li)vRpJ* z`oPo&lL@e|fzyZhad`%67;&i6Fz)lkIZ>MwsuzDH~PnqRG z`OIJ$|9)2DfY^&-;H*|F(vPEr%MpczAG+`N0ft_ts$GHh+9r!U>Usa0*sa@cpPy7O zoCMvD>e+a5Fy)Sv2Fz=*evaT_fl8YqOT1|DgRppzlAsct3UL&GbdJ5qV#d;csVfbL zw$n961?5aBXVWUFg_z7TgJ`Ac15tMdpPtTdxfB?5;jrG+O?VA3AXK!&5HxCRZ7&Ep zrTM0n4ip+I0bOlsNeTbgDBf$DiRsU^h#8cTHSYjwkgly`f+2ij5^#+&q)={H70;4z zv;)j=>U>AfbP+dKz~>qd^j*tI=kgq+9dZ-3%MJ_6Bv0f*OD3CBRjgE9Y0D?r6SWHr zD`05?W1HyDCRA}pxlVRY)@{#!VSb`>uV1#nf8ti*J-eQxe-sEME}K@tH-)8efZy)0 zsj~sqGT=Zz{-lQe79eE%qf~eciUB!C+?H&!?av<^aZ{w_2lu)(Y06rXgUji!g<$t; z7U*IEcPd!O*<;(tEp`8B%gh+yN46M#qLc#Mu&k@S3yMGQ6`Y!Ck+zp$E(%M_NoX*H zOw``R@}RBwA8q9e}1zq3kp9Nkx=BG?# zwWaH$Q*tzHozTE@Hq}40scs#nOy**MGmGsgJ#zout_2K#XBH1E?|$u_+ann}XW-f2 zwlmlI4V}x!U4xU%y1N8C7GTpBB--Xw8B${}vpP0UD`HDX?S$c)+_@9249LJn_ z22YL`T>Awe+B}aJ#OE&ct^-7)AuN~LR1Hebfq>i)aFtbJmo2dO7E1a4+d{;;y|+Itlr7c0TPxXa>MA5d zAh4`T(Jv51d#n>%s9pt<+i;x2Q;A{kX8!P&Hw7L-cH24?R$Fq>?*g9sb?>zLCBi+> zi@bLMHZQM3y%Bszz$g|HDc0q1&BJ^CQ`0V3fk%jf75Ot`g;Nf|Y=}>x)Xr_|-6prz za~v-q`OFlHZF;L#=JH7&Z~ts==dC>kHbcPSW-`KGqFH4Fjzs}GWWx9|)*=YNEt`F5 zH9D*U&Ki8?kM}ope&9)-8Jq&h2^^J7EsfRhXVCk+aM*XmZQllDEPd9PNONk=-UY7z z2MWwU*kpkYbw4byw!3Ps!6(g?fICt7>VmO~GOXcs4$U|~ibX`X05Y1-UC+s2V9k}; zobml>HnZO7Cf*PH5QuX1)Z~NC_;I``V?`YR^?Rb|XLKX3><`8IJ^-eYfJeU!M0a8a zc*1}?BH^jO`)Ip<>%DqDke*Z3)-gTCn4x z!TWzCB+gE$`P2%xGi5>o{1*?Rd%JH&df$)z2UZ-z2yQAQT1%3*XT z9x=c9tl|W{VASP5ZMs~;uDOZiw^kex)uG+^3{(mr2EyJewv|7_#&qTshuhe(yLv&# z-l4Sa$#IZftEp8Ei-(~rJS`Ipf5EW=uw9DESo~>Itf5!UDpj}b4)WRb2OLd*4$EJD zUR;7Zmr30DwR^lq=5GUGAu-mf4a_}=`$S#urOT16E8q2%S5H;ZlI$#+2u-4+8dLP1 z-*xn((t7x#G#;j^UV^A=Y$fhg+=6i^L~2;Ppy!}pxsjAUyOzqTlpeIFKG-sVDzJ8K zzsCy43jpcHEgUMXV&L9zX^ERIcK!(aoR(JLe@YMp>u)VTf%!!8?yEIL0qGbKjzcQ) z9X01g<1GUkk}rOx$Y?~p;3AiW$Q2WiT@v_$ z2|tNAkNt-Uv~PJWe7H-hr)75U4(V(U4KZ=`Mo2D=wwnAf@VTMXGH<*;L_Wnemzods zdRusr!WmRx^z{K=YbrHKBI-(I=71XvWMW{D1DNy#fEs9|gVZd)0g+^5=rRgNK};Fr znOAIo@p-AMv-PO?_GU5K&bn_{bRzb~=dk@J-SBt7 z0fE(Hi??k7h)auR$nSJNETA(c!y1+WPdxzbK}j4R@S^w)?KM&M3hj~eeR}Ct^h?|$ zEQOu#V+(A?`ttIrJavJ^fz5JA>bUW?Z;@u%)JiGm6rfKfgXeSy5(%JAZ_Zhp4m$=& zgYPT26yjiXJ10l@f*nxXO+u>$??QdH2u{+ybriw|(O-U>z`7Tovs8Vzf33i@+kz|eBM|s5XI+N6Ie~?lAG;H@{H`W5edHi_ z`!_=)WB|&&^>b_l->ZX%1xCv!>m7(UD?f@Glt3+Wob4kEhpOAPBVjPX=)Obr-EFOD zB46vQHjlS5E07nm%y=&z6rG@4Sj!y==QaW}{YBj2U@`;p;6v$$6!x$h;TrPy z-oTk}(agUd6BO+(f<9e?g`Xj-FOG=`=ymS-Ky^`sDAxMv07$~RZ+WEuecu2-X4&iWd^B=gF)tlbty;xA(&9;jP0QN8h)g z4Dla5FwqIH3_)_MC>A-HmrU=w3^jc*raxy`Skkw&+iz+&{&mKn@P={u_FyEp+(k|i zG4PS7*B0yd?AbGe*W^jyuVBPa8zh5|hnE`yTaoi#TAC7)EpM!t=a#xO$+wA+w z3HXy5-)`K;{;l0j1HR?uoB!wnct3yU1-$ywnWrTGmwuGQ_I@H8F%gmXG2iJVp6H96 z*7C3I^4j+#ozFxqzB9Wj{xKaL8-jfb`nJE@| z9)oNfn7@CsA>|m$(QBt@;cLA<*HZu8B1Rs`e^yH1{{4aEV=1g>!_w8Z%7u5!4eeYC|hn3RDz!bw+OykzF>)axUh z(Pyf{4L`Ftrt|Pid#4}UT)fJGlqfEEeah^keVNC zbvd3TTN~;0eHf*1zr8Q@&8wV8M&9ncY?4eVH3q}awV27_<9R7#v&IK*h3}3AuH2qo zZ>IbQGcBJR6^R<5Qd0MI*URNoVk$l`Xs#*P*H3RpbSzcfK54ZfR@A5QTK5fGY$W5* z-nLd@&PA$aw62Pg8FRqxKH0YOSM*ZuWRc>?=~2;c59?D*7qKrBXwF=PVT6;!v#b4Ex9Td_ zIPYFn5Edb)z#GQdrpcVWKaC^jbFrv%@@_&3OJ%dm2Abi6y}}ccq}ucop{Uq-bN3#3 zWNl${NeKaWVf-TY7V9Vu_8^7alOJkQ3W=%{JtIvVGD(wd#u3I*!MQDQ_ti%nH4kBL zMV1?2nA?4UhwM6UV(rDPgUTgFz2W_>IjZi&He=G#y+bfy zizD*G=hHQsALW$UoM2XQy2ew|i;TkY7jU(3#yq-`J}djHvUXIpjcP_*ZfE+OuAfOc z*S02k31gL{;O5Zzc(rozNN?7}EKj~G3^y+5& z#&D{Pn3&F0nl~efXTLl;8Zk^hVD;nqwc;7Vs&@gVKc<#Vgl@=w{uu z&%58pbc|?APw4QzSg5mR_FAllYfs11`Sb7^)02*#-kcbsv_Q@nii=)zd@?_>MK?Yw zxR4u|*^FsbZhYgo9}}>9TvYaIjq>os$SL7~$f_O|#&^fg%ys)V$JP+Q&4Kc(CQ0^w zeR3;epZ@(fQsy5TqOwbP>@}~C9=GYH-+AOhQas;+#Bq@LarJnRvxsb!i$M&?KOGZdbRCH-P%Pv*DJ`VFgmiYw_fsoux#s{c=g^OIE=SfuSEx(Rtc7^S>DGo zF5Ic7aC)pH?n{+9`>L&&)lx#(_^fL5scW-Sf^N%8qsepv5>DIdQ+8}oZ*LU9sM7lW z6T;}t-S2nZcW#Y;zj)iqrC{ZK!gsMq(R4MZ)iM#XY;=Qk-fc^?y57X+yKY7W1?xPW z!R0M|DGwFJ9q44T(t6s0myW4`S<}WK;bYB)9CM@!LYc!{jrNo(4#{5ug!AU7L zwA}M(G0Qb#(3}SOhaX!^MEoM(`Yo8lBArUbg}1rXExF}=rg(hDLJ0VHN)D^*Rr#(C4TU$ z!kz-C4A&4-RRbeAq}-JW-E=zJ{VmbF$41Yil%lfdIr-k}qVCcfd%x3-nq=Sm@>oRW zHQhMfG~EJSoR9x*vIPQedxPoE9vn|30l~*%(LY>Jx9c{AQ9@YKG#Kt=N34! z@BJ2XG~mVZ&p>e!4Hl<3ozAJJ73KC1!F%a?{g~HX;&|#cItrNmCEz?Iy~HRS zEyO5=EB6*pR!l=1{NCs6$mrcEUf!nk7{4#haDCE$Z_b&0;a=_%uc}c|D4+dMH7V4d z`fW)4mSW*dU5~Wb-p7yQ;M=s@=X9*n@@^hWOC1_yyfC&p^&vgp^b4W5*j_ETM@ z;imEI`ko0+8n@*Xy|+5UVGaU;%c)92uQUaAWA>OCC~&b?d&>U$%`pC*T&|3y3%v>% z#3F>~WaH_@T&}_a+3vQt#XB>tik%dzt?@>@7Nr`dpK=%YDvjFRbZX&yzKJtn z>7O!@MtZ@fnVwwh1+VHWJ?Z+5&vaHg-*`2ANiQAEXdsn&kafSt_>j7Dcg(fXf;nM^ zCAd}Oo(ab}nag}I3Kywd@-n@2?Qn?x1_Q%BTs}V&XSo+s*6)*&($&)=OFB_rsroh6 zXQUG7;PNI(3hcD6Tg%e}i&OpBWrkCN@JWH39X>(|{TObdz1G!gr^`g%hv7T5Z0VhT z4c6n4LsMXrSnUPi`T28AI}^%Xf=lfb-O)59`_B5B-P5mL5+b=->t3ojMz#B0l83wN zn5?T>&W*J>OQi5v{dc@|lTk5}Vz_K!E#W*1cFUpTFA~Qlr-NqO?moLjl`H=I*%x2J zIIvNWtFvW!RvJtvUJ!fpg4e-7%bvns`N#^a;V&P-ySOfaBU7#S>c7f*I zKTDD5g5r+b8O6ymw(efcHbdXfW0Lao)e?|$R=X-6tkyancSbxh<>;%6sF69}QT7n| zNUHU4S7sDXoeWBA0GAjnRwBIp9cQY(y1Uz=8m%2y_^0ZOA5>|NDW+2pa01}MQ#{s24VIbpObYp(H-oxPIn7h~s$ z0`q<9EmDf6sD6hJE_UgSU;VoUg;FVwh$hw+b30`^$AbWTsc{%1sCrlfgSkX`Cj!s~ zuk(?!xGV;csPJBtQh%v?&H7%$t#@-M>S>JykWQR>z`82Ke@COY{ZjKR54|h?-UHez z4=ru~DqV6}K0O*(7U(Mb2GUIupO!NgrEeu^29+;xX1O|D-aN%>zW-*~>an&_fSu>) z$*;uIG48o@Fd0fK*c+U0hJx%K?^?3~;)@|RpDVe`VURlx| zPCD8vH^{o3&Of&5DwW=-OoLb3a3}9A2Yq3mANlf8sYt?%Q0~{)PnRCwHsx*Od*`+< z)&3phE|eL1WbDes#1~J$lT;N6xHbbNu8yIZVd2a|j+bXS7Q4T zQXNcuq1sG=pkp9oJS8J`*nCuO-N3-)CBrF3--36Gqqemxocp3-A{oJpr-ux@Dex}x zx@6S)8C{a_KfH!XKbBKx$gxE#r*&#*1r>WtS)(FVuH3~e(C7&}8YP)Qva{V8+*#K> z#5F6(lw-<&X`(UaJoSJpJZr%Lc^({?=lKb`e>g|a)hCN@y_z4``Ns8O-`e`T5Rxm- zmSDfEwcfCRYWN)CNT{^s(768lu6SQ_Yj>KO=>>{J-TE|1P>}Q)Wj<}~iy$|av!w}$ zJ^92W#8bFafPzLX=~>lLRh=%gtl(mFWx(B=2I1Meha`X8%pg&HaYmbE$q|VckB5Bl zqg*XBdLdgaj6U3tt25opeCv4Bm%Yu_BS(f-7Eja42DW&U9xpf*$9ZVfw51rNj78xJ z{)bg*%9Fe=QxOZ{uB&`1<*!*hd`u~ExJ+C4T~6GXp@>z~`MyL2M!1|-JB*aEh>8Wko9F~AkBwIZcko!UT?Ufx^Y!C*KND%#H+}d zG>vPD8}kb_F~oWA=q|+BHXDqI;kHl*y{V5U9$>EQ&+ZJ*OfuMXGU9ufzN0HahA(e$n%%1lz z@5pi1wnvjq)NOj#we^j?@a0x$aLK|ynsA{bSZIm{g)iio!2X0XJ=8#pL6)72@Gybu zaRgHGeROSB(CakY8>5keHSAjFwz-XN)&@^(;75Il>6Q*O_`pXT#okKc%}S{=L$b4w zUdQY*e6IG?L3O-c)owoj(%t#{>ADUPlAYSVqA}F0FUWj;bgZjlCQ>Fy9v zx?8%tK|orhy9K1Xq|e;`-|KnabDi_WFK$-Mxz?Ox-1l#cwbJS+oR}@UaTtpOQ|{@P zNIu0g^}^T-caLHZR_7~bu9BwGHS&b9dLw0`GU+0`e2*WC;+#N}7p-d$8Mp)=EE%Ht~QFSL>OlZICapAs$7%O>jV4l@G>_**4V0}-~-S8Tug_!++% zeve9va4$!Ml7q6*ASfg%74$x-F*38wz2CY0;5~A9RCtBn{8aZt zKsp+$`O_)8v|`Qh>dF#><-)n3VTV!);lkAIHe+UK%Nbwm;aEWM_fKUr{G3I~D0<@V zyN>6viEhoy}?Yn09i>Q z?E2t0N6YW;MNXNQxH(?-vm|?&=H6F9*>x_%#Ye5iQT#82(T(pSjp2~@R6FmoZ!E&^L_9|xe}sElQ{tagmx4MbH-tUt)lNdNQ1#^7-5twScAF_ z(=Bs{?^PF)riT0D!Kq(GLZyCkX-kV2T$jc81<`cwH~3i65)C6{25B~ksn>@C9Qe$< zpNMMC3>l6o_Rk_c*wn69v<|svD6Y$SX;+&*q_%lBQNDM^SbsG(5oB*0 zWSK`jac-qBY9EA8IrWm@4Xyjpou%^-qC!!iTOT)FTd2^vqd+jfOCv421hyWb(n^Mjyca2jDG>S2Mj{bLh{}Mr!+J_IU@cVotmVXB?o;)9 z!8}hmj195Zv;>OAm#2}FhysYpe&%JAO7nT;u}PU)T>1zD; zct7XSPH-?FE-5E>ubpd^YLC?1Pc^jo87SjbFb7_kj}FBTo9D|EUfrBs5s4cAZ=msK zZ23b3w!5=kT#JotHjO+gL_3_5r;u5@A~~bPR<`>nKE`PIH7^KDK+=XweoMsY?2JKk zvZ%H|u{gBwWBs?_)B4(*f!acFisd!q2smp5e}RpR}$;P{0KRb#=PwVVO6k zn1Fz;t-e#+g~)EU5!=?nb376^CGIr@1YaQi2!G|OQNUun%*!^@J_aIm-1U}v!8r}t z_;`+sqPrmC|B+ul!*twigj6PX!{EHe|JE;M*D1T~*z*G?dA0he`Y8AX$O8!dgv&sI zuI-r)2qisB-);K2IQC3yCjVrfT8}6^pi09vUo>@5Xxl85koEkc8nqF=v9|2c+aj40 z0WyV<;L>vD_XIeQjW_f^l?j|Y?dpZ(R7kr<~=z& zoyqdb*tJvjan)Lqij7C2A~lQdRd`liITRZz?r^ z7frE?jkYIMpVm}3s_*!1o$>Ein%pU;3BF%7U1o-ik4chH%uEKNWE}~LM5Kyl`H=;| z1GK5y`lWGbDg5ZJW4(c#(Yp;r!L85mbtDW+iV{9G_w<_A`Q%HPEreNoB$s~Mzmq|B zCyWo`h3y8O{!F%?{e>=vD&D1}+a~p@#;RB4o-n6^mo3l_f1u?*naQi5u0S6y_sMf! zjmKIh!r&b%mtd28W`|RF2fo(p>)GK_oor~PWa1d2&qPge`zdl-Y!jz{uXS^_k|?oK zPmOsGlVfEJ+j(_w9#vV4-3nYXyBP-qzfRaYsw{q9&0lmfld__#5BnI!)oPbEIlj{b zST|7BFiP6VJj*J)<)dwZ9;;`70U-$}?aK9dyftnmC6WpI({q{?Oq zoVJJM-|y32h^hpw2{G^ENCka`>QxR)KTckgSpj`9Uehh zk{0jGpHn`oQ1RrQXT~i)MT80T&!mkrZxUi6kId_yj_7N8LlFTrpxEDFbZXP^KPcSvZB1TaKbL#*Yc67j z;OUfW{Mul!2%~_3-r!u`alEX)b>$LR=L|$dS!{)k>y%iOu!5PO&w5N@gW6En0{YEk z357Eg>+L5*HBu6r7&}9r4C9ipZd`B#?~?6C&EW>hkv#)9pc%DKHTv8y!Q22z;Fb_e z*X`Ine5Xx?68RelwFDEj;rDcH!}f1N z@+U}baA-h*`%00kI0uBt&L_!~y#GM#o4zATdwE zRIXYF&gC~EyMx%QPB*0)`r){9^Kbk4kEa)lo=|~l$2#j`d)8$D8Uz?pDrRPl+?MA% zZcR|sx9v-ntIaf)m@4+UP@G|aVUESIX+NudSs!Ex86mFPHZ5kddP)69>ETePK?ETh$C4i=kC}-gwP!hs99s3+nc~`m+zUs9<@?Bo= z)`FASK+GP^;INcR4zj6RAIr1;u8wu|&cajP*I8RPP7qnE0R2CT!y4p!yj)p%I#-U9 zIMY5SD=Ut83a8(F+{#bq1Gmkk#f;56G=Y7p9JG7rI>1x1W#M%9 z)J#D}p2N4PABeL%PP9QN*?h-f(SGvi<9@zD$;!YbkA1lAOv(#e09je0W`md&jrN?^ zdR+zvs%R|ItJbLIudc_>!xaWF3CJFtpXLyzWG2xJp0a#kNi$uUqA#9#OuH9HQH?6s zuc=}-U#q?Uc@TbE8a|*4w(p4d*Oh{_;`2z3lk*+KJH*ztGCHyP_3?9g^;@v5R>9rU z#A7-Ei3Kf*3UqXpn&mWe*Y?hFdo|rJDup%i*Xp(UtE)((qq49n#`c2nc~0)>$Ad#{ z{__1cR?H&9%c2%g^^*AOCHPK_0U>&})P@`103kDr8Y_ypUkXc{_S1I$5AChbFXd)r zy-?N>Ax@}~5^twbjt@1Bb1}12a`RU`_mkGMEmK6TrNA!YWyPIUkSg0 z&sTAD^h{H+69S?%R4*TRF9X`1eb%@QwW^knr|gy%hlFknZa#@(>@Hxzz}o5JiVmZD zBh%6FA;JJ#Yp0`|fHV*b6|=_b^`g2pN`Md*Y{9rtw#bgy@YLEU+@g{h?3>XOpt%B> z5ZCB&yPS1*$9agWGPxiL6Dy{XTOxuspv?QYiM{R`&NS@y4nh4E8%ucys;6K+mBJRqm z=q9Dc(l^iRp;{kRP0aXvXOWoEQT?*>nTvEgvN94hW}#TtR#n-QoP7yCKBAEHpib;~ z9=Nz!?fOL)2#g&FSW&Pbcpz9Tf-8F2I9qho78x|TO^nPL$EGmiqTnAm`cRsLJK$Yv zE~{CoYA~-}Xh)tK16|3CtcG)FZZ;N89Y^bXS)E1F4P?Z`I)2~-p`>m@>vQT`oUj7^yYsAEY zUJs8)uBy+iNU_&$w{(q{N2-C$=4-^=V9-*)AGe0?-g99@umLRUd6jXsk*@^Suf8X>wgXfE3s74jw zbNwanLw)kr@Jodm*|2~(2NXiELa&1uiuT97rExQG*EfI37Vc2zplI%u&$fEoclSmf z;J%9V-%U=7ppAF9eUXcK_Tvsu1+3RcSugXGf@_8fY&ncMeL$F@QuozO?x>?h318t) zSU)Q5V2R>J{3vBaTv?l( z_XC8(wO83Ee!61>#zm33W7+jqgHyOXmE8IXUuLBCNg8q(jeI{EgNz64V#qN2E>i=% z`B7(q))7>Lw$rlxnw34&3(b;c3xjZl2^9iKU=;G9v3tgY%IXZ$h(5aIp^L?0`b1^M z7}Q&1RdCGQ=T5vcQh_jxIvda1vdOBHiK`sog9k)LCtV%en0`;d9vGJyf9>hh_j4I? zu($_Dn&3u$(+y7KPv;++j+~VzOkS23Rvjrb1G@m((e8kUoXJ;@Qn0B(i-t;KKi}U! zP922F-faEhInAYpRyuc^7T%3OM3Zrrt(*cM`NPq!`i{iFHcrDcI3AmX&7jKqftq)) zAmhGl4>q#XZCoSn-MsRN$5D@!yN7i?pG*IT8GdAFh$eiH@dB-67-iWVsIr$TPrFVQ zpqnvc_+*E>rX{2#c28kmce+^NJ-0*fyYw~t4`~^%A#Al9RGPf=In*y0Fh2?t7)mT# zAMM0Fx!)y!y5gqhpi|KC)GPDEodO$uz!XAg+UB)g;^4I=p0trmo57wZ{{!Q+jq=JI zW$PPW6JO_~_!;M77Rq(>4SnR=gN5)BMyK=NrYbs-d#OkXEEYMoMJH@f70`SM5IxZ_6)7vKNMQB2UMJ`Ic-aFacG%&T!w`&F(X(*O{OsBAx$ z>zZpA_|obUqN1O>VgtmQtGLA@Y7c%-J*wqKN__d>{0I|7E7XGCr+!}ROVW-C%BcqL zICmJo3!cwja}4)Qm~jXtNkHBX(rmw^83yudeP^oj2e$KXoY-Za#{DfX@1esaCNKL1 zguq8-dd+S##oj>3nZUShET$=su1sdxJU>O%e4WqQPW5-m(WQW}zx!?Z(sTW5l8$nV?4!tU9k{0R zTf^Ib1{$Ayw3v8^qa7A&=+z-CW1gbYaZm}mejy1f{#8H8eXXtG(c{_q+@J3cY2da< z?wN$xqnUfZL)XjnaA^S~<)(@4!xtmMc)8i-i#Y*tkf5S^U8}A4Hc1A*U4YVkL9M*L zf66qXhOuFSCzts*Tfut;5i`b?Z;#}8G>m3TP9|E2hw)SnsR4&}6c6hR)(Jm3(K6t3 zgfhg!SfTQ_q2p6oO^7YtrhR0EoLPTbn1Ug_bE z4~h1A zu>^2-W80zyz6-fr&lYeOIT3lA(8U&(^NUzuygXAGB713XdhliK!td%FvkJ2$vfsX3 z|M7dvOQN}YNp^+DyLw7&o2Xb`#?0KLNVFCbpKF(dgNlPO*#HCuFYdwhAak!_Nff-H zNE@6@|MZ-m_{^<8H z2G;>FKp^hx>aqLqu~#}PnD#sA!~;jhE#S-K4WjT1y6h=f8`k}81=GJrI;S%SvWRuT z96Ej3#F=-SYR^~2R(~(TEcq~}I-Qd_{wAm;@HWUV2s8L=G-j}45L4bXat_iR8Sc8X zs52UR2xjmRFJ&7{$FsF$Hzso{tn*N*O3yAouvvY7JX2_{bGaPuG&owU#;w4#(CcGh zvCrk19E4|h(dR~+zVxj8Sr=-S7p>RhBP&TKZ_CWsZBTa5ZOx@c8nPTMDN$3@*XV3x zScW_}Y++jui z_U~qmzlA;DY{n?v%BwMJ-d^}ny?8%~`$gCOzQ4uzR_6rBb>+`RSsGqJI4GH4l`CbI z!*uN-Xv!yc|I}g;7e6YS1ja<9Mt+y7^)sE%ku4^X<|3cR6P%V@QHAz*)>^i-6{AXz z;W0@1M~U{fUyZTi4Zv)dd2W0GgZymfxGbUZdb$)d0eic%b-`F-mlD#lwOtv%Pu&Fr z$?9T2>_ZylUMH7Y*X`(XQnF{hdmNH3;ia3wpGUg~=M5>*%p6k*qQi)^544ZgP!6L0 z*eZ*nkZFW0Jk+!Xqwfk7VM(svDLyl9@0U@~!NTNo^`#xM8T`d+6JZutR>QH*U{5f4 z4aarrsi(lIJ?I{8`Q7I_96K*mguCba25VJEaL`Oo(4(?Wn8dSDq{CM}2iFAF78OYc zA)4!I=&4P$SNF$X7~4sI9Bm&fcJoA%p#Ra`VzRv4>a@A`h4u?*IqPi~dC?*<5FnBny2qXs*VUIXb4pi(iU2gMeu*Q0lh z))6KvKd9P2c@Z>z{k|DwcW9S5gY`2(v{1G|cQg0*e;%XlFW%!XsQW8(zy=fq*G_NUaExGs z^UBUIHH->>=PMDSSO5O+d~6`GnUsr_FSfno+gSzMoq#U3BOk-%i9!XR9Arpgx=Gq5 zjU-^JB7t|CByGvE7wetgc)~mR*JwFU3B<1K63gBSH}jwKYu>BWELBlSGNEBuuvqLK z#m%~8eucsh$4~D5E#KP9awIc0OHw`a0TsNg$F23AUIDMeCo z8t8{XA34(IOtCkWu5U9K@kHz)&!*Twj3fbu)!5HhK+y9vTkcm_g03K&GB_7^cza!* z2FRRr0H{D-if<(W>~Ko5kX(GJ{rcV&-rvK(o^&z)4Efv$I8}RNV8z zV$q&2GT1?oFG;c7I2|#1+lP}RbDt)>I)#d7CKrD7_qPOmyYZRwSOQ~w&pPQk(c%r^ z$mz0d7BgXC$mWXUGJ_ODq9iOC3JJA z9Kzs1Tr33Q;xlZTMRsdnxu?+xIuGfcp2LsOG_gP~EKVJz*3`;u&CD1=fh-P2$KY>P zZChMCfpyBVolyRJvufARdU9EALe-^hCrYOhCPCSiJEc#VkrFJsI zFv{cw17N8M!I>#9y05Hm)}(5eoNTIFe)8ZFmmDeu4t(Kq8Rqz0vz43j3W$6ZXYhfz zP9J!@5}|rUuo~iKNUQ;*gw(? z958%rlF$zh)hKGRSmDnM8<+)8e@HdRTkky{K(Voi={r9_KGqB6yvEqbVoou$N|#@S z=C^%dh=KrYxA*A2+U(duj~GJ-Gh?}qL~eB&k2@We6o;K>M@~WE3lapvO?&;q`-9*Y zX9=HCOm^$k+S%P~#>^?R5?>XzoFcOx{JU)~@D^j>$uGYVD>q1FdihgoRyJ^w7lCk! zyXeBLG*!+?0^OVv%pp7Y9dU*I-7a{U91RlnI9-7R>(xMPsS#(nKySto#;4Xo5+2qK zvga6h&E|)LV3iv=wL*Qf5$kY0v3Mk(&)7Dy-verbHP7t1_?0rEm{vd+wF7eE68-N?Xlx zlcdq%DUhx!SH1t58+Ns?i7x%2OufTv-K5>*e!BjuNO&_1gJY=v)+AL~IXx;pjFx~! zO8Lj_VMt!U-qWRQ;U4uyX?>|-y-<5Yt3thy5$lMSwZ#fiN*FDm`jy2zHV=&_7M7Wy z5GB(q!S>`RFVA|bU>z3o0Ayu42MzDHfRbW^r;FgWUgc%%f8Dy3X&rG9dm1RbX%Vc$ z${{XakdlB~4yGel31sA0TfTxt@$GnrI$>|(cN`8lJ-uBskd=eAPpw!-26z8mATIO* z-FEW`-Jg{5pc@R;e1GBoM?iCOyj0V0EF%;%_&Gli9wtHsLGq%c0P$~;Yiz~W$ zJ;Aqv!30B4Rd8n-NNi(6SLsz>3>TXB0twYMyG0+3LU4Sh6#P(dz|K!jOl-yIYi?EW zO!ghn6ZvQHhY#As+NU~)_ISYrBUmp?tGgxrLRv{9#lae%1NS4ut@kjozmv$VoBQdi zUb>E2gP!II?eB`=G$U9o{g#}2KWVFdElavpgeEus3qEz)^+M%3xanL1G!zu8V3Fx` zY`UE~SiiI49B!4&j7x3Ei_PE`PkdPx+uXceted4J$LVdi$_-U)u7F~5+C5m~)#BSv zRsZR77-g|^i_}xG2%k2n2-xz_cW6CYIN~0jyri{Ll*DZx-E!Y@N>))iLO#j2eeL=~ zWA7ckoH~bVDW>zre6!>DPt^9Q>z2Fp7jc#bEKI6!MW?AM{(y`J9^8$5R;{GZY2S7z zsxo{~aVwL%+Q-CdL;2ac6^Ni`u^MAa0y)r%cJn)eeHoJbo^50&D#*rIzub--{)7yQ zQi$ddgnj%^m0C+zc#OjWW{%+JRnIdUd_ks?5ls?$f14ocXsevMDl%o=y0`gszhzu( zv6o1yZ%F^-s0RcKb&8v|b)<}DGCge+`ULKL0(xxcce3-cpy%F)KWnfdvgUTB z9h~nl+B~#WewP7to0QZ##xrY~Y2S6G1iymRK=UVHLd8U(6Izv;x5cKav1@JavNH9$ z_XEiTo*k43WJ$~2eETwrzREi_wuE!KHdCO^Kwr6WNVWBs`-0JN zhR!+rR>O*gyYm9$iMbUfsMKTdoBt!?k|@eZ@TJx^D+_7r}dpn@T?SkV)y!nWr^>~EdaR*yeQl$ux2NQauUUm>Z#HP z&r_1h2A?Wg_z%qn;DFgpe^BRXQ@an0f>aQFojmTb~`mN!`ySxi6X z5%&MfO41Ob?~}kG2jWHzW;HBP-dQ*9S$A+yS{JufKM*!=>&S)i)SRlNVQ`k%wu!Z> zqfunBbl~@%{K2+fa6wD_IZ;u{*!}Ca!zD>m=QY^Cj-K$LVIO zMV(h#dxYj;-p#EdjcUd$_M6t{Z++TSlwBqKy3-zBb=vxVesS3jXOVxzVU5C_zXTu! z;<}Gykq`MXU-p^`PR@pe(xGBz>*+Xmm?=loGfK@gjsZ||tT3bQ#71DoDmIZZbgJQU zusXz+M`e{#eWZN>snjszM*y6HmF20%pmcO1-76MW9tMq?*pIOv8l_x2Wit-!6KE8o zaoe=6Y1NpeVlW~FR1ND+wdyk0fI~{}44bnh4?j8CMom4J=HHV*5BueARCgcAcKWo`Z$nCU zYfu){(7CX!qf(lIDLtMnRPhtWR4FKDV>8ib-z!qaP)<@FZ6LBt=;xd*@jlX5&(2i7 zwqHV{mRI>o!mD)b8s9i1gR-bk&iXVn2hP;T3ez}8BR{k9#cgk82 z9LB1~w@ioM?)S26(*kaN?-bPLqMh4F?7Kw?x>>3Yhj2y$_0`RIr`HfUu@Z z@n82g2nEsp1qnJ&h4;#`cT=_0`}>=E;@j8(V9tVnD=6!&yiX{Vo@-w}bAJAGc&axu zRvv&xh6=M64s$s*7ws2x5=dqy>I7av==oNwXS}f`-#(i;m0zBV#=+BxsfxBc_p>{- zknWcL<;KwPy7Dr}_`P7fF$oFtRc|=s*AsV5_Uj$%$9l_a79O?v?B^3uvM%<_<5F*W zj3(jI|Dk>T4??4Ku*NpoSLb87kQNF|BjQVxQAB-2ZHsAkk+#$P??ritl0}AE5*Zgk zw`NoPl<8=Vm7Q=kN8=|T3FwAxQ8$>I&#t^7RiMo*mzMDBYX4Owp!MNkprYZ2>8eEO za~*_}?~PB2fwODdgv)&X7qM5(8|T;5b$sMxFgj_N$-lCAwN-EqSbcRGpiVRtf^5F& z=7~-7*~^SQK4eG&Ha4LAPIN{!%2qp0y1qN~@11YU#n&GbW4JB%_?pA!EGC*3oAW72 zMtZPm>7+Yn+Y-Pamn$Nk2JXMvTimQ8s3%S2Z;cEMeD`@H(!|j4KQIh<5;#pcR?>bg zc+XZ(#tBVfUjm^qDV-$|7D7IHgtM`DXK(M=6Fxv-Z3@fewTO^T6}1-Pp!}Cd;(K=o zH_HcNeU?5Se-)Ll+LCUosjP2V8bmiSO{E!)G_ReLXHIZ>A@YcPr0U5>RSj13#`Z@?f2`gnCrF z$d-F>>V$>74s86d!tg8XPHYe7l3w{ ze(o);hcV+?vp+OLUn-bpW|xk9td76lDasziZ4$)DzEq66plZE899fPn;D0*bLQ$8+ zo)L6C)th&3l7NG}(8<6|9>a!<(ph^mB&*4wVUZw0Ao^G2tH*l#gH=|gzGs6+$odLK z`prXLhd5l@(RwFGA0_#Z?8ls7+^0ij2>*VTGUOz3%w&qEF54qIPvn6u+UURZ)mNXCF6Ft<#Nlc8&mOny+{b*LYz|f z3~|3XJ*!7?>a{&z##2L-_^;XqHs=evdMR^o;;Z)aWC8R_VEB@iFT0;R-J-hYS&ef#%>KF@2!8~0aP2QzF#n7NomnB4}eK5lFE@O2_L6k_YI zxkaXyHD3x; zddm08d35K)RhcI^%MTv1a;iYzRPL1gg2@m zBE?y8%Fl*h7Zz8bmZn^9p22xV1BNs9&NlfC4z^7!E^ke9H3br=u>hw6lvOTsaH*Sp z;NNqUxGjuEyg~WT5DN%*1GXEb?A?;>lz?DlUUL<#ws(anS}cSMIBUQf^8qn6w*A|P zr)3>Fg_ofhQTVA(Hu!OREQ|cRYn|okRKtZd#ijQaZhyU?wJ9C0y;L^|SIy;90-Y9z zPA0BH1Jy_Fq0UToC!NT_K?rtPkSJpBvr9?WA;GK6F$cVrs-meYtn@5zlqb^CS?|Q?;}KgG{F!K}2(x(T;d<(pYfZ&K{J){g zAU1*sTjo@3Mu#Q zxuRozeOihYW63jPbgmc5Y!1?D=1725GYz3~;EMNx3Hx({(F=wVZ^ zu;B;B{{I{0ynFWh$Bs`Ed?In+j6;BfpxlR7S}v8Zhnpx+lYAim7s|O-#C#R zbqKEjwcPAa^aFf3s4o;XDl5o#T>eeOGrm9xn7=96CH$9E!(5D61uZvM8g;w*qG^S2 zZSEt8TvBmoc^5 zO6kGXV}C13a@*}SC>N1v$6qb^*w8GZZvd30&9~s)`ZSiy&LyavxuBAtlEGlaUBUP1j&JwCc__nonY!}$Pf+H6>ML$MpaGMjs3G3~waUa} zx?6{Pvq!DE+2I^&;(G~c#GvL_p)u^RukpGr5t-Lsp;+~_`e*P!b)rpTcsgVmz%Whs zUSG^8Hpq0<>=pwpm1fwRiI~VCIlwZ-!SQ-J7>vuu8vs*NY}pMS?j2Bx8zhbwv6JgVZA=Et+Gs+8TD&dHaGF1d<3nw;m{>UDydK8&&+f0R zpu+fgp)vSNP5?vcadN39mh@*VGE>Fp)xokVH z)~|8!4g9A!xPigG&|n%-FPA4xsNbQ^`efkHvgC6l)_lAb=r}jbqS#DVedf!Q_QtTe zNQm>WGKrMG)zF31Zn_a03(Fhye1YR%8tUS2R0}p>We+OW70e4RcFuRa2)ceTV7?6j z(M%Tk%h4eveZRy*?Uz-81cF%YiJ^=-)izS#& zi23e#bW~mN+7lqE{i~H<0pbh2Tu|#Nf~b>k@V7`On#*OMTC~;PETqgJv9N%XTVpjp z$>VsTcm8bc@cdijDxIP4$E3EJT8&lE8z%9WhoPLz*xo+1Ww29&Fn2RaxC-N@3_8s}jMnXehs*n}(6v#75vjY<|U&P7aV#D|}nO(MJ=Cg^Hz z-pAda98=fSrbDOq-`{B`v%L}MqhRvoJKIHM%t`_cAu_UQ4$Dp_snXaSv4L%iU#z>x zcV*kmcd}=ch2{dG$Xx?I3%Sk686U^SO?ZPr`{rbMdRBfgQJoxd{DQ{Qh*q@cGXeX3 zy_D2f5J3;KPQF{KBf|<__7coLQNWto z>SFpCM|=2WFS_ZRXCX`p&eyk#F<}1a+W!zs5J!_VdS5u1*!ghZYjvj`SMhawMNl#E z*JG_(JrQUaV|ZN<&v6v<(&b4bfnogW=AhdSe7yWLqw_G~b>im0gk`bE;6T};GNoM- z`@ppZ-cZmFi}opB=C^mXizVN3i*=#9nSg3?!9R%}Ad6?EvoenqNw~`;&*QMZI>r?g zU#8)EslqW@99zD#$r{&br`L2ojk?n9nntOeW-#?>KFV(S{cDw`pm#`LQ!Z{%Adac> zs3Z>R#9nNiEjCfQDKlwy^UX3T8stChc8r~beMUxeLN=Rv^n|Zp?>$hZI5#C`Gy+<@XCOH zepcL&DRKD`ma1vLJ5+stQWqghWq+qbbRUPrQ18k~{SS&of`{=a5|3l9D$}cG@O%!N z7ZeUL%@Ct%B|l&4`;)`;Gb!?i#m#KJ=jLvC!o;zO9WR!0(Ha5W*{eG4hpP;`qOGOP zT~^BTk9cKc&*8YNjQ0GUUlm5hh%_21|M|cnf$VQxX0WOcS^UBYRY>=#^UlFKIPcK} zf-L8lZ$GpzC%zZi?I&zE%ntPTr$S?&tqC3+s4<8Ox`oibR~q+nsBBj}-`GYUFh^FM zR(D@<1MC~{3ghkD<<-}Y@TOj<5JdNzTTGK+Q2>lA~1AOPMo11Ofg)(uX?7|i1OKGzsn%7J1(KV=L)zzdTlx78Z+%ozUF2X zrqf^MqrVc|b&|WMy*6GI9E_VaAEt+&WpRzhp7k-_%yu4uRxIq$4cnp(Y+ZBRW$Pe7 z-jivo7D`Ty%PRVlvUlLTm%l;D#G&zcSz~$Divk%=yW899A0_?To?rvrx1b&&vh~hy zPb=AcH4fK(>Xl}9%gmnxQJTwM`t2LO8|%$C(q|j5%?56Ich3avh*je}G`O5Z6e)6r zz`j+Lm_d}+^7r3H?`Ahr;|2P`4tXcH2jMT zgnmy-iU?RRNLLm5>6B=P{AUKcbN#sF@pxwarM4X_K1qO&VD{e@HB2sizA{S+!h@rd zX)uQ|f?(ef6SBtE$-gBw#t>`-V_b}LaQ4|bUl^}I<@d+4d=yA2PtlcH-5|6&!bURn z609wo7~ou3e-z{qs7M8+K(s23I3x!HQwr)pi; z>xV+OD=*MzhXNixvr~0}HlO3rV{mTCMWI7ZrqNn>>npcjmun&Q&tH$9)656kq@~}; zJ&fv_!nBjKVJTBV&CM80=IgMjf{g z$6gtRSC?2N zt#m!6Pb00xkTisjh{d4 zyUeMH%=&vXvomR6;X3-uosE51m;3EYQIqL;{1MC0kH1u!-7w{}5QcDqvQ{WXP=@d#G_UeJkoAeIgrKKOmUFCGF#; zUmdT}INX>yM+wa1J?Q%YpljUmu{W2$C8r&iFg5}ow{oB3Dfm3d>;%yP^t!Pky~51i z@X4Y4{-F1TqY#S5%J+E8cJ!n@#)Ca48IW>&)Pb51*@SBz#RySP0#(ViSNpX6E(e8I zvm~HFN#NQ046A@J3dJdDP%FQw32aKzB^t%m<{$c)RAW)~fW?Q>(M+f1z?hwU?kCz& z@7Q91t@BuY9hB;61puPv^)jMCsYs12MD_tT4X1c9%YA*F9pN!3`eSU~In{V6>y#v_ z(@OjX_R@NN;K3e^o|4_YVngdFRGR+9@X>!XaxA`*>H+>?yB0OWuQ%Z=_@GwLdQq+< zb6tz(P~K<(0YC*{{qjSaA%he2DiCALOGVP(nd3(XwdJJainj#-*nkm6I(~g_ zT)wLPcGR{s*0<9rk*NGQap;c$v=v@Ug8*J`09>~ksH+35@Ti%nbqY*=$hgGHqZnx5 zJ)XQ|TCh?P{v2lUZ+#BnkxEdjANK8Z(IRPbj-CU(dW!AHht7xrLEuUD&A7`k%OgFCE0XV zBtaiEwHy9cM=;GmU~F3SU#RYfbVUZl#(2B3Wd_5}PbEKp$xg|7ACoi4HP?NG2FxW% zup~N0nD{bQEhar3H1iHiTwIRm2q+Mm0ct>LX(*%u0>=jlF1gyx(puX5Ioc*&Cw#jt&$MzqB%rwJg8Oh_%|0wR1bpJ1Z%$@%K z<&W8vuwq^#JjX=)w~^H6tL*7K@HP={d`oA%Zld#Lu26zjh#G3^zESkm>c`y5Uzia% zJm<|3kPK4xs@S=rqyPpAA(h|=<1Ev!@$UFzJ5si}P6GjT{lV)y-}qhXj`5WZCCJmU zfRh%9HbuqYhsUHKI^IPtS zbdt~HhjA;qJ)i8;{?*po_;W?n95_D77go?iJLY-s#@kg4B=vW)tMXSd83eNO{W2*s zcJJP|GtA6S98UnPta>`K8ot0BPrqcw`+;G|UE=+#eD9nlcL2(dMW!YFDNZ9q_<+04 z1-`Ew2flJSQe7{X)4B^7O_7$Pea3V+^3}8 z^M9|bvzY(KQsm~nTNGA{Jswf!F>qQ)GW|zR=KiQ2`vQligPpytQE{=~9<&_n*nF+% zrBo*`Zz$M(i3%#QJ1U+6q8n^`aIV?L=f%c-UCr zJmq!c9MIZn-sPGi_cQAhRFMwx{S+&Yd8fT2@ZVhC$MVWi;O5{BYLP~a zi?|f{UH6pIlwL<~00CLyXkulR*jo0Izt7gdr_Jj!K<^iiIIjO3h4?4S$h9(+G3wAe4_URTx{Apy+M)Yk1yRYuS)@o9 zw3`}Svk!8vLwr@Pni*;PZo~gQr;W&gr75DOh4Z_axjcisKh_g#<{QdiNlIrz1HW^r z&55L7{p4GJ_@FnN@_fN!E$(`HTTv_rv}m+|Wp11TeDMp9<~tx2%Yc%qdw11l14pxE zZ$>;XFC>^=M5UdD*XVtsIdDiu$Xx?$kvUsP>%(qqS{7Yr^yjE%7WyJ6bD-npp80Ph z*vhUhgnbJn(P8{<{O2iM(Am%^|37_?nl}1XxBei0gd>V$m~@kD}j&HD3iFC1S<)E!da^ zRRSh|x(87&vkReXgpC&Tp)}5loS|p#(?CPl>TsEE`&2D?K1!!d^}Ew67fYmcY9)db z=rbire+|`eTW*l^Tbdu*y8 zEbD^!SmHzm^^!1w5%^Y`hiDBq@AKLK%IQ<>k!XNT04R)`(IlDavi(L7jWH4Hm{+QT za`z;`kMB6jpWPr-=;(ce>-kH7&JKxC1E36H@K&&8Yzi*Js2#>fsjiWzbFWhq8Md8Qk5! zntm4XHF3r!BaRGmHsuqt&k-PwdLyCCmp|^zN&ZH&@X{~{8p(|x+tR7j`a*hjF3Q;n zLANM9;K6sc<|}DfWI+Tp>#(u0zysjEz97ysF}Cvdn8acX9I0GB*?dn)KlI+lDc|57 zUtQ{&!|qQt_Z_F;vvS$<&^A*PZ)^bws-CaCe2yL;rMP!=^~Yce3Jju;3NSe6fg}8f z0xNHP-S(6D?DvVLRd6k!*lur2ph`S3Q9yO_!wgfjn5i=Ct_kfKtA(BY9xb8b|-?YE{^UWCxS+KCB zjtp9d#d}JlO&Os4Dht^l2f2$DGEdVCO0TjADM9tpbenE6Wl!8@Reao zfexPFY+*#Dwf3hAfGQl~Fag-M-y)wS5SptqxS=zk>WmQW1Ar7Tl`uFJ!pO|pe?X>D z6cU7e_*DP(cWi@gVcn-|>-8aWw8Mvq zg~PEK;)y&PQL-Lx`fDha^R7kOf$zHZ^hA$KI&y?+uo~YPj^eqhPMf%Hqs)g$?d1Y- z-uQPUKeR?l>OqcS2+h5_d8CL-k7Ip(3&cp8Y${wnkakM{Kh=G8R8?Kq@1YTiLkdVs zcStDRDN0HR(%m85jeydE64Ia`T>=tHODG7^2q+~jAqaPE@CnrS8{d7${pX%B4nEI5 zd(BmQ&o%QmId!YxL7Y_<)bHt$t;&l3L~y}sHuX` zP&e17HXPPT<~1n3=`1(VuPus5-oD&U`P6zqE2gS0-=uVj?M8dEoscp4f>jZMt?255 zk=bur%Hf0hFKms&LF_LGO+H{<3>A;; z41=uB3>|eE7$6eP>RlfQpCir-4?hAn%g(SQr5h@f-Y17G`}dxSTQ%Hp-L@4OW#sTy z&rZg}jfH@@4~T(X^Lv3#_vLyhoRl-fu4zx<@_a5irrKEq@VqfF25MIb3Doby*1xPh z!x+AE`}8*;vdp91?(2^$(GP3T!`pvMibHpWO9#>)yhOikfe>(j4Tu{}2x4?IYSGef z7wFa^2VKy4^nGerdh2r&ez`A08vz&uNLxARikd*y77^yPsNbjJVbW>x(scu z2-1&`S_yRW0OTdhi*>U{z>Gu$jU(;$6ZS4gJ`bkO&raPp9K#A-1);@ifKpFk&w%(9 z@Wr*b5rqDBDn=)+7druy|6^byAB0jM{f{cO>NaiM9%1mIt4%k0);E+k0>!9CA3#rJ z#R6v)#>2~f-LcD`DO^up8t`zvE%}_{c~3W&C~uS-%t95+0%1OVvq9nx!?!>xZYI5p zYR@9)Q*4K~K8RE+odue!z}Oxo(DFFrFLb?a8F_;ikDFJL&VJLr7&BG-V?=l$2}l?A zFV;@VukXhmab2cs$)&oYJh`}U|M)>qJ03(O4XCOr{&XLUk@UPWsVCX?<+nH z4|_joQe$6F;)d>kqQaH)Oxt_jRM1-(GP~PZ2@wP{xorP1eedY8ZjcS7MuTVfYK#MA z6EN0nZGyyXT7feYiR_dJ{W=ds1*{jTteINE%lr1$4mAqmj>>`F>&p@c*+hAKXtOz4 zQc{qg-{J{dMmoK=JlEE0HFG1aJGIiROb5;@5A|vaXj6f_kAe6|7lSAAHlHg<`LQ;$ z3!EqpDV(-5`0H2gE-tGEb~>u5E+an#sV->x59Tr_ zMl*ojOge37u}8``B(nN@i|y7lkdQI2tb9WCRBi|brqD@7O-wg` z32WT0b!X#%#mlc@A9`xbf19uV57cs;?JlmK8wfLBj#2XDHK znARmFk$<@K6oxK`GeL`AFI{2co9xo-;WT8LRB32~z_f!7H$ zD8a4iV4uQOw5cL5XOYf0Op`b`BrcWxW9bX|dt^9i0bh@+|H<$z6kppMGy}erQ`b{7 zri^OBv@F*8j2Wr3$33BnEJ}^s~xIE zaMRG-1a=`#Ow}o`#po+>vBc21Fsvwpt*5bXe*C@3?4#D$bJVc+ivaO`{;1WY&PKCn z_co7$jTtI4jnkYMEDK(0=F!w}WJ0o)?qOyB zdhmBLT$#sT}r7T9Oe`}|E&#Lb^Bp4++C$}yInB?ll z1@4KID)XOS`DVe(f4WDndxhCu5O;e&j+P3-@Na?8MYv4KlX!aaMrA^Wra}}vWPGvO zx^J;~-#9-5!U^Hg1A0M;=NJvdA|MG$eh~*$ViQO(2vlcPL1*El}Zd} z60!AQ4d!|T&hpTg=nVy_Sirj(gL^yWA1=IC0|!W=XBX4rJ*&mV+YEb8iN!C>zR{8y z8QKW{6yT9kmjV+JJh97y+FcxkJi<8;a`GsoW3)aEfo>O;Iz5 z0(`!x6zC@D8{4=AQG3F~zH7HODnPa>nvL*SUMt}gTKc9oF@(E6j2D*iAn7`5_M0B( zjHff(?O&$W4M537T2S8u1@q;uH&RgNx~F#yWYbNF&&Wxx*ERk-V^}%t164nlutkc5 zdyCC*jso z%?jA7j+EY>2gx8I{V-xrQfl@A8^FClt>M;gytxtyrFzwWgJ)+F3ip=8Hd9HE{ON=NRf!*Q=|3E7$A^c5*^>3 z?OH^9?X_d`4Y7gJh6fQ>r>S&ma87;2A|kM*=4FcrdV)KLI~Bnv4~NXleIOm#Je(#{ z2}lgoiw&P#Rczlkf2%3NuOkxPw%D3i;D!XgZOx^bCh92d{O2~=b#}4eC z379~&k=!G0CwltQz5wBizb2DQG8PJ(ss(kcS6dk;dpGgQ)rn0RLiY=K9-Ks@=91fGr+ zJP&@AGZdo~3+Y7}IrSTKmBr6IyCfJosROON?qUM1_%R{2i`{Khc4X6wB5iH>?K~vK z;_b$qm2i^vY5(bqra{wJ0?BlGHYyMTa9VKJTX;G>?tR7bHDDc0xx>q$w>o&_tUwSU zF!}^BH0bS*Ie_a3vj3chhP{cyedncWj*b$Yd{&k?!%3-Ii4TJY0{!PdR(-xejd%z` zDcfgkuT0FiFDgq4aH9qrKTqV+w1A}+7%t>~%xdrBw?I2gLu3uoYa#*23&iG+%PJZ)jvJOB74;6tQ^`@g zh$R?P(?iLpvEudcRi>+TEYVI>nT`~J$37tdMtPf&Knsw?77E$&>-UogXhHM?`$GUp z$9!d4f}cuc8X)O$OW{fjKtX4vo*wB(#?u$B-T6XsHHHZ)orVVL)N$#_1)8zCAJM`LJ9zxRsO-Z(zAV0< zb#C?F11Z(rZ+Is78DdOX2yi`S44g5DvHA8yUB3PR?hdON4-hVqoL2Twd1efmh*ZbxmN4G ze=P%3nT-jg#SX!~0p!f`pNYe4H{mp``~Ol-K85X!$k1Jd}d46yytQkkB_^ z5lv}0 zX;_p$O`Z-{s5}{wh*TV_PkZ-n@0Rby8+$smNd@x%if>3s9fSA@XewH+#llV_ zb6)dJycKk!yde3H%!OZZ&u1QD>e&+e1(%2$lkDZT zsUz|==5`T}Mw>s+zH@^&^K00T&Fc*mJr}sfR;p})J&OPn3UVI>aSZAsV<69T2M;KM zpe{icXU$JvwddjFTqvly;0E0|0kR9Vh3KTyC%8rQyg~9_6gW^3pKGTx0QX$iF%aB? zfiw@)5=KOW%<926vOq(IAh4*}pQKRlT2wrr)_#@@#~suHuZuK1TchY{<4q2bky!?m zok*(qcVEk`42jUv@o^8(0ox0PQc)qCmhl+A6*}PUWdj344`y%57ua|bZqW-yL<9ev zn3`&toL>WJUeO>`MkN@8XWRv_2l3_jX`UCrMWENJ1S{OH=~~XM1H8Ig0aV($4~7^B zLRjd0l#?6k)`RsyC{i|1kqKrsIb8eMh6m>c6oJ1#2kPPu(7Zsjml#hsg>_|xYavykKg8>evvh$?&HP!Jk$l(b90Hv;yfmGk`$h;fg&LIMN z4Bx;8k%FWyT%Xn>d3kO@(O76$86bc%JQP>}YIf5e2JwU-Js`kaF@os2j z;7!LJEQR8c@)%=B?u|g?=YdER-X~Y3U|X2*xz88cKL{exMMjNhZXSeZ%y+R7LexmW z1QyjG#TqqjozZ#_%pCpnlC-pRmlf~aHQn6sa3Qd*gW;@c>C7IM_dLvW6QN}V)UFx< z%R#p@r6%w**MMsTAED)V%^h!K@^;Jn-X<>Y5_CbmME@Zjkdi+FXB&7bBJV&=t!g82 zid6yp5EvRGH`GDF+it}KIyJSA;PJu*AQ#~cftrQIVX07&2B?`3Xf~gy^*9BoKZ5ZS zXc0RC6(-mmB+>?MVW@j;s5hkvq<)s%rsCUB8#1UXdi?j`0aU4m;{5);Xa>PxLUkSh zCK7l%vO0n0E+tZC=8-N`mAE&1C94yHO%y4srIH3J|0c5t%_%O}JP)z^@mLAI(~eX= z)FlW33GXylowF_X)Gn!yd=Sov2X-U&rXClEB3WPj7QoDasBZw4CnZwjS@=?;sIlWI zcvnJz(~xGXF6#+0@5+JN>ZdDNoDf(hFnwz`tuosuPIl;mXCi9@DoEjL$Sd2mys$Rj z0ot)Z?H)U0yr%`&r5rXdpe<_!(6G1%(eGVV?X&^|Kv2Q(mxMLnbwgJcjarEvrz4rQ$!J|m&y<3S?Ct#hP;sXXHTU-^kKB)o6 z{N(~tAK8@!zeT&TQ@rR*WsXhkR$Kr^Rg^9aaG2PjvT-lc0ylWnuTeD^RBwYcI_&2s z0Om;tK!8`+Sj8zlhO_*{!qSNOkYRuFqg1EetL<=k(Y1(WIm#SqS9+jj6Zbi1lcfMa z^J#oASi7*Q#7mW?Mh};!2abDURHhS&8Z}T%@Mye378pl3CHfs^JNz}%(JH?J)!8%R zax10;Tmnzx?To{2eDVWO(t+(JNQNtFUO3ne{r*wLq0M^jUG-%{D@pnHVg{FcxA&WN z?qAMRFbll#oCsTjA@b@G1^^`ItUc=Ds+OX*AfB{c#;C$=Z9=Q!41UNx3Mq3>(YCpt zR(0X)JOJ9{{QLSfc;yDg0I8|ViJ^?s&3zAxDv9RS{vDgx*2X=|ec=ty>_f-5alP-W z54+>XmvctC*hRABuEKMOShc8BR8*E7XG1P6=d$vbPS~<8T+(xi)h8XzxXiSGj(=!< z{TtqTrs*QclvE!f4#a6iGdpgtz_ke_y$b-Jh_V6PR^vPY8NRsjk93(~qmU8-N$;qG zN}|HpRxin#Ck&NRSfNRrMYdu)3ZWni*&MYDQukMVA zE^vr=HZ$B_#2PN`fbg}`gMV5F687@_NY?yIpFXBdy9Y`fIAiCwkN}NIOUF%Ky8LTu^Dk# zYW!tCo!jK~BdBg~u~1r;K;ew#*^h{y55(YtA4YlLL-5D}-f;6u^jVU_*^l_uBpstp zIj#nrjkpu-82n;u%cdg~KwZBNEM2-eM>sWp2M?f15$jaQ)MO;L+emKrU=7FdOu(Fx zi5iYUg*>ZCcQ(Y{581XzhdBCsSMS_UXmJ*dd9WtgU_bZc)1FvoAh5}3bn;M5JY{hx z_`qX-BzAZ$B&7^OSQP_*Fs{VEGnzkSVOX-BY9Vw$zXED^SYgHw#s#%ZwsT`%%7V?s z4s6YR6C_52}6+paU@)qL3E^~Mn%QyTLy#I*rONJx@kX0NTE!b)kxVs<+{ zfwT=SP4E=B>Ji$A3Y!-}xPHvs*R8M{!=4uoF6uNB-B7p{5DzT8P%Q~1z?c8lns}6C zT4wE~W9meudtiN0RC`~ZPf5nG$W5i@Yjjsa zD^lHIeKW$&dfhH1#I$0ujrIlpkm zPmWPwp*!TFU+hxsX}E(5H4D)`Z_D$G0P|^UQO5>#AE6Q{?>@{K!0EDX{^ZiwX8=kX z&$?w7zLqb@Jx;})yoB!&di~io1v8V5!tp)>c%9;*9IK8t>&uOB3*s}j+tN`;7n1Iq zOqv-J!48VM$jQ6r*DqX(~tsz z7VwqAfuIjXzWItFaBw8v0Em_E#~4hpgqaOAc=w99`!C}@;EzI5ykAqqgaJ>Wx5hy( z7!r8q^6lCi5OeVC5L%e->*g-OICy;bA``pi$~^@|w^u|ZWWYVl z0ZJm-PErex@gZ|ZwK<)E8Aaj!3TEVcg){e!Zl&up+V)3pC~Wb*-dc8t8}mN<0PsHm zkPUPSMzXShy{Y(OE@v5ADyfBB{r^^L!975cz^?Bf7!KW(T_nAlWNb^%o05CO-jW;j z-rQL@-X9f}(`r{h&H-ZUf2f=b#JIl-Z~;Z;|6SqRe-*C+g~5KU*Zco-udf{Il@$PZ zYFeW*P?LWPkTeiA_IsX9HeQx7cGqj>n*erq^pA+}cHQ5@BgLq(0#H4mB9n}^jfxkA z(XT_vS*xG~*Z*s03WhMcLgNqih7 zDr{J+)l9Emt<+>=l7q^E<_Pq#D}TL7*L|vfLDFqBj*G@@#sR3EYiev+K}x2a9iM0t z4<%8SYZs2)eal#uLQ)Xk8I6Px-kRVTGM4v_=%9N{)#H2H^-xBR;p$z>jOh#CuF*t& za+a>4#D#b^vDLa`LHvnZ#x>Rlb|osss#ovrlbzJpX|DP1hJW`SuLqU8Xd=~D$Fltm zNAwMVI2fJF1_JVQ8ei8moz?O!Y8idxzRks^H43Ejty} zLL+Y<;7S7=yi-w4((Qda2nu|S<_e5E6MpZn5_*1M?IJ^`MHd1GXnqJ&f-neRQ?P!C zn)KpHJRdwu=*)V)rlni-0XH1}P)PC;CbmLpc7so+aqF%1p1Z&gPILKW0YBt|iy*Jd z&LN!?b*DiyuTBgnc{3=pTS&pE3*!DlSdkE;aI*$zDqR$^Sf3Ap4y){BtKFHW>=s# zwj!e@i!O!1Q7k@kA!24KVhwn@+`4!}CYem42NX*qY>2YsMJ8?2qX<9+K^Su%(bXiy zIa__xAGCnb&*7B-u*AAJ;~QcHmziA-NOdMX)5yG)2_k@mgkbFQHTGn54*%$SDH*~A zc;D#fL~nylx6&9d$%O zh@4Iv91-`Ox3EaJS|y#r@lFT{C~zQ+2U(G3-yJjgZ4M&&VyVhdweaW|3Uw%w2uZ>N zlereXz9x+Y*a;e!)-hnBc4#=Hi+4NQB;aPD;?T%mBxsE@e^_suBDg^^eng&Qqw~;n ze%FX=cCAl}K;>`YPP*eRTpgYc>tDzs__N!f|Eo zXO|9U%zg|<=wj>;38JoqY7K)bz_X~GdW}#S0I5?ktM*5a-}7xBf3a}HN<5Ncd2|+w z191bc`rQHHu+ktqf#9^K01(6s6MJv9XxnBOaW%+MTQ{b%$aT&fb8W0GbN4Cc8tP6J zrA3CUp&2U>n`q$BtJC7Y{Ws)hlVMb}#4|j^Xf8bj;<;q?XK_;@W=hunTP^Sg&U;;p z<(G?k`q4#XM$*f0VlK9G2TshC2={O5p!(hWdTIsV0#uV<&MiZX+nbgruT3XQP(2*Y8+ROAJGm;fm7KmFxzt(d*U#L{|M;3qt8SVlo;$}5=6r%dAKetHc-{pO_guK|x zsdyNf!c=Zx6bLF8({}aq=BCbQ(Ak5 z!4*D{>qARa9L09))F76H{&^@4vHlo1+?SJ>1zE1=0KScF(SkuuGeNCHWZhyZQ?2*; z3xk}vXOvZ4#kdmL2`FX>8ETMzk<;oxfkv;L!WqIMc$8C|ZQNrrwu3^hzx>)uG!IiY z1o2O8h`3l6i#2{ICu30Gd#s&${czX?;~ybS=^Y6xCpPO}cIU=Dc&6&yb6{Q}2qQu* zHp73p0;<+RR;Qr>P7s`qeG{E-?8KV-4KQ~pTQ04Qv?fZDjvWpY2C|K1%Z`VNg*t+C zfG=Bxu2Cwjn-l%*ZO)UlAiI>dLuaVj9yzbl{eHDw;%nlH(d-*phpDZRsfmfDow+jybTOdGjRQDS`PK>;u%B>aa6pH2=>PDHgZ z1mUF9A5+kt)^#^q$ zu^ZGOAfh$X23-!8pc7{%%S5?wB}h~fTavj55zqY&rczXAne=l_+yV(1RP)ReXA%tm zH94bB8co4FY48ExhquK%(C4vhkttB+8adR{NvvKlaPGYKXQw8FeGLl}E!z!hrPM45 z+7e`(GVt)bdJ-hzI1e+>L6#Q%=#Trz=}{e(C8h9s1=0;H2WDorK7;1IBcr;)hc=H5 zNmFob@gBi1TxI0Qdzk54%M_CMDijkH(-$+MnUpI2X;ko*7KYYwKsUZ773u=1Q7f8y zd-D+W`1*xPVL~mUpov(;oXhi_j3;8Iyq%4ps$womRWI!uGKEz%*ni$WRInj;olI?h z-82M%i}nNjHj4;@UHtnVcIeLHxJd;hE_lc~$~1Ma5C1qb%{v==sl_xoAAjnUNvz4E zhe}mGUO|4fr6r9UPTb~w-p-w#&MrajPZMl6Fp@N|0voW~zbm(FuNgXCq~Y-llHACd zks{%HyYS|F1nN9@g4g8=Ms^XF#gw_U1ns?f&fC;+9BF*CVRyQRy23plkaub5O?U3R zM@o&&A0Qq5dN z-mWJr$VQ=(xvr{xsIy6@}^-hp*=7>w-vjVAWSuC}IjF6{2M zHmB>`m~_Lgl@lJam*^SRdDzb77ZTZ=SM<6_RT^i8Hr{}AT*aoy=@9!CqTJ}D)<>z- zGNEnDBmLEbE!hu){FO2miFiZ|w1|l-5(Uh387npUOc7BFMKe{J595T1%kKz@^onMF zCgM+twonSzNRaPpANw4l8gDP=gujAHP?AueIAJuZSvh-f>4iUboQcHv3aN>s8jlVk zljZFyaJz$skCgm2pW0VA99ZL5nTO{QW zY)J_%m-R%&7;0f(?WlYAu#DhwE&ia+dM#P+wK+)xaY7v{(-EO(FU$sW8wkXCi|!S4 z5}7-aNGETp?$GtVHor}zo?_?K+W;5OT?&2VNv$R4S4*AV2zP(A=a_h-0ZvU4H94|R zzjQpEzi)%-xvivqgm|7|b=f1{%LJPh2VM?*uvxm2_I55{hwiF-IG8%?K^s+-*rVLW z376iJJCdAdv$~^26`Wc=Ls#a{-i=n1Y_EaqZl+VNhv9#^H^}WvaK#(|NiQh3HDU1$`hh_2Y2= z2d%e|1VRKa^vNoV9qcjxzzQ5%!RroSkVh{t=s7B`aY5MSpEgM-+Pim0#>LF9|ASPw z%;&Jr_Us8v>)$vjQ$cS3Bf8geU&a=_pV=5&pPco7S|^D8o_(MujZaX{Gvo6s^(#Au8lDaI^ZACq zG3Q@bjVP=#>@^<@wpoDq%c_M^{v7qcY5Y$!_-o6~CS95Ga|Y++s`JzMRkHeL8lV2q z`n;U=>qJJZ(1hK=PLX57V0aKA@HtzOcRD{OVg}ftx}lNHzxMyn+jo91JoSIJw>34f zH2m$Um3qr0Q5FV+<%2KLS-(F!&OYDJ($>)2l#AWU!PNZM!Fxscihl`!!6w1?JdKn~ zKbP^W^D`Qp><)In(U=ctZbqO-ge}q`!U)fe!-)yu>|y#B4emdY;P>RvuU3S?%E0$L ziAxzszmeei6A3++Fm;ieFxWNlJx?O<=I+i*sJy00wP%9C ztibm?3AoMg6A}0mi5PxEmrC$Z6oKz~66JuaoQiAz+SF@*B7yrDC7B6uAS&WtUkne; zpKD>~3UnVQp!)p7*Zw(rCQLlO#e*Zm47^q6`KklBaykTOQx_LVar#qpUT(~}`&cj- zsVNMGbMCRM{fjL+yLi}`{;To-=B4B&`PsLNg{iISZ!hIw$@=Skz=dhSZRgib_k6?C Z=3Hk3M>#zhLBtcx87Pk?nV>!F{{RZcHFp32 diff --git a/doc/插入图片用例描述文档.txt b/doc/插入图片用例描述文档.txt deleted file mode 100644 index d212e50..0000000 --- a/doc/插入图片用例描述文档.txt +++ /dev/null @@ -1,23 +0,0 @@ -用例名称:编辑便签插入图片 - -业务目标:编辑便签的时候进行插入图片 - -执行者:用户 - -前置条件: -- 用户需要登录到便签应用中 -- 用户已经创建了一个新的便签或者正在编辑一个已有的便签 - -基本交互动作: -1. 在当前编辑器中,用户点击“插入图片”按钮。 -2. 系统显示一个文件选择框,让用户选择待上传的图片文件。 -3. 用户选择并确认要上传的图片文件。 -4. 系统从本地设备上传选定的图片文件,并自动将其插入到当前编辑器中光标所在的位置。 -5. 在成功添加图片后,用户可以对添加的图片进行调整大小、旋转和定位等操作。 -6. 用户完成编辑后,可以保存或分享该便签,以确保所有内容(包括插入的图片)得以保存。 - - -后置条件: -- 图片成功地添加到了当前编辑器中的光标位置 -- 该图片将在用户保存或分享该便签时一起被保存或分享 - diff --git a/doc/登录功能用例描述文档.txt b/doc/登录功能用例描述文档.txt deleted file mode 100644 index f7177b5..0000000 --- a/doc/登录功能用例描述文档.txt +++ /dev/null @@ -1,18 +0,0 @@ -用例名称:小米便签登录功能 - -业务目标:用户需要登录后才能进入小米便签 - -执行者:用户 - -前置条件: -- 用户需要注册一个账号 - - -基本交互动作: -1. 在小米便签登录页面,用户输入 账号和密码。 -2. 点击确定后系统验证身份正确后可进入小米便签 -3. 可以点击注册去注册一个账号 - -后置条件: -- 用户成功登录后就进入小米便签。 -