From 06711ccca6473a9b6387381f988d43ec6f6847d0 Mon Sep 17 00:00:00 2001 From: AetherPendragon Date: Tue, 23 Dec 2025 18:46:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E4=BA=86=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/net/micode/notes/data/Contact.java | 33 +++-- .../src/net/micode/notes/data/Notes.java | 126 +++++++----------- .../notes/data/NotesDatabaseHelper.java | 100 ++++++-------- .../net/micode/notes/data/NotesProvider.java | 41 +++--- .../src/net/micode/notes/model/Note.java | 94 ++++++------- .../net/micode/notes/model/WorkingNote.java | 75 +++++------ .../net/micode/notes/tool/BackupUtils.java | 49 +++---- .../src/net/micode/notes/tool/DataUtils.java | 32 +++-- .../micode/notes/tool/GTaskStringUtils.java | 5 +- .../net/micode/notes/tool/ResourceParser.java | 33 ++--- .../micode/notes/ui/NotesListActivity.java | 28 ++-- .../net/micode/notes/ui/NotesListAdapter.java | 6 +- .../notes/ui/NotesPreferenceActivity.java | 29 ++-- 13 files changed, 297 insertions(+), 354 deletions(-) diff --git a/src/Notes-master/src/net/micode/notes/data/Contact.java b/src/Notes-master/src/net/micode/notes/data/Contact.java index 2b1de54..479516d 100644 --- a/src/Notes-master/src/net/micode/notes/data/Contact.java +++ b/src/Notes-master/src/net/micode/notes/data/Contact.java @@ -26,15 +26,19 @@ import android.util.Log; import java.util.HashMap; /** - * 联系人查询工具类 - * 用于根据电话号码查询联系人姓名 + * 联系人查询工具类。 + *

职责:根据电话号码在系统通讯录中查找联系人姓名,并通过内存缓存减少重复查询。

+ *

使用场景:通话记录笔记等功能需要把电话号码转成可读的联系人姓名。

*/ public class Contact { - /** 联系人缓存,用于提高查询效率 */ + /** 联系人缓存,用于提高查询效率,key 为原始电话号码字符串,value 为联系人姓名 */ private static HashMap sContactCache; private static final String TAG = "Contact"; - /** 查询联系人的SQL选择语句,用于匹配电话号码 */ + /** + * 查询联系人的 SQL 选择语句,用于匹配电话号码。 + *

这里借助 PHONE_NUMBERS_EQUAL 的最小匹配规则,以处理不同国家码、分隔符格式的号码差异。

+ */ 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 " @@ -43,26 +47,27 @@ public class Contact { + " WHERE min_match = '+')"; /** - * 根据电话号码获取联系人姓名 - * @param context 上下文对象 - * @param phoneNumber 电话号码 - * @return 联系人姓名,如果未找到则返回null + * 根据电话号码获取联系人姓名。 + * + * @param context 上下文对象,用于访问 ContentResolver + * @param phoneNumber 电话号码(原始字符串,不做预处理) + * @return 联系人姓名;未找到或异常时返回 null */ public static String getContact(Context context, String phoneNumber) { - // 初始化缓存 + // 初始化缓存:首次调用时创建,后续复用 if(sContactCache == null) { sContactCache = new HashMap(); } - // 先从缓存中查找 + // 先从缓存中查找,命中则直接返回,避免再次访问数据库 if(sContactCache.containsKey(phoneNumber)) { return sContactCache.get(phoneNumber); } - // 构建查询选择语句,使用电话号码的最小匹配格式 + // 构建查询条件:将占位符中的“+”替换为待查询号码的最小匹配值 String selection = CALLER_ID_SELECTION.replace("+", PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); - // 查询联系人数据库 + // 查询联系人数据库,仅投影联系人显示名 Cursor cursor = context.getContentResolver().query( Data.CONTENT_URI, new String [] { Phone.DISPLAY_NAME }, @@ -72,9 +77,9 @@ public class Contact { if (cursor != null && cursor.moveToFirst()) { try { - // 获取联系人姓名 + // 取出第一条记录的联系人姓名 String name = cursor.getString(0); - // 将结果存入缓存 + // 将结果存入缓存,便于下次直接复用 sContactCache.put(phoneNumber, name); return name; } catch (IndexOutOfBoundsException e) { diff --git a/src/Notes-master/src/net/micode/notes/data/Notes.java b/src/Notes-master/src/net/micode/notes/data/Notes.java index dccc41f..0f6e011 100644 --- a/src/Notes-master/src/net/micode/notes/data/Notes.java +++ b/src/Notes-master/src/net/micode/notes/data/Notes.java @@ -19,8 +19,9 @@ package net.micode.notes.data; import android.net.Uri; /** - * 笔记应用的常量定义类 - * 定义了笔记类型、文件夹ID、URI、数据库列名等常量 + * 笔记应用的数据常量定义类。 + *

职责:集中管理 ContentProvider 相关的 URI、表字段、类型常量和系统文件夹 ID,避免硬编码分散。

+ *

主要被数据层(Provider、DatabaseHelper)和业务层(UI、同步)引用。

*/ public class Notes { /** ContentProvider的授权标识 */ @@ -34,10 +35,13 @@ public class Notes { public static final int TYPE_SYSTEM = 2; /** - * 系统文件夹的ID标识符 - * {@link Notes#ID_ROOT_FOLDER } 是默认文件夹 - * {@link Notes#ID_TEMPARAY_FOLDER } 用于存放不属于任何文件夹的笔记 - * {@link Notes#ID_CALL_RECORD_FOLDER} 用于存储通话记录 + * 系统文件夹的 ID 定义。 + *
    + *
  • {@link #ID_ROOT_FOLDER} 默认根文件夹
  • + *
  • {@link #ID_TEMPARAY_FOLDER} 临时文件夹,移动笔记时的中转
  • + *
  • {@link #ID_CALL_RECORD_FOLDER} 通话记录专用文件夹
  • + *
  • {@link #ID_TRASH_FOLER} 回收站
  • + *
*/ /** 根文件夹ID */ public static final int ID_ROOT_FOLDER = 0; @@ -62,9 +66,7 @@ public class Notes { /** 4x4小部件类型 */ public static final int TYPE_WIDGET_4X = 1; - /** - * 数据常量类 - */ + /** 数据类型常量,指明不同数据行的 MIME 类型 */ public static class DataConstants { /** 普通笔记的MIME类型 */ public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; @@ -72,121 +74,97 @@ public class Notes { public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; } - /** - * 查询所有笔记和文件夹的URI - */ + /** 查询所有笔记和文件夹的URI */ public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); - /** - * 查询数据的URI - */ + /** 查询数据表的URI */ public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); - /** - * 笔记表的列名接口 - */ + /** 笔记表的列名接口,声明 note 表包含的所有字段 */ public interface NoteColumns { /** - * 行的唯一ID - *

类型: INTEGER (long)

+ * 行的唯一ID,类型: INTEGER (long) */ public static final String ID = "_id"; /** - * 笔记或文件夹的父ID - *

类型: INTEGER (long)

+ * 笔记或文件夹的父ID,类型: INTEGER (long) */ public static final String PARENT_ID = "parent_id"; /** - * 笔记或文件夹的创建日期 - *

类型: INTEGER (long)

+ * 笔记或文件夹的创建日期,类型: INTEGER (long) */ public static final String CREATED_DATE = "created_date"; /** - * 最后修改日期 - *

类型: INTEGER (long)

+ * 最后修改日期,类型: INTEGER (long) */ public static final String MODIFIED_DATE = "modified_date"; /** - * 提醒日期 - *

类型: INTEGER (long)

+ * 提醒日期,类型: INTEGER (long) */ public static final String ALERTED_DATE = "alert_date"; /** - * 文件夹名称或笔记的文本内容摘要 - *

类型: TEXT

+ * 文件夹名称或笔记的文本内容摘要,类型: TEXT */ public static final String SNIPPET = "snippet"; /** - * 笔记的小部件ID - *

类型: INTEGER (long)

+ * 笔记的小部件ID,类型: INTEGER (long) */ public static final String WIDGET_ID = "widget_id"; /** - * 笔记的小部件类型 - *

类型: INTEGER (long)

+ * 笔记的小部件类型,类型: INTEGER (long) */ public static final String WIDGET_TYPE = "widget_type"; /** - * 笔记的背景颜色ID - *

类型: INTEGER (long)

+ * 笔记的背景颜色ID,类型: INTEGER (long) */ public static final String BG_COLOR_ID = "bg_color_id"; /** - * 是否有附件 - * 对于文本笔记,没有附件;对于多媒体笔记,至少有一个附件 - *

类型: INTEGER

+ * 是否有附件,类型: INTEGER;对于文本笔记没有附件,多媒体笔记至少有一个附件 */ public static final String HAS_ATTACHMENT = "has_attachment"; /** - * 文件夹中的笔记数量 - *

类型: INTEGER (long)

+ * 文件夹中的笔记数量,类型: INTEGER (long) */ public static final String NOTES_COUNT = "notes_count"; /** - * 文件类型:文件夹或笔记 - *

类型: INTEGER

+ * 文件类型:文件夹或笔记,类型: INTEGER */ public static final String TYPE = "type"; /** - * 最后一次同步的ID - *

类型: INTEGER (long)

+ * 最后一次同步的ID,类型: INTEGER (long) */ public static final String SYNC_ID = "sync_id"; /** - * 标记是否在本地被修改 - *

类型: INTEGER

+ * 标记是否在本地被修改,类型: INTEGER */ public static final String LOCAL_MODIFIED = "local_modified"; /** - * 移动到临时文件夹之前的原始父ID - *

类型: INTEGER

+ * 移动到临时文件夹之前的原始父ID,类型: INTEGER */ public static final String ORIGIN_PARENT_ID = "origin_parent_id"; /** - * Google Task的ID - *

类型: TEXT

+ * Google Task的ID,类型: TEXT */ public static final String GTASK_ID = "gtask_id"; /** - * 版本号 - *

类型: INTEGER (long)

+ * 版本号,类型: INTEGER (long) */ public static final String VERSION = "version"; } @@ -196,69 +174,58 @@ public class Notes { */ public interface DataColumns { /** - * 行的唯一ID - *

类型: INTEGER (long)

+ * 行的唯一ID,类型: INTEGER (long) */ public static final String ID = "_id"; /** - * 该行数据项的MIME类型 - *

类型: Text

+ * 该行数据项的MIME类型,类型: TEXT */ public static final String MIME_TYPE = "mime_type"; /** - * 该数据所属笔记的引用ID - *

类型: INTEGER (long)

+ * 该数据所属笔记的引用ID,类型: INTEGER (long) */ public static final String NOTE_ID = "note_id"; /** - * 笔记或文件夹的创建日期 - *

类型: INTEGER (long)

+ * 笔记或文件夹的创建日期,类型: INTEGER (long) */ public static final String CREATED_DATE = "created_date"; /** - * 最后修改日期 - *

类型: INTEGER (long)

+ * 最后修改日期,类型: INTEGER (long) */ public static final String MODIFIED_DATE = "modified_date"; /** - * 数据内容 - *

类型: TEXT

+ * 数据内容,类型: TEXT */ public static final String CONTENT = "content"; /** - * 通用数据列1,含义由{@link #MIME_TYPE}决定,用于存储整数类型数据 - *

类型: INTEGER

+ * 通用数据列1,含义由{@link #MIME_TYPE}决定,用于存储整数类型数据,类型: INTEGER */ public static final String DATA1 = "data1"; /** - * 通用数据列2,含义由{@link #MIME_TYPE}决定,用于存储整数类型数据 - *

类型: INTEGER

+ * 通用数据列2,含义由{@link #MIME_TYPE}决定,用于存储整数类型数据,类型: INTEGER */ public static final String DATA2 = "data2"; /** - * 通用数据列3,含义由{@link #MIME_TYPE}决定,用于存储TEXT类型数据 - *

类型: TEXT

+ * 通用数据列3,含义由{@link #MIME_TYPE}决定,用于存储TEXT类型数据,类型: TEXT */ public static final String DATA3 = "data3"; /** - * 通用数据列4,含义由{@link #MIME_TYPE}决定,用于存储TEXT类型数据 - *

类型: TEXT

+ * 通用数据列4,含义由{@link #MIME_TYPE}决定,用于存储TEXT类型数据,类型: TEXT */ public static final String DATA4 = "data4"; /** - * 通用数据列5,含义由{@link #MIME_TYPE}决定,用于存储TEXT类型数据 - *

类型: TEXT

+ * 通用数据列5,含义由{@link #MIME_TYPE}决定,用于存储TEXT类型数据,类型: TEXT */ public static final String DATA5 = "data5"; } @@ -268,8 +235,7 @@ public class Notes { */ public static final class TextNote implements DataColumns { /** - * 模式标识:文本是否为清单模式 - *

类型: Integer 1:清单模式 0:普通模式

+ * 模式标识:文本是否为清单模式,类型: Integer(1 清单模式,0 普通模式) */ public static final String MODE = DATA1; @@ -291,14 +257,12 @@ public class Notes { */ public static final class CallNote implements DataColumns { /** - * 通话日期 - *

类型: INTEGER (long)

+ * 通话日期,类型: INTEGER (long) */ public static final String CALL_DATE = DATA1; /** - * 电话号码 - *

类型: TEXT

+ * 电话号码,类型: TEXT */ public static final String PHONE_NUMBER = DATA3; diff --git a/src/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java b/src/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java index 9a3ef8d..1c585dc 100644 --- a/src/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java +++ b/src/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java @@ -27,8 +27,9 @@ import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.NoteColumns; /** - * 笔记数据库帮助类 - * 负责创建和管理SQLite数据库,包括笔记表和数据表 + * 笔记数据库帮助类。 + *

职责:负责 SQLite 数据库的创建、升级以及触发器维护;提供 note/data 两张表及其索引、系统文件夹初始化。

+ *

使用方式:通过 {@link #getInstance(Context)} 获取单例,供 ContentProvider 等数据层组件使用。

*/ public class NotesDatabaseHelper extends SQLiteOpenHelper { /** 数据库名称 */ @@ -93,9 +94,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { "CREATE INDEX IF NOT EXISTS note_id_index ON " + TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; - /** - * 触发器:当笔记移动到文件夹时,增加文件夹的笔记计数 - */ + /** 触发器:当笔记移动到文件夹时,增加目标文件夹的笔记计数 */ private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER increase_folder_count_on_update "+ " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + @@ -105,9 +104,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END"; - /** - * 触发器:当笔记从文件夹移出时,减少文件夹的笔记计数 - */ + /** 触发器:当笔记从文件夹移出时,减少原文件夹的笔记计数 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_update " + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + @@ -118,9 +115,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + " END"; - /** - * 触发器:当向文件夹插入新笔记时,增加文件夹的笔记计数 - */ + /** 触发器:向某文件夹插入新笔记时,增加该文件夹的计数 */ private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = "CREATE TRIGGER increase_folder_count_on_insert " + " AFTER INSERT ON " + TABLE.NOTE + @@ -130,9 +125,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END"; - /** - * 触发器:当从文件夹删除笔记时,减少文件夹的笔记计数 - */ + /** 触发器:删除笔记时,减少其父文件夹的计数 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + @@ -143,9 +136,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " AND " + NoteColumns.NOTES_COUNT + ">0;" + " END"; - /** - * 触发器:当插入类型为{@link DataConstants#NOTE}的数据时,更新笔记内容 - */ + /** 触发器:插入 TEXT_NOTE 类型的数据行时,用数据内容刷新 note.snippet */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = "CREATE TRIGGER update_note_content_on_insert " + " AFTER INSERT ON " + TABLE.DATA + @@ -156,9 +147,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END"; - /** - * 触发器:当类型为{@link DataConstants#NOTE}的数据更新时,更新笔记内容 - */ + /** 触发器:更新 TEXT_NOTE 数据行时,同步更新 note.snippet */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = "CREATE TRIGGER update_note_content_on_update " + " AFTER UPDATE ON " + TABLE.DATA + @@ -169,9 +158,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END"; - /** - * 触发器:当类型为{@link DataConstants#NOTE}的数据删除时,更新笔记内容 - */ + /** 触发器:删除 TEXT_NOTE 数据行时,清空 note.snippet */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = "CREATE TRIGGER update_note_content_on_delete " + " AFTER delete ON " + TABLE.DATA + @@ -182,9 +169,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + " END"; - /** - * 触发器:当笔记被删除时,删除属于该笔记的所有数据 - */ + /** 触发器:删除笔记时,级联删除 data 表中对应数据 */ private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = "CREATE TRIGGER delete_data_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + @@ -193,9 +178,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + " END"; - /** - * 触发器:当文件夹被删除时,删除属于该文件夹的所有笔记 - */ + /** 触发器:删除文件夹时,级联删除该文件夹下的笔记 */ private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = "CREATE TRIGGER folder_delete_notes_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + @@ -204,9 +187,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END"; - /** - * 触发器:当文件夹被移动到回收站时,将其中的笔记也移动到回收站 - */ + /** 触发器:移动文件夹到回收站时,其子笔记也同步移动到回收站 */ private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = "CREATE TRIGGER folder_move_notes_on_trash " + " AFTER UPDATE ON " + TABLE.NOTE + @@ -218,7 +199,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * 构造函数 + * 构造函数。 + * * @param context 上下文对象 */ public NotesDatabaseHelper(Context context) { @@ -226,7 +208,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 创建笔记表 + * 创建笔记表并初始化触发器、系统文件夹。 + * * @param db 数据库对象 */ public void createNoteTable(SQLiteDatabase db) { @@ -237,7 +220,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 重新创建笔记表的触发器 + * 重新创建笔记表的触发器。 + *

升级或重建表后调用,确保触发器定义与最新结构一致。

+ * * @param db 数据库对象 */ private void reCreateNoteTableTriggers(SQLiteDatabase db) { @@ -259,38 +244,32 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 创建系统文件夹 + * 创建系统文件夹。 + *

依次插入通话记录、根、临时、回收站四个系统文件夹。

+ * * @param db 数据库对象 */ private void createSystemFolder(SQLiteDatabase db) { ContentValues values = new ContentValues(); - /** - * 创建通话记录文件夹 - */ + // 创建通话记录文件夹 values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); db.insert(TABLE.NOTE, null, values); - /** - * 创建根文件夹(默认文件夹) - */ + // 创建根文件夹(默认文件夹) values.clear(); values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); db.insert(TABLE.NOTE, null, values); - /** - * 创建临时文件夹(用于移动笔记) - */ + // 创建临时文件夹(用于移动笔记) values.clear(); values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); db.insert(TABLE.NOTE, null, values); - /** - * 创建回收站文件夹 - */ + // 创建回收站文件夹 values.clear(); values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); @@ -298,7 +277,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 创建数据表 + * 创建数据表并初始化触发器、索引。 + * * @param db 数据库对象 */ public void createDataTable(SQLiteDatabase db) { @@ -309,7 +289,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 重新创建数据表的触发器 + * 重新创建数据表的触发器。 + * * @param db 数据库对象 */ private void reCreateDataTableTriggers(SQLiteDatabase db) { @@ -323,7 +304,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 获取数据库帮助类的单例实例 + * 获取数据库帮助类的单例实例。 + * * @param context 上下文对象 * @return 数据库帮助类实例 */ @@ -334,9 +316,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { return mInstance; } - /** - * 创建数据库 - */ + /** 创建数据库:依次创建 note 表与 data 表 */ @Override public void onCreate(SQLiteDatabase db) { createNoteTable(db); @@ -344,7 +324,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 升级数据库 + * 升级数据库。 + *

根据旧版本依次执行升级步骤,并在必要时重建触发器。

*/ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { @@ -380,7 +361,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 升级数据库到版本2 + * 升级数据库到版本2:重建所有表。 + * * @param db 数据库对象 */ private void upgradeToV2(SQLiteDatabase db) { @@ -391,7 +373,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 升级数据库到版本3 + * 升级数据库到版本3:移除旧触发器,增加 gtask_id 列,并插入回收站系统文件夹。 + * * @param db 数据库对象 */ private void upgradeToV3(SQLiteDatabase db) { @@ -410,7 +393,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 升级数据库到版本4 + * 升级数据库到版本4:为 note 表新增 version 字段,用于同步冲突控制。 + * * @param db 数据库对象 */ private void upgradeToV4(SQLiteDatabase db) { diff --git a/src/Notes-master/src/net/micode/notes/data/NotesProvider.java b/src/Notes-master/src/net/micode/notes/data/NotesProvider.java index 1b98dc2..50b5876 100644 --- a/src/Notes-master/src/net/micode/notes/data/NotesProvider.java +++ b/src/Notes-master/src/net/micode/notes/data/NotesProvider.java @@ -35,13 +35,14 @@ import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.NotesDatabaseHelper.TABLE; /** - * 笔记内容提供者 - * 提供对笔记数据的CRUD操作和搜索功能 + * 笔记内容提供者。 + *

职责:对外暴露笔记与数据表的 CRUD、搜索、以及通知能力;封装 URI 匹配和权限检查。

+ *

使用场景:UI、同步服务等通过 ContentResolver 访问笔记内容,统一走此 Provider。

*/ public class NotesProvider extends ContentProvider { private static final UriMatcher mMatcher; - /** 数据库帮助类实例 */ + /** 数据库帮助类实例,负责获取读写数据库 */ private NotesDatabaseHelper mHelper; private static final String TAG = "NotesProvider"; @@ -72,9 +73,8 @@ public class NotesProvider extends ContentProvider { } /** - * 笔记搜索投影字段 - * x'0A'代表SQLite中的'\n'字符。对于搜索结果中的标题和内容, - * 我们将去除'\n'和空格以便显示更多信息。 + * 笔记搜索投影字段。 + *

x'0A' 代表 SQLite 中的换行符;搜索时去掉换行与空格,便于列表展示更多内容。

*/ private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," @@ -91,7 +91,7 @@ public class NotesProvider extends ContentProvider { + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; /** - * 初始化ContentProvider + * 初始化 ContentProvider,创建数据库帮助类单例。 */ @Override public boolean onCreate() { @@ -100,7 +100,8 @@ public class NotesProvider extends ContentProvider { } /** - * 查询数据 + * 查询数据。 + *

支持 note/data 全表与单行查询,以及搜索入口。

*/ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, @@ -159,6 +160,7 @@ public class NotesProvider extends ContentProvider { throw new IllegalArgumentException("Unknown URI " + uri); } if (c != null) { + // 通知游标所关联的 URI,用于后续数据变更时自动刷新 c.setNotificationUri(getContext().getContentResolver(), uri); } return c; @@ -186,13 +188,13 @@ public class NotesProvider extends ContentProvider { default: throw new IllegalArgumentException("Unknown URI " + uri); } - // 通知笔记URI的变化 + // 通知笔记 URI 变化(noteId>0 时) if (noteId > 0) { getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); } - // 通知数据URI的变化 + // 通知数据 URI 变化(dataId>0 时) if (dataId > 0) { getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); @@ -202,7 +204,8 @@ public class NotesProvider extends ContentProvider { } /** - * 删除数据 + * 删除数据。 + *

笔记删除时禁止操作系统文件夹(ID<=0);data 删除会同步通知 note 列表以刷新 UI。

*/ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { @@ -242,6 +245,7 @@ public class NotesProvider extends ContentProvider { } if (count > 0) { if (deleteData) { + // 数据行删除会影响笔记摘要,通知笔记 URI getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); } getContext().getContentResolver().notifyChange(uri, null); @@ -250,7 +254,8 @@ public class NotesProvider extends ContentProvider { } /** - * 更新数据 + * 更新数据。 + *

更新 note 时会先自增 version 字段,便于同步冲突检测;data 更新同样通知 note 列表刷新。

*/ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { @@ -285,6 +290,7 @@ public class NotesProvider extends ContentProvider { if (count > 0) { if (updateData) { + // 数据行更新影响笔记摘要,通知笔记 URI getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); } getContext().getContentResolver().notifyChange(uri, null); @@ -293,7 +299,8 @@ public class NotesProvider extends ContentProvider { } /** - * 解析选择条件字符串 + * 拼接 WHERE 子句,如果传入 selection 非空则加上 AND (...)。 + * * @param selection 选择条件 * @return 格式化后的选择条件 */ @@ -302,8 +309,9 @@ public class NotesProvider extends ContentProvider { } /** - * 增加笔记版本号 - * @param id 笔记ID,如果小于0则忽略 + * 增加笔记版本号,用于标记被修改过。 + * + * @param id 笔记ID;小于0表示不按ID过滤,仅使用 selection * @param selection 选择条件 * @param selectionArgs 选择参数 */ @@ -333,7 +341,8 @@ public class NotesProvider extends ContentProvider { } /** - * 获取URI的MIME类型 + * 获取 URI 的 MIME 类型。 + *

当前未使用返回值,保持默认 null。

*/ @Override public String getType(Uri uri) { diff --git a/src/Notes-master/src/net/micode/notes/model/Note.java b/src/Notes-master/src/net/micode/notes/model/Note.java index 306b883..7e8bee8 100644 --- a/src/Notes-master/src/net/micode/notes/model/Note.java +++ b/src/Notes-master/src/net/micode/notes/model/Note.java @@ -34,23 +34,25 @@ import net.micode.notes.data.Notes.TextNote; import java.util.ArrayList; /** - * 笔记模型类 - * 用于表示和操作笔记数据,包括笔记内容和笔记数据 + * 笔记模型类。 + *

职责:封装笔记的元数据(note 表)与数据行(data 表),负责本地修改记录、同步入库以及数据完整性校验。

+ *

调用方式:UI/业务层通过该类设置字段,最后调用 {@link #syncNote(Context, long)} 将变更写回数据库。

*/ public class Note { - /** 笔记差异值,用于记录笔记的修改 */ + /** 笔记差异值,用于记录笔记表的修改字段(增量更新) */ private ContentValues mNoteDiffValues; - /** 笔记数据对象 */ + /** 笔记数据对象,负责文本与通话相关的数据行 */ private NoteData mNoteData; private static final String TAG = "Note"; /** - * 创建新笔记ID,用于向数据库添加新笔记 + * 创建新笔记并返回ID。 + * * @param context 上下文对象 - * @param folderId 文件夹ID - * @return 新创建的笔记ID + * @param folderId 目标父文件夹ID + * @return 新创建的笔记ID(>0);失败抛出异常或返回0 */ public static synchronized long getNewNoteId(Context context, long folderId) { - // 在数据库中创建新笔记 + // 在数据库中创建新笔记:设置创建/修改时间、类型、父文件夹等初始值 ContentValues values = new ContentValues(); long createdTime = System.currentTimeMillis(); values.put(NoteColumns.CREATED_DATE, createdTime); @@ -74,7 +76,7 @@ public class Note { } /** - * 构造函数 + * 构造函数,初始化差异值及数据容器。 */ public Note() { mNoteDiffValues = new ContentValues(); @@ -82,7 +84,8 @@ public class Note { } /** - * 设置笔记值 + * 设置笔记表字段的值,并标记本地修改。 + * * @param key 列名 * @param value 值 */ @@ -93,7 +96,8 @@ public class Note { } /** - * 设置文本数据 + * 设置文本数据字段(data 表)。 + * * @param key 列名 * @param value 值 */ @@ -102,7 +106,8 @@ public class Note { } /** - * 设置文本数据ID + * 设置文本数据ID。 + * * @param id 数据ID */ public void setTextDataId(long id) { @@ -110,7 +115,8 @@ public class Note { } /** - * 获取文本数据ID + * 获取文本数据ID。 + * * @return 文本数据ID */ public long getTextDataId() { @@ -118,7 +124,8 @@ public class Note { } /** - * 设置通话数据ID + * 设置通话数据ID。 + * * @param id 数据ID */ public void setCallDataId(long id) { @@ -126,7 +133,8 @@ public class Note { } /** - * 设置通话数据 + * 设置通话数据字段(data 表)。 + * * @param key 列名 * @param value 值 */ @@ -135,18 +143,20 @@ public class Note { } /** - * 检查是否在本地被修改 - * @return 如果被修改返回true,否则返回false + * 检查笔记或数据是否有本地修改。 + * + * @return true 表示存在未同步的修改 */ public boolean isLocalModified() { return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); } /** - * 同步笔记到数据库 + * 将笔记的增量更新同步到数据库。 + * * @param context 上下文对象 * @param noteId 笔记ID - * @return 同步成功返回true,否则返回false + * @return 同步成功返回 true,失败返回 false */ public boolean syncNote(Context context, long noteId) { if (noteId <= 0) { @@ -157,11 +167,7 @@ public class Note { return true; } - /** - * 理论上,一旦数据改变,笔记应该在{@link NoteColumns#LOCAL_MODIFIED}和 - * {@link NoteColumns#MODIFIED_DATE}上更新。为了数据安全,即使更新笔记失败, - * 我们也会更新笔记数据信息 - */ + // 理论上任何变更都应更新 LOCAL_MODIFIED 与 MODIFIED_DATE;即便 note 表更新失败,也继续尝试写 data if (context.getContentResolver().update( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null, null) == 0) { @@ -179,8 +185,8 @@ public class Note { } /** - * 笔记数据内部类 - * 用于管理笔记的文本数据和通话数据 + * 笔记数据内部类。 + *

职责:管理 data 表中的文本内容与通话记录两类行,负责增量更新和批处理提交。

*/ private class NoteData { /** 文本数据ID */ @@ -197,9 +203,7 @@ public class Note { private static final String TAG = "NoteData"; - /** - * 构造函数 - */ + /** 构造函数:初始化两个数据集与对应 ID */ public NoteData() { mTextDataValues = new ContentValues(); mCallDataValues = new ContentValues(); @@ -208,17 +212,15 @@ public class Note { } /** - * 检查是否在本地被修改 - * @return 如果被修改返回true + * 检查 data 是否被修改。 + * + * @return true 表示文本或通话数据有变更 */ boolean isLocalModified() { return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; } - /** - * 设置文本数据ID - * @param id 数据ID - */ + /** 设置文本数据ID(必须大于0) */ void setTextDataId(long id) { if(id <= 0) { throw new IllegalArgumentException("Text data id should larger than 0"); @@ -226,10 +228,7 @@ public class Note { mTextDataId = id; } - /** - * 设置通话数据ID - * @param id 数据ID - */ + /** 设置通话数据ID(必须大于0) */ void setCallDataId(long id) { if (id <= 0) { throw new IllegalArgumentException("Call data id should larger than 0"); @@ -238,7 +237,8 @@ public class Note { } /** - * 设置通话数据 + * 设置通话数据字段,并同步标记 note 为本地修改。 + * * @param key 列名 * @param value 值 */ @@ -249,7 +249,8 @@ public class Note { } /** - * 设置文本数据 + * 设置文本数据字段,并同步标记 note 为本地修改。 + * * @param key 列名 * @param value 值 */ @@ -260,15 +261,14 @@ public class Note { } /** - * 将数据推送到ContentResolver + * 将数据行推送到 ContentResolver,按需插入或更新。 + * * @param context 上下文对象 * @param noteId 笔记ID - * @return 操作成功返回URI,失败返回null + * @return 成功返回笔记 URI;失败返回 null */ Uri pushIntoContentResolver(Context context, long noteId) { - /** - * 安全检查 - */ + // 安全检查 if (noteId <= 0) { throw new IllegalArgumentException("Wrong note id:" + noteId); } @@ -277,6 +277,7 @@ public class Note { ContentProviderOperation.Builder builder = null; if(mTextDataValues.size() > 0) { + // 写入或更新文本数据(MIME: text_note) mTextDataValues.put(DataColumns.NOTE_ID, noteId); if (mTextDataId == 0) { mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); @@ -299,6 +300,7 @@ public class Note { } if(mCallDataValues.size() > 0) { + // 写入或更新通话数据(MIME: call_note) mCallDataValues.put(DataColumns.NOTE_ID, noteId); if (mCallDataId == 0) { mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); diff --git a/src/Notes-master/src/net/micode/notes/model/WorkingNote.java b/src/Notes-master/src/net/micode/notes/model/WorkingNote.java index c4d4f2a..4d11341 100644 --- a/src/Notes-master/src/net/micode/notes/model/WorkingNote.java +++ b/src/Notes-master/src/net/micode/notes/model/WorkingNote.java @@ -32,11 +32,12 @@ import net.micode.notes.data.Notes.TextNote; import net.micode.notes.tool.ResourceParser.NoteBgResources; /** - * 工作笔记类 - * 表示正在编辑的笔记,提供笔记的加载、保存和属性设置功能 + * 工作笔记类。 + *

职责:代表当前正在编辑/展示的笔记,封装从数据库加载、修改、保存、以及小部件联动等操作。

+ *

使用场景:编辑页、列表点击进入编辑、或小部件创建笔记时,都通过该类聚合业务逻辑。

*/ public class WorkingNote { - /** 笔记对象 */ + /** 底层笔记数据模型,负责具体增量同步 */ private Note mNote; /** 笔记ID */ private long mNoteId; @@ -114,7 +115,8 @@ public class WorkingNote { private static final int NOTE_MODIFIED_DATE_COLUMN = 5; /** - * 新建笔记的构造函数 + * 新建笔记的构造函数。 + * * @param context 上下文对象 * @param folderId 文件夹ID */ @@ -131,7 +133,8 @@ public class WorkingNote { } /** - * 加载已有笔记的构造函数 + * 加载已有笔记的构造函数。 + * * @param context 上下文对象 * @param noteId 笔记ID * @param folderId 文件夹ID @@ -146,7 +149,8 @@ public class WorkingNote { } /** - * 加载笔记数据 + * 加载笔记元数据(note 表),包括父文件夹、背景色、小部件、提醒、修改时间等。 + * 加载完成后再拉取 data 表详细内容。 */ private void loadNote() { Cursor cursor = mContext.getContentResolver().query( @@ -171,7 +175,8 @@ public class WorkingNote { } /** - * 加载笔记的数据内容 + * 加载笔记的数据内容(data 表)。 + *

遍历该笔记的所有数据行:找到文本行(NOTE)记录内容与模式;找到通话行(CALL_NOTE)记录其数据ID。

*/ private void loadNoteData() { Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, @@ -202,12 +207,13 @@ public class WorkingNote { } /** - * 创建空笔记 + * 创建空白笔记实例(尚未写入数据库)。 + * * @param context 上下文对象 - * @param folderId 文件夹ID - * @param widgetId 小部件ID + * @param folderId 目标文件夹ID + * @param widgetId 关联小部件ID * @param widgetType 小部件类型 - * @param defaultBgColorId 默认背景颜色ID + * @param defaultBgColorId 默认背景色 * @return 工作笔记对象 */ public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, @@ -220,7 +226,8 @@ public class WorkingNote { } /** - * 加载笔记 + * 根据笔记ID加载已有笔记。 + * * @param context 上下文对象 * @param id 笔记ID * @return 工作笔记对象 @@ -230,7 +237,8 @@ public class WorkingNote { } /** - * 保存笔记 + * 保存笔记:必要时创建新记录,然后同步增量到 note/data,并刷新小部件。 + * * @return 保存成功返回true,否则返回false */ public synchronized boolean saveNote() { @@ -244,9 +252,7 @@ public class WorkingNote { mNote.syncNote(mContext, mNoteId); - /** - * 如果该笔记存在小部件,更新小部件内容 - */ + // 如果该笔记存在小部件,更新小部件内容 if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { @@ -259,7 +265,7 @@ public class WorkingNote { } /** - * 检查笔记是否存在于数据库中 + * 判断笔记是否已有持久化记录(noteId>0)。 * @return 存在返回true */ public boolean existInDatabase() { @@ -267,7 +273,8 @@ public class WorkingNote { } /** - * 检查笔记是否值得保存 + * 判断笔记是否值得保存。 + *

删除标记、空内容的新建笔记、或无本地改动的已有笔记均不保存。

* @return 值得保存返回true */ private boolean isWorthSaving() { @@ -280,7 +287,7 @@ public class WorkingNote { } /** - * 设置笔记设置变化监听器 + * 注册笔记设置变化监听器(用于通知 UI 或小部件刷新)。 * @param l 监听器对象 */ public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { @@ -288,7 +295,7 @@ public class WorkingNote { } /** - * 设置提醒日期 + * 设置提醒时间,并通知监听器。 * @param date 提醒日期时间戳 * @param set 是否设置提醒 */ @@ -303,7 +310,7 @@ public class WorkingNote { } /** - * 标记笔记为已删除 + * 标记笔记为已删除,若关联小部件则触发刷新。 * @param mark 是否标记为删除 */ public void markDeleted(boolean mark) { @@ -315,7 +322,7 @@ public class WorkingNote { } /** - * 设置背景颜色ID + * 设置背景颜色,并通知监听器、记录本地修改。 * @param id 背景颜色ID */ public void setBgColorId(int id) { @@ -329,8 +336,8 @@ public class WorkingNote { } /** - * 设置清单模式 - * @param mode 模式(0为普通模式,1为清单模式) + * 设置清单模式。 + * @param mode 模式(0 普通,1 清单) */ public void setCheckListMode(int mode) { if (mMode != mode) { @@ -342,10 +349,7 @@ public class WorkingNote { } } - /** - * 设置小部件类型 - * @param type 小部件类型 - */ + /** 设置小部件类型,并记录本地修改 */ public void setWidgetType(int type) { if (type != mWidgetType) { mWidgetType = type; @@ -353,10 +357,7 @@ public class WorkingNote { } } - /** - * 设置小部件ID - * @param id 小部件ID - */ + /** 设置小部件ID,并记录本地修改 */ public void setWidgetId(int id) { if (id != mWidgetId) { mWidgetId = id; @@ -365,7 +366,7 @@ public class WorkingNote { } /** - * 设置工作文本内容 + * 设置当前编辑的文本内容,同时更新 data 表文本字段。 * @param text 文本内容 */ public void setWorkingText(String text) { @@ -376,7 +377,7 @@ public class WorkingNote { } /** - * 转换为通话记录笔记 + * 将当前笔记转换为通话记录笔记:写入通话日期与号码,并移动到通话记录文件夹。 * @param phoneNumber 电话号码 * @param callDate 通话日期 */ @@ -387,7 +388,7 @@ public class WorkingNote { } /** - * 检查是否有时钟提醒 + * 检查是否设置了提醒时间。 * @return 有提醒返回true */ public boolean hasClockAlert() { @@ -438,9 +439,7 @@ public class WorkingNote { return mWidgetType; } - /** - * 笔记设置变化监听器接口 - */ + /** 笔记设置变化监听器接口 */ public interface NoteSettingChangedListener { /** * 当笔记背景颜色改变时调用 diff --git a/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java b/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java index e20f6ba..e22428d 100644 --- a/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java @@ -36,8 +36,9 @@ import java.io.IOException; import java.io.PrintStream; /** - * 备份工具类 - * 提供笔记的导出和备份功能 + * 备份工具类。 + *

职责:导出笔记为可读文本文件,提供状态码供 UI 反馈。

+ *

当前实现仅支持导出,未包含导入逻辑。

*/ public class BackupUtils { private static final String TAG = "BackupUtils"; @@ -45,7 +46,8 @@ public class BackupUtils { private static BackupUtils sInstance; /** - * 获取备份工具类的单例实例 + * 获取备份工具类单例。 + * * @param context 上下文对象 * @return 备份工具类实例 */ @@ -56,9 +58,7 @@ public class BackupUtils { return sInstance; } - /** - * 备份或恢复状态常量 - */ + /** 备份或恢复状态常量 */ /** SD卡未挂载 */ public static final int STATE_SD_CARD_UNMOUONTED = 0; /** 备份文件不存在 */ @@ -73,16 +73,13 @@ public class BackupUtils { /** 文本导出对象 */ private TextExport mTextExport; - /** - * 构造函数 - * @param context 上下文对象 - */ + /** 私有构造:初始化文本导出器 */ private BackupUtils(Context context) { mTextExport = new TextExport(context); } /** - * 检查外部存储是否可用 + * 检查外部存储是否已挂载。 * @return 可用返回true */ private static boolean externalStorageAvailable() { @@ -90,15 +87,15 @@ public class BackupUtils { } /** - * 导出笔记为文本文件 - * @return 导出状态 + * 导出所有笔记为文本文件。 + * @return 导出状态码 */ public int exportToText() { return mTextExport.exportToText(); } /** - * 获取导出的文本文件名 + * 获取最近一次导出的文件名。 * @return 文件名 */ public String getExportedTextFileName() { @@ -106,7 +103,7 @@ public class BackupUtils { } /** - * 获取导出的文本文件目录 + * 获取最近一次导出的文件目录。 * @return 文件目录 */ public String getExportedTextFileDir() { @@ -114,7 +111,7 @@ public class BackupUtils { } /** - * 文本导出内部类 + * 文本导出内部类:遍历 note/data 表,将结果写入 SD 卡上的 txt 文件。 */ private static class TextExport { private static final String[] NOTE_PROJECTION = { @@ -167,9 +164,7 @@ public class BackupUtils { return TEXT_FORMAT[id]; } - /** - * Export the folder identified by folder id to text - */ + /** 将指定文件夹下的笔记导出为文本 */ private void exportFolderToText(String folderId, PrintStream ps) { // Query notes belong to this folder Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, @@ -193,9 +188,7 @@ public class BackupUtils { } } - /** - * Export note identified by id to a print stream - */ + /** 将指定 noteId 的笔记数据写入输出流 */ private void exportNoteToText(String noteId, PrintStream ps) { Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { @@ -246,9 +239,7 @@ 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"); @@ -313,9 +304,7 @@ public class BackupUtils { return STATE_SUCCESS; } - /** - * Get a print stream pointed to the file {@generateExportedTextFile} - */ + /** 创建指向导出文件的 PrintStream;失败返回 null */ private PrintStream getExportToTextPrintStream() { File file = generateFileMountedOnSDcard(mContext, R.string.file_path, R.string.file_name_txt_format); @@ -340,9 +329,7 @@ public class BackupUtils { } } - /** - * Generate the text file to store imported data - */ + /** 生成存储导出内容的文件,位于 SD 卡指定目录下 */ private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { StringBuilder sb = new StringBuilder(); sb.append(Environment.getExternalStorageDirectory()); diff --git a/src/Notes-master/src/net/micode/notes/tool/DataUtils.java b/src/Notes-master/src/net/micode/notes/tool/DataUtils.java index c9eb3bc..c44a2f5 100644 --- a/src/Notes-master/src/net/micode/notes/tool/DataUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/DataUtils.java @@ -35,14 +35,16 @@ import java.util.ArrayList; import java.util.HashSet; /** - * 数据工具类 - * 提供批量删除、移动笔记等数据操作方法 + * 数据工具类。 + *

职责:封装常用的数据库批量操作(删除、移动、查询校验等),统一错误处理与日志。

+ *

使用场景:列表/编辑/同步等需要对 note 表或 data 表做批量操作时复用。

*/ public class DataUtils { public static final String TAG = "DataUtils"; /** - * 批量删除笔记 + * 批量删除笔记。 + * * @param resolver ContentResolver对象 * @param ids 要删除的笔记ID集合 * @return 删除成功返回true,否则返回false @@ -82,13 +84,7 @@ public class DataUtils { return false; } - /** - * 将笔记移动到文件夹 - * @param resolver ContentResolver对象 - * @param id 笔记ID - * @param srcFolderId 源文件夹ID - * @param desFolderId 目标文件夹ID - */ + /** 单条笔记移动到文件夹:记录原父ID并打本地修改标记 */ public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) { ContentValues values = new ContentValues(); values.put(NoteColumns.PARENT_ID, desFolderId); @@ -98,7 +94,8 @@ public class DataUtils { } /** - * 批量移动笔记到文件夹 + * 批量移动笔记到文件夹。 + * * @param resolver ContentResolver对象 * @param ids 要移动的笔记ID集合 * @param folderId 目标文件夹ID @@ -135,9 +132,7 @@ public class DataUtils { return false; } - /** - * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}} - */ + /** 获取用户文件夹数量(排除系统文件夹与回收站) */ public static int getUserFolderCount(ContentResolver resolver) { Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI, new String[] { "COUNT(*)" }, @@ -160,6 +155,7 @@ public class DataUtils { return count; } + /** 判断指定类型的笔记是否存在且未在回收站 */ public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null, @@ -177,6 +173,7 @@ public class DataUtils { return exist; } + /** 判断指定 noteId 是否存在于 note 表 */ public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null, null, null, null); @@ -191,6 +188,7 @@ public class DataUtils { return exist; } + /** 判断指定 dataId 是否存在于 data 表 */ public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null, null, null, null); @@ -205,6 +203,7 @@ public class DataUtils { return exist; } + /** 校验可见文件夹名称是否已存在(排除回收站内) */ public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + @@ -221,6 +220,7 @@ public class DataUtils { 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 }, @@ -248,6 +248,7 @@ public class DataUtils { return set; } + /** 根据 noteId 读取通话笔记的电话号码,未找到则返回空串 */ public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.PHONE_NUMBER }, @@ -267,6 +268,7 @@ public class DataUtils { return ""; } + /** 根据号码与通话日期查找对应的通话记录笔记ID,未找到返回0 */ public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.NOTE_ID }, @@ -288,6 +290,7 @@ public class DataUtils { return 0; } + /** 根据 noteId 获取摘要字段,找不到则抛出异常 */ public static String getSnippetById(ContentResolver resolver, long noteId) { Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, new String [] { NoteColumns.SNIPPET }, @@ -306,6 +309,7 @@ public class DataUtils { throw new IllegalArgumentException("Note is not found with id: " + noteId); } + /** 对摘要进行格式化:去首尾空格并截断首个换行后的内容 */ public static String getFormattedSnippet(String snippet) { if (snippet != null) { snippet = snippet.trim(); diff --git a/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java b/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java index 091c1ab..3ba4f1a 100644 --- a/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java @@ -17,8 +17,9 @@ package net.micode.notes.tool; /** - * Google Task字符串工具类 - * 提供Google Task相关的字符串常量定义 + * Google Task 字符串常量工具类。 + *

职责:集中定义 GTask 协议中使用的 JSON 字段名、动作类型及内置文件夹名,避免各处硬编码。

+ *

使用范围:同步模块读写 GTask JSON 时统一引用。

*/ public class GTaskStringUtils { diff --git a/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java b/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java index b46643f..add8fd2 100644 --- a/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java +++ b/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java @@ -23,8 +23,9 @@ import net.micode.notes.R; import net.micode.notes.ui.NotesPreferenceActivity; /** - * 资源解析器 - * 提供笔记背景颜色、字体大小等资源的解析和获取功能 + * 资源解析器。 + *

职责:集中管理笔记编辑、列表、小部件的背景资源及文字样式尺寸,并提供默认值选择逻辑。

+ *

使用场景:UI 层根据颜色/字号 ID 获取对应的 drawable 或 style 资源。

*/ public class ResourceParser { @@ -54,9 +55,7 @@ public class ResourceParser { /** 默认字体大小 */ 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, @@ -74,27 +73,20 @@ public class ResourceParser { R.drawable.edit_title_red }; - /** - * 获取笔记编辑背景资源ID - * @param id 颜色ID - * @return 背景资源ID - */ + /** 获取笔记编辑背景资源ID */ public static int getNoteBgResource(int id) { return BG_EDIT_RESOURCES[id]; } - /** - * 获取笔记标题背景资源ID - * @param id 颜色ID - * @return 标题背景资源ID - */ + /** 获取笔记标题背景资源ID */ public static int getNoteTitleBgResource(int id) { return BG_EDIT_TITLE_RESOURCES[id]; } } /** - * 获取默认背景ID + * 获取默认背景ID:若开启随机背景则随机选取,否则使用默认黄色。 + * * @param context 上下文对象 * @return 背景颜色ID */ @@ -195,12 +187,11 @@ public class ResourceParser { R.style.TextAppearanceSuper }; + /** + * 获取字号对应的样式资源ID。 + *

修复 SharedPreferences 可能存入非法 index 的问题;越界则回退默认字号。

+ */ public static int getTexAppearanceResource(int id) { - /** - * HACKME: Fix bug of store the resource id in shared preference. - * The id may larger than the length of resources, in this case, - * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} - */ if (id >= TEXTAPPEARANCE_RESOURCES.length) { return BG_DEFAULT_FONT_SIZE; } diff --git a/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java b/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java index e843aec..383bc68 100644 --- a/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java +++ b/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java @@ -78,6 +78,11 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashSet; +/** + * 笔记列表页 Activity。 + *

职责:展示文件夹/笔记列表,支持新建笔记、文件夹管理、批量删除与移动、导出文本、同步入口。

+ *

状态:根目录/子文件夹/通话记录三种视图模式;同步模式下删除改为移动到回收站。

+ */ public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; @@ -91,6 +96,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; + /** + * 列表所处的编辑状态: + * NOTE_LIST 根目录;SUB_FOLDER 子文件夹;CALL_RECORD_FOLDER 通话记录专用文件夹。 + */ private enum ListEditState { NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER }; @@ -141,9 +150,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt setContentView(R.layout.note_list); initResources(); - /** - * Insert an introduction when user firstly use this application - */ + // 首次进入时插入“介绍”笔记 setAppInfoFromRawRes(); } @@ -356,22 +363,13 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt int newNoteViewHeight = mAddNewNote.getHeight(); int start = screenHeight - newNoteViewHeight; int eventY = start + (int) event.getY(); - /** - * Minus TitleBar's height - */ + // 子文件夹状态需减去标题栏高度 if (mState == ListEditState.SUB_FOLDER) { eventY -= mTitleBar.getHeight(); start -= mTitleBar.getHeight(); } - /** - * HACKME:When click the transparent part of "New Note" button, dispatch - * the event to the list view behind this button. The transparent part of - * "New Note" button could be expressed by formula y=-0.12x+94(Unit:pixel) - * and the line top of the button. The coordinate based on left of the "New - * Note" button. The 94 represents maximum height of the transparent part. - * Notice that, if the background of the button changes, the formula should - * also change. This is very bad, just for the UI designer's strong requirement. - */ + // HACKME: 点击“新建”按钮透明区时,将事件派发给下方列表。 + // 透明区近似线性公式 y = -0.12x + 94(px),背景改动需同步更新该公式。 if (event.getY() < (event.getX() * (-0.12) + 94)) { View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1 - mNotesListView.getFooterViewsCount()); diff --git a/src/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java b/src/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java index 4a6e519..a0ed61e 100644 --- a/src/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java +++ b/src/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java @@ -31,14 +31,14 @@ import java.util.HashSet; import java.util.Iterator; /** - * 笔记列表适配器 - * 用于在ListView中显示笔记列表,支持多选模式 + * 笔记列表适配器。 + *

职责:为列表提供笔记/文件夹数据视图绑定,管理多选状态(批量删除/移动),并暴露选中项信息。

*/ public class NotesListAdapter extends CursorAdapter { private static final String TAG = "NotesListAdapter"; /** 上下文对象 */ private Context mContext; - /** 选中的索引映射 */ + /** 选中的索引映射(position -> 是否选中) */ private HashMap mSelectedIndex; /** 笔记数量 */ private int mNotesCount; diff --git a/src/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java b/src/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java index e13e62d..1b62671 100644 --- a/src/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java +++ b/src/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java @@ -48,8 +48,9 @@ import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.gtask.remote.GTaskSyncService; /** - * 笔记设置活动 - * 提供应用的设置界面,包括账户管理、同步等功能 + * 笔记设置页面。 + *

职责:承载账户绑定/切换、GTask 同步开关、上次同步时间展示、背景随机开关等设置。

+ *

关键点:绑定账户时需清理本地 gtask 关联字段;同步过程中禁止修改账户;页面通过广播实时刷新同步状态。

*/ public class NotesPreferenceActivity extends PreferenceActivity { public static final String PREFERENCE_NAME = "notes_preferences"; @@ -76,7 +77,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { protected void onCreate(Bundle icicle) { super.onCreate(icicle); - /* using the app icon for navigation */ + // ActionBar 返回上一层 getActionBar().setDisplayHomeAsUpEnabled(true); addPreferencesFromResource(R.xml.preferences); @@ -95,8 +96,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { protected void onResume() { super.onResume(); - // need to set sync account automatically if user has added a new - // account + // 若用户刚新增了 Google 账号,自动选中新账号为同步账号 if (mHasAddedAccount) { Account[] accounts = getGoogleAccounts(); if (mOriAccounts != null && accounts.length > mOriAccounts.length) { @@ -136,13 +136,12 @@ public class NotesPreferenceActivity extends PreferenceActivity { accountPref.setSummary(getString(R.string.preferences_account_summary)); accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { - if (!GTaskSyncService.isSyncing()) { + if (!GTaskSyncService.isSyncing()) { // 同步中禁止切换账号 if (TextUtils.isEmpty(defaultAccount)) { - // the first time to set account + // 首次设置账户 showSelectAccountAlertDialog(); } else { - // if the account has already been set, we need to promp - // user about the risk + // 已绑定过账号,提示更换风险 showChangeAccountConfirmAlertDialog(); } } else { @@ -161,7 +160,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { Button syncButton = (Button) findViewById(R.id.preference_sync_button); TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview); - // set button state + // 根据同步状态配置按钮文案与行为 if (GTaskSyncService.isSyncing()) { syncButton.setText(getString(R.string.preferences_button_sync_cancel)); syncButton.setOnClickListener(new View.OnClickListener() { @@ -179,7 +178,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { } syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); - // set last sync time + // 展示最近同步时间或实时进度 if (GTaskSyncService.isSyncing()) { lastSyncTimeView.setText(GTaskSyncService.getProgressString()); lastSyncTimeView.setVisibility(View.VISIBLE); @@ -276,7 +275,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (which == 0) { - showSelectAccountAlertDialog(); + showSelectAccountAlertDialog(); // 重新选择账户 } else if (which == 1) { removeSyncAccount(); refreshUI(); @@ -302,10 +301,10 @@ public class NotesPreferenceActivity extends PreferenceActivity { } editor.commit(); - // clean up last sync time + // 清空上次同步时间 setLastSyncTime(this, 0); - // clean up local gtask related info + // 清理本地 gtask 关联信息,避免账号切换后污染 new Thread(new Runnable() { public void run() { ContentValues values = new ContentValues(); @@ -332,7 +331,7 @@ public class NotesPreferenceActivity extends PreferenceActivity { } editor.commit(); - // clean up local gtask related info + // 清理本地 gtask 关联信息 new Thread(new Runnable() { public void run() { ContentValues values = new ContentValues();