diff --git a/doc/小米便签开源代码泛读报告.docx b/doc/小米便签开源代码泛读报告.docx new file mode 100644 index 0000000..88a6b89 Binary files /dev/null and b/doc/小米便签开源代码泛读报告.docx differ diff --git a/doc/小米标签MiNote+泛读报告.docx b/doc/小米标签MiNote+泛读报告.docx deleted file mode 100644 index 3981294..0000000 Binary files a/doc/小米标签MiNote+泛读报告.docx and /dev/null differ diff --git a/src/Contact.java b/src/Contact.java deleted file mode 100644 index b9b793b..0000000 --- a/src/Contact.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.micode.notes.data; - -import android.content.Context; // 导入Android上下文类,用于访问系统资源 -import android.database.Cursor; // 导入Android游标类,用于查询数据库 -import android.provider.ContactsContract.CommonDataKinds.Phone; // 导入Android联系人电话信息类 -import android.provider.ContactsContract.Data; // 导入Android联系人数据类 -import android.telephony.PhoneNumberUtils; // 导入Android电话号码工具类 -import android.util.Log; // 导入Android日志工具类 - -import java.util.HashMap; // 导入Java哈希表类,用于缓存查询结果 - -public class Contact { - // 静态的哈希表,用于缓存电话号码和对应的联系人姓名 - private static HashMap sContactCache; - // 日志标签,用于在日志中标识来自该类的消息 - private static final String TAG = "Contact"; - - // 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 " - + "(SELECT raw_contact_id " - + " FROM phone_lookup" - + " WHERE min_match = '+')"; - - // 根据给定的电话号码获取联系人的姓名 - public static String getContact(Context context, String phoneNumber) { - // 如果缓存为空,则初始化缓存 - if(sContactCache == null) { - sContactCache = new HashMap(); - } - - // 检查缓存中是否已有该电话号码对应的联系人姓名 - if(sContactCache.containsKey(phoneNumber)) { - return sContactCache.get(phoneNumber); // 如果存在,则直接返回缓存中的姓名 - } - - // 构造SQL查询条件,将占位符"+"替换为电话号码的最小匹配字符 - String selection = CALLER_ID_SELECTION.replace("+", - PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); - - // 执行数据库查询,获取与电话号码匹配的联系人姓名 - Cursor cursor = context.getContentResolver().query( - Data.CONTENT_URI, // 查询联系人数据表 - new String [] { Phone.DISPLAY_NAME }, // 需要查询的字段:联系人显示名称 - selection, // 查询条件 - new String[] { phoneNumber }, // 查询条件中的占位符参数 - null); // 排序条件,这里为null表示不排序 - - // 检查查询结果是否为空且是否可以移动到第一行 - if (cursor != null && cursor.moveToFirst()) { - try { - String name = cursor.getString(0); // 获取联系人显示名称 - sContactCache.put(phoneNumber, name); // 将查询结果存入缓存 - return name; // 返回联系人姓名 - } catch (IndexOutOfBoundsException e) { - // 如果发生数组越界异常,记录错误日志并返回null - Log.e(TAG, " Cursor get string error " + e.toString()); - return null; - } finally { - cursor.close(); // 关闭游标,释放资源 - } - } else { - // 如果没有找到匹配的联系人,记录调试日志并返回null - Log.d(TAG, "No contact matched with number:" + phoneNumber); - return null; - } - } -} diff --git a/src/Notes.java b/src/Notes.java deleted file mode 100644 index 2f2907e..0000000 --- a/src/Notes.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 你可以在不违反许可协议的情况下使用此文件。 - * 你可以在以下地址获取许可证的副本: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 除非适用法律要求或书面同意,软件 - * 根据许可证分发是按“原样”基础进行的, - * 不附带任何明示或暗示的担保或条件。 - * 请参阅许可证以获取特定语言的权限和 - * 限制。 - */ - -package net.micode.notes.data; - -import android.net.Uri; - -// 定义了一个名为Notes的类,包含了与笔记应用相关的常量和接口 -public class Notes { - // 定义了Content Provider的权限字符串 - public static final String AUTHORITY = "micode_notes"; - // 定义了日志标签字符串 - public static final String TAG = "Notes"; - - // 定义了笔记类型的常量 - public static final int TYPE_NOTE = 0; // 笔记类型 - public static final int TYPE_FOLDER = 1; // 文件夹类型 - public static final int TYPE_SYSTEM = 2; // 系统类型 - - /** - * 以下ID是系统文件夹的标识符 - * {@link Notes#ID_ROOT_FOLDER } 是默认文件夹 - * {@link Notes#ID_TEMPARAY_FOLDER } 用于不属于任何文件夹的笔记 - * {@link Notes#ID_CALL_RECORD_FOLDER} 用于存储通话记录 - * {@link Notes#ID_TRASH_FOLER} 用于存储已删除的笔记 - */ - public static final int ID_ROOT_FOLDER = 0; - public static final int ID_TEMPARAY_FOLDER = -1; - public static final int ID_CALL_RECORD_FOLDER = -2; - public static final int ID_TRASH_FOLER = -3; - - // 定义了一些Intent的extra键名 - public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; // 提醒日期 - public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; // 背景颜色ID - public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; // 小部件ID - public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; // 小部件类型 - public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; // 文件夹ID - public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; // 通话日期 - - // 定义了小部件类型的常量 - public static final int TYPE_WIDGET_INVALIDE = -1; // 无效的小部件 - public static final int TYPE_WIDGET_2X = 0; // 2x尺寸的小部件 - public static final int TYPE_WIDGET_4X = 1; // 4x尺寸的小部件 - - // 定义一个内部类DataConstants,包含一些与数据类型相关的常量 - public static class DataConstants { - // 定义了文本笔记的数据类型 - public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; - // 定义了通话笔记的数据类型 - public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; - } - - /** - * Uri用于查询所有的笔记和文件夹 - * 解析为:content://micode_notes/note - */ - public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); - - /** - * Uri用于查询数据 - * 解析为:content://micode_notes/data - */ - public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); - - // 定义了一个接口NoteColumns,包含了一些与笔记和文件夹相关的列名 - public interface NoteColumns { - /** - * 笔记或文件夹的唯一ID - *

类型:INTEGER (long)

- */ - public static final String ID = "_id"; - - /** - * 笔记或文件夹的父ID - *

类型:INTEGER (long)

- */ - public static final String PARENT_ID = "parent_id"; - - /** - * 笔记或文件夹的创建日期 - *

类型:INTEGER (long)

- */ - public static final String CREATED_DATE = "created_date"; - - /** - * 笔记或文件夹的最新修改日期 - *

类型:INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; - - /** - * 笔记的提醒日期 - *

类型:INTEGER (long)

- */ - public static final String ALERTED_DATE = "alert_date"; - - /** - * 文件夹的名称或笔记的文本内容 - *

类型:TEXT

- */ - public static final String SNIPPET = "snippet"; - - /** - * 笔记的小部件ID - *

类型:INTEGER (long)

- */ - public static final String WIDGET_ID = "widget_id"; - - /** - * 笔记的小部件类型 - *

类型:INTEGER (long)

- */ - public static final String WIDGET_TYPE = "widget_type"; - - /** - * 笔记的背景颜色ID - *

类型:INTEGER (long)

- */ - public static final String BG_COLOR_ID = "bg_color_id"; - - /** - * 对于文本笔记,它没有附件;对于多媒体笔记,至少有一个附件 - *

类型:INTEGER

- */ - public static final String HAS_ATTACHMENT = "has_attachment"; - - /** - * 文件夹中的笔记数量 - *

类型:INTEGER (long)

- */ - public static final String NOTES_COUNT = "notes_count"; - - /** - * 笔记或文件夹的类型 - *

类型:INTEGER

- */ - public static final String TYPE = "type"; - - /** - * 最后同步ID - *

类型:INTEGER (long)

- */ - public static final String SYNC_ID = "sync_id"; - - /** - * 标志以指示是否本地修改过 - *

类型:INTEGER

- */ - public static final String LOCAL_MODIFIED = "local_modified"; - - /** - * 移动到临时文件夹之前的原始父ID - *

类型:INTEGER

- */ - public static final String ORIGIN_PARENT_ID = "origin_parent_id"; - - /** - * Google任务ID - *

类型:TEXT

- */ - public static final String GTASK_ID = "gtask_id"; - - /** - * 版本号 - *

类型:INTEGER (long)

- */ - public static final String VERSION = "version"; - } - - // 定义了一个接口DataColumns,包含了一些与数据相关的列名 - public interface DataColumns { - /** - * 数据的唯一ID - *

类型:INTEGER (long)

- */ - public static final String ID = "_id"; - - /** - * 此行所代表项目的数据类型(MIME类型)。 - *

类型:TEXT

- */ - public static final String MIME_TYPE = "mime_type"; - - /** - * 引用此数据属于的笔记ID - *

类型:INTEGER (long)

- */ - public static final String NOTE_ID = "note_id"; - - /** - * 数据的创建日期 - *

类型:INTEGER (long)

- */ - public static final String CREATED_DATE = "created_date"; - - /** - * 数据的最新修改日期 - *

类型:INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; - - /** - * 数据的内容 - *

类型:TEXT

- */ - public static final String CONTENT = "content"; - - /** - * 通用数据列,含义取决于 {@link #MIME_TYPE},用于整型数据类型 - *

类型:INTEGER

- */ - public static final String DATA1 = "data1"; - - /** - * 通用数据列,含义取决于 {@link #MIME_TYPE},用于整型数据类型 - *

类型:INTEGER

- */ - public static final String DATA2 = "data2"; - - /** - * 通用数据列,含义取决于 {@link #MIME_TYPE},用于文本数据类型 - *

类型:TEXT

- */ - public static final String DATA3 = "data3"; - - /** - * 通用数据列,含义取决于 {@link #MIME_TYPE},用于文本数据类型 - *

类型:TEXT

- */ - public static final String DATA4 = "data4"; - - /** - * 通用数据列,含义取决于 {@link #MIME_TYPE},用于文本数据类型 - *

类型:TEXT

- */ - public static final String DATA5 = "data5"; - } - - // 定义了一个内部类TextNote,继承自DataColumns,表示文本笔记的数据结构 - public static final class TextNote implements DataColumns { - /** - * 模式以指示文本是否处于检查列表模式 - *

类型:Integer 1:检查列表模式 0:正常模式

- */ - public static final String MODE = DATA1; - - // 定义了文本笔记模式的常量 - public static final int MODE_CHECK_LIST = 1; - - // 定义了文本笔记的MIME类型 - 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"; - - /** - * 文本笔记的Uri - * 解析为:content://micode_notes/text_note - */ - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); - } - - // 定义了一个内部类CallNote,继承自DataColumns,表示通话笔记的数据结构 - public static final class CallNote implements DataColumns { - /** - * 此记录的通话日期 - *

类型:INTEGER (long)

- */ - public static final String CALL_DATE = DATA1; - - /** - * 此记录的电话号码 - *

类型:TEXT

- */ - public static final String PHONE_NUMBER = DATA3; - - // 定义了通话笔记的MIME类型 - 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"; - - /** - * 通话笔记的Uri - * 解析为:content://micode_notes/call_note - */ - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); - } -} diff --git a/src/NotesDatabaseHelper.java b/src/NotesDatabaseHelper.java deleted file mode 100644 index 3674cb6..0000000 --- a/src/NotesDatabaseHelper.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * 你可以在不违反许可协议的情况下使用此文件。 - * 你可以在以下地址获取许可证的副本: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 除非适用法律要求或书面同意,软件 - * 根据许可证分发是按“原样”基础进行的, - * 不附带任何明示或暗示的担保或条件。 - * 请参阅许可证以获取特定语言的权限和 - * 限制。 - */ - -package net.micode.notes.data; - -import android.content.ContentValues; -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; - -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; - -// NotesDatabaseHelper 是一个 SQLiteOpenHelper 类的子类,用于管理笔记应用的数据库 -public class NotesDatabaseHelper extends SQLiteOpenHelper { - // 定义了数据库名称 - private static final String DB_NAME = "note.db"; - - // 定义了数据库版本号 - private static final int DB_VERSION = 4; - - // 定义了一个内部接口TABLE,包含了表名常量 - public interface TABLE { - public static final String NOTE = "note"; // 笔记表名 - public static final String DATA = "data"; // 数据表名 - } - - // 定义了日志标签字符串 - private static final String TAG = "NotesDatabaseHelper"; - - // 定义了单例实例 - private static NotesDatabaseHelper mInstance; - - // 定义了创建笔记表的SQL语句 - private static final String CREATE_NOTE_TABLE_SQL = - "CREATE TABLE " + TABLE.NOTE + "(" + - NoteColumns.ID + " INTEGER PRIMARY KEY," + - NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + - NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + - ")"; - - // 定义了创建 DATA 表的SQL语句 - private static final String CREATE_DATA_TABLE_SQL = - "CREATE TABLE " + TABLE.DATA + "(" + - DataColumns.ID + " INTEGER PRIMARY KEY," + - DataColumns.MIME_TYPE + " TEXT NOT NULL," + - DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA1 + " INTEGER," + - DataColumns.DATA2 + " INTEGER," + - DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + - ")"; - - // 定义了创建数据表中note_id索引的SQL语句 - private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = - "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 + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " 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 + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + - " END"; - - /** - * 当向文件夹中插入新笔记时,增加文件夹的笔记数量 - */ - private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = - "CREATE TRIGGER increase_folder_count_on_insert " + - " AFTER INSERT ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; - - /** - * 当从文件夹中删除笔记时,减少文件夹的笔记数量 - */ - private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = - "CREATE TRIGGER decrease_folder_count_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0;" + - " END"; - - /** - * 当插入类型为 {@link DataConstants#NOTE} 的数据时,更新笔记的内容 - */ - private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = - "CREATE TRIGGER update_note_content_on_insert " + - " AFTER INSERT ON " + TABLE.DATA + - " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; - - /** - * 当更新类型为 {@link DataConstants#NOTE} 的数据时,更新笔记的内容 - */ - private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER update_note_content_on_update " + - " AFTER UPDATE ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; - - /** - * 当删除类型为 {@link DataConstants#NOTE} 的数据时,清空笔记的内容 - */ - private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = - "CREATE TRIGGER update_note_content_on_delete " + - " AFTER delete ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=''" + - " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + - " END"; - - /** - * 当删除笔记时,删除属于该笔记的所有数据 - */ - private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = - "CREATE TRIGGER delete_data_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN" + - " DELETE FROM " + TABLE.DATA + - " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + - " END"; - - /** - * 当删除文件夹时,删除属于该文件夹的所有笔记 - */ - private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = - "CREATE TRIGGER folder_delete_notes_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN" + - " DELETE FROM " + TABLE.NOTE + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; - - /** - * 当文件夹被移动到回收站文件夹时,将文件夹中的所有笔记也移动到回收站文件夹 - */ - private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = - "CREATE TRIGGER folder_move_notes_on_trash " + - " AFTER UPDATE ON " + TABLE.NOTE + - " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; - - // 构造函数,初始化数据库帮助器 - public NotesDatabaseHelper(Context context) { - super(context, DB_NAME, null, DB_VERSION); - } - - // 创建笔记表的方法 - public void createNoteTable(SQLiteDatabase db) { - db.execSQL(CREATE_NOTE_TABLE_SQL); - reCreateNoteTableTriggers(db); - createSystemFolder(db); - Log.d(TAG, "note table has been created"); - } - - // 重新创建笔记表触发器的方法 - private void reCreateNoteTableTriggers(SQLiteDatabase db) { - db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert"); - db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); - - db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); - db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); - db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER); - db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER); - db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); - db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); - db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); - } - - // 创建系统文件夹的方法 - private void createSystemFolder(SQLiteDatabase db) { - ContentValues values = new ContentValues(); - - /** - * 创建通话记录文件夹,用于存储通话笔记 - */ - 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); - db.insert(TABLE.NOTE, null, values); - } - - // 创建数据表的方法 - public void createDataTable(SQLiteDatabase db) { - db.execSQL(CREATE_DATA_TABLE_SQL); - reCreateDataTableTriggers(db); - db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); - Log.d(TAG, "data table has been created"); - } - - // 重新创建数据表触发器的方法 - private void reCreateDataTableTriggers(SQLiteDatabase db) { - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); - - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); - } - - // 获取 NotesDatabaseHelper 单例实例的方法 - static synchronized NotesDatabaseHelper getInstance(Context context) { - if (mInstance == null) { - mInstance = new NotesDatabaseHelper(context); - } - return mInstance; - } - - // 当数据库第一次创建时调用的方法 - @Override - public void onCreate(SQLiteDatabase db) { - createNoteTable(db); - createDataTable(db); - } - - // 当数据库需要升级时调用的方法 - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - boolean reCreateTriggers = false; - boolean skipV2 = false; - - // 如果当前版本是1,直接删除旧表并创建新表 - if (oldVersion == 1) { - upgradeToV2(db); - skipV2 = true; // 这次升级包含了从v2到v3的升级 - oldVersion++; - } - - // 如果当前版本是2,添加新的列并创建系统文件夹 - if (oldVersion == 2 && !skipV2) { - upgradeToV3(db); - reCreateTriggers = true; - oldVersion++; - } - - // 如果当前版本是3,添加版本号列 - if (oldVersion == 3) { - upgradeToV4(db); - oldVersion++; - } - - // 如果需要重新创建触发器,调用相应的方法 - if (reCreateTriggers) { - reCreateNoteTableTriggers(db); - reCreateDataTableTriggers(db); - } - - // 如果升级失败,抛出异常 - if (oldVersion != newVersion) { - throw new IllegalStateException("Upgrade notes database to version " + newVersion - + " fails"); - } - } - - // 升级到数据库版本2的方法 - private void upgradeToV2(SQLiteDatabase db) { - db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); - db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); - createNoteTable(db); - createDataTable(db); - } - - // 升级到数据库版本3的方法 - private void upgradeToV3(SQLiteDatabase db) { - // 删除不再使用的触发器 - db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update"); - - // 添加 gtask id 列 - db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID - + " TEXT NOT NULL DEFAULT ''"); - - // 添加回收站系统文件夹 - ContentValues values = new ContentValues(); - values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); - } - - // 升级到数据库版本4的方法 - private void upgradeToV4(SQLiteDatabase db) { - // 添加版本号列 - db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION - + " INTEGER NOT NULL DEFAULT 0"); - } -} diff --git a/src/NotesProvider.java b/src/NotesProvider.java deleted file mode 100644 index 2cd497c..0000000 --- a/src/NotesProvider.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.micode.notes.data; - -import android.app.SearchManager; -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Intent; -import android.content.UriMatcher; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.net.Uri; -import android.text.TextUtils; -import android.util.Log; - -import net.micode.notes.R; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.data.NotesDatabaseHelper.TABLE; - -public class NotesProvider extends ContentProvider { - // UriMatcher用于匹配不同的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); - mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); - mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); - mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); - mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); - mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); - mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); - } - - /** - * x'0A'表示在sqlite中的'\n'字符。对于搜索结果中的标题和内容, - * 我们将修剪'\n'和空白字符,以便显示更多信息。 - */ - 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; - - // 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; - - // 创建ContentProvider时调用,初始化NotesDatabaseHelper - @Override - public boolean onCreate() { - mHelper = NotesDatabaseHelper.getInstance(getContext()); - return true; - } - - // 根据不同的URI请求类型执行查询操作 - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - Cursor c = null; - SQLiteDatabase db = mHelper.getReadableDatabase(); - String id = null; - switch (mMatcher.match(uri)) { - case URI_NOTE: - // 查询所有笔记 - c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, - sortOrder); - break; - case URI_NOTE_ITEM: - // 查询特定ID的笔记 - 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的笔记数据 - 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( - "不允许在搜索时指定排序条件、选择条件、选择参数或投影"); - } - - String searchString = null; - // 获取搜索字符串 - if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { - if (uri.getPathSegments().size() > 1) { - searchString = uri.getPathSegments().get(1); - } - } else { - searchString = uri.getQueryParameter("pattern"); - } - - // 如果搜索字符串为空,返回null - if (TextUtils.isEmpty(searchString)) { - return null; - } - - try { - // 格式化搜索字符串,使其可以用于LIKE查询 - searchString = String.format("%%%s%%", searchString); - // 执行搜索查询 - c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, - new String[] { searchString }); - } catch (IllegalStateException ex) { - Log.e(TAG, "发生异常: " + ex.toString()); - } - break; - default: - // 如果URI请求类型未知,抛出异常 - throw new IllegalArgumentException("未知的URI " + uri); - } - // 设置游标的通知URI,以便内容变化时通知监听者 - if (c != null) { - c.setNotificationUri(getContext().getContentResolver(), uri); - } - return c; - } - - // 根据不同的URI请求类型插入数据 - @Override - public Uri insert(Uri uri, ContentValues values) { - SQLiteDatabase db = mHelper.getWritableDatabase(); - long dataId = 0, noteId = 0, insertedId = 0; - switch (mMatcher.match(uri)) { - case URI_NOTE: - // 插入新的笔记 - insertedId = noteId = db.insert(TABLE.NOTE, null, values); - break; - case URI_DATA: - // 插入新的笔记数据 - if (values.containsKey(DataColumns.NOTE_ID)) { - noteId = values.getAsLong(DataColumns.NOTE_ID); - } else { - Log.d(TAG, "数据格式错误,缺少笔记ID:" + values.toString()); - } - insertedId = dataId = db.insert(TABLE.DATA, null, values); - break; - default: - // 如果URI请求类型未知,抛出异常 - throw new IllegalArgumentException("未知的URI " + uri); - } - // 通知笔记URI变化 - if (noteId > 0) { - getContext().getContentResolver().notifyChange( - ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); - } - - // 通知数据URI变化 - if (dataId > 0) { - getContext().getContentResolver().notifyChange( - ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); - } - - return ContentUris.withAppendedId(uri, insertedId); - } - - // 根据不同的URI请求类型删除数据 - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - int count = 0; - String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); - boolean deleteData = false; - switch (mMatcher.match(uri)) { - case URI_NOTE: - // 删除笔记时,确保ID大于0 - selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; - count = db.delete(TABLE.NOTE, selection, selectionArgs); - break; - case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); - long noteId = Long.valueOf(id); - // ID小于等于0的笔记为系统文件夹,不允许删除 - if (noteId <= 0) { - break; - } - // 删除特定ID的笔记 - 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); - // 删除特定ID的笔记数据 - count = db.delete(TABLE.DATA, - DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); - deleteData = true; - break; - default: - // 如果URI请求类型未知,抛出异常 - throw new IllegalArgumentException("未知的URI " + uri); - } - // 如果有数据被删除,通知URI变化 - if (count > 0) { - if (deleteData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); - } - getContext().getContentResolver().notifyChange(uri, null); - } - return count; - } - - // 根据不同的URI请求类型更新数据 - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - int count = 0; - String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); - boolean updateData = false; - switch (mMatcher.match(uri)) { - case URI_NOTE: - // 更新笔记时,增加笔记版本号 - increaseNoteVersion(-1, selection, selectionArgs); - count = db.update(TABLE.NOTE, values, selection, selectionArgs); - break; - case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); - long noteId = Long.valueOf(id); - // 更新特定ID的笔记,并增加笔记版本号 - increaseNoteVersion(noteId, 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); - // 更新特定ID的笔记数据 - count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id - + parseSelection(selection), selectionArgs); - updateData = true; - break; - default: - // 如果URI请求类型未知,抛出异常 - throw new IllegalArgumentException("未知的URI " + uri); - } - - // 如果有数据被更新,通知URI变化 - if (count > 0) { - if (updateData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); - } - getContext().getContentResolver().notifyChange(uri, null); - } - return count; - } - - // 解析选择条件字符串,如果存在选择条件,则添加到SQL查询中 - private String parseSelection(String selection) { - return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); - } - - // 增加笔记版本号 - private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { - StringBuilder sql = new StringBuilder(120); - sql.append("UPDATE "); - sql.append(TABLE.NOTE); - sql.append(" SET "); - sql.append(NoteColumns.VERSION); - sql.append("=" + NoteColumns.VERSION + "+1 "); - - // 构建WHERE子句 - if (id > 0 || !TextUtils.isEmpty(selection)) { - sql.append(" WHERE "); - } - if (id > 0) { - sql.append(NoteColumns.ID + "=" + String.valueOf(id)); - } - if (!TextUtils.isEmpty(selection)) { - String selectString = id > 0 ? parseSelection(selection) : selection; - for (String args : selectionArgs) { - selectString = selectString.replaceFirst("\\?", args); - } - sql.append(selectString); - } - - // 执行更新操作 - mHelper.getWritableDatabase().execSQL(sql.toString()); - } - - // 返回URI对应的数据类型,这里未实现,返回null - @Override - public String getType(Uri uri) { - // TODO Auto-generated method stub - return null; - } -} diff --git a/src/net/micode/notes/data/Contact.java b/src/net/micode/notes/data/Contact.java index d97ac5d..b9b793b 100644 --- a/src/net/micode/notes/data/Contact.java +++ b/src/net/micode/notes/data/Contact.java @@ -16,56 +16,70 @@ package net.micode.notes.data; -import android.content.Context; -import android.database.Cursor; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.Data; -import android.telephony.PhoneNumberUtils; -import android.util.Log; +import android.content.Context; // 导入Android上下文类,用于访问系统资源 +import android.database.Cursor; // 导入Android游标类,用于查询数据库 +import android.provider.ContactsContract.CommonDataKinds.Phone; // 导入Android联系人电话信息类 +import android.provider.ContactsContract.Data; // 导入Android联系人数据类 +import android.telephony.PhoneNumberUtils; // 导入Android电话号码工具类 +import android.util.Log; // 导入Android日志工具类 -import java.util.HashMap; +import java.util.HashMap; // 导入Java哈希表类,用于缓存查询结果 public class Contact { + // 静态的哈希表,用于缓存电话号码和对应的联系人姓名 private static HashMap sContactCache; + // 日志标签,用于在日志中标识来自该类的消息 private static final String TAG = "Contact"; + // 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 " + + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + + " AND " + Data.RAW_CONTACT_ID + " IN " + "(SELECT raw_contact_id " + " FROM phone_lookup" + " WHERE min_match = '+')"; + // 根据给定的电话号码获取联系人的姓名 public static String getContact(Context context, String phoneNumber) { + // 如果缓存为空,则初始化缓存 if(sContactCache == null) { sContactCache = new HashMap(); } + // 检查缓存中是否已有该电话号码对应的联系人姓名 if(sContactCache.containsKey(phoneNumber)) { - return sContactCache.get(phoneNumber); + return sContactCache.get(phoneNumber); // 如果存在,则直接返回缓存中的姓名 } + // 构造SQL查询条件,将占位符"+"替换为电话号码的最小匹配字符 String selection = CALLER_ID_SELECTION.replace("+", PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); + + // 执行数据库查询,获取与电话号码匹配的联系人姓名 Cursor cursor = context.getContentResolver().query( - Data.CONTENT_URI, - new String [] { Phone.DISPLAY_NAME }, - selection, - new String[] { phoneNumber }, - null); + Data.CONTENT_URI, // 查询联系人数据表 + new String [] { Phone.DISPLAY_NAME }, // 需要查询的字段:联系人显示名称 + selection, // 查询条件 + new String[] { phoneNumber }, // 查询条件中的占位符参数 + null); // 排序条件,这里为null表示不排序 + // 检查查询结果是否为空且是否可以移动到第一行 if (cursor != null && cursor.moveToFirst()) { try { - String name = cursor.getString(0); - sContactCache.put(phoneNumber, name); - return name; + String name = cursor.getString(0); // 获取联系人显示名称 + sContactCache.put(phoneNumber, name); // 将查询结果存入缓存 + return name; // 返回联系人姓名 } catch (IndexOutOfBoundsException e) { + // 如果发生数组越界异常,记录错误日志并返回null Log.e(TAG, " Cursor get string error " + e.toString()); return null; } finally { - cursor.close(); + cursor.close(); // 关闭游标,释放资源 } } else { + // 如果没有找到匹配的联系人,记录调试日志并返回null Log.d(TAG, "No contact matched with number:" + phoneNumber); return null; } diff --git a/src/net/micode/notes/data/Notes.java b/src/net/micode/notes/data/Notes.java index f240604..2f2907e 100644 --- a/src/net/micode/notes/data/Notes.java +++ b/src/net/micode/notes/data/Notes.java @@ -2,278 +2,297 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 你可以在不违反许可协议的情况下使用此文件。 + * 你可以在以下地址获取许可证的副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,软件 + * 根据许可证分发是按“原样”基础进行的, + * 不附带任何明示或暗示的担保或条件。 + * 请参阅许可证以获取特定语言的权限和 + * 限制。 */ package net.micode.notes.data; import android.net.Uri; + +// 定义了一个名为Notes的类,包含了与笔记应用相关的常量和接口 public class Notes { + // 定义了Content Provider的权限字符串 public static final String AUTHORITY = "micode_notes"; + // 定义了日志标签字符串 public static final String TAG = "Notes"; - public static final int TYPE_NOTE = 0; - public static final int TYPE_FOLDER = 1; - public static final int TYPE_SYSTEM = 2; + + // 定义了笔记类型的常量 + public static final int TYPE_NOTE = 0; // 笔记类型 + public static final int TYPE_FOLDER = 1; // 文件夹类型 + public static final int TYPE_SYSTEM = 2; // 系统类型 /** - * Following IDs are system folders' identifiers - * {@link Notes#ID_ROOT_FOLDER } is default folder - * {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder - * {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records + * 以下ID是系统文件夹的标识符 + * {@link Notes#ID_ROOT_FOLDER } 是默认文件夹 + * {@link Notes#ID_TEMPARAY_FOLDER } 用于不属于任何文件夹的笔记 + * {@link Notes#ID_CALL_RECORD_FOLDER} 用于存储通话记录 + * {@link Notes#ID_TRASH_FOLER} 用于存储已删除的笔记 */ public static final int ID_ROOT_FOLDER = 0; public static final int ID_TEMPARAY_FOLDER = -1; public static final int ID_CALL_RECORD_FOLDER = -2; public static final int ID_TRASH_FOLER = -3; - public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; - public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; - public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; - public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; - public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; - public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; + // 定义了一些Intent的extra键名 + public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; // 提醒日期 + public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; // 背景颜色ID + public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; // 小部件ID + public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; // 小部件类型 + public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; // 文件夹ID + public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; // 通话日期 - public static final int TYPE_WIDGET_INVALIDE = -1; - public static final int TYPE_WIDGET_2X = 0; - public static final int TYPE_WIDGET_4X = 1; + // 定义了小部件类型的常量 + public static final int TYPE_WIDGET_INVALIDE = -1; // 无效的小部件 + public static final int TYPE_WIDGET_2X = 0; // 2x尺寸的小部件 + public static final int TYPE_WIDGET_4X = 1; // 4x尺寸的小部件 + // 定义一个内部类DataConstants,包含一些与数据类型相关的常量 public static class DataConstants { + // 定义了文本笔记的数据类型 public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; + // 定义了通话笔记的数据类型 public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; } /** - * Uri to query all notes and folders + * Uri用于查询所有的笔记和文件夹 + * 解析为:content://micode_notes/note */ public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); /** - * Uri to query data + * Uri用于查询数据 + * 解析为:content://micode_notes/data */ public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); + // 定义了一个接口NoteColumns,包含了一些与笔记和文件夹相关的列名 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

+ * Google任务ID + *

类型:TEXT

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

Type : INTEGER (long)

+ * 版本号 + *

类型:INTEGER (long)

*/ public static final String VERSION = "version"; } + // 定义了一个接口DataColumns,包含了一些与数据相关的列名 public interface DataColumns { /** - * The unique ID for a row - *

Type: INTEGER (long)

+ * 数据的唯一ID + *

类型:INTEGER (long)

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

Type: Text

+ * 此行所代表项目的数据类型(MIME类型)。 + *

类型:TEXT

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

Type: INTEGER (long)

+ * 引用此数据属于的笔记ID + *

类型:INTEGER (long)

*/ public static final String NOTE_ID = "note_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"; /** - * Data's content - *

Type: TEXT

+ * 数据的内容 + *

类型:TEXT

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

Type: INTEGER

+ * 通用数据列,含义取决于 {@link #MIME_TYPE},用于整型数据类型 + *

类型:INTEGER

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

Type: INTEGER

+ * 通用数据列,含义取决于 {@link #MIME_TYPE},用于整型数据类型 + *

类型:INTEGER

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

Type: TEXT

+ * 通用数据列,含义取决于 {@link #MIME_TYPE},用于文本数据类型 + *

类型:TEXT

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

Type: TEXT

+ * 通用数据列,含义取决于 {@link #MIME_TYPE},用于文本数据类型 + *

类型:TEXT

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

Type: TEXT

+ * 通用数据列,含义取决于 {@link #MIME_TYPE},用于文本数据类型 + *

类型:TEXT

*/ public static final String DATA5 = "data5"; } + // 定义了一个内部类TextNote,继承自DataColumns,表示文本笔记的数据结构 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

+ * 模式以指示文本是否处于检查列表模式 + *

类型:Integer 1:检查列表模式 0:正常模式

*/ public static final String MODE = DATA1; + // 定义了文本笔记模式的常量 public static final int MODE_CHECK_LIST = 1; + // 定义了文本笔记的MIME类型 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"; + /** + * 文本笔记的Uri + * 解析为:content://micode_notes/text_note + */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); } + // 定义了一个内部类CallNote,继承自DataColumns,表示通话笔记的数据结构 public static final class CallNote implements DataColumns { /** - * Call date for this record - *

Type: INTEGER (long)

+ * 此记录的通话日期 + *

类型:INTEGER (long)

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

Type: TEXT

+ * 此记录的电话号码 + *

类型:TEXT

*/ public static final String PHONE_NUMBER = DATA3; + // 定义了通话笔记的MIME类型 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"; + /** + * 通话笔记的Uri + * 解析为:content://micode_notes/call_note + */ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); } } diff --git a/src/net/micode/notes/data/NotesDatabaseHelper.java b/src/net/micode/notes/data/NotesDatabaseHelper.java index ffe5d57..f60de93 100644 --- a/src/net/micode/notes/data/NotesDatabaseHelper.java +++ b/src/net/micode/notes/data/NotesDatabaseHelper.java @@ -2,16 +2,16 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 你可以在不违反许可协议的情况下使用此文件。 + * 你可以在以下地址获取许可证的副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,软件 + * 根据许可证分发是按“原样”基础进行的, + * 不附带任何明示或暗示的担保或条件。 + * 请参阅许可证以获取特定语言的权限和 + * 限制。 */ package net.micode.notes.data; @@ -26,198 +26,209 @@ import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.NoteColumns; - +// NotesDatabaseHelper 是一个 SQLiteOpenHelper 类的子类,用于管理笔记应用的数据库 public class NotesDatabaseHelper extends SQLiteOpenHelper { + // 定义了数据库名称 private static final String DB_NAME = "note.db"; + // 定义了数据库版本号 private static final int DB_VERSION = 4; + // 定义了一个内部接口TABLE,包含了表名常量 public interface TABLE { - public static final String NOTE = "note"; - - public static final String DATA = "data"; + public static final String NOTE = "note"; // 笔记表名 + public static final String DATA = "data"; // 数据表名 } + // 定义了日志标签字符串 private static final String TAG = "NotesDatabaseHelper"; + // 定义了单例实例 private static NotesDatabaseHelper mInstance; + // 定义了创建笔记表的SQL语句 private static final String CREATE_NOTE_TABLE_SQL = "CREATE TABLE " + TABLE.NOTE + "(" + - NoteColumns.ID + " INTEGER PRIMARY KEY," + - NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + - NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + + NoteColumns.ID + " INTEGER PRIMARY KEY," + // 笔记ID,主键 + NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 父文件夹ID,默认为0 + NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + // 提醒日期,默认为0 + NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + // 背景颜色ID,默认为0 + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建日期,默认为当前时间(毫秒) + NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + // 是否有附件,默认为0 + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改日期,默认为当前时间(毫秒) + NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + // 笔记数量,默认为0 + NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + // 笔记摘要,默认为空字符串 + NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + // 笔记类型,默认为0 + NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + // 小部件ID,默认为0 + NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + // 小部件类型,默认为-1 + NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + // 同步ID,默认为0 + NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + // 是否本地修改,默认为0 + NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 原始父文件夹ID,默认为0 + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + // GTasks ID,默认为空字符串 + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + // 版本号,默认为0 ")"; + // 定义了创建 DATA 表的SQL语句 private static final String CREATE_DATA_TABLE_SQL = "CREATE TABLE " + TABLE.DATA + "(" + - DataColumns.ID + " INTEGER PRIMARY KEY," + - DataColumns.MIME_TYPE + " TEXT NOT NULL," + - DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA1 + " INTEGER," + - DataColumns.DATA2 + " INTEGER," + - DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + + DataColumns.ID + " INTEGER PRIMARY KEY," + // 数据ID,主键 + DataColumns.MIME_TYPE + " TEXT NOT NULL," + // MIME类型,默认为空字符串 + DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + // 关联的笔记ID,默认为0 + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建日期,默认为当前时间(毫秒) + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改日期,默认为当前时间(毫秒) + DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + // 数据内容,默认为空字符串 + DataColumns.DATA1 + " INTEGER," + // 自定义数据1 + DataColumns.DATA2 + " INTEGER," + // 自定义数据2 + DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + // 自定义数据3,默认为空字符串 + DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + // 自定义数据4,默认为空字符串 + DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + // 自定义数据5,默认为空字符串 ")"; + // 定义了创建数据表中note_id索引的SQL语句 private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = "CREATE INDEX IF NOT EXISTS note_id_index ON " + - TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; + TABLE.DATA + "(" + DataColumns.NOTE_ID + "); "; // 为data表中的note_id列创建索引 /** - * Increase folder's note count when move note to the folder + * 当笔记移动到文件夹时,增加文件夹的笔记数量 */ private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER increase_folder_count_on_update "+ " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + // 更新父文件夹的笔记数量加1 + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + // 父文件夹ID为移动后的文件夹ID " END"; /** - * Decrease folder's note count when move note from folder + * 当笔记从文件夹中移除时,减少文件夹的笔记数量 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_update " + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + // 更新父文件夹的笔记数量减1 + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + // 父文件夹ID为移动前的文件夹ID + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + // 仅当笔记数量大于0时更新 " END"; /** - * Increase folder's note count when insert new note to the folder + * 当向文件夹中插入新笔记时,增加文件夹的笔记数量 */ private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = "CREATE TRIGGER increase_folder_count_on_insert " + " AFTER INSERT ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + // 更新父文件夹的笔记数量加1 + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + // 父文件夹ID为新笔记的父文件夹ID " END"; /** - * Decrease folder's note count when delete note from the folder + * 当从文件夹中删除笔记时,减少文件夹的笔记数量 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0;" + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + // 更新父文件夹的笔记数量减1 + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + // 父文件夹ID为删除笔记的父文件夹ID + " AND " + NoteColumns.NOTES_COUNT + ">0;" + // 仅当笔记数量大于0时更新 " 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 " + " AFTER INSERT ON " + TABLE.DATA + - " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + + " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + // 当插入的数据类型为笔记时 " BEGIN" + " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + // 更新笔记的摘要为新插入的数据内容 + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + // 笔记ID为新插入数据关联的笔记ID " 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 " + " AFTER UPDATE ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + // 当更新的数据类型为笔记时 " BEGIN" + " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + // 更新笔记的摘要为更新后的数据内容 + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + // 笔记ID为更新数据关联的笔记ID " 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 " + " AFTER delete ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + // 当删除的数据类型为笔记时 " BEGIN" + " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=''" + - " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + + " SET " + NoteColumns.SNIPPET + "=''" + // 清空笔记的摘要 + " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + // 笔记ID为删除数据关联的笔记ID " END"; /** - * Delete datas belong to note which has been deleted + * 当删除笔记时,删除属于该笔记的所有数据 */ private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = "CREATE TRIGGER delete_data_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + " BEGIN" + - " DELETE FROM " + TABLE.DATA + - " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + + " DELETE FROM " + TABLE.DATA + // 删除data表中与笔记ID关联的所有数据 + " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + // 笔记ID为删除笔记的ID " END"; /** - * Delete notes belong to folder which has been deleted + * 当删除文件夹时,删除属于该文件夹的所有笔记 */ private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = "CREATE TRIGGER folder_delete_notes_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + " BEGIN" + - " DELETE FROM " + TABLE.NOTE + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + + " DELETE FROM " + TABLE.NOTE + // 删除note表中与文件夹ID关联的所有笔记 + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + // 父文件夹ID为删除文件夹的ID " END"; /** - * Move notes belong to folder which has been moved to trash folder + * 当文件夹被移动到回收站文件夹时,将文件夹中的所有笔记也移动到回收站文件夹 */ private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = "CREATE TRIGGER folder_move_notes_on_trash " + " AFTER UPDATE ON " + TABLE.NOTE + - " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + + " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + // 当笔记被移动到回收站文件夹时 " BEGIN" + " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + + " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + // 将笔记的父文件夹ID设置为回收站文件夹ID + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + // 笔记的父文件夹ID为移动前的文件夹ID " END"; + // 构造函数,初始化数据库帮助器 public NotesDatabaseHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } + // 创建笔记表的方法 public void createNoteTable(SQLiteDatabase db) { - db.execSQL(CREATE_NOTE_TABLE_SQL); - reCreateNoteTableTriggers(db); - createSystemFolder(db); - Log.d(TAG, "note table has been created"); + db.execSQL(CREATE_NOTE_TABLE_SQL); // 执行创建笔记表的SQL语句 + reCreateNoteTableTriggers(db); // 重新创建笔记表的触发器 + createSystemFolder(db); // 创建系统文件夹 + Log.d(TAG, "note table has been created"); // 记录日志,表示笔记表已创建 } + // 重新创建笔记表触发器的方法 private void reCreateNoteTableTriggers(SQLiteDatabase db) { + // 删除旧的触发器 db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); @@ -226,6 +237,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); + // 创建新的触发器 db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER); @@ -235,128 +247,147 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); } + // 创建系统文件夹的方法 private void createSystemFolder(SQLiteDatabase db) { ContentValues values = new ContentValues(); /** - * call record foler for call notes + * 创建通话记录文件夹,用于存储通话笔记 */ - values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); // 设置系统文件夹ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统类型 + db.insert(TABLE.NOTE, null, values); // 插入通话记录文件夹到笔记表 /** - * root folder which is default folder + * 创建根文件夹,默认文件夹 */ - values.clear(); - values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + values.clear(); // 清空之前插入的值 + values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); // 设置系统文件夹ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统类型 + db.insert(TABLE.NOTE, null, values); // 插入根文件夹到笔记表 /** - * temporary folder which is used for moving note + * 创建临时文件夹,用于移动笔记 */ - values.clear(); - values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + values.clear(); // 清空之前插入的值 + values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); // 设置系统文件夹ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统类型 + db.insert(TABLE.NOTE, null, values); // 插入临时文件夹到笔记表 /** - * create trash folder + * 创建回收站文件夹 */ - values.clear(); - values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + values.clear(); // 清空之前插入的值 + values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); // 设置系统文件夹ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统类型 + db.insert(TABLE.NOTE, null, values); // 插入回收站文件夹到笔记表 } + // 创建数据表的方法 public void createDataTable(SQLiteDatabase db) { - db.execSQL(CREATE_DATA_TABLE_SQL); - reCreateDataTableTriggers(db); - db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); - Log.d(TAG, "data table has been created"); + db.execSQL(CREATE_DATA_TABLE_SQL); // 执行创建数据表的SQL语句 + reCreateDataTableTriggers(db); // 重新创建数据表的触发器 + db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); // 创建note_id索引 + Log.d(TAG, "data table has been created"); // 记录日志,表示数据表已创建 } + // 重新创建数据表触发器的方法 private void reCreateDataTableTriggers(SQLiteDatabase db) { + // 删除旧的触发器 db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); + // 创建新的触发器 db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); } + // 获取 NotesDatabaseHelper 单例实例的方法 static synchronized NotesDatabaseHelper getInstance(Context context) { if (mInstance == null) { - mInstance = new NotesDatabaseHelper(context); + mInstance = new NotesDatabaseHelper(context); // 初始化单例实例 } - return mInstance; + return mInstance; // 返回单例实例 } + // 当数据库第一次创建时调用的方法 @Override public void onCreate(SQLiteDatabase db) { - createNoteTable(db); - createDataTable(db); + createNoteTable(db); // 创建笔记表 + createDataTable(db); // 创建数据表 } + // 当数据库需要升级时调用的方法 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { boolean reCreateTriggers = false; boolean skipV2 = false; + // 如果当前版本是1,直接删除旧表并创建新表 if (oldVersion == 1) { - upgradeToV2(db); - skipV2 = true; // this upgrade including the upgrade from v2 to v3 + upgradeToV2(db); // 升级到版本2 + skipV2 = true; // 这次升级包含了从v2到v3的升级 oldVersion++; } + // 如果当前版本是2,添加新的列并创建系统文件夹 if (oldVersion == 2 && !skipV2) { - upgradeToV3(db); - reCreateTriggers = true; + upgradeToV3(db); // 升级到版本3 + reCreateTriggers = true; // 标记需要重新创建触发器 oldVersion++; } + // 如果当前版本是3,添加版本号列 if (oldVersion == 3) { - upgradeToV4(db); + upgradeToV4(db); // 升级到版本4 oldVersion++; } + // 如果需要重新创建触发器,调用相应的方法 if (reCreateTriggers) { - reCreateNoteTableTriggers(db); - reCreateDataTableTriggers(db); + reCreateNoteTableTriggers(db); // 重新创建笔记表的触发器 + reCreateDataTableTriggers(db); // 重新创建数据表的触发器 } + // 如果升级失败,抛出异常 if (oldVersion != newVersion) { throw new IllegalStateException("Upgrade notes database to version " + newVersion - + "fails"); + + " fails"); // 抛出异常,表示数据库升级失败 } } + // 升级到数据库版本2的方法 private void upgradeToV2(SQLiteDatabase db) { - db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); - db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); - createNoteTable(db); - createDataTable(db); + db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); // 删除旧的笔记表 + db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); // 删除旧的数据表 + createNoteTable(db); // 创建新的笔记表 + createDataTable(db); // 创建新的数据表 } + // 升级到数据库版本3的方法 private void upgradeToV3(SQLiteDatabase db) { - // drop unused triggers + // 删除不再使用的触发器 db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete"); db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update"); - // add a column for gtask id + + // 添加 gtask id 列 db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID - + " TEXT NOT NULL DEFAULT ''"); - // add a trash system folder + + " TEXT NOT NULL DEFAULT ''"); // 为笔记表添加gtask_id列 + + // 添加回收站系统文件夹 ContentValues values = new ContentValues(); - values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); // 设置系统文件夹ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统类型 + db.insert(TABLE.NOTE, null, values); // 插入回收站文件夹到笔记表 } + // 升级到数据库版本4的方法 private void upgradeToV4(SQLiteDatabase db) { + // 添加版本号列 db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION - + " INTEGER NOT NULL DEFAULT 0"); + + " INTEGER NOT NULL DEFAULT 0"); // 为笔记表添加version列 } } diff --git a/src/net/micode/notes/data/NotesProvider.java b/src/net/micode/notes/data/NotesProvider.java index edb0a60..39a3477 100644 --- a/src/net/micode/notes/data/NotesProvider.java +++ b/src/net/micode/notes/data/NotesProvider.java @@ -16,7 +16,6 @@ package net.micode.notes.data; - import android.app.SearchManager; import android.content.ContentProvider; import android.content.ContentUris; @@ -34,22 +33,26 @@ 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 { + // UriMatcher用于匹配不同的URI请求,返回相应的请求类型 private static final UriMatcher mMatcher; + // 数据库辅助类,用于创建和管理数据库 private NotesDatabaseHelper mHelper; + // 日志标签,便于调试和日志记录 private static final String TAG = "NotesProvider"; - private static final int URI_NOTE = 1; - private static final int URI_NOTE_ITEM = 2; - private static final int URI_DATA = 3; - private static final int URI_DATA_ITEM = 4; + // 定义URI请求类型常量 + private static final int URI_NOTE = 1; // 匹配所有笔记的URI + private static final int URI_NOTE_ITEM = 2; // 匹配特定笔记ID的URI + private static final int URI_DATA = 3; // 匹配所有笔记数据的URI + private static final int URI_DATA_ITEM = 4; // 匹配特定笔记数据ID的URI - private static final int URI_SEARCH = 5; - private static final int URI_SEARCH_SUGGEST = 6; + private static final int URI_SEARCH = 5; // 匹配搜索请求的URI + private static final int URI_SEARCH_SUGGEST = 6; // 匹配搜索建议请求的URI + // 静态代码块,在类加载时初始化UriMatcher static { mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); @@ -62,8 +65,8 @@ public class NotesProvider extends ContentProvider { } /** - * 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. + * x'0A'表示在sqlite中的'\n'字符。对于搜索结果中的标题和内容, + * 我们将修剪'\n'和空白字符,以便显示更多信息。 */ private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," @@ -73,233 +76,266 @@ public class NotesProvider extends ContentProvider { + "'" + 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; + // 创建ContentProvider时调用,初始化NotesDatabaseHelper @Override public boolean onCreate() { - mHelper = NotesDatabaseHelper.getInstance(getContext()); + mHelper = NotesDatabaseHelper.getInstance(getContext()); // 获取数据库帮助器的单例实例 return true; } + // 根据不同的URI请求类型执行查询操作 @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor c = null; - SQLiteDatabase db = mHelper.getReadableDatabase(); + 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); + // 查询所有笔记 + c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, sortOrder); break; case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); + // 查询特定ID的笔记 + id = uri.getPathSegments().get(1); // 获取URI路径中的笔记ID 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); + // 查询所有笔记数据 + c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, sortOrder); break; case URI_DATA_ITEM: - id = uri.getPathSegments().get(1); + // 查询特定ID的笔记数据 + id = uri.getPathSegments().get(1); // 获取URI路径中的笔记数据ID c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder); break; case URI_SEARCH: case URI_SEARCH_SUGGEST: + // 搜索时不允许指定排序条件、选择条件、选择参数或投影 if (sortOrder != null || projection != null) { throw new IllegalArgumentException( - "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); + "不允许在搜索时指定排序条件、选择条件、选择参数或投影"); } String searchString = null; + // 获取搜索字符串 if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { if (uri.getPathSegments().size() > 1) { - searchString = uri.getPathSegments().get(1); + searchString = uri.getPathSegments().get(1); // 从URI路径中获取搜索字符串 } } else { - searchString = uri.getQueryParameter("pattern"); + searchString = uri.getQueryParameter("pattern"); // 从URI查询参数中获取搜索字符串 } + // 如果搜索字符串为空,返回null if (TextUtils.isEmpty(searchString)) { return null; } try { + // 格式化搜索字符串,使其可以用于LIKE查询 searchString = String.format("%%%s%%", searchString); + // 执行搜索查询 c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, new String[] { searchString }); } catch (IllegalStateException ex) { - Log.e(TAG, "got exception: " + ex.toString()); + Log.e(TAG, "发生异常: " + ex.toString()); // 记录异常日志 } break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + // 如果URI请求类型未知,抛出异常 + throw new IllegalArgumentException("未知的URI " + uri); } + // 设置游标的通知URI,以便内容变化时通知监听者 if (c != null) { c.setNotificationUri(getContext().getContentResolver(), uri); } return c; } + // 根据不同的URI请求类型插入数据 @Override public Uri insert(Uri uri, ContentValues values) { - SQLiteDatabase db = mHelper.getWritableDatabase(); + 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); + noteId = values.getAsLong(DataColumns.NOTE_ID); // 获取关联的笔记ID } else { - Log.d(TAG, "Wrong data format without note id:" + values.toString()); + Log.d(TAG, "数据格式错误,缺少笔记ID:" + values.toString()); // 记录日志,表示数据格式错误 } insertedId = dataId = db.insert(TABLE.DATA, null, values); break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + // 如果URI请求类型未知,抛出异常 + throw new IllegalArgumentException("未知的URI " + uri); } - // Notify the note uri + // 通知笔记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); } - return ContentUris.withAppendedId(uri, insertedId); + return ContentUris.withAppendedId(uri, insertedId); // 返回插入数据的URI } + // 根据不同的URI请求类型删除数据 @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); + SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写的数据库实例 boolean deleteData = false; switch (mMatcher.match(uri)) { case URI_NOTE: + // 删除笔记时,确保ID大于0 selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; count = db.delete(TABLE.NOTE, selection, selectionArgs); break; case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); - /** - * ID that smaller than 0 is system folder which is not allowed to - * trash - */ + id = uri.getPathSegments().get(1); // 获取URI路径中的笔记ID long noteId = Long.valueOf(id); + // ID小于等于0的笔记为系统文件夹,不允许删除 if (noteId <= 0) { break; } + // 删除特定ID的笔记 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); + id = uri.getPathSegments().get(1); // 获取URI路径中的笔记数据ID + // 删除特定ID的笔记数据 count = db.delete(TABLE.DATA, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); deleteData = true; break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + // 如果URI请求类型未知,抛出异常 + throw new IllegalArgumentException("未知的URI " + uri); } + // 如果有数据被删除,通知URI变化 if (count > 0) { if (deleteData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); // 通知笔记URI变化 } - getContext().getContentResolver().notifyChange(uri, null); + getContext().getContentResolver().notifyChange(uri, null); // 通知特定数据URI变化 } - return count; + return count; // 返回删除的数据条目数 } + // 根据不同的URI请求类型更新数据 @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); + 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); + id = uri.getPathSegments().get(1); // 获取URI路径中的笔记ID + long noteId = Long.valueOf(id); + // 更新特定ID的笔记,并增加笔记版本号 + increaseNoteVersion(noteId, 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); + id = uri.getPathSegments().get(1); // 获取URI路径中的笔记数据ID + // 更新特定ID的笔记数据 count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); updateData = true; break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + // 如果URI请求类型未知,抛出异常 + throw new IllegalArgumentException("未知的URI " + uri); } + // 如果有数据被更新,通知URI变化 if (count > 0) { if (updateData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); // 通知笔记URI变化 } - getContext().getContentResolver().notifyChange(uri, null); + getContext().getContentResolver().notifyChange(uri, null); // 通知特定数据URI变化 } - return count; + return count; // 返回更新的数据条目数 } + // 解析选择条件字符串,如果存在选择条件,则添加到SQL查询中 private String parseSelection(String selection) { + // 如果选择条件不为空,则将其添加到SQL查询中 return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); } + // 增加笔记版本号 private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); sql.append(TABLE.NOTE); sql.append(" SET "); sql.append(NoteColumns.VERSION); - sql.append("=" + NoteColumns.VERSION + "+1 "); + sql.append("=" + NoteColumns.VERSION + "+1 "); // 将笔记版本号加1 + // 构建WHERE子句 if (id > 0 || !TextUtils.isEmpty(selection)) { sql.append(" WHERE "); } if (id > 0) { - sql.append(NoteColumns.ID + "=" + String.valueOf(id)); + sql.append(NoteColumns.ID + "=" + String.valueOf(id)); // 指定更新特定ID的笔记 } if (!TextUtils.isEmpty(selection)) { String selectString = id > 0 ? parseSelection(selection) : selection; for (String args : selectionArgs) { - selectString = selectString.replaceFirst("\\?", args); + selectString = selectString.replaceFirst("\\?", args); // 替换选择条件中的占位符 } sql.append(selectString); } + // 执行更新操作 mHelper.getWritableDatabase().execSQL(sql.toString()); } + // 返回URI对应的数据类型,这里未实现,返回null @Override public String getType(Uri uri) { // TODO Auto-generated method stub - return null; + return null; // 未实现,返回null } - }