From 83e8b7b32f31c94e5422cadaf294d891d254b33f Mon Sep 17 00:00:00 2001 From: nononaku Date: Tue, 18 Jun 2024 21:35:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/net/micode/notes/data/Contact.java | 30 +- .../java/net/micode/notes/data/Notes.java | 280 +++++++++--------- .../notes/data/NotesDatabaseHelper.java | 28 +- .../net/micode/notes/data/NotesProvider.java | 87 +++--- .../net/micode/notes/gtask/data/MetaData.java | 25 +- .../net/micode/notes/gtask/data/Node.java | 58 ++-- .../net/micode/notes/gtask/data/SqlData.java | 62 ++-- .../net/micode/notes/gtask/data/SqlNote.java | 46 ++- .../net/micode/notes/gtask/data/Task.java | 62 +++- .../net/micode/notes/gtask/data/TaskList.java | 151 ++++++++-- .../exception/ActionFailureException.java | 34 ++- .../exception/NetworkFailureException.java | 34 ++- .../notes/gtask/remote/GTaskASyncTask.java | 116 ++++---- .../notes/gtask/remote/GTaskClient.java | 191 ++++++------ .../notes/gtask/remote/GTaskManager.java | 183 ++++++------ .../notes/gtask/remote/GTaskSyncService.java | 41 +++ .../java/net/micode/notes/model/Note.java | 92 ++++-- .../net/micode/notes/model/WorkingNote.java | 194 +++++++----- .../net/micode/notes/tool/BackupUtils.java | 64 ++-- .../java/net/micode/notes/tool/DataUtils.java | 107 ++++++- .../micode/notes/tool/GTaskStringUtils.java | 47 +++ .../net/micode/notes/tool/ResourceParser.java | 127 +++++--- 22 files changed, 1303 insertions(+), 756 deletions(-) diff --git a/app/src/main/java/net/micode/notes/data/Contact.java b/app/src/main/java/net/micode/notes/data/Contact.java index d97ac5d..b80672b 100644 --- a/app/src/main/java/net/micode/notes/data/Contact.java +++ b/app/src/main/java/net/micode/notes/data/Contact.java @@ -1,17 +1,16 @@ /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有(c)2010-2011年,The MiCode开源社区(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 + * 根据Apache许可证2.0版(“许可证”)获得许可; + * 除非符合许可证的规定,否则您不得使用此文件。 + * 您可以在以下网址获取许可证副本: * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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; @@ -30,12 +29,19 @@ public class Contact { 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 " + + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + + " AND " + Data.RAW_CONTACT_ID + " IN " + "(SELECT raw_contact_id " + " FROM phone_lookup" + " WHERE min_match = '+')"; + /** + * 获取电话号码对应的联系人姓名 + * + * @param context 上下文 + * @param phoneNumber 电话号码 + * @return 联系人姓名,如果未找到匹配的联系人,则返回null + */ public static String getContact(Context context, String phoneNumber) { if(sContactCache == null) { sContactCache = new HashMap(); diff --git a/app/src/main/java/net/micode/notes/data/Notes.java b/app/src/main/java/net/micode/notes/data/Notes.java index f240604..f800dab 100644 --- a/app/src/main/java/net/micode/notes/data/Notes.java +++ b/app/src/main/java/net/micode/notes/data/Notes.java @@ -1,22 +1,23 @@ + /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有(c)2010-2011年,The MiCode开源社区(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 + * 根据Apache许可证2.0版(“许可证”)获得许可; + * 除非符合许可证的规定,否则您不得使用此文件。 + * 您可以在以下网址获取许可证副本: * * 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"; @@ -25,10 +26,10 @@ public class Notes { 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 + * 下面的ID是系统文件夹的标识符 + * {@link Notes#ID_ROOT_FOLDER } 是默认文件夹 + * {@link Notes#ID_TEMPARAY_FOLDER } 是不属于任何文件夹的便签 + * {@link Notes#ID_CALL_RECORD_FOLDER} 用于存储通话记录 */ public static final int ID_ROOT_FOLDER = 0; public static final int ID_TEMPARAY_FOLDER = -1; @@ -52,228 +53,223 @@ public class Notes { } /** - * Uri to query all notes and folders + * 用于查询所有便签和文件夹的Uri */ public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); /** - * Uri to query data + * 用于查询数据的Uri */ public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); public interface NoteColumns { /** - * The unique ID for a row - *

Type: INTEGER (long)

+ * 行的唯一ID + *

类型:INTEGER(long)

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

Type: INTEGER (long)

+ * 便签或文件夹的父ID + *

类型:INTEGER(long)

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

Type: INTEGER (long)

+ * 便签或文件夹的创建日期 + *

类型:INTEGER(long)

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

Type: INTEGER (long)

+ * 最新修改日期 + *

类型:INTEGER(long)

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

Type: INTEGER (long)

+ * 提醒日期 + *

类型:INTEGER(long)

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

Type: TEXT

+ * 文件夹的名称或便签的文本内容 + *

类型:TEXT

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

Type: INTEGER (long)

+ * 便签的小部件ID + *

类型:INTEGER(long)

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

Type: INTEGER (long)

+ * 便签的小部件类型 + *

类型:INTEGER(long)

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

Type: INTEGER (long)

+ * 便签的背景颜色ID + *

类型: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

+ * 对于文本便签,它没有附件,对于多媒体便签,它至少有一个附件 + *

类型:INTEGER

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

Type: INTEGER (long)

+ * 文件夹中便签的计数 + *

类型:INTEGER(long)

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

Type: INTEGER

+ * 文件类型:文件夹或便签 + *

类型:INTEGER

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

Type: INTEGER (long)

+ * 最后同步ID + *

类型:INTEGER(long)

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

Type: INTEGER

+ * 表示是否本地修改的标志 + *

类型:INTEGER

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

Type : INTEGER

+ * 移动到临时文件夹之前的原始父ID + *

类型:INTEGER

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

Type : TEXT

+ * GTask ID + *

类型: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"; + * 版本号 + *

+ * 类型:INTEGER(long)

+ */ +public static final String VERSION = "version"; + } + +public interface DataColumns { + /** + * 行的唯一ID + *

类型: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"; + /** + * 此行表示的项的MIME类型。 + *

类型: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"; + /** + * 引用便签的ID,此数据属于该便签 + *

类型: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"; + /** + * 便签或文件夹的创建日期 + *

类型:INTEGER(long)

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

Type: INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; + /** + * 最新修改日期 + *

类型:INTEGER(long)

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

Type: TEXT

- */ - public static final String CONTENT = "content"; + /** + * 数据的内容 + *

类型: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"; + /** + * 通用数据列,含义与{@link #MIMETYPE}特定,用于整数数据类型 + *

类型: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"; + /** + * 通用数据列,含义与{@link #MIMETYPE}特定,用于整数数据类型 + *

类型: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"; + /** + * 通用数据列,含义与{@link #MIMETYPE}特定,用于TEXT数据类型 + *

类型: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"; + /** + * 通用数据列,含义与{@link #MIMETYPE}特定,用于TEXT数据类型 + *

类型: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"; - } + /** + * 通用数据列,含义与{@link #MIMETYPE}特定,用于TEXT数据类型 + *

类型: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 class TextNote implements DataColumns { + /** + * 模式,指示文本是否处于检查列表模式 + *

类型:Integer 1:检查列表模式 0:普通模式

+ */ + public static final String MODE = DATA1; - public static final int MODE_CHECK_LIST = 1; + 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_TYPE = "vnd.android.cursor.dir/text_note"; - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/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 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; +public static final class CallNote implements DataColumns { + /** + * 此记录的通话日期 + *

类型:INTEGER(long)

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

Type: TEXT

- */ - public static final String PHONE_NUMBER = DATA3; + /** + * 此记录的电话号码 + *

类型: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_TYPE = "vnd.android.cursor.dir/call_note"; - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/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"); - } + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); +} } diff --git a/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java b/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java index ffe5d57..a65430f 100644 --- a/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java +++ b/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java @@ -83,7 +83,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { 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 "+ @@ -95,7 +95,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " 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 " + @@ -108,7 +108,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " 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 " + @@ -120,7 +120,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " 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 " + @@ -133,7 +133,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Update note's content when insert data with type {@link DataConstants#NOTE} + * 当插入类型为{@link DataConstants# note}的数据时,更新注释的内容 */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = "CREATE TRIGGER update_note_content_on_insert " + @@ -146,7 +146,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Update note's content when data with {@link DataConstants#NOTE} type has changed + * 当{@link DataConstants# note}类型的数据发生变化时,更新注释的内容 */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = "CREATE TRIGGER update_note_content_on_update " + @@ -159,7 +159,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Update note's content when data with {@link DataConstants#NOTE} type has deleted + * 当{@link DataConstants# note}类型的数据被删除时,更新注释的内容 */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = "CREATE TRIGGER update_note_content_on_delete " + @@ -172,7 +172,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " 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 " + @@ -183,7 +183,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " 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 " + @@ -194,7 +194,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " 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 " + @@ -239,14 +239,14 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { 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); @@ -254,7 +254,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.insert(TABLE.NOTE, null, values); /** - * temporary folder which is used for moving note + *用于移动笔记的临时文件夹 */ values.clear(); values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); @@ -262,7 +262,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.insert(TABLE.NOTE, null, values); /** - * create trash folder + * 创建垃圾文件夹 */ values.clear(); values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); diff --git a/app/src/main/java/net/micode/notes/data/NotesProvider.java b/app/src/main/java/net/micode/notes/data/NotesProvider.java index edb0a60..98cb0c5 100644 --- a/app/src/main/java/net/micode/notes/data/NotesProvider.java +++ b/app/src/main/java/net/micode/notes/data/NotesProvider.java @@ -1,22 +1,9 @@ /* - * 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. + * 这个类为笔记应用提供了一个内容提供者,用于管理数据。 + * 它通过 CRUD 操作与底层的 SQLite 数据库进行交互。 */ - package net.micode.notes.data; - import android.app.SearchManager; import android.content.ContentProvider; import android.content.ContentUris; @@ -34,22 +21,25 @@ 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 { + // 定义用于 URI 匹配的常量 private static final UriMatcher mMatcher; + // 数据库帮助类实例 private NotesDatabaseHelper mHelper; + // 日志标签 private static final String TAG = "NotesProvider"; + // URI 代码 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; + // 初始化 UriMatcher static { mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); @@ -61,62 +51,67 @@ public class NotesProvider extends ContentProvider { 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; + + 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; + // 用于搜索笔记的 SQL 查询 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; + + " FROM " + TABLE.NOTE + + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" + + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + // onCreate 方法 @Override public boolean onCreate() { mHelper = NotesDatabaseHelper.getInstance(getContext()); return true; } + // 查询方法 @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { + 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) { @@ -125,11 +120,10 @@ public class NotesProvider extends ContentProvider { } else { searchString = uri.getQueryParameter("pattern"); } - if (TextUtils.isEmpty(searchString)) { return null; } - + // 执行搜索查询 try { searchString = String.format("%%%s%%", searchString); c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, @@ -147,14 +141,17 @@ public class NotesProvider extends ContentProvider { 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); @@ -166,13 +163,14 @@ public class NotesProvider extends ContentProvider { 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 + // 通知数据 URI 有变化 if (dataId > 0) { getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); @@ -181,6 +179,7 @@ public class NotesProvider extends ContentProvider { return ContentUris.withAppendedId(uri, insertedId); } + // 删除方法 @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; @@ -188,10 +187,12 @@ public class NotesProvider extends ContentProvider { 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); /** @@ -205,10 +206,12 @@ public class NotesProvider extends ContentProvider { 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, @@ -227,6 +230,7 @@ public class NotesProvider extends ContentProvider { return count; } + // 更新方法 @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; @@ -234,20 +238,24 @@ public class NotesProvider extends ContentProvider { 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 @@ -267,10 +275,12 @@ public class NotesProvider extends ContentProvider { 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 "); @@ -296,9 +306,10 @@ public class NotesProvider extends ContentProvider { mHelper.getWritableDatabase().execSQL(sql.toString()); } + // 获取类型方法 @Override public String getType(Uri uri) { - // TODO Auto-generated method stub + // 暂不实现 return null; } diff --git a/app/src/main/java/net/micode/notes/gtask/data/MetaData.java b/app/src/main/java/net/micode/notes/gtask/data/MetaData.java index 3a2050b..7018e96 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/MetaData.java +++ b/app/src/main/java/net/micode/notes/gtask/data/MetaData.java @@ -1,17 +1,16 @@ /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有 (c) 2010-2011,MiCode开源社区(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 + * 根据Apache许可证2.0版(“许可证”)许可; + * 除非符合许可证,否则您不得使用此文件。 + * 您可以在以下网址获取许可证副本: * * 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; @@ -65,18 +64,18 @@ public class MetaData extends Task { @Override public void setContentByLocalJSON(JSONObject js) { - // this function should not be called - throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); + // 不应调用此函数 + throw new IllegalAccessError("MetaData:setContentByLocalJSON不应该被调用"); } @Override public JSONObject getLocalJSONFromContent() { - throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); + throw new IllegalAccessError("MetaData:getLocalJSONFromContent不应该被调用"); } @Override public int getSyncAction(Cursor c) { - throw new IllegalAccessError("MetaData:getSyncAction should not be called"); + throw new IllegalAccessError("MetaData:getSyncAction不应该被调用"); } } diff --git a/app/src/main/java/net/micode/notes/gtask/data/Node.java b/app/src/main/java/net/micode/notes/gtask/data/Node.java index 63950e0..44c1b0c 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/Node.java +++ b/app/src/main/java/net/micode/notes/gtask/data/Node.java @@ -1,17 +1,16 @@ /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有 (c) 2010-2011,MiCode开源社区(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 + * 根据Apache许可证2.0版(“许可证”)许可; + * 除非符合许可证,否则您不得使用此文件。 + * 您可以在以下网址获取许可证副本: * * 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; @@ -20,33 +19,29 @@ import android.database.Cursor; import org.json.JSONObject; +/** + * Node类是所有与GTask同步的数据模型类的基类。 + */ 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; - - private long mLastModified; - - private boolean mDeleted; + private String mGid; // Google任务的ID + private String mName; // 名称 + private long mLastModified; // 最后修改时间 + private boolean mDeleted; // 是否已删除 + /** + * 构造函数,初始化属性 + */ public Node() { mGid = null; mName = ""; @@ -54,48 +49,51 @@ public abstract class Node { mDeleted = false; } + // 抽象方法,由子类实现具体逻辑 public abstract JSONObject getCreateAction(int actionId); - public abstract JSONObject getUpdateAction(int actionId); - public abstract void setContentByRemoteJSON(JSONObject js); - public abstract void setContentByLocalJSON(JSONObject js); - public abstract JSONObject getLocalJSONFromContent(); - public abstract int getSyncAction(Cursor c); + // 设置Google任务ID public void setGid(String gid) { this.mGid = gid; } + // 设置名称 public void setName(String name) { this.mName = name; } + // 设置最后修改时间 public void setLastModified(long lastModified) { this.mLastModified = lastModified; } + // 设置删除状态 public void setDeleted(boolean deleted) { this.mDeleted = deleted; } + // 获取Google任务ID public String getGid() { return this.mGid; } + // 获取名称 public String getName() { return this.mName; } + // 获取最后修改时间 public long getLastModified() { return this.mLastModified; } + // 获取删除状态 public boolean getDeleted() { return this.mDeleted; } - } diff --git a/app/src/main/java/net/micode/notes/gtask/data/SqlData.java b/app/src/main/java/net/micode/notes/gtask/data/SqlData.java index d3ec3be..1c8bcf3 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/SqlData.java +++ b/app/src/main/java/net/micode/notes/gtask/data/SqlData.java @@ -1,17 +1,16 @@ /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有 (c) 2010-2011,MiCode开源社区(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 + * 根据Apache许可证2.0版(“许可证”)许可; + * 除非符合许可证,否则您不得使用此文件。 + * 您可以在以下网址获取许可证副本: * * 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; @@ -34,7 +33,9 @@ import net.micode.notes.gtask.exception.ActionFailureException; import org.json.JSONException; import org.json.JSONObject; - +/** + * SqlData类用于处理与数据库的交互操作,包括创建、更新和获取数据等操作。 + */ public class SqlData { private static final String TAG = SqlData.class.getSimpleName(); @@ -71,6 +72,9 @@ public class SqlData { private ContentValues mDiffDataValues; + /** + * 构造函数,初始化属性 + */ public SqlData(Context context) { mContentResolver = context.getContentResolver(); mIsCreate = true; @@ -82,6 +86,9 @@ public class SqlData { mDiffDataValues = new ContentValues(); } + /** + * 通过数据库查询结果构造SqlData对象 + */ public SqlData(Context context, Cursor c) { mContentResolver = context.getContentResolver(); mIsCreate = false; @@ -89,6 +96,9 @@ public class SqlData { mDiffDataValues = new ContentValues(); } + /** + * 从数据库查询结果中加载数据到对象属性 + */ private void loadFromCursor(Cursor c) { mDataId = c.getLong(DATA_ID_COLUMN); mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); @@ -97,6 +107,9 @@ public class SqlData { mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } + /** + * 设置数据内容 + */ public void setContent(JSONObject js) throws JSONException { long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; if (mIsCreate || mDataId != dataId) { @@ -130,9 +143,12 @@ public class SqlData { mDataContentData3 = dataContentData3; } + /** + * 获取数据内容 + */ public JSONObject getContent() throws JSONException { if (mIsCreate) { - Log.e(TAG, "it seems that we haven't created this in database yet"); + Log.e(TAG, "似乎我们还没有在数据库中创建此数据"); return null; } JSONObject js = new JSONObject(); @@ -144,20 +160,21 @@ public class SqlData { return js; } + /** + * 提交更改到数据库 + */ 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"); + Log.e(TAG, "获取笔记ID错误:" + e.toString()); + throw new ActionFailureException("创建笔记失败"); } } else { if (mDiffDataValues.size() > 0) { @@ -167,23 +184,24 @@ public class SqlData { 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) - }); + 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"); + Log.w(TAG, "没有更新。可能是用户在同步时更新了笔记"); } } } - mDiffDataValues.clear(); mIsCreate = false; } + /** + * 获取数据ID + */ public long getId() { return mDataId; } } + diff --git a/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java b/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java index 79a4095..8dc3c0f 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java +++ b/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java @@ -37,7 +37,7 @@ import org.json.JSONObject; import java.util.ArrayList; - +// SqlData类用于处理与数据库的交互操作,包括创建、更新和获取数据等操作。 public class SqlNote { private static final String TAG = SqlNote.class.getSimpleName(); @@ -121,7 +121,7 @@ public class SqlNote { private ContentValues mDiffNoteValues; private ArrayList mDataList; - + //构造函数、初始化属性 public SqlNote(Context context) { mContext = context; mContentResolver = context.getContentResolver(); @@ -142,7 +142,7 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); mDataList = new ArrayList(); } - + //通过数据库查询结果构造SqlData对象 public SqlNote(Context context, Cursor c) { mContext = context; mContentResolver = context.getContentResolver(); @@ -165,6 +165,7 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); } + //从数据库查询结果中加载数据到对象属性 private void loadFromCursor(long id) { Cursor c = null; @@ -225,14 +226,15 @@ public class SqlNote { c.close(); } } - + // 设置数据内容 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)) { @@ -247,6 +249,7 @@ public class SqlNote { } 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) { @@ -254,6 +257,7 @@ public class SqlNote { } mId = id; + // 提醒日期 long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note .getLong(NoteColumns.ALERTED_DATE) : 0; if (mIsCreate || mAlertDate != alertDate) { @@ -261,6 +265,7 @@ public class SqlNote { } mAlertDate = alertDate; + // 背景颜色 ID int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note .getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext); if (mIsCreate || mBgColorId != bgColorId) { @@ -268,6 +273,7 @@ public class SqlNote { } mBgColorId = bgColorId; + // 创建日期 long createDate = note.has(NoteColumns.CREATED_DATE) ? note .getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis(); if (mIsCreate || mCreatedDate != createDate) { @@ -275,6 +281,7 @@ public class SqlNote { } mCreatedDate = createDate; + // 是否有附件 int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note .getInt(NoteColumns.HAS_ATTACHMENT) : 0; if (mIsCreate || mHasAttachment != hasAttachment) { @@ -282,6 +289,7 @@ public class SqlNote { } mHasAttachment = hasAttachment; + // 修改日期 long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note .getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis(); if (mIsCreate || mModifiedDate != modifiedDate) { @@ -289,6 +297,7 @@ public class SqlNote { } mModifiedDate = modifiedDate; + // 父笔记 ID long parentId = note.has(NoteColumns.PARENT_ID) ? note .getLong(NoteColumns.PARENT_ID) : 0; if (mIsCreate || mParentId != parentId) { @@ -296,6 +305,7 @@ public class SqlNote { } mParentId = parentId; + // 摘要 String snippet = note.has(NoteColumns.SNIPPET) ? note .getString(NoteColumns.SNIPPET) : ""; if (mIsCreate || !mSnippet.equals(snippet)) { @@ -303,6 +313,7 @@ public class SqlNote { } mSnippet = snippet; + // 笔记类型 int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) : Notes.TYPE_NOTE; if (mIsCreate || mType != type) { @@ -310,6 +321,7 @@ public class SqlNote { } mType = type; + // 小部件 ID int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID) : AppWidgetManager.INVALID_APPWIDGET_ID; if (mIsCreate || mWidgetId != widgetId) { @@ -317,6 +329,7 @@ public class SqlNote { } mWidgetId = widgetId; + // 小部件类型 int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note .getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE; if (mIsCreate || mWidgetType != widgetType) { @@ -324,6 +337,7 @@ public class SqlNote { } mWidgetType = widgetType; + // 原始父笔记 ID long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note .getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; if (mIsCreate || mOriginParent != originParent) { @@ -331,6 +345,7 @@ public class SqlNote { } mOriginParent = originParent; + // 遍历数据内容数组,设置笔记数据 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); SqlData sqlData = null; @@ -349,6 +364,7 @@ public class SqlNote { } sqlData.setContent(data); + } } } catch (JSONException e) { @@ -359,6 +375,7 @@ public class SqlNote { return true; } + // 获取笔记内容 public JSONObject getContent() { try { JSONObject js = new JSONObject(); @@ -407,41 +424,51 @@ public class SqlNote { return null; } + // 设置父笔记 ID public void setParentId(long id) { mParentId = id; mDiffNoteValues.put(NoteColumns.PARENT_ID, id); } + // 设置 Google 任务 ID public void setGtaskId(String gid) { mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); } + // 设置同步 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 public long getParentId() { return mParentId; } + // 获取摘要 public String getSnippet() { return mSnippet; } + // 判断是否为普通笔记类型 public boolean isNoteType() { return mType == Notes.TYPE_NOTE; } + // 提交笔记更改 public void commit(boolean validateVersion) { if (mIsCreate) { + // 创建新笔记 if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { mDiffNoteValues.remove(NoteColumns.ID); } @@ -457,12 +484,14 @@ public class SqlNote { throw new IllegalStateException("Create thread id failed"); } + // 如果是普通笔记,则提交笔记数据 if (mType == Notes.TYPE_NOTE) { for (SqlData sqlData : mDataList) { 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"); @@ -473,11 +502,11 @@ public class SqlNote { if (!validateVersion) { result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" + NoteColumns.ID + "=?)", new String[] { - String.valueOf(mId) + String.valueOf(mId) }); } else { result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" - + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", + + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", new String[] { String.valueOf(mId), String.valueOf(mVersion) }); @@ -487,6 +516,7 @@ public class SqlNote { } } + // 如果是普通笔记,则提交笔记数据 if (mType == Notes.TYPE_NOTE) { for (SqlData sqlData : mDataList) { sqlData.commit(mId, validateVersion, mVersion); @@ -494,7 +524,7 @@ public class SqlNote { } } - // refresh local info + // 刷新本地信息 loadFromCursor(mId); if (mType == Notes.TYPE_NOTE) loadDataContent(); diff --git a/app/src/main/java/net/micode/notes/gtask/data/Task.java b/app/src/main/java/net/micode/notes/gtask/data/Task.java index 6a19454..0223c7f 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/Task.java +++ b/app/src/main/java/net/micode/notes/gtask/data/Task.java @@ -31,20 +31,30 @@ 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; + /** + * Task 类的构造函数 + */ public Task() { super(); mCompleted = false; @@ -54,13 +64,15 @@ public class Task extends Node { mMetaInfo = null; } + /** + * 生成用于创建任务的 JSON 对象 + */ 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); + js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); // action_id js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); @@ -72,8 +84,7 @@ public class Task extends Node { JSONObject entity = new JSONObject(); 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_TASK); + entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, GTaskStringUtils.GTASK_JSON_TYPE_TASK); if (getNotes() != null) { entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); } @@ -83,8 +94,7 @@ public class Task extends Node { 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); + js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE, GTaskStringUtils.GTASK_JSON_TYPE_GROUP); // list_id js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid()); @@ -103,13 +113,15 @@ public class Task extends Node { return js; } + /** + * 生成用于更新任务的 JSON 对象 + */ 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); + js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); // action_id js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); @@ -135,6 +147,9 @@ public class Task extends Node { return js; } + /** + * 根据远程 JSON 设置任务内容 + */ public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { @@ -175,10 +190,12 @@ public class Task extends Node { } } + /** + * 根据本地 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"); + if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) || !js.has(GTaskStringUtils.META_HEAD_DATA)) { + Log.w(TAG, "setContentByLocalJSON: nothing is available"); } try { @@ -204,6 +221,9 @@ public class Task extends Node { } } + /** + * 从内容生成本地 JSON + */ public JSONObject getLocalJSONFromContent() { String name = getName(); try { @@ -247,6 +267,9 @@ public class Task extends Node { } } + /** + * 设置元信息 + */ public void setMetaInfo(MetaData metaData) { if (metaData != null && metaData.getNotes() != null) { try { @@ -258,6 +281,9 @@ public class Task extends Node { } } + /** + * 获取同步操作 + */ public int getSyncAction(Cursor c) { try { JSONObject noteInfo = null; @@ -311,41 +337,51 @@ public class Task extends Node { return SYNC_ACTION_ERROR; } + /** + * 判断任务是否值得保存 + */ 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/app/src/main/java/net/micode/notes/gtask/data/TaskList.java b/app/src/main/java/net/micode/notes/gtask/data/TaskList.java index 4ea21c5..7392770 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/TaskList.java +++ b/app/src/main/java/net/micode/notes/gtask/data/TaskList.java @@ -1,17 +1,17 @@ /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有 (c) 2010-2011,The MiCode开放源社区 (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 + * 根据Apache许可证2.0版("许可证")获得许可; + * 除非符合许可证,否则您不得使用此文件。 + * 您可以在以下网址获得许可证副本 * * 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; @@ -43,6 +43,12 @@ public class TaskList extends Node { mIndex = 1; } + /** + * 获取创建动作 + * + * @param actionId 动作ID + * @return JSON对象 + */ public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); @@ -74,6 +80,12 @@ public class TaskList extends Node { return js; } + /** + * 获取更新动作 + * + * @param actionId 动作ID + * @return JSON对象 + */ public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); @@ -103,6 +115,11 @@ public class TaskList extends Node { return js; } + /** + * 通过远程JSON设置内容 + * + * @param js 远程JSON对象 + */ public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { @@ -129,6 +146,11 @@ public class TaskList extends Node { } } + /** + * 通过本地JSON设置内容 + * + * @param js 本地JSON对象 + */ public void setContentByLocalJSON(JSONObject js) { if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); @@ -157,6 +179,11 @@ public class TaskList extends Node { } } + /** + * 从内容获取本地JSON + * + * @return 本地JSON对象 + */ public JSONObject getLocalJSONFromContent() { try { JSONObject js = new JSONObject(); @@ -183,28 +210,34 @@ public class TaskList extends Node { } } + /** + * 获取同步动作 + * + * @param c 光标 + * @return 同步动作 + */ 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 + // 验证gtask id if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { - Log.e(TAG, "gtask id doesn't match"); + Log.e(TAG, "gtask id不匹配"); 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; } } @@ -216,16 +249,27 @@ public class TaskList extends Node { return SYNC_ACTION_ERROR; } + /** + * 获取子任务数量 + * + * @return 子任务数量 + */ public int getChildTaskCount() { return mChildren.size(); } + /** + * 添加子任务 + * + * @param task 子任务 + * @return 是否添加成功 + */ 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); @@ -234,9 +278,16 @@ public class TaskList extends Node { return ret; } + /** + * 添加子任务到指定位置 + * + * @param task 子任务 + * @param index 位置索引 + * @return 是否添加成功 + */ public boolean addChildTask(Task task, int index) { if (index < 0 || index > mChildren.size()) { - Log.e(TAG, "add child task: invalid index"); + Log.e(TAG, "添加子任务:无效的索引"); return false; } @@ -244,7 +295,7 @@ public class TaskList extends Node { if (task != null && pos == -1) { mChildren.add(index, task); - // update the task list + // 更新任务列表 Task preTask = null; Task afterTask = null; if (index != 0) @@ -260,6 +311,12 @@ public class TaskList extends Node { return true; } + /** + * 移除子任务 + * + * @param task 子任务 + * @return 是否移除成功 + */ public boolean removeChildTask(Task task) { boolean ret = false; int index = mChildren.indexOf(task); @@ -267,11 +324,11 @@ public class TaskList extends Node { 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)); @@ -281,16 +338,23 @@ public class TaskList extends Node { return ret; } + /** + * 移动子任务到指定位置 + * + * @param task 子任务 + * @param index 位置索引 + * @return 是否移动成功 + */ public boolean moveChildTask(Task task, int index) { if (index < 0 || index >= mChildren.size()) { - Log.e(TAG, "move child task: invalid index"); + Log.e(TAG, "移动子任务:无效的索引"); return false; } int pos = mChildren.indexOf(task); if (pos == -1) { - Log.e(TAG, "move child task: the task should in the list"); + Log.e(TAG, "移动子任务:任务应在列表中"); return false; } @@ -299,6 +363,12 @@ public class TaskList extends Node { return (removeChildTask(task) && addChildTask(task, index)); } + /** + * 通过GID查找子任务 + * + * @param gid GID + * @return 子任务 + */ public Task findChildTaskByGid(String gid) { for (int i = 0; i < mChildren.size(); i++) { Task t = mChildren.get(i); @@ -309,18 +379,36 @@ public class TaskList extends Node { return null; } + /** + * 获取子任务索引 + * + * @param task 子任务 + * @return 索引 + */ public int getChildTaskIndex(Task task) { return mChildren.indexOf(task); } + /** + * 通过索引获取子任务 + * + * @param index 索引 + * @return 子任务 + */ public Task getChildTaskByIndex(int index) { if (index < 0 || index >= mChildren.size()) { - Log.e(TAG, "getTaskByIndex: invalid index"); + Log.e(TAG, "根据索引获取任务:无效的索引"); return null; } return mChildren.get(index); } + /** + * 通过GID获取子任务 + * + * @param gid GID + * @return 子任务 + */ public Task getChilTaskByGid(String gid) { for (Task task : mChildren) { if (task.getGid().equals(gid)) @@ -329,14 +417,29 @@ public class TaskList extends Node { return null; } + /** + * 获取子任务列表 + * + * @return 子任务列表 + */ public ArrayList getChildTaskList() { return this.mChildren; } + /** + * 设置索引 + * + * @param index 索引 + */ public void setIndex(int index) { this.mIndex = index; } + /** + * 获取索引 + * + * @return 索引 + */ public int getIndex() { return this.mIndex; } diff --git a/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java b/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java index 15504be..1ad478a 100644 --- a/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java +++ b/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java @@ -1,32 +1,48 @@ /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有 (c) 2010-2011年,The MiCode 开源社区 (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 + * 根据 Apache 许可证 2.0 版本(“许可证”)许可; + * 除非符合许可证,否则您不得使用此文件。 + * 您可以在以下网址获取许可证副本: * * 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.exception; +/** + * 表示操作失败的异常。 + */ public class ActionFailureException extends RuntimeException { private static final long serialVersionUID = 4425249765923293627L; + /** + * 创建一个新的 ActionFailureException 实例。 + */ public ActionFailureException() { super(); } + /** + * 使用指定的详细信息创建一个新的 ActionFailureException 实例。 + * + * @param paramString 异常的详细信息 + */ public ActionFailureException(String paramString) { super(paramString); } + /** + * 使用指定的详细信息和原因创建一个新的 ActionFailureException 实例。 + * + * @param paramString 异常的详细信息 + * @param paramThrowable 异常的原因 + */ public ActionFailureException(String paramString, Throwable paramThrowable) { super(paramString, paramThrowable); } diff --git a/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java b/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java index b08cfb1..1566a5f 100644 --- a/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java +++ b/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java @@ -1,32 +1,48 @@ /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有 (c) 2010-2011年,The MiCode 开源社区 (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 + * 根据 Apache 许可证 2.0 版本(“许可证”)许可; + * 除非符合许可证,否则您不得使用此文件。 + * 您可以在以下网址获取许可证副本: * * 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.exception; +/** + * 表示网络故障的异常。 + */ public class NetworkFailureException extends Exception { private static final long serialVersionUID = 2107610287180234136L; + /** + * 创建一个新的 NetworkFailureException 实例。 + */ public NetworkFailureException() { super(); } + /** + * 使用指定的详细信息创建一个新的 NetworkFailureException 实例。 + * + * @param paramString 异常的详细信息 + */ public NetworkFailureException(String paramString) { super(paramString); } + /** + * 使用指定的详细信息和原因创建一个新的 NetworkFailureException 实例。 + * + * @param paramString 异常的详细信息 + * @param paramThrowable 异常的原因 + */ public NetworkFailureException(String paramString, Throwable paramThrowable) { super(paramString, paramThrowable); } diff --git a/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java b/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java index 9b2b03f..38d58aa 100644 --- a/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java +++ b/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java @@ -1,18 +1,16 @@ - /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有 (c) 2010-2011年,The MiCode 开源社区 (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 + * 根据 Apache 许可证 2.0 版本(“许可证”)许可; + * 除非符合许可证,否则您不得使用此文件。 + * 您可以在以下网址获取许可证副本: * * 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; @@ -28,118 +26,106 @@ import net.micode.notes.R; import net.micode.notes.ui.NotesListActivity; import net.micode.notes.ui.NotesPreferenceActivity; - +// 异步任务用于执行与 GTask 同步相关的操作 public class GTaskASyncTask extends AsyncTask { + // GTask 同步通知的 ID private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; + // 定义接口,用于在任务完成时通知调用者 public interface OnCompleteListener { void onComplete(); } - private Context mContext; - - private NotificationManager mNotifiManager; - - private GTaskManager mTaskManager; - - private OnCompleteListener mOnCompleteListener; + private Context mContext; // 上下文对象 + private NotificationManager mNotifiManager; // 通知管理器对象 + private GTaskManager mTaskManager; // GTask 管理器对象 + private OnCompleteListener mOnCompleteListener; // 完成监听器对象 + // 构造函数,接收上下文和完成监听器对象作为参数 public GTaskASyncTask(Context context, OnCompleteListener listener) { mContext = context; mOnCompleteListener = listener; - mNotifiManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); + mNotifiManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); mTaskManager = GTaskManager.getInstance(); } + // 取消同步任务 public void cancelSync() { mTaskManager.cancelSync(); } + // 更新进度信息 public void publishProgess(String message) { - publishProgress(new 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); - + // 如果同步失败,则跳转到偏好设置界面 + pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesPreferenceActivity.class), PendingIntent.FLAG_IMMUTABLE); } else { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesListActivity.class), 0); + // 如果同步成功,则跳转到笔记列表界面 + pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesListActivity.class), PendingIntent.FLAG_IMMUTABLE); } - notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, - pendingIntent); + Notification.Builder builder = new Notification.Builder(mContext) + .setAutoCancel(true) + .setContentTitle(mContext.getString(R.string.app_name)) + .setContentText(content) + .setContentIntent(pendingIntent) + .setWhen(System.currentTimeMillis()) + .setOngoing(true); + Notification notification = builder.build(); mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); } - this function is changed to follows -*/ - -private void showNotification(int tickerId, String content) { - PendingIntent pendingIntent; - if (tickerId != R.string.ticker_success) { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesPreferenceActivity.class), PendingIntent.FLAG_IMMUTABLE); - } else { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesListActivity.class), PendingIntent.FLAG_IMMUTABLE); - } - Notification.Builder builder = new Notification.Builder(mContext) - .setAutoCancel(true) - .setContentTitle(mContext.getString(R.string.app_name)) - .setContentText(content) - .setContentIntent(pendingIntent) - .setWhen(System.currentTimeMillis()) - .setOngoing(true); - Notification notification=builder.getNotification(); - mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); -} + // 执行后台任务,进行 GTask 同步 @Override protected Integer doInBackground(Void... unused) { - publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity - .getSyncAccountName(mContext))); + // 发布登录进度信息 + publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity.getSyncAccountName(mContext))); + // 执行 GTask 同步操作,并返回结果状态码 return mTaskManager.sync(mContext, this); } + // 更新任务进度 @Override protected void onProgressUpdate(String... progress) { + // 显示同步通知 showNotification(R.string.ticker_syncing, progress[0]); + // 如果上下文是 GTaskSyncService 类型,则发送广播 if (mContext instanceof GTaskSyncService) { ((GTaskSyncService) mContext).sendBroadcast(progress[0]); } } + // 后台任务执行完成后调用,根据结果状态码显示相应的通知,并通知完成监听器 @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())); + // 显示同步成功通知,并更新上次同步时间 + 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)); +// 显示同步取消通知 + 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(); } } -} +} \ No newline at end of file diff --git a/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java b/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java index c67dfdf..411406f 100644 --- a/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java +++ b/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java @@ -1,17 +1,15 @@ /* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * 版权所有 (c) 2010-2011, MiCode 开源社区 (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 + * 根据 Apache License 2.0 许可进行许可; + * 您不能使用此文件,除非符合许可。 + * 您可以在以下网址获取许可副本: * * 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; @@ -60,36 +58,44 @@ 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(); + // Google Tasks 的URL 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; + // HTTP客户端 private DefaultHttpClient mHttpClient; + // 请求URL private String mGetUrl; - private String mPostUrl; + // 客户端版本 private long mClientVersion; + // 登录状态 private boolean mLoggedin; + // 上次登录时间 private long mLastLoginTime; + // 动作ID private int mActionId; + // 账号 private Account mAccount; + // 更新数组 private JSONArray mUpdateArray; + // 构造函数 private GTaskClient() { mHttpClient = null; mGetUrl = GTASK_GET_URL; @@ -102,6 +108,7 @@ public class GTaskClient { mUpdateArray = null; } + // 获取单例实例 public static synchronized GTaskClient getInstance() { if (mInstance == null) { mInstance = new GTaskClient(); @@ -109,34 +116,34 @@ public class GTaskClient { return mInstance; } + // 登录方法 public boolean login(Activity activity) { - // we suppose that the cookie would expire after 5 minutes - // then we need to re-login + // 假设cookie在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))) { + .getSyncAccountName(activity))) { mLoggedin = false; } if (mLoggedin) { - Log.d(TAG, "already logged in"); + Log.d(TAG, "已经登录"); return true; } mLastLoginTime = System.currentTimeMillis(); String authToken = loginGoogleAccount(activity, false); if (authToken == null) { - Log.e(TAG, "login google account failed"); + Log.e(TAG, "登录Google账户失败"); 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/"); @@ -151,7 +158,7 @@ public class GTaskClient { } } - // try to login with google official url + // 尝试使用Google官方URL登录 if (!mLoggedin) { mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -164,13 +171,14 @@ public class GTaskClient { return true; } + // 登录Google账户 private String loginGoogleAccount(Activity activity, boolean invalidateToken) { String authToken; AccountManager accountManager = AccountManager.get(activity); Account[] accounts = accountManager.getAccountsByType("com.google"); if (accounts.length == 0) { - Log.e(TAG, "there is no available google account"); + Log.e(TAG, "没有可用的Google账户"); return null; } @@ -185,11 +193,11 @@ public class GTaskClient { if (account != null) { mAccount = account; } else { - Log.e(TAG, "unable to get an account with the same name in the settings"); + Log.e(TAG, "无法获取设置中相同名称的账户"); return null; } - // get the token now + // 获取token AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, "goanna_mobile", null, activity, null, null); try { @@ -198,6 +206,7 @@ public class GTaskClient { if (invalidateToken) { accountManager.invalidateAuthToken("com.google", authToken); loginGoogleAccount(activity, false); + } } catch (Exception e) { Log.e(TAG, "get auth token failed"); @@ -207,27 +216,29 @@ public class GTaskClient { return authToken; } + + // 尝试登录GTask服务 private boolean tryToLoginGtask(Activity activity, String authToken) { if (!loginGtask(authToken)) { - // maybe the auth token is out of date, now let's invalidate the - // token and try again + // 可能auth token已经过期,现在让我们使token失效并重试 authToken = loginGoogleAccount(activity, true); if (authToken == null) { - Log.e(TAG, "login google account failed"); + Log.e(TAG, "登录Google账户失败"); return false; } if (!loginGtask(authToken)) { - Log.e(TAG, "login gtask failed"); + Log.e(TAG, "登录GTask失败"); return false; } } return true; } + // 使用auth token登录GTask private boolean loginGtask(String authToken) { - int timeoutConnection = 10000; - int timeoutSocket = 15000; + int timeoutConnection = 10000; // 连接超时设定 + int timeoutSocket = 15000; // 套接字超时设定 HttpParams httpParameters = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); @@ -236,14 +247,14 @@ public class GTaskClient { mHttpClient.setCookieStore(localBasicCookieStore); HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); - // login gtask + // 登录GTask try { String loginUrl = mGetUrl + "?auth=" + authToken; HttpGet httpGet = new HttpGet(loginUrl); HttpResponse response = null; response = mHttpClient.execute(httpGet); - // get the cookie now + // 获取cookie List cookies = mHttpClient.getCookieStore().getCookies(); boolean hasAuthCookie = false; for (Cookie cookie : cookies) { @@ -252,10 +263,10 @@ public class GTaskClient { } } if (!hasAuthCookie) { - Log.w(TAG, "it seems that there is no auth cookie"); + Log.w(TAG, "似乎没有auth cookie"); } - // get the client version + // 获取客户端版本 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -272,18 +283,20 @@ public class GTaskClient { e.printStackTrace(); return false; } catch (Exception e) { - // simply catch all exceptions - Log.e(TAG, "httpget gtask_url failed"); + // 捕获所有异常 + Log.e(TAG, "httpget gtask_url失败"); return false; } return true; } + // 获取动作ID private int getActionId() { return mActionId++; } + // 创建HttpPost对象 private HttpPost createHttpPost() { HttpPost httpPost = new HttpPost(mPostUrl); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); @@ -291,11 +304,12 @@ public class GTaskClient { return httpPost; } + // 获取响应内容 private String getResponseContent(HttpEntity entity) throws IOException { String contentEncoding = null; if (entity.getContentEncoding() != null) { contentEncoding = entity.getContentEncoding().getValue(); - Log.d(TAG, "encoding: " + contentEncoding); + Log.d(TAG, "编码: " + contentEncoding); } InputStream input = entity.getContent(); @@ -323,10 +337,11 @@ public class GTaskClient { } } + // 发送POST请求 private JSONObject postRequest(JSONObject js) throws NetworkFailureException { if (!mLoggedin) { - Log.e(TAG, "please login first"); - throw new ActionFailureException("not logged in"); + Log.e(TAG, "请先登录"); + throw new ActionFailureException("未登录"); } HttpPost httpPost = createHttpPost(); @@ -336,7 +351,7 @@ public class GTaskClient { UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); httpPost.setEntity(entity); - // execute the post + // 执行POST请求 HttpResponse response = mHttpClient.execute(httpPost); String jsString = getResponseContent(response.getEntity()); return new JSONObject(jsString); @@ -344,36 +359,37 @@ public class GTaskClient { } catch (ClientProtocolException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new NetworkFailureException("postRequest failed"); + throw new NetworkFailureException("postRequest失败"); } catch (IOException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new NetworkFailureException("postRequest failed"); + throw new NetworkFailureException("postRequest失败"); } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new ActionFailureException("unable to convert response content to jsonobject"); + throw new ActionFailureException("无法将响应内容转换为JSONObject"); } catch (Exception e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new ActionFailureException("error occurs when posting request"); + throw new ActionFailureException("发送请求时发生错误"); } } + // 创建任务 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); @@ -382,24 +398,25 @@ public class GTaskClient { } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new ActionFailureException("create task: handing jsonobject failed"); + throw new ActionFailureException("创建任务: 处理JSONObject失败"); } } + // 创建任务列表 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); @@ -408,35 +425,38 @@ public class GTaskClient { } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new ActionFailureException("create tasklist: handing jsonobject failed"); + throw new ActionFailureException("创建任务列表: 处理JSONObject失败"); } } + + // 提交更新 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"); + throw new ActionFailureException("提交更新: 处理JSONObject失败"); } } } + // 添加更新节点 public void addUpdateNode(Node node) throws NetworkFailureException { if (node != null) { - // too many update items may result in an error - // set max to 10 items + // 太多的更新项可能会导致错误,设置最大数量为10项 if (mUpdateArray != null && mUpdateArray.length() > 10) { commitUpdate(); } @@ -447,80 +467,80 @@ public class GTaskClient { } } - public void moveTask(Task task, TaskList preParent, TaskList curParent) - throws NetworkFailureException { + // 移动任务 + 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_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 + // 仅在任务列表内移动且不是第一个时设置prior_sibling_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 + // 仅在不同任务列表之间移动时设置dest_list action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); } actionList.put(action); 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"); + throw new ActionFailureException("移动任务: 处理JSONObject失败"); } } + // 删除节点 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())); 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"); + throw new ActionFailureException("删除节点: 处理JSONObject失败"); } } + // 获取任务列表 public JSONArray getTaskLists() throws NetworkFailureException { if (!mLoggedin) { - Log.e(TAG, "please login first"); - throw new ActionFailureException("not logged in"); + Log.e(TAG, "请先登录"); + throw new ActionFailureException("未登录"); } try { HttpGet httpGet = new HttpGet(mGetUrl); - HttpResponse response = null; - response = mHttpClient.execute(httpGet); + HttpResponse response = mHttpClient.execute(httpGet); - // get the task list + // 获取任务列表 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -535,18 +555,19 @@ public class GTaskClient { } catch (ClientProtocolException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new NetworkFailureException("gettasklists: httpget failed"); + throw new NetworkFailureException("获取任务列表: HTTP GET失败"); } catch (IOException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new NetworkFailureException("gettasklists: httpget failed"); + throw new NetworkFailureException("获取任务列表: HTTP GET失败"); } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new ActionFailureException("get task lists: handing jasonobject failed"); + throw new ActionFailureException("获取任务列表: 处理JSONObject失败"); } } + // 获取特定任务列表 public JSONArray getTaskList(String listGid) throws NetworkFailureException { commitUpdate(); try { @@ -554,31 +575,33 @@ public class GTaskClient { 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_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, 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"); + throw new ActionFailureException("获取特定任务列表: 处理JSONObject失败"); } } + // 获取同步账户 public Account getSyncAccount() { return mAccount; } + // 重置更新数组 public void resetUpdateArray() { mUpdateArray = null; } diff --git a/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java b/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java index d2b4082..9f1bea0 100644 --- a/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java +++ b/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java @@ -49,56 +49,70 @@ import java.util.Map; public class GTaskManager { + // 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; + // 单例模式的GTaskManager实例 private static GTaskManager mInstance = null; + // 活动对象 private Activity mActivity; + // 上下文对象 private Context mContext; + // 内容解析器 private ContentResolver mContentResolver; + // 同步标志 private boolean mSyncing; + // 取消标志 private boolean mCancelled; + // Google任务列表哈希映射 private HashMap mGTaskListHashMap; + // Google任务哈希映射 private HashMap mGTaskHashMap; + // 元数据哈希映射 private HashMap mMetaHashMap; + // 元数据列表 private TaskList mMetaList; + // 本地删除ID映射集合 private HashSet mLocalDeleteIdMap; + // Google ID到笔记ID映射 private HashMap mGidToNid; + // 笔记ID到Google ID映射 private HashMap mNidToGid; + // 私有构造函数,初始化各个字段 private GTaskManager() { mSyncing = false; mCancelled = false; - mGTaskListHashMap = new HashMap(); - mGTaskHashMap = new HashMap(); - mMetaHashMap = new HashMap(); + mGTaskListHashMap = new HashMap<>(); + mGTaskHashMap = new HashMap<>(); + mMetaHashMap = new HashMap<>(); mMetaList = null; - mLocalDeleteIdMap = new HashSet(); - mGidToNid = new HashMap(); - mNidToGid = new HashMap(); + mLocalDeleteIdMap = new HashSet<>(); + mGidToNid = new HashMap<>(); + mNidToGid = new HashMap<>(); } + + // 获取单例 public static synchronized GTaskManager getInstance() { if (mInstance == null) { mInstance = new GTaskManager(); @@ -106,14 +120,16 @@ public class GTaskManager { return mInstance; } + // 设置活动上下文 public synchronized void setActivityContext(Activity activity) { - // used for getting authtoken + // 用于获取authtoken mActivity = activity; } + // 同步任务 public int sync(Context context, GTaskASyncTask asyncTask) { if (mSyncing) { - Log.d(TAG, "Sync is in progress"); + Log.d(TAG, "同步进行中"); return STATE_SYNC_IN_PROGRESS; } mContext = context; @@ -131,18 +147,18 @@ public class GTaskManager { GTaskClient client = GTaskClient.getInstance(); client.resetUpdateArray(); - // login google task + // 登录Google任务 if (!mCancelled) { if (!client.login(mActivity)) { - throw new NetworkFailureException("login google task failed"); + throw new NetworkFailureException("登录Google任务失败"); } } - // get the task list from google + // 从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) { @@ -168,6 +184,7 @@ public class GTaskManager { return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; } + // 初始化任务列表 private void initGTaskList() throws NetworkFailureException { if (mCancelled) return; @@ -175,22 +192,22 @@ public class GTaskManager { try { JSONArray jsTaskLists = client.getTaskLists(); - // init meta list first + // 先初始化meta列表 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)) { + // 处理meta列表 + if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { mMetaList = new TaskList(); mMetaList.setContentByRemoteJSON(object); - // load meta data + // 加载meta数据 JSONArray jsMetas = client.getTaskList(gid); for (int j = 0; j < jsMetas.length(); j++) { - object = (JSONObject) jsMetas.getJSONObject(j); + object = jsMetas.getJSONObject(j); MetaData metaData = new MetaData(); metaData.setContentByRemoteJSON(object); if (metaData.isWorthSaving()) { @@ -203,7 +220,7 @@ public class GTaskManager { } } - // create meta list if not existed + //如果不存在,创建元列表 if (mMetaList == null) { mMetaList = new TaskList(); mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX @@ -211,7 +228,7 @@ public class GTaskManager { 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); @@ -225,7 +242,7 @@ public class GTaskManager { 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); @@ -247,19 +264,21 @@ public class GTaskManager { } } + // 同步内容 private void syncContent() throws NetworkFailureException { int syncType; Cursor c = null; String gid; Node node; + // 清空本地删除ID集合 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[] { @@ -277,7 +296,7 @@ public class GTaskManager { mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); } } else { - Log.w(TAG, "failed to query trash folder"); + Log.w(TAG, "查询垃圾文件夹失败"); } } finally { if (c != null) { @@ -286,10 +305,10 @@ public class GTaskManager { } } - // 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[] { @@ -306,17 +325,17 @@ public class GTaskManager { 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"); + Log.w(TAG, "查询数据库中现有的笔记失败"); } } finally { @@ -326,7 +345,7 @@ public class GTaskManager { } } - // go through remaining items + // 处理剩余项 Iterator> iter = mGTaskHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -334,16 +353,15 @@ public class GTaskManager { 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 + // mCancelled可以被另一个线程设置,所以需要逐一检查 + // 清空本地删除表 if (!mCancelled) { if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { - throw new ActionFailureException("failed to batch-delete local deleted notes"); + throw new ActionFailureException("批量删除本地删除的笔记失败"); } } - // refresh local sync id + // 刷新本地同步ID if (!mCancelled) { GTaskClient.getInstance().commitUpdate(); refreshLocalSyncId(); @@ -351,6 +369,7 @@ public class GTaskManager { } + // 同步文件夹 private void syncFolder() throws NetworkFailureException { Cursor c = null; String gid; @@ -361,7 +380,7 @@ public class GTaskManager { return; } - // for root folder + // 处理根文件夹 try { c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); @@ -373,7 +392,7 @@ public class GTaskManager { 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); @@ -381,7 +400,7 @@ public class GTaskManager { doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); } } else { - Log.w(TAG, "failed to query root folder"); + Log.w(TAG, "查询根文件夹失败"); } } finally { if (c != null) { @@ -390,11 +409,11 @@ public class GTaskManager { } } - // 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) + String.valueOf(Notes.ID_CALL_RECORD_FOLDER) }, null); if (c != null) { if (c.moveToNext()) { @@ -404,8 +423,7 @@ public class GTaskManager { 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)) @@ -415,7 +433,7 @@ public class GTaskManager { } } } else { - Log.w(TAG, "failed to query call note folder"); + Log.w(TAG, "查询通话记录文件夹失败"); } } finally { if (c != null) { @@ -424,7 +442,7 @@ public class GTaskManager { } } - // for local existing folders + // 处理本地存在的文件夹 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type=? AND parent_id<>?)", new String[] { @@ -441,17 +459,17 @@ public class GTaskManager { 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"); + Log.w(TAG, "查询现有文件夹失败"); } } finally { if (c != null) { @@ -460,7 +478,7 @@ public class GTaskManager { } } - // for remote add folders + // 处理远程新增的文件夹 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -510,15 +528,14 @@ public class GTaskManager { 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"); + throw new ActionFailureException("未知的同步操作类型"); } } @@ -549,7 +566,7 @@ public class GTaskManager { 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 + // ID不可用,必须创建一个新的 note.remove(NoteColumns.ID); } } @@ -562,8 +579,7 @@ public class GTaskManager { 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 ID不可用,必须创建一个新的 data.remove(DataColumns.ID); } } @@ -578,21 +594,21 @@ public class GTaskManager { 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"); + Log.e(TAG, "在本地找不到任务的父ID"); + throw new ActionFailureException("无法添加本地节点"); } sqlNote.setParentId(parentId.longValue()); } - // create the local node + // 创建本地节点 sqlNote.setGtaskId(node.getGid()); sqlNote.commit(false); - // update gid-nid mapping + // 更新GID-NID映射 mGidToNid.put(node.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), node.getGid()); - // update meta + // 更新meta信息 updateRemoteMeta(node.getGid(), sqlNote); } @@ -602,23 +618,24 @@ public class GTaskManager { } 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"); + Log.e(TAG, "在本地找不到任务的父ID"); + throw new ActionFailureException("无法更新本地节点"); } sqlNote.setParentId(parentId.longValue()); sqlNote.commit(true); - // update meta info + // 更新meta信息 updateRemoteMeta(node.getGid(), sqlNote); } + private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -627,27 +644,27 @@ public class GTaskManager { 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"); + Log.e(TAG, "找不到任务的父任务列表"); + throw new ActionFailureException("无法添加远程任务"); } 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; @@ -671,7 +688,7 @@ public class GTaskManager { } } - // no match we can add now + // 没有匹配的,现在可以添加 if (tasklist == null) { tasklist = new TaskList(); tasklist.setContentByLocalJSON(sqlNote.getContent()); @@ -681,13 +698,13 @@ public class GTaskManager { n = (Node) tasklist; } - // update local note + // 更新本地笔记 sqlNote.setGtaskId(n.getGid()); sqlNote.commit(false); sqlNote.resetLocalModified(); sqlNote.commit(true); - // gid-id mapping + // gid-id 映射 mGidToNid.put(n.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), n.getGid()); } @@ -699,22 +716,22 @@ public class GTaskManager { 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"); + Log.e(TAG, "找不到任务的父任务列表"); + throw new ActionFailureException("无法更新远程任务"); } TaskList curParentList = mGTaskListHashMap.get(curParentGid); @@ -725,7 +742,7 @@ public class GTaskManager { } } - // clear local modified flag + // 清除本地修改标志 sqlNote.resetLocalModified(); sqlNote.commit(true); } @@ -751,7 +768,7 @@ public class GTaskManager { return; } - // get the latest gtask list + // 获取最新的gtask列表 mGTaskHashMap.clear(); mGTaskListHashMap.clear(); mMetaHashMap.clear(); @@ -774,13 +791,13 @@ public class GTaskManager { mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(SqlNote.ID_COLUMN)), values, null, null); } else { - Log.e(TAG, "something is missed"); + Log.e(TAG, "有些数据缺失"); throw new ActionFailureException( - "some local items don't have gid after sync"); + "同步后某些本地项目没有gid"); } } } else { - Log.w(TAG, "failed to query local note to refresh sync id"); + Log.w(TAG, "查询本地笔记以刷新同步ID失败"); } } finally { if (c != null) { diff --git a/app/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java b/app/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java index cca36f7..9dbe4f5 100644 --- a/app/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java +++ b/app/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java @@ -24,38 +24,57 @@ 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; + // GTask服务广播名称 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(); @@ -64,6 +83,7 @@ public class GTaskSyncService extends Service { @Override public void onCreate() { + // 清空同步任务 mSyncTask = null; } @@ -73,9 +93,11 @@ public class GTaskSyncService extends Service { 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: @@ -89,39 +111,58 @@ public class GTaskSyncService extends Service { @Override public void onLowMemory() { if (mSyncTask != null) { + // 低内存时取消同步任务 mSyncTask.cancelSync(); } } + @Override 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/app/src/main/java/net/micode/notes/model/Note.java b/app/src/main/java/net/micode/notes/model/Note.java index 6706cf6..d1d270e 100644 --- a/app/src/main/java/net/micode/notes/model/Note.java +++ b/app/src/main/java/net/micode/notes/model/Note.java @@ -35,14 +35,15 @@ import java.util.ArrayList; public class Note { - private ContentValues mNoteDiffValues; - private NoteData mNoteData; - private static final String TAG = "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 + * 为添加新笔记创建新的笔记ID */ 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); @@ -56,11 +57,11 @@ public class Note { try { noteId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { - Log.e(TAG, "Get note id error :" + e.toString()); + Log.e(TAG, "获取笔记ID错误:" + e.toString()); noteId = 0; } if (noteId == -1) { - throw new IllegalStateException("Wrong note id:" + noteId); + throw new IllegalStateException("错误的笔记ID:" + noteId); } return noteId; } @@ -77,48 +78,55 @@ public class Note { } public void setTextData(String key, String value) { + // 设置文本数据 mNoteData.setTextData(key, value); } public void setTextDataId(long id) { + // 设置文本数据的ID mNoteData.setTextDataId(id); } public long getTextDataId() { + // 获取文本数据的ID return mNoteData.mTextDataId; } public void setCallDataId(long id) { + // 设置通话数据的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); + // 如果笔记ID无效,抛出异常 + throw new IllegalArgumentException("错误的笔记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 + * 理论上,一旦数据发生变化,笔记应更新 {@link NoteColumns#LOCAL_MODIFIED} 和 + * {@link NoteColumns#MODIFIED_DATE}。为了数据安全性,即使更新笔记失败,也会更新笔记数据信息 */ 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 + Log.e(TAG, "更新笔记错误,不应该发生"); + // 不要返回,继续执行 } mNoteDiffValues.clear(); @@ -131,17 +139,18 @@ public class Note { } private class NoteData { - private long mTextDataId; + private long mTextDataId; // 文本数据ID - private ContentValues mTextDataValues; + private ContentValues mTextDataValues; // 文本数据值 - private long mCallDataId; + private long mCallDataId; // 通话数据ID - private ContentValues mCallDataValues; + private ContentValues mCallDataValues; // 通话数据值 - private static final String TAG = "NoteData"; + private static final String TAG = "NoteData"; // 日志标签 public NoteData() { + // 初始化NoteData对象,创建文本数据和通话数据的ContentValues对象,并将ID初始化为0 mTextDataValues = new ContentValues(); mCallDataValues = new ContentValues(); mTextDataId = 0; @@ -149,103 +158,126 @@ public class Note { } boolean isLocalModified() { + // 检查本地数据是否被修改 return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; } void setTextDataId(long id) { + // 设置文本数据ID,ID必须大于0 if(id <= 0) { - throw new IllegalArgumentException("Text data id should larger than 0"); + throw new IllegalArgumentException("文本数据ID应大于0"); } mTextDataId = id; } void setCallDataId(long id) { + // 设置通话数据ID,ID必须大于0 if (id <= 0) { - throw new IllegalArgumentException("Call data id should larger than 0"); + throw new IllegalArgumentException("通话数据ID应大于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); + // 检查笔记ID是否合法,若不合法则抛出异常 + throw new IllegalArgumentException("错误的笔记ID:" + noteId); } +// 创建一个操作列表用于批量操作数据库 ArrayList operationList = new ArrayList(); ContentProviderOperation.Builder builder = null; - if(mTextDataValues.size() > 0) { + if (mTextDataValues.size() > 0) { + // 若文本数据存在修改,将笔记ID添加到文本数据中 mTextDataValues.put(DataColumns.NOTE_ID, noteId); if (mTextDataId == 0) { + // 若文本数据ID为0,表示需要插入新数据 mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); - Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, - mTextDataValues); + Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, mTextDataValues); try { + // 尝试从返回的URI中获取新插入的数据ID,并设置为文本数据ID setTextDataId(Long.valueOf(uri.getPathSegments().get(1))); } catch (NumberFormatException e) { - Log.e(TAG, "Insert new text data fail with noteId" + noteId); + // 若获取ID失败,记录日志并清空文本数据值,返回null + Log.e(TAG, "插入新文本数据失败,笔记ID:" + noteId); mTextDataValues.clear(); return null; } } else { + // 若文本数据ID不为0,表示需要更新已有数据 builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( Notes.CONTENT_DATA_URI, mTextDataId)); builder.withValues(mTextDataValues); operationList.add(builder.build()); } + // 清空文本数据值 mTextDataValues.clear(); } - if(mCallDataValues.size() > 0) { + if (mCallDataValues.size() > 0) { + // 若通话数据存在修改,将笔记ID添加到通话数据中 mCallDataValues.put(DataColumns.NOTE_ID, noteId); if (mCallDataId == 0) { + // 若通话数据ID为0,表示需要插入新数据 mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); - Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, - mCallDataValues); + Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, mCallDataValues); try { + // 尝试从返回的URI中获取新插入的数据ID,并设置为通话数据ID setCallDataId(Long.valueOf(uri.getPathSegments().get(1))); } catch (NumberFormatException e) { - Log.e(TAG, "Insert new call data fail with noteId" + noteId); + // 若获取ID失败,记录日志并清空通话数据值,返回null + Log.e(TAG, "插入新通话数据失败,笔记ID:" + noteId); mCallDataValues.clear(); return null; } } else { + // 若通话数据ID不为0,表示需要更新已有数据 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); + // 返回操作结果,若无结果或结果为空则返回null return (results == null || results.length == 0 || results[0] == null) ? null : ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId); } catch (RemoteException e) { + // 捕获远程异常,记录日志并返回null Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); return null; } catch (OperationApplicationException e) { + // 捕获操作应用异常,记录日志并返回null Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); return null; } + } return null; } diff --git a/app/src/main/java/net/micode/notes/model/WorkingNote.java b/app/src/main/java/net/micode/notes/model/WorkingNote.java index be081e4..a5d987a 100644 --- a/app/src/main/java/net/micode/notes/model/WorkingNote.java +++ b/app/src/main/java/net/micode/notes/model/WorkingNote.java @@ -33,75 +33,82 @@ import net.micode.notes.tool.ResourceParser.NoteBgResources; public class WorkingNote { - // Note for the working note + // 工作笔记的笔记对象 private Note mNote; - // Note Id + // 笔记ID private long mNoteId; - // Note content + // 笔记内容 private String mContent; - // Note mode + // 笔记模式 + // 笔记的模式 private int mMode; + // 提醒日期 private long mAlertDate; + // 修改日期 private long mModifiedDate; + // 背景颜色ID private int mBgColorId; + // 小部件ID private int mWidgetId; + // 小部件类型 private int mWidgetType; + // 文件夹ID 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, + DataColumns.ID, // 数据ID + DataColumns.CONTENT, // 数据内容 + DataColumns.MIME_TYPE, // 数据MIME类型 + DataColumns.DATA1, // 数据1 + DataColumns.DATA2, // 数据2 + DataColumns.DATA3, // 数据3 + DataColumns.DATA4, // 数据4 }; + // 笔记查询的投影(列名) 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 + NoteColumns.PARENT_ID, // 父ID + NoteColumns.ALERTED_DATE, // 提醒日期 + NoteColumns.BG_COLOR_ID, // 背景颜色ID + NoteColumns.WIDGET_ID, // 小部件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 static final int DATA_ID_COLUMN = 0; // 数据ID列索引 + private static final int DATA_CONTENT_COLUMN = 1; // 数据内容列索引 + private static final int DATA_MIME_TYPE_COLUMN = 2; // 数据MIME类型列索引 + private static final int DATA_MODE_COLUMN = 3; // 数据模式列索引 + + // 笔记表中各列的索引 + private static final int NOTE_PARENT_ID_COLUMN = 0; // 父ID列索引 + private static final int NOTE_ALERTED_DATE_COLUMN = 1; // 提醒日期列索引 + private static final int NOTE_BG_COLOR_ID_COLUMN = 2; // 背景颜色ID列索引 + private static final int NOTE_WIDGET_ID_COLUMN = 3; // 小部件ID列索引 + private static final int NOTE_WIDGET_TYPE_COLUMN = 4; // 小部件类型列索引 + private static final int NOTE_MODIFIED_DATE_COLUMN = 5; // 修改日期列索引 + + // 新笔记构造函数 private WorkingNote(Context context, long folderId) { mContext = context; mAlertDate = 0; @@ -114,7 +121,7 @@ public class WorkingNote { mWidgetType = Notes.TYPE_WIDGET_INVALIDE; } - // Existing note construct + // 已存在笔记构造函数 private WorkingNote(Context context, long noteId, long folderId) { mContext = context; mNoteId = noteId; @@ -124,83 +131,94 @@ public class WorkingNote { loadNote(); } + // 加载笔记 private void loadNote() { + // 查询指定笔记ID的数据 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); + mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); // 获取父文件夹ID + mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); // 获取背景颜色ID + mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); // 获取小部件ID + 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); + // 如果查询结果为空,记录错误日志并抛出异常 + Log.e(TAG, "没有ID为" + mNoteId + "的笔记"); + throw new IllegalArgumentException("找不到ID为 " + mNoteId + " 的笔记"); } - loadNoteData(); + loadNoteData(); // 加载笔记的具体数据 } + // 加载笔记的具体数据 private void loadNoteData() { + // 查询笔记的具体数据 Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { - String.valueOf(mNoteId) + String.valueOf(mNoteId) }, null); + // 检查查询结果是否为空 if (cursor != null) { + // 如果查询到数据,逐行加载 if (cursor.moveToFirst()) { do { - String type = cursor.getString(DATA_MIME_TYPE_COLUMN); + 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)); + mContent = cursor.getString(DATA_CONTENT_COLUMN); // 获取笔记内容 + mMode = cursor.getInt(DATA_MODE_COLUMN); // 获取笔记模式 + mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN)); // 设置文本数据ID } else if (DataConstants.CALL_NOTE.equals(type)) { - mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); + mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); // 设置通话数据ID } else { - Log.d(TAG, "Wrong note type with type:" + type); + Log.d(TAG, "笔记类型错误,类型:" + 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); + // 如果查询结果为空,记录错误日志并抛出异常 + Log.e(TAG, "没有ID为" + mNoteId + "的数据"); + throw new IllegalArgumentException("找不到ID为 " + mNoteId + " 的笔记数据"); } } + // 创建一个空的笔记 public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, - int widgetType, int defaultBgColorId) { + int widgetType, int defaultBgColorId) { WorkingNote note = new WorkingNote(context, folderId); - note.setBgColorId(defaultBgColorId); - note.setWidgetId(widgetId); - note.setWidgetType(widgetType); + note.setBgColorId(defaultBgColorId); // 设置背景颜色ID + note.setWidgetId(widgetId); // 设置小部件ID + note.setWidgetType(widgetType); // 设置小部件类型 return note; } + // 加载指定ID的笔记 public static WorkingNote load(Context context, long id) { return new WorkingNote(context, id, 0); } + // 同步笔记 public synchronized boolean saveNote() { - if (isWorthSaving()) { - if (!existInDatabase()) { + if (isWorthSaving()) { // 检查笔记是否值得保存 + if (!existInDatabase()) { // 检查笔记是否存在于数据库中 if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { - Log.e(TAG, "Create new note fail with id:" + mNoteId); + Log.e(TAG, "创建新笔记失败,ID为:" + mNoteId); return false; } } - mNote.syncNote(mContext, mNoteId); + 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) { @@ -212,10 +230,12 @@ public class WorkingNote { } } + // 检查笔记是否存在于数据库中 public boolean existInDatabase() { return mNoteId > 0; } + // 检查笔记是否值得保存 private boolean isWorthSaving() { if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) || (existInDatabase() && !mNote.isLocalModified())) { @@ -225,10 +245,14 @@ public class WorkingNote { } } + // 设置笔记设置变化监听器 public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { mNoteSettingStatusListener = l; } + + + // 设置提醒日期 public void setAlertDate(long date, boolean set) { if (date != mAlertDate) { mAlertDate = date; @@ -239,14 +263,16 @@ public class WorkingNote { } } + // 标记为已删除 public void markDeleted(boolean mark) { mIsDeleted = mark; if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onWidgetChanged(); + mNoteSettingStatusListener.onWidgetChanged(); } } + // 设置背景颜色ID public void setBgColorId(int id) { if (id != mBgColorId) { mBgColorId = id; @@ -257,6 +283,7 @@ public class WorkingNote { } } + // 设置检查列表模式 public void setCheckListMode(int mode) { if (mMode != mode) { if (mNoteSettingStatusListener != null) { @@ -267,6 +294,7 @@ public class WorkingNote { } } + // 设置小部件类型 public void setWidgetType(int type) { if (type != mWidgetType) { mWidgetType = type; @@ -274,6 +302,7 @@ public class WorkingNote { } } + // 设置小部件ID public void setWidgetId(int id) { if (id != mWidgetId) { mWidgetId = id; @@ -281,6 +310,7 @@ public class WorkingNote { } } + // 设置工作文本 public void setWorkingText(String text) { if (!TextUtils.equals(mContent, text)) { mContent = text; @@ -288,80 +318,94 @@ public class WorkingNote { } } + // 转换为通话笔记 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; } + // 获取背景颜色资源ID public int getBgColorResId() { return NoteBgResources.getNoteBgResource(mBgColorId); } + // 获取背景颜色ID public int getBgColorId() { return mBgColorId; } + // 获取标题背景资源ID public int getTitleBgResId() { return NoteBgResources.getNoteTitleBgResource(mBgColorId); } + // 获取检查列表模式 public int getCheckListMode() { return mMode; } + // 获取笔记ID public long getNoteId() { return mNoteId; } + // 获取文件夹ID public long getFolderId() { return mFolderId; } + // 获取小部件ID 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 + * 在检查列表模式和普通模式之间切换时调用 + * @param oldMode 变化前的模式 + * @param newMode 新模式 */ void onCheckListModeChanged(int oldMode, int newMode); } diff --git a/app/src/main/java/net/micode/notes/tool/BackupUtils.java b/app/src/main/java/net/micode/notes/tool/BackupUtils.java index 39f6ec4..cf2a0b4 100644 --- a/app/src/main/java/net/micode/notes/tool/BackupUtils.java +++ b/app/src/main/java/net/micode/notes/tool/BackupUtils.java @@ -35,10 +35,9 @@ 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) { @@ -49,38 +48,43 @@ public class BackupUtils { } /** - * Following states are signs to represents backup or restore - * status + * 以下状态表示备份或还原的状态 */ - // Currently, the sdcard is not mounted + // 当前,SD卡未挂载 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; + // 备份或还原成功 + + public static final int STATE_SUCCESS = 4; - private TextExport mTextExport; + private TextExport mTextExport; // 声明一个私有的TextExport对象mTextExport。 + // 构造方法,接受一个Context参数,用于初始化mTextExport对象。 private BackupUtils(Context context) { mTextExport = new TextExport(context); } + // 静态方法,检查外部存储是否可用。 private static boolean externalStorageAvailable() { return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); } + // 公共方法,调用mTextExport对象的exportToText方法,返回int值。 public int exportToText() { return mTextExport.exportToText(); } + // 公共方法,获取导出的文本文件的文件名。 public String getExportedTextFileName() { return mTextExport.mFileName; } + // 公共方法,获取导出的文本文件的目录。 public String getExportedTextFileDir() { return mTextExport.mFileDirectory; } @@ -137,23 +141,23 @@ public class BackupUtils { } /** - * Export the folder identified by folder id to text + * 将由文件夹ID标识的文件夹导出为文本 */ 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 + 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()); @@ -163,12 +167,12 @@ public class BackupUtils { } /** - * Export note identified by id to a print stream + * 将由ID标识的笔记导出到打印流中 */ private void exportNoteToText(String noteId, PrintStream ps) { Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { - noteId + noteId }, null); if (dataCursor != null) { @@ -176,7 +180,7 @@ public class BackupUtils { 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); @@ -185,11 +189,11 @@ public class BackupUtils { 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)); @@ -205,7 +209,7 @@ public class BackupUtils { } dataCursor.close(); } - // print a line separator between note + // 在笔记之间打印一行分隔符 try { ps.write(new byte[] { Character.LINE_SEPARATOR, Character.LETTER_NUMBER @@ -216,20 +220,20 @@ public class BackupUtils { } /** - * Note will be exported as text which is user readable + * 将笔记导出为文本,以便用户阅读 */ public int exportToText() { if (!externalStorageAvailable()) { - Log.d(TAG, "Media was not mounted"); + Log.d(TAG, "存储设备未挂载"); return STATE_SD_CARD_UNMOUONTED; } PrintStream ps = getExportToTextPrintStream(); if (ps == null) { - Log.e(TAG, "get print stream error"); + Log.e(TAG, "获取打印流错误"); return STATE_SYSTEM_ERROR; } - // First export folder and its notes + // 首先导出文件夹及其笔记 Cursor folderCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, @@ -240,7 +244,7 @@ public class BackupUtils { 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); @@ -257,7 +261,7 @@ public class BackupUtils { folderCursor.close(); } - // Export notes in root's folder + //在根目录下导出笔记 Cursor noteCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, @@ -283,7 +287,7 @@ public class BackupUtils { } /** - * Get a print stream pointed to the file {@generateExportedTextFile} + * *获取一个指向文件{@generateExportedTextFile}的打印流 */ private PrintStream getExportToTextPrintStream() { File file = generateFileMountedOnSDcard(mContext, R.string.file_path, @@ -310,7 +314,7 @@ public class BackupUtils { } /** - * Generate the text file to store imported data + *生成用于存储导入数据的文本文件 */ private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { StringBuilder sb = new StringBuilder(); diff --git a/app/src/main/java/net/micode/notes/tool/DataUtils.java b/app/src/main/java/net/micode/notes/tool/DataUtils.java index 2a14982..01148c4 100644 --- a/app/src/main/java/net/micode/notes/tool/DataUtils.java +++ b/app/src/main/java/net/micode/notes/tool/DataUtils.java @@ -36,86 +36,125 @@ import java.util.HashSet; public class DataUtils { + // 定义一个用于日志的标签常量 public static final String TAG = "DataUtils"; + + // 批量删除笔记的方法,接受ContentResolver对象和一组笔记的ID集合 public static boolean batchDeleteNotes(ContentResolver resolver, HashSet ids) { + // 检查ID集合是否为null,如果为null,记录日志并返回true if (ids == null) { Log.d(TAG, "the ids is null"); return true; } - if (ids.size() == 0) { + // 检查ID集合是否为空,如果为空,记录日志并返回true + if(ids.size() == 0) { Log.d(TAG, "no id is in the hashset"); return true; } + // 创建一个ContentProviderOperation列表,用于存储删除操作 ArrayList operationList = new ArrayList(); + + // 遍历ID集合,为每个ID创建一个删除操作 for (long id : ids) { + // 如果ID是根文件夹ID,记录错误日志并跳过删除操作 if(id == Notes.ID_ROOT_FOLDER) { Log.e(TAG, "Don't delete system folder root"); continue; } + // 创建删除操作的Builder对象 ContentProviderOperation.Builder builder = ContentProviderOperation .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); + // 将构建好的删除操作添加到操作列表中 operationList.add(builder.build()); } + try { + // 执行批量操作,应用删除操作 ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); + // 检查删除结果,如果结果为空、长度为0或第一个结果为null,记录日志并返回false if (results == null || results.length == 0 || results[0] == null) { Log.d(TAG, "delete notes failed, ids:" + ids.toString()); return false; } + // 删除成功,返回true return true; } catch (RemoteException e) { + // 捕获RemoteException,记录错误日志 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } catch (OperationApplicationException e) { + // 捕获OperationApplicationException,记录错误日志 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } + // 如果发生异常,返回false return false; } + + // 将笔记移动到指定文件夹 public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) { + // 创建一个ContentValues对象,用于存储更新的值 ContentValues values = new ContentValues(); + // 将目标文件夹ID设置为新的父文件夹ID values.put(NoteColumns.PARENT_ID, desFolderId); + // 将原始父文件夹ID设置为源文件夹ID values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); + // 将LOCAL_MODIFIED标记设置为1,表示已修改 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) { + // 批量将笔记移动到指定文件夹 + public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids, long folderId) { + // 检查ID集合是否为空,如果为空,记录日志并返回true if (ids == null) { Log.d(TAG, "the ids is null"); return true; } + // 创建一个操作列表,用于存储更新操作 ArrayList operationList = new ArrayList(); + // 遍历ID集合,为每个ID创建一个更新操作 for (long id : ids) { + // 创建更新操作的Builder对象 ContentProviderOperation.Builder builder = ContentProviderOperation .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); + // 设置更新的值,将目标文件夹ID设置为新的父文件夹ID,将LOCAL_MODIFIED标记设置为1 builder.withValue(NoteColumns.PARENT_ID, folderId); builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); + // 将更新操作添加到操作列表中 operationList.add(builder.build()); } try { + // 应用批量更新操作 ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); + // 检查更新结果,如果结果为空、长度为0或第一个结果为null,记录日志并返回false if (results == null || results.length == 0 || results[0] == null) { Log.d(TAG, "delete notes failed, ids:" + ids.toString()); return false; } + // 更新成功,返回true return true; } catch (RemoteException e) { + // 捕获RemoteException,记录错误日志 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } catch (OperationApplicationException e) { + // 捕获OperationApplicationException,记录错误日志 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } + // 更新失败,返回false 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, + // 查询笔记数据库,统计用户文件夹的数量 + 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)}, @@ -125,18 +164,24 @@ public class DataUtils { if(cursor != null) { if(cursor.moveToFirst()) { try { + // 从查询结果中获取用户文件夹的数量 count = cursor.getInt(0); } catch (IndexOutOfBoundsException e) { + // 捕获IndexOutOfBoundsException异常,记录错误日志 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, @@ -148,12 +193,16 @@ public class DataUtils { 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); @@ -162,12 +211,16 @@ public class DataUtils { 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); @@ -176,28 +229,37 @@ public class DataUtils { 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 + "=?", + " 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 + "=?", @@ -207,24 +269,31 @@ public class DataUtils { HashSet set = null; if (c != null) { if (c.moveToFirst()) { + // 如果查询结果不为空,创建一个HashSet对象,用于存储小部件信息 set = new HashSet(); do { try { + // 遍历查询结果,为每个笔记创建一个小部件属性对象,并将其添加到HashSet中 AppWidgetAttribute widget = new AppWidgetAttribute(); widget.widgetId = c.getInt(0); widget.widgetType = c.getInt(1); set.add(widget); } catch (IndexOutOfBoundsException e) { + // 捕获IndexOutOfBoundsException异常,记录错误日志 Log.e(TAG, e.toString()); } } while (c.moveToNext()); } + // 关闭游标 c.close(); } + // 返回文件夹中所有笔记的小部件信息集合 return set; } + // 根据笔记ID获取通话记录号码 public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { + // 查询指定笔记ID的通话记录号码 Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.PHONE_NUMBER }, CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", @@ -233,38 +302,51 @@ public class DataUtils { if (cursor != null && cursor.moveToFirst()) { try { + // 如果查询结果不为空,获取通话记录号码并返回 return cursor.getString(0); } catch (IndexOutOfBoundsException e) { + // 捕获IndexOutOfBoundsException异常,记录错误日志 Log.e(TAG, "Get call number fails " + e.toString()); } finally { + // 关闭游标 cursor.close(); } } + // 如果查询结果为空或发生异常,返回空字符串 return ""; } - public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { + + // 根据通话日期和电话号码查询通话记录的笔记ID + public static long getCallNoteIdByCallDateAndPhoneNumber(ContentResolver resolver, long callDate, String phoneNumber) { + // 查询通话日期和电话号码匹配的通话记录的笔记ID 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 + ",?)", + + CallNote.PHONE_NUMBER + ",?)", new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, null); if (cursor != null) { if (cursor.moveToFirst()) { try { + // 如果查询结果不为空,获取通话记录的笔记ID并返回 return cursor.getLong(0); } catch (IndexOutOfBoundsException e) { + // 捕获IndexOutOfBoundsException异常,记录错误日志 Log.e(TAG, "Get call note id fails " + e.toString()); } } + // 关闭游标 cursor.close(); } + // 如果查询结果为空或发生异常,返回0 return 0; } + // 根据笔记ID查询摘要 public static String getSnippetById(ContentResolver resolver, long noteId) { + // 查询指定笔记ID的摘要信息 Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, new String [] { NoteColumns.SNIPPET }, NoteColumns.ID + "=?", @@ -274,22 +356,31 @@ public class DataUtils { if (cursor != null) { String snippet = ""; if (cursor.moveToFirst()) { + // 如果查询结果不为空,获取摘要信息并返回 snippet = cursor.getString(0); } + // 关闭游标 cursor.close(); return snippet; } + // 如果查询结果为空,抛出IllegalArgumentException异常 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/app/src/main/java/net/micode/notes/tool/GTaskStringUtils.java b/app/src/main/java/net/micode/notes/tool/GTaskStringUtils.java index 666b729..c0d3a33 100644 --- a/app/src/main/java/net/micode/notes/tool/GTaskStringUtils.java +++ b/app/src/main/java/net/micode/notes/tool/GTaskStringUtils.java @@ -18,96 +18,143 @@ package net.micode.notes.tool; public class GTaskStringUtils { + // GTASK JSON 中的操作 ID public final static String GTASK_JSON_ACTION_ID = "action_id"; + // GTASK JSON 中的操作列表 public final static String GTASK_JSON_ACTION_LIST = "action_list"; + // GTASK JSON 中的操作类型 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"; + // GTASK JSON 中的创建者 ID public final static String GTASK_JSON_CREATOR_ID = "creator_id"; + // GTASK JSON 中的子实体 public final static String GTASK_JSON_CHILD_ENTITY = "child_entity"; + // GTASK JSON 中的客户端版本 public final static String GTASK_JSON_CLIENT_VERSION = "client_version"; + // GTASK JSON 中的完成状态 public final static String GTASK_JSON_COMPLETED = "completed"; + // GTASK JSON 中的当前列表 ID public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id"; + // GTASK JSON 中的默认列表 ID public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id"; + // GTASK JSON 中的已删除标志 public final static String GTASK_JSON_DELETED = "deleted"; + // GTASK JSON 中的目标列表 public final static String GTASK_JSON_DEST_LIST = "dest_list"; + // GTASK JSON 中的目标父实体 public final static String GTASK_JSON_DEST_PARENT = "dest_parent"; + // GTASK JSON 中的目标父实体类型 public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type"; + // GTASK JSON 中的实体变更 public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta"; + // GTASK JSON 中的实体类型 public final static String GTASK_JSON_ENTITY_TYPE = "entity_type"; + // GTASK JSON 中的已删除获取标志 public final static String GTASK_JSON_GET_DELETED = "get_deleted"; + // GTASK JSON 中的 ID public final static String GTASK_JSON_ID = "id"; + // GTASK JSON 中的索引 public final static String GTASK_JSON_INDEX = "index"; + // GTASK JSON 中的最后修改时间 public final static String GTASK_JSON_LAST_MODIFIED = "last_modified"; + // GTASK JSON 中的最新同步点 public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point"; + // GTASK JSON 中的列表 ID public final static String GTASK_JSON_LIST_ID = "list_id"; + // GTASK JSON 中的列表 public final static String GTASK_JSON_LISTS = "lists"; + // GTASK JSON 中的名称 public final static String GTASK_JSON_NAME = "name"; + // GTASK JSON 中的新 ID public final static String GTASK_JSON_NEW_ID = "new_id"; + // GTASK JSON 中的笔记 public final static String GTASK_JSON_NOTES = "notes"; + // GTASK JSON 中的父 ID public final static String GTASK_JSON_PARENT_ID = "parent_id"; + // GTASK JSON 中的上一个兄弟 ID public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id"; + // GTASK JSON 中的结果 public final static String GTASK_JSON_RESULTS = "results"; + // GTASK JSON 中的源列表 public final static String GTASK_JSON_SOURCE_LIST = "source_list"; + // GTASK JSON 中的任务 public final static String GTASK_JSON_TASKS = "tasks"; + // GTASK JSON 中的类型 public final static String GTASK_JSON_TYPE = "type"; + // GTASK JSON 中的组类型 public final static String GTASK_JSON_TYPE_GROUP = "GROUP"; + // GTASK JSON 中的任务类型 public final static String GTASK_JSON_TYPE_TASK = "TASK"; + // GTASK JSON 中的用户 public final static String GTASK_JSON_USER = "user"; + // MIUI 文件夹前缀 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"; + // 元数据头部 GTask ID 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/app/src/main/java/net/micode/notes/tool/ResourceParser.java b/app/src/main/java/net/micode/notes/tool/ResourceParser.java index 1ad3ad6..21c8c9f 100644 --- a/app/src/main/java/net/micode/notes/tool/ResourceParser.java +++ b/app/src/main/java/net/micode/notes/tool/ResourceParser.java @@ -24,149 +24,180 @@ 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 + 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 + 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]; } } + // 获取默认背景颜色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 + 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 + 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, + 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 + 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 { + // 2x小部件背景资源数组 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, + 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, }; + // 获取2x小部件背景资源 public static int getWidget2xBgResource(int id) { return BG_2X_RESOURCES[id]; } + // 4x小部件背景资源数组 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 + 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 }; + // 获取4x小部件背景资源 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 + 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} + * HACKME: 修复存储资源ID在共享首选项中的bug。 + * ID可能大于资源的长度,在这种情况下,返回BG_DEFAULT_FONT_SIZE */ if (id >= TEXTAPPEARANCE_RESOURCES.length) { return BG_DEFAULT_FONT_SIZE; @@ -174,8 +205,10 @@ public class ResourceParser { return TEXTAPPEARANCE_RESOURCES[id]; } + // 获取资源数组的长度 public static int getResourcesSize() { return TEXTAPPEARANCE_RESOURCES.length; } } + }