diff --git a/.tgitconfig b/.tgitconfig new file mode 100644 index 0000000..e69de29 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 af8f053..e1f8942 100644 --- a/src/Notes-master/src/net/micode/notes/data/Contact.java +++ b/src/Notes-master/src/net/micode/notes/data/Contact.java @@ -25,7 +25,7 @@ import android.util.Log; import java.util.HashMap; -//ceshihebing +//ceshihebing2 public class Contact { private static HashMap sContactCache; diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java b/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java index 3a2050b..41021a3 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.micode.notes.gtask.data; +package net.micode.notes.gtask.data;//测试 import android.database.Cursor; import android.util.Log; 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 6706cf6..bcfc524 100644 --- a/src/Notes-master/src/net/micode/notes/model/Note.java +++ b/src/Notes-master/src/net/micode/notes/model/Note.java @@ -33,73 +33,121 @@ import net.micode.notes.data.Notes.TextNote; import java.util.ArrayList; - +// 定义 Note 类,用于管理笔记相关的数据和操作 public class Note { + // 存储笔记的不同部分的变更数据 private ContentValues mNoteDiffValues; + // 存储笔记的数据 private NoteData mNoteData; + // 日志标记 private static final String TAG = "Note"; /** * Create a new note id for adding a new note to databases */ + + /** + * 创建一个新的笔记 ID 并添加到数据库 + * 此方法是同步的,避免并发创建笔记时出现问题 + * @param context 应用程序上下文 + * @param folderId 笔记所在的文件夹 ID + * @return 新创建的笔记 ID + */ public static synchronized long getNewNoteId(Context context, long folderId) { // Create a new note in the database + // 创建一个新的 ContentValues 对象来存储笔记的初始信息 ContentValues values = new ContentValues(); + // 获取当前时间作为创建时间 long createdTime = System.currentTimeMillis(); values.put(NoteColumns.CREATED_DATE, createdTime); values.put(NoteColumns.MODIFIED_DATE, createdTime); values.put(NoteColumns.TYPE, Notes.TYPE_NOTE); values.put(NoteColumns.LOCAL_MODIFIED, 1); values.put(NoteColumns.PARENT_ID, folderId); + // 将笔记信息插入到内容提供者的 URI 中 Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); long noteId = 0; try { + // 从 URI 中提取笔记 ID,通常 URI 包含笔记的路径信息,路径中的一部分是笔记 ID noteId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { + // 若出现异常,打印错误日志并将笔记 ID 设为 0 Log.e(TAG, "Get note id error :" + e.toString()); noteId = 0; } if (noteId == -1) { + // 若笔记 ID 为 -1,抛出异常 throw new IllegalStateException("Wrong note id:" + noteId); } return noteId; } - + // 构造函数,初始化笔记的数据存储和变更存储 public Note() { mNoteDiffValues = new ContentValues(); mNoteData = new NoteData(); } + /** + * 设置笔记的值 + * @param key 要设置的键 + * @param value 要设置的值 + */ public void setNoteValue(String key, String value) { mNoteDiffValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } + /** + * 设置文本数据的键值对 + * @param key 文本数据的键 + * @param value 文本数据的值 + */ public void setTextData(String key, String value) { mNoteData.setTextData(key, value); } - + /** + * 设置文本数据的 ID + * @param id 文本数据的 ID + */ public void setTextDataId(long id) { mNoteData.setTextDataId(id); } - + /** + * 获取文本数据的 ID + * @return 文本数据的 ID + */ public long getTextDataId() { return mNoteData.mTextDataId; } - + /** + * 设置通话数据的 ID + * @param id 通话数据的 ID + */ public void setCallDataId(long id) { mNoteData.setCallDataId(id); } - + /** + * 设置通话数据的键值对 + * @param key 通话数据的键 + * @param value 通话数据的值 + */ public void setCallData(String key, String value) { mNoteData.setCallData(key, value); } - + /** + * 检查笔记是否在本地被修改 + * @return 若笔记在本地被修改,返回 true,否则返回 false + */ public boolean isLocalModified() { return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); } - + /** + * 同步笔记数据到数据库 + * @param context 应用程序上下文 + * @param noteId 笔记的 ID + * @return 若同步成功,返回 true,否则返回 false + */ public boolean syncNote(Context context, long noteId) { if (noteId <= 0) { throw new IllegalArgumentException("Wrong note id:" + noteId); @@ -110,15 +158,14 @@ public class Note { } /** - * In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and - * {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the - * note data info + * 理论上,一旦数据发生变化,笔记应该更新 LOCAL_MODIFIED 和 MODIFIED_DATE 字段。 + * 即使更新笔记失败,为了数据安全,我们也会更新笔记的数据信息 */ if (context.getContentResolver().update( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null, null) == 0) { Log.e(TAG, "Update note error, should not happen"); - // Do not return, fall through + // 不返回,继续执行后续代码 } mNoteDiffValues.clear(); @@ -129,7 +176,7 @@ public class Note { return true; } - + // 内部类 NoteData,用于存储笔记的数据 private class NoteData { private long mTextDataId; @@ -140,44 +187,67 @@ public class Note { private ContentValues mCallDataValues; private static final String TAG = "NoteData"; - + // 构造函数,初始化数据存储 public NoteData() { mTextDataValues = new ContentValues(); mCallDataValues = new ContentValues(); mTextDataId = 0; mCallDataId = 0; } - + /** + * 检查数据是否在本地被修改 + * @return 若数据在本地被修改,返回 true,否则返回 false + */ boolean isLocalModified() { return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; } - + + /** + * 设置文本数据的 ID + * @param id 文本数据的 ID + */ void setTextDataId(long id) { if(id <= 0) { throw new IllegalArgumentException("Text data id should larger than 0"); } mTextDataId = id; } - + /** + * 设置通话数据的 ID + * @param id 通话数据的 ID + */ void setCallDataId(long id) { if (id <= 0) { throw new IllegalArgumentException("Call data id should larger than 0"); } mCallDataId = id; } - + /** + * 设置通话数据的键值对 + * @param key 通话数据的键 + * @param value 通话数据的值 + */ void setCallData(String key, String value) { mCallDataValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } - + /** + * 设置文本数据的键值对 + * @param key 文本数据的键 + * @param value 文本数据的值 + */ void setTextData(String key, String value) { mTextDataValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } - + /** + * 将数据更新到内容提供者中 + * @param context 应用程序上下文 + * @param noteId 笔记的 ID + * @return 更新操作的结果 URI,若失败返回 null + */ Uri pushIntoContentResolver(Context context, long noteId) { /** * Check for safety @@ -193,9 +263,11 @@ public class Note { mTextDataValues.put(DataColumns.NOTE_ID, noteId); if (mTextDataId == 0) { mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); + // 插入新的文本数据 Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, mTextDataValues); try { + // 从 URI 中提取新插入的文本数据的 ID setTextDataId(Long.valueOf(uri.getPathSegments().get(1))); } catch (NumberFormatException e) { Log.e(TAG, "Insert new text data fail with noteId" + noteId); @@ -203,6 +275,7 @@ public class Note { return null; } } else { + // 更新已有的文本数据 builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( Notes.CONTENT_DATA_URI, mTextDataId)); builder.withValues(mTextDataValues); @@ -215,9 +288,11 @@ public class Note { mCallDataValues.put(DataColumns.NOTE_ID, noteId); if (mCallDataId == 0) { mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); + // 插入新的通话数据 Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, mCallDataValues); try { + // 从 URI 中提取新插入的通话数据的 ID setCallDataId(Long.valueOf(uri.getPathSegments().get(1))); } catch (NumberFormatException e) { Log.e(TAG, "Insert new call data fail with noteId" + noteId); @@ -225,6 +300,7 @@ public class Note { return null; } } else { + // 更新已有的通话数据 builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( Notes.CONTENT_DATA_URI, mCallDataId)); builder.withValues(mCallDataValues); @@ -235,6 +311,7 @@ public class Note { if (operationList.size() > 0) { try { + // 执行批量操作 ContentProviderResult[] results = context.getContentResolver().applyBatch( Notes.AUTHORITY, operationList); return (results == null || results.length == 0 || results[0] == null) ? null 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 be081e4..67c7f3c 100644 --- a/src/Notes-master/src/net/micode/notes/model/WorkingNote.java +++ b/src/Notes-master/src/net/micode/notes/model/WorkingNote.java @@ -31,37 +31,37 @@ import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.TextNote; import net.micode.notes.tool.ResourceParser.NoteBgResources; - +// 表示正在编辑或处理的笔记的类 public class WorkingNote { - // Note for the working note + // 笔记对象 private Note mNote; - // Note Id + // 笔记的 ID private long mNoteId; - // Note content + // 笔记的内容 private String mContent; - // Note mode + // 笔记的模式 private int mMode; - + // 提醒日期 private long mAlertDate; - + // 最后修改日期 private long mModifiedDate; - + // 背景颜色 ID private int mBgColorId; - + // 小部件的 ID private int mWidgetId; - + // 小部件的类型 private int mWidgetType; - + // 笔记所在的文件夹 ID private long mFolderId; - + // 上下文对象 private Context mContext; - + // 日志标记 private static final String TAG = "WorkingNote"; - + // 笔记是否已删除 private boolean mIsDeleted; - + // 笔记设置变更监听器 private NoteSettingChangedListener mNoteSettingStatusListener; - + // 数据投影,用于查询笔记数据时指定要查询的列 public static final String[] DATA_PROJECTION = new String[] { DataColumns.ID, DataColumns.CONTENT, @@ -71,7 +71,7 @@ public class WorkingNote { DataColumns.DATA3, DataColumns.DATA4, }; - + // 笔记投影,用于查询笔记时指定要查询的列 public static final String[] NOTE_PROJECTION = new String[] { NoteColumns.PARENT_ID, NoteColumns.ALERTED_DATE, @@ -80,7 +80,7 @@ public class WorkingNote { NoteColumns.WIDGET_TYPE, NoteColumns.MODIFIED_DATE }; - + // 数据投影中各列的索引 private static final int DATA_ID_COLUMN = 0; private static final int DATA_CONTENT_COLUMN = 1; @@ -88,7 +88,7 @@ public class WorkingNote { private static final int DATA_MIME_TYPE_COLUMN = 2; private static final int DATA_MODE_COLUMN = 3; - + // 笔记投影中各列的索引 private static final int NOTE_PARENT_ID_COLUMN = 0; private static final int NOTE_ALERTED_DATE_COLUMN = 1; @@ -101,20 +101,22 @@ public class WorkingNote { private static final int NOTE_MODIFIED_DATE_COLUMN = 5; - // New note construct + // 创建新笔记的构造函数 private WorkingNote(Context context, long folderId) { mContext = context; mAlertDate = 0; + //初始化修改日期为当前系统时间 mModifiedDate = System.currentTimeMillis(); mFolderId = folderId; mNote = new Note(); mNoteId = 0; + // 标记笔记未删除 mIsDeleted = false; mMode = 0; mWidgetType = Notes.TYPE_WIDGET_INVALIDE; } - // Existing note construct + // 加载现有笔记的构造函数 private WorkingNote(Context context, long noteId, long folderId) { mContext = context; mNoteId = noteId; @@ -123,18 +125,25 @@ public class WorkingNote { mNote = new Note(); loadNote(); } - + // 加载笔记的方法,从数据库中查询笔记的基本信息 private void loadNote() { + // 1. 通过 ContentResolver 查询笔记信息,使用 NOTE_PROJECTION 投影指定要查询的列 Cursor cursor = mContext.getContentResolver().query( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, null, null); if (cursor != null) { + // 2. 将游标移动到第一个结果 if (cursor.moveToFirst()) { + // 3. 从游标中读取并存储父文件夹 ID mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); + // 4. 从游标中读取并存储背景颜色 ID mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); + // 5. 从游标中读取并存储小部件 ID mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); + // 6. 从游标中读取并存储小部件类型 mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); + // 7. 从游标中读取并存储提醒日期 mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); } @@ -145,24 +154,30 @@ public class WorkingNote { } loadNoteData(); } - + // 加载笔记的数据,从数据库中查询笔记的数据信息 private void loadNoteData() { + // 1. 通过 ContentResolver 查询笔记数据,使用 DATA_PROJECTION 投影指定要查询的列,并通过 NOTE_ID 筛选 Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { String.valueOf(mNoteId) }, null); if (cursor != null) { + // 2. 将游标移动到第一个结果 if (cursor.moveToFirst()) { do { + // 3. 读取数据的 MIME 类型 String type = cursor.getString(DATA_MIME_TYPE_COLUMN); if (DataConstants.NOTE.equals(type)) { + // 4. 如果是普通笔记,存储内容和模式,并设置文本数据的 ID mContent = cursor.getString(DATA_CONTENT_COLUMN); mMode = cursor.getInt(DATA_MODE_COLUMN); mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN)); } else if (DataConstants.CALL_NOTE.equals(type)) { + // 5. 如果是通话笔记,设置通话数据的 ID mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); } else { + // 6. 对于不识别的类型,打印调试日志 Log.d(TAG, "Wrong note type with type:" + type); } } while (cursor.moveToNext()); @@ -173,7 +188,7 @@ public class WorkingNote { throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); } } - + // 创建一个空的笔记 public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, int widgetType, int defaultBgColorId) { WorkingNote note = new WorkingNote(context, folderId); @@ -182,24 +197,25 @@ public class WorkingNote { note.setWidgetType(widgetType); return note; } - + // 从数据库加载一个笔记 public static WorkingNote load(Context context, long id) { return new WorkingNote(context, id, 0); } - + // 保存笔记到数据库 public synchronized boolean saveNote() { if (isWorthSaving()) { if (!existInDatabase()) { + // 如果笔记不存在于数据库中,创建一个新的笔记 ID if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { Log.e(TAG, "Create new note fail with id:" + mNoteId); return false; } } - + // 调用 Note 对象的 syncNote 方法同步笔记信息 mNote.syncNote(mContext, mNoteId); - /** - * Update widget content if there exist any widget of this note + /** + * 如果笔记有小部件,更新小部件的内容 */ if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && mWidgetType != Notes.TYPE_WIDGET_INVALIDE @@ -212,11 +228,13 @@ public class WorkingNote { } } + // 检查笔记是否存在于数据库中 public boolean existInDatabase() { return mNoteId > 0; } - + // 判断笔记是否值得保存 private boolean isWorthSaving() { + // 1. 判断笔记是否已删除,或者如果笔记不存在且内容为空,或者笔记存在但未被本地修改,则不值得保存 if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) || (existInDatabase() && !mNote.isLocalModified())) { return false; @@ -224,11 +242,11 @@ public class WorkingNote { return true; } } - + // 设置笔记设置变更监听器 public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { mNoteSettingStatusListener = l; } - + // 设置提醒日期 public void setAlertDate(long date, boolean set) { if (date != mAlertDate) { mAlertDate = date; @@ -238,7 +256,7 @@ public class WorkingNote { mNoteSettingStatusListener.onClockAlertChanged(date, set); } } - + // 标记笔记是否已删除 public void markDeleted(boolean mark) { mIsDeleted = mark; if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID @@ -246,7 +264,7 @@ public class WorkingNote { mNoteSettingStatusListener.onWidgetChanged(); } } - + // 设置背景颜色 ID public void setBgColorId(int id) { if (id != mBgColorId) { mBgColorId = id; @@ -256,7 +274,7 @@ public class WorkingNote { mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); } } - + // 设置检查列表模式 public void setCheckListMode(int mode) { if (mMode != mode) { if (mNoteSettingStatusListener != null) { @@ -266,102 +284,102 @@ public class WorkingNote { mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); } } - +// 设置小部件类型 public void setWidgetType(int type) { if (type != mWidgetType) { mWidgetType = type; mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); } } - + // 设置小部件 ID public void setWidgetId(int id) { if (id != mWidgetId) { mWidgetId = id; mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); } } - + // 设置笔记的工作文本 public void setWorkingText(String text) { if (!TextUtils.equals(mContent, text)) { mContent = text; mNote.setTextData(DataColumns.CONTENT, mContent); } } - + // 将笔记转换为通话笔记 public void convertToCallNote(String phoneNumber, long callDate) { mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER)); } - + // 检查是否有闹钟提醒 public boolean hasClockAlert() { return (mAlertDate > 0 ? true : false); } - + // 获取笔记内容 public String getContent() { return mContent; } - + // 获取提醒日期 public long getAlertDate() { return mAlertDate; } - + // 获取最后修改日期 public long getModifiedDate() { return mModifiedDate; } - + // 获取背景颜色的资源 ID public int getBgColorResId() { return NoteBgResources.getNoteBgResource(mBgColorId); } - + // 获取背景颜色 ID public int getBgColorId() { return mBgColorId; } - + // 获取标题背景的资源 ID public int getTitleBgResId() { return NoteBgResources.getNoteTitleBgResource(mBgColorId); } - + // 获取检查列表模式 public int getCheckListMode() { return mMode; } - + // 获取笔记 ID public long getNoteId() { return mNoteId; } - + // 获取文件夹 ID public long getFolderId() { return mFolderId; } - + // 获取小部件 ID public int getWidgetId() { return mWidgetId; } - + // 获取小部件类型 public int getWidgetType() { return mWidgetType; } - +// 笔记设置变更监听器接口 public interface NoteSettingChangedListener { - /** - * Called when the background color of current note has just changed + /** + * 当笔记的背景颜色发生变化时调用 */ void onBackgroundColorChanged(); - /** - * Called when user set clock + /** + * 当用户设置闹钟时调用 */ void onClockAlertChanged(long date, boolean set); /** - * Call when user create note from widget + * 当用户从小部件创建笔记时调用 */ void onWidgetChanged(); - /** - * Call when switch between check list mode and normal mode - * @param oldMode is previous mode before change - * @param newMode is new mode + /** + * 当在检查列表模式和普通模式之间切换时调用 + * @param oldMode 切换前的模式 + * @param newMode 切换后的模式 */ void onCheckListModeChanged(int oldMode, int newMode); } diff --git a/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java b/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java index 39f6ec4..6c30e18 100644 --- a/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java @@ -35,12 +35,15 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; - +// BackupUtils 类用于实现笔记数据的备份和导出为文本文件的功能 public class BackupUtils { + // 用于日志记录的标签 private static final String TAG = "BackupUtils"; // Singleton stuff + // 单例模式相关 + // 保存单例实例 private static BackupUtils sInstance; - + // 获取单例实例的方法,如果实例不存在则创建一个新的实例 public static synchronized BackupUtils getInstance(Context context) { if (sInstance == null) { sInstance = new BackupUtils(context); @@ -53,52 +56,60 @@ public class BackupUtils { * status */ // Currently, the sdcard is not mounted + // 以下是表示备份或恢复状态的常量 + // 表示 SD 卡未挂载 public static final int STATE_SD_CARD_UNMOUONTED = 0; // The backup file not exist + // 表示备份文件不存在 public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; // The data is not well formated, may be changed by other programs + // 表示数据格式不正确,可能被其他程序修改 public static final int STATE_DATA_DESTROIED = 2; // Some run-time exception which causes restore or backup fails + // 表示一些运行时异常导致恢复或备份失败 public static final int STATE_SYSTEM_ERROR = 3; // Backup or restore success + // 表示备份或恢复成功 public static final int STATE_SUCCESS = 4; - + // 用于文本导出的内部类实例 private TextExport mTextExport; - + // 私有构造函数,初始化时创建 TextExport 实例 private BackupUtils(Context context) { mTextExport = new TextExport(context); } - + // 检查外部存储是否可用的方法 private static boolean externalStorageAvailable() { + // 比较外部存储状态是否为已挂载 return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); } - + // 调用 TextExport 的 exportToText 方法进行数据导出为文本,并返回结果状态 public int exportToText() { return mTextExport.exportToText(); } - + // 获取导出的文本文件名 public String getExportedTextFileName() { return mTextExport.mFileName; } - + // 获取导出的文本文件目录 public String getExportedTextFileDir() { return mTextExport.mFileDirectory; } - + // 内部类 TextExport,用于实现具体的文本导出功能 private static class TextExport { + // 用于查询笔记的投影,包含笔记的 ID、修改日期、摘要和类型 private static final String[] NOTE_PROJECTION = { NoteColumns.ID, NoteColumns.MODIFIED_DATE, NoteColumns.SNIPPET, NoteColumns.TYPE }; - + // 笔记投影中 ID 列的索引 private static final int NOTE_COLUMN_ID = 0; - + // 笔记投影中修改日期列的索引 private static final int NOTE_COLUMN_MODIFIED_DATE = 1; - + // 笔记投影中摘要列的索引 private static final int NOTE_COLUMN_SNIPPET = 2; - + // 用于查询数据的投影,包含数据的内容、MIME 类型等多个字段 private static final String[] DATA_PROJECTION = { DataColumns.CONTENT, DataColumns.MIME_TYPE, @@ -107,31 +118,36 @@ public class BackupUtils { DataColumns.DATA3, DataColumns.DATA4, }; - + // 数据投影中内容列的索引 private static final int DATA_COLUMN_CONTENT = 0; - + // 数据投影中 MIME 类型列的索引 private static final int DATA_COLUMN_MIME_TYPE = 1; - + // 数据投影中通话日期列的索引 private static final int DATA_COLUMN_CALL_DATE = 2; - + // 数据投影中电话号码列的索引 private static final int DATA_COLUMN_PHONE_NUMBER = 4; - + // 用于格式化输出的文本格式数组 private final String [] TEXT_FORMAT; + // 格式化文件夹名称的索引 private static final int FORMAT_FOLDER_NAME = 0; + // 格式化笔记日期的索引 private static final int FORMAT_NOTE_DATE = 1; + // 格式化笔记内容的索引 private static final int FORMAT_NOTE_CONTENT = 2; - + // 上下文对象,用于获取资源等操作 private Context mContext; + // 导出的文件名 private String mFileName; + // 导出的文件目录 private String mFileDirectory; - + // 构造函数,初始化文本格式数组、上下文对象,并设置文件名和目录为空字符串 public TextExport(Context context) { TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); mContext = context; mFileName = ""; mFileDirectory = ""; } - + // 根据索引获取对应的文本格式字符串 private String getFormat(int id) { return TEXT_FORMAT[id]; } @@ -139,8 +155,10 @@ public class BackupUtils { /** * Export the folder identified by folder id to text */ + // 将指定文件夹及其下的笔记导出到 PrintStream private void exportFolderToText(String folderId, PrintStream ps) { // Query notes belong to this folder + // 查询属于该文件夹的笔记 Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { folderId @@ -150,14 +168,18 @@ public class BackupUtils { if (notesCursor.moveToFirst()) { do { // Print note's last modified date + // 打印笔记的最后修改日期 ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( mContext.getString(R.string.format_datetime_mdhm), notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); // Query data belong to this note + // 获取笔记 ID String noteId = notesCursor.getString(NOTE_COLUMN_ID); + // 导出该笔记 exportNoteToText(noteId, ps); } while (notesCursor.moveToNext()); } + // 关闭游标 notesCursor.close(); } } @@ -165,7 +187,9 @@ public class BackupUtils { /** * Export note identified by id to a print stream */ - private void exportNoteToText(String noteId, PrintStream ps) { + // 将指定笔记及其相关数据导出到 PrintStream + private void exportNoteToText(String noteId, PrintStream ps) { + // 查询属于该笔记的数据 Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { noteId @@ -177,6 +201,7 @@ public class BackupUtils { String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); if (DataConstants.CALL_NOTE.equals(mimeType)) { // Print phone number + // 如果是通话笔记,打印电话号码 String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER); long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE); String location = dataCursor.getString(DATA_COLUMN_CONTENT); @@ -186,15 +211,18 @@ public class BackupUtils { phoneNumber)); } // Print call date + // 打印通话日期 ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat .format(mContext.getString(R.string.format_datetime_mdhm), callDate))); // Print call attachment location + // 打印通话附件位置 if (!TextUtils.isEmpty(location)) { ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), location)); } } else if (DataConstants.NOTE.equals(mimeType)) { + // 如果是普通笔记,打印内容 String content = dataCursor.getString(DATA_COLUMN_CONTENT); if (!TextUtils.isEmpty(content)) { ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), @@ -203,9 +231,11 @@ public class BackupUtils { } } while (dataCursor.moveToNext()); } + // 关闭游标 dataCursor.close(); } // print a line separator between note + // 在笔记之间打印换行符 try { ps.write(new byte[] { Character.LINE_SEPARATOR, Character.LETTER_NUMBER @@ -218,18 +248,22 @@ public class BackupUtils { /** * Note will be exported as text which is user readable */ - public int exportToText() { + // 将笔记数据导出为用户可读的文本文件 + public int exportToText() { + // 检查外部存储是否可用 if (!externalStorageAvailable()) { Log.d(TAG, "Media was not mounted"); return STATE_SD_CARD_UNMOUONTED; } + // 获取用于导出的 PrintStream PrintStream ps = getExportToTextPrintStream(); if (ps == null) { Log.e(TAG, "get print stream error"); return STATE_SYSTEM_ERROR; } // First export folder and its notes + // 首先导出文件夹及其下的笔记 Cursor folderCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, @@ -241,6 +275,7 @@ public class BackupUtils { if (folderCursor.moveToFirst()) { do { // Print folder's name + // 获取文件夹名称 String folderName = ""; if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) { folderName = mContext.getString(R.string.call_record_folder_name); @@ -254,10 +289,12 @@ public class BackupUtils { exportFolderToText(folderId, ps); } while (folderCursor.moveToNext()); } + // 关闭游标 folderCursor.close(); } // Export notes in root's folder + // 导出根文件夹下的笔记 Cursor noteCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, @@ -271,12 +308,15 @@ public class BackupUtils { mContext.getString(R.string.format_datetime_mdhm), noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); // Query data belong to this note + // 获取笔记 ID String noteId = noteCursor.getString(NOTE_COLUMN_ID); exportNoteToText(noteId, ps); } while (noteCursor.moveToNext()); } + // 关闭游标 noteCursor.close(); } + // 关闭 PrintStream ps.close(); return STATE_SUCCESS; @@ -285,7 +325,9 @@ public class BackupUtils { /** * Get a print stream pointed to the file {@generateExportedTextFile} */ + // 获取指向导出文件的 PrintStream private PrintStream getExportToTextPrintStream() { + // 在 SD 卡上生成导出文件 File file = generateFileMountedOnSDcard(mContext, R.string.file_path, R.string.file_name_txt_format); if (file == null) { @@ -296,6 +338,7 @@ public class BackupUtils { mFileDirectory = mContext.getString(R.string.file_path); PrintStream ps = null; try { + // 创建文件输出流和 PrintStream FileOutputStream fos = new FileOutputStream(file); ps = new PrintStream(fos); } catch (FileNotFoundException e) { @@ -312,6 +355,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()); @@ -324,9 +368,11 @@ public class BackupUtils { File file = new File(sb.toString()); try { + // 如果目录不存在则创建目录 if (!filedir.exists()) { filedir.mkdir(); } + // 如果文件不存在则创建文件 if (!file.exists()) { file.createNewFile(); } @@ -340,5 +386,13 @@ public class BackupUtils { return null; } } +/* + * 这个类主要实现了以下功能: +采用单例模式,确保整个应用中只有一个BackupUtils实例。 +定义了一系列表示备份和恢复状态的常量,方便在操作过程中返回状态信息。 +通过内部类TextExport实现了将笔记数据按照特定格式导出到文本文件的功能,包括文件夹、笔记及其相关数据的导出,并且在导出过程中会根据外部存储的状态进行相应处理,如果外部存储不可用或获取打印流失败等情况会返回相应的错误状态。同时,还提供了生成导出文件的方法,确保文件在 SD 卡上的正确创建和存储路径的设置。 +在使用过程中,可以通过getInstance方法获取BackupUtils实例,然后调用exportToText方法进行数据导出,并根据返回的状态判断导出是否成功,还可以获取导出文件的名称和目录信息。 +请注意,代码中的Notes类及其内部的常量(如NoteColumns、DataColumns、DataConstants等)和资源字符串(如R.string中的相关字符串)应该是在其他地方定义的,这里假设它们已经正确导入和定义。同时,在实际应用中,可能需要进一步处理异常情况和优化代码逻辑。 + */ 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 2a14982..396bc6b 100644 --- a/src/Notes-master/src/net/micode/notes/tool/DataUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/DataUtils.java @@ -36,85 +36,142 @@ import java.util.HashSet; public class DataUtils { + // 用于日志记录的标签 public static final String TAG = "DataUtils"; + + /** + * 批量删除笔记 + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param ids 要删除的笔记 ID 的 HashSet + * @return 如果删除成功返回 true,否则返回 false + */ + + public static boolean batchDeleteNotes(ContentResolver resolver, HashSet ids) { + // 检查 ids 是否为 null if (ids == null) { Log.d(TAG, "the ids is null"); + // 如果为 null,视为删除操作成功(可能是因为没有要删除的内容) return true; } + // 检查 ids 集合是否为空 if (ids.size() == 0) { Log.d(TAG, "no id is in the hashset"); + // 如果为空,视为删除操作成功(没有实际要删除的笔记) return true; } ArrayList operationList = new ArrayList(); + // 遍历要删除的笔记 ID 集合 for (long id : ids) { + // 不允许删除系统根文件夹 if(id == Notes.ID_ROOT_FOLDER) { Log.e(TAG, "Don't delete system folder root"); continue; } + // 创建一个删除操作的构建器,指定要删除的笔记 URI ContentProviderOperation.Builder builder = ContentProviderOperation .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); operationList.add(builder.build()); } try { + // 执行批量操作 ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); + // 检查结果是否为空或长度为 0 或第一个结果为 null if (results == null || results.length == 0 || results[0] == null) { Log.d(TAG, "delete notes failed, ids:" + ids.toString()); return false; } + // 如果操作成功,返回 true return true; } catch (RemoteException e) { Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } catch (OperationApplicationException e) { Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } + // 如果发生异常,返回 false return false; } - + /** + * 将笔记移动到指定文件夹 + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param id 要移动的笔记 ID + * @param srcFolderId 笔记的源文件夹 ID + * @param desFolderId 笔记的目标文件夹 ID + */ public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) { ContentValues values = new ContentValues(); + // 设置目标文件夹 ID values.put(NoteColumns.PARENT_ID, desFolderId); + // 设置源文件夹 ID values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); + // 设置本地已修改标志 values.put(NoteColumns.LOCAL_MODIFIED, 1); + // 执行更新操作,将笔记移动到目标文件夹 resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); } - + /** + * 批量将笔记移动到指定文件夹 + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param ids 要移动的笔记 ID 的 HashSet + * @param folderId 目标文件夹 ID + * @return 如果移动成功返回 true,否则返回 false + */ public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids, long folderId) { + // 检查 ids 是否为 null if (ids == null) { Log.d(TAG, "the ids is null"); return true; } ArrayList operationList = new ArrayList(); + // 遍历要移动的笔记 ID 集合 for (long id : ids) { + // 创建一个更新操作的构建器,指定要更新的笔记 URI ContentProviderOperation.Builder builder = ContentProviderOperation .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); + // 设置目标文件夹 ID builder.withValue(NoteColumns.PARENT_ID, folderId); + // 设置本地已修改标志 builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); operationList.add(builder.build()); } try { - ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); - if (results == null || results.length == 0 || results[0] == null) { + // 执行批量操作 + ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); + // 检查结果是否为空或长度为 0 或第一个结果为 null + if (results == null || results.length == 0 || results[0] == null) { Log.d(TAG, "delete notes failed, ids:" + ids.toString()); return false; } + // 如果操作成功,返回 true return true; } catch (RemoteException e) { Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } catch (OperationApplicationException e) { Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } + // 如果发生异常,返回 false return false; } /** * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}} + */ + + /** + * 获取除系统文件夹({@link Notes#TYPE_SYSTEM})之外的所有文件夹数量 + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @return 文件夹数量 */ public static int getUserFolderCount(ContentResolver resolver) { + // 查询数据库,计算符合条件的文件夹数量 Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI, new String[] { "COUNT(*)" }, NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", @@ -125,18 +182,28 @@ public class DataUtils { if(cursor != null) { if(cursor.moveToFirst()) { try { + // 获取查询结果中的数量 count = cursor.getInt(0); } catch (IndexOutOfBoundsException e) { Log.e(TAG, "get folder count failed:" + e.toString()); } finally { + // 关闭游标 cursor.close(); } } } return count; } - + /** + * 检查笔记在笔记数据库中是否可见(不在回收站且类型匹配) + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param noteId 笔记 ID + * @param type 笔记类型 + * @return 如果可见返回 true,否则返回 false + */ public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { + // 查询数据库,检查笔记是否存在且符合可见条件 Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null, NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, @@ -152,8 +219,15 @@ public class DataUtils { } return exist; } - + /** + * 检查笔记在笔记数据库中是否存在 + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param noteId 笔记 ID + * @return 如果存在返回 true,否则返回 false + */ public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { + // 查询数据库,检查笔记是否存在 Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null, null, null, null); @@ -166,8 +240,15 @@ public class DataUtils { } return exist; } - +/** + * 检查数据在数据数据库中是否存在 + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param dataId 数据 ID + * @return 如果存在返回 true,否则返回 false + */ public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { + // 查询数据库,检查数据是否存在 Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null, null, null, null); @@ -180,8 +261,15 @@ public class DataUtils { } return exist; } - + /** + * 检查指定名称的文件夹在数据库中是否可见(不在回收站且名称匹配) + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param name 文件夹名称 + * @return 如果可见返回 true,否则返回 false + */ public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { + // 查询数据库,检查文件夹是否存在且符合可见条件 Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + @@ -196,8 +284,15 @@ public class DataUtils { } return exist; } - + /** + * 获取指定文件夹下的笔记小部件信息 + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param folderId 文件夹 ID + * @return 包含笔记小部件信息的 HashSet + */ public static HashSet getFolderNoteWidget(ContentResolver resolver, long folderId) { + // 查询数据库,获取指定文件夹下的笔记小部件信息 Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, NoteColumns.PARENT_ID + "=?", @@ -223,8 +318,15 @@ public class DataUtils { } return set; } - + /** + * 根据笔记 ID 获取对应的电话号码 + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param noteId 笔记 ID + * @return 电话号码,如果获取失败返回空字符串 + */ public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { + // 查询数据库,获取指定笔记对应的电话号码 Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.PHONE_NUMBER }, CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", @@ -242,8 +344,16 @@ public class DataUtils { } return ""; } - + /** + * 根据电话号码和通话日期获取对应的笔记 ID + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param phoneNumber 电话号码 + * @param callDate 通话日期 + * @return 笔记 ID,如果获取失败返回 0 + */ public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { + // 查询数据库,获取指定电话号码和通话日期对应的笔记 ID Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.NOTE_ID }, CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" @@ -263,8 +373,15 @@ public class DataUtils { } return 0; } - +/** + * 根据笔记 ID 获取对应的摘要信息 + * + * @param resolver 用于与内容提供器交互的 ContentResolver + * @param noteId 笔记 ID + * @return 摘要信息,如果笔记不存在则抛出异常 + */ public static String getSnippetById(ContentResolver resolver, long noteId) { + // 查询数据库,获取指定笔记的摘要信息 Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, new String [] { NoteColumns.SNIPPET }, NoteColumns.ID + "=?", @@ -281,7 +398,12 @@ public class DataUtils { } throw new IllegalArgumentException("Note is not found with id: " + noteId); } - +/** + * 格式化摘要信息,去除换行符并截断 + * + * @param snippet 要格式化的摘要信息 + * @return 格式化后的摘要信息 + */ 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 666b729..e64b580 100644 --- a/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java @@ -13,101 +13,104 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +// 该类属于 net.micode.notes.tool 包 package net.micode.notes.tool; - +// 定义了一个公共类 GTaskStringUtils public class GTaskStringUtils { - + // 以下是一系列公共的静态常量字符串,它们很可能是用于 JSON 数据处理或数据交互时的键(Key) + // 表示操作的 ID public final static String GTASK_JSON_ACTION_ID = "action_id"; - + // 表示操作列表 public final static String GTASK_JSON_ACTION_LIST = "action_list"; - + // 表示操作类型 public final static String GTASK_JSON_ACTION_TYPE = "action_type"; - + // 操作类型为创建 public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create"; - + // 操作类型为获取全部 public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all"; - + // 操作类型为移动 public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move"; - + // 操作类型为更新 public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update"; - + // 表示创建者的 ID public final static String GTASK_JSON_CREATOR_ID = "creator_id"; - + // 表示子实体 public final static String GTASK_JSON_CHILD_ENTITY = "child_entity"; - + // 表示客户端版本 public final static String GTASK_JSON_CLIENT_VERSION = "client_version"; - + // 表示完成状态 public final static String GTASK_JSON_COMPLETED = "completed"; - + // 表示当前列表的 ID public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id"; - + // 表示默认列表的 ID public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id"; - + // 表示已删除状态 public final static String GTASK_JSON_DELETED = "deleted"; - + // 表示目标列表 public final static String GTASK_JSON_DEST_LIST = "dest_list"; - + // 表示目标父级 public final static String GTASK_JSON_DEST_PARENT = "dest_parent"; - + // 表示目标父级的类型 public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type"; - + // 表示实体的增量 public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta"; - + // 表示实体类型 public final static String GTASK_JSON_ENTITY_TYPE = "entity_type"; - + // 表示获取已删除的内容 public final static String GTASK_JSON_GET_DELETED = "get_deleted"; - + // 表示 ID public final static String GTASK_JSON_ID = "id"; - + // 表示索引 public final static String GTASK_JSON_INDEX = "index"; - + // 表示最后修改时间 public final static String GTASK_JSON_LAST_MODIFIED = "last_modified"; - + // 表示最新的同步点 public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point"; - + // 表示列表的 ID public final static String GTASK_JSON_LIST_ID = "list_id"; - + // 表示列表 public final static String GTASK_JSON_LISTS = "lists"; - + // 表示名称 public final static String GTASK_JSON_NAME = "name"; - + // 表示新的 ID public final static String GTASK_JSON_NEW_ID = "new_id"; - + // 表示笔记 public final static String GTASK_JSON_NOTES = "notes"; - + // 表示父级的 ID public final static String GTASK_JSON_PARENT_ID = "parent_id"; - + // 表示前一个兄弟节点的 ID public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id"; - + // 表示结果 public final static String GTASK_JSON_RESULTS = "results"; - + // 表示源列表 public final static String GTASK_JSON_SOURCE_LIST = "source_list"; - + // 表示任务 public final static String GTASK_JSON_TASKS = "tasks"; - + // 表示类型 public final static String GTASK_JSON_TYPE = "type"; - + // 类型为组 public final static String GTASK_JSON_TYPE_GROUP = "GROUP"; - + // 类型为任务 public final static String GTASK_JSON_TYPE_TASK = "TASK"; - + // 表示用户 public final static String GTASK_JSON_USER = "user"; - + // 以下可能是一些应用相关的常量,可能用于文件或文件夹的名称或前缀 + // MIUI 笔记的文件夹前缀 public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]"; - + // 默认文件夹 public final static String FOLDER_DEFAULT = "Default"; - + // 呼叫笔记的文件夹 public final static String FOLDER_CALL_NOTE = "Call_Note"; - + // 元数据文件夹 public final static String FOLDER_META = "METADATA"; - + // 以下是一些元数据的头部信息,可能用于存储一些特殊的元数据 + // 元数据的 GTask ID 头部 public final static String META_HEAD_GTASK_ID = "meta_gid"; - + // 元数据的笔记头部 public final static String META_HEAD_NOTE = "meta_note"; - + // 元数据的数据头部 public final static String META_HEAD_DATA = "meta_data"; - + // 元数据的笔记名称 public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE"; } diff --git a/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java b/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java index 1ad3ad6..309e587 100644 --- a/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java +++ b/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java @@ -21,25 +21,26 @@ import android.preference.PreferenceManager; import net.micode.notes.R; import net.micode.notes.ui.NotesPreferenceActivity; - +// 资源解析器类,用于管理笔记应用中的各种资源 public class ResourceParser { - + // 定义背景颜色的常量,使用整数表示不同颜色 public static final int YELLOW = 0; public static final int BLUE = 1; public static final int WHITE = 2; public static final int GREEN = 3; public static final int RED = 4; - + // 默认的背景颜色为黄色 public static final int BG_DEFAULT_COLOR = YELLOW; - + // 定义字体大小的常量,使用整数表示不同大小 public static final int TEXT_SMALL = 0; public static final int TEXT_MEDIUM = 1; public static final int TEXT_LARGE = 2; public static final int TEXT_SUPER = 3; - + // 默认的字体大小为中等 public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM; - + // 内部类 NoteBgResources 用于管理笔记编辑界面的背景资源 public static class NoteBgResources { + // 存储笔记编辑界面背景的资源 ID 数组,分别对应不同颜色的背景 private final static int [] BG_EDIT_RESOURCES = new int [] { R.drawable.edit_yellow, R.drawable.edit_blue, @@ -47,7 +48,7 @@ public class ResourceParser { R.drawable.edit_green, R.drawable.edit_red }; - + // 存储笔记编辑界面标题背景的资源 ID 数组,分别对应不同颜色的标题背景 private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] { R.drawable.edit_title_yellow, R.drawable.edit_title_blue, @@ -55,26 +56,30 @@ public class ResourceParser { R.drawable.edit_title_green, R.drawable.edit_title_red }; - + // 根据传入的颜色 ID 获取笔记编辑界面的背景资源 ID public static int getNoteBgResource(int id) { return BG_EDIT_RESOURCES[id]; } - + // 根据传入的颜色 ID 获取笔记编辑界面的标题背景资源 ID public static int getNoteTitleBgResource(int id) { return BG_EDIT_TITLE_RESOURCES[id]; } } - + // 根据上下文获取默认的背景 ID public static int getDefaultBgId(Context context) { + // 检查用户偏好设置中是否设置了背景颜色 if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { + // 如果设置了,随机选择一个背景颜色 return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length); } else { + // 否则使用默认的背景颜色 return BG_DEFAULT_COLOR; } } - + // 内部类 NoteItemBgResources 用于管理笔记列表项的背景资源 public static class NoteItemBgResources { + // 存储笔记列表项的不同状态(如第一个、正常、最后一个、单个)的背景资源 ID 数组,分别对应不同颜色 private final static int [] BG_FIRST_RESOURCES = new int [] { R.drawable.list_yellow_up, R.drawable.list_blue_up, @@ -106,29 +111,30 @@ public class ResourceParser { R.drawable.list_green_single, R.drawable.list_red_single }; - + // 根据传入的颜色 ID 获取笔记列表项第一个元素的背景资源 ID public static int getNoteBgFirstRes(int id) { return BG_FIRST_RESOURCES[id]; } - + // 根据传入的颜色 ID 获取笔记列表项最后一个元素的背景资源 ID public static int getNoteBgLastRes(int id) { return BG_LAST_RESOURCES[id]; } - + // 根据传入的颜色 ID 获取笔记列表项单个元素的背景资源 ID public static int getNoteBgSingleRes(int id) { return BG_SINGLE_RESOURCES[id]; } - + // 根据传入的颜色 ID 获取笔记列表项正常元素的背景资源 ID public static int getNoteBgNormalRes(int id) { return BG_NORMAL_RESOURCES[id]; } - + // 获取文件夹的背景资源 ID public static int getFolderBgRes() { return R.drawable.list_folder; } } - + // 内部类 WidgetBgResources 用于管理小部件的背景资源 public static class WidgetBgResources { + // 存储 2x 小部件的不同颜色的背景资源 ID 数组 private final static int [] BG_2X_RESOURCES = new int [] { R.drawable.widget_2x_yellow, R.drawable.widget_2x_blue, @@ -136,11 +142,11 @@ public class ResourceParser { R.drawable.widget_2x_green, R.drawable.widget_2x_red, }; - + // 根据传入的颜色 ID 获取 2x 小部件的背景资源 ID public static int getWidget2xBgResource(int id) { return BG_2X_RESOURCES[id]; } - + // 存储 4x 小部件的不同颜色的背景资源 ID 数组 private final static int [] BG_4X_RESOURCES = new int [] { R.drawable.widget_4x_yellow, R.drawable.widget_4x_blue, @@ -148,20 +154,21 @@ public class ResourceParser { R.drawable.widget_4x_green, R.drawable.widget_4x_red }; - + // 根据传入的颜色 ID 获取 4x 小部件的背景资源 ID public static int getWidget4xBgResource(int id) { return BG_4X_RESOURCES[id]; } } - + // 内部类 TextAppearanceResources 用于管理文本外观资源 public static class TextAppearanceResources { + // 存储不同字体大小的文本外观资源 ID 数组 private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] { R.style.TextAppearanceNormal, R.style.TextAppearanceMedium, R.style.TextAppearanceLarge, R.style.TextAppearanceSuper }; - + // 根据传入的字体大小 ID 获取文本外观资源 ID public static int getTexAppearanceResource(int id) { /** * HACKME: Fix bug of store the resource id in shared preference. @@ -173,6 +180,7 @@ public class ResourceParser { } return TEXTAPPEARANCE_RESOURCES[id]; } + // 获取文本外观资源的数量 public static int getResourcesSize() { return TEXTAPPEARANCE_RESOURCES.length; diff --git a/src/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java b/src/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java index 85723be..42b7810 100644 --- a/src/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java +++ b/src/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java @@ -39,33 +39,42 @@ import net.micode.notes.tool.DataUtils; import java.io.IOException; - +// 闹钟提醒活动类,继承自 Activity 并实现 OnClickListener 和 OnDismissListener 接口 public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { + // 笔记的 ID private long mNoteId; + // 笔记的摘要 private String mSnippet; + // 摘要的最大长度 private static final int SNIPPET_PREW_MAX_LEN = 60; + // 媒体播放器,用于播放闹钟声音 MediaPlayer mPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + // 隐藏标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE); final Window win = getWindow(); + // 当屏幕锁定时也显示该窗口 win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); - +// 如果屏幕未开启,添加相关标志保持屏幕开启等操作 if (!isScreenOn()) { win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); } - + // 获取启动该活动的 Intent Intent intent = getIntent(); try { + // 从 Intent 的数据中提取笔记 ID mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); + // 根据笔记 ID 获取笔记的摘要 mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); + // 如果摘要长度超过最大长度,截取并添加额外信息 mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info) : mSnippet; @@ -73,36 +82,45 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD e.printStackTrace(); return; } - + // 创建媒体播放器 mPlayer = new MediaPlayer(); + // 检查笔记是否存在于数据库中 if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { + // 显示操作对话框 showActionDialog(); + // 播放闹钟声音 playAlarmSound(); } else { + // 若笔记不存在,结束活动 finish(); } } - + // 检查屏幕是否开启的方法 private boolean isScreenOn() { PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); return pm.isScreenOn(); } - + // 播放闹钟声音的方法 private void playAlarmSound() { + // 获取闹钟的铃声 URI Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); - - int silentModeStreams = Settings.System.getInt(getContentResolver(), + // 获取系统的静音模式设置 + int silentModeStreams = Settings.System.getInt(getContentResolver(), Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); - + // 根据静音模式设置音频流类型 if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { mPlayer.setAudioStreamType(silentModeStreams); } else { mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); } try { + // 设置媒体播放器的数据源 mPlayer.setDataSource(this, url); + // 准备播放 mPlayer.prepare(); + // 设置为循环播放 mPlayer.setLooping(true); + // 开始播放 mPlayer.start(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block @@ -118,39 +136,53 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD e.printStackTrace(); } } - + // 显示操作对话框的方法 private void showActionDialog() { + // 创建对话框构建器 AlertDialog.Builder dialog = new AlertDialog.Builder(this); + // 设置对话框标题 dialog.setTitle(R.string.app_name); + // 设置对话框消息为笔记摘要 dialog.setMessage(mSnippet); + // 设置对话框的确认按钮及点击事件 dialog.setPositiveButton(R.string.notealert_ok, this); + // 如果屏幕开启,设置进入按钮及点击事件 if (isScreenOn()) { dialog.setNegativeButton(R.string.notealert_enter, this); } + // 显示对话框并设置对话框关闭监听器 dialog.show().setOnDismissListener(this); } - + // 点击事件处理方法 public void onClick(DialogInterface dialog, int which) { switch (which) { + // 点击进入按钮 case DialogInterface.BUTTON_NEGATIVE: - Intent intent = new Intent(this, NoteEditActivity.class); + // 创建一个新的 Intent 指向 NoteEditActivity + Intent intent = new Intent(this, NoteEditActivity.class); intent.setAction(Intent.ACTION_VIEW); + // 传递笔记的唯一标识符 intent.putExtra(Intent.EXTRA_UID, mNoteId); + // 启动活动 startActivity(intent); break; default: break; } } - + // 对话框关闭时的处理方法 public void onDismiss(DialogInterface dialog) { + // 停止播放闹钟声音 stopAlarmSound(); + // 结束活动 finish(); } - + // 停止播放闹钟声音的方法 private void stopAlarmSound() { if (mPlayer != null) { + // 停止播放 mPlayer.stop(); + // 释放资源 mPlayer.release(); mPlayer = null; } diff --git a/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider.java b/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider.java index ec6f819..573530a 100644 --- a/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider.java +++ b/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider.java @@ -32,31 +32,37 @@ import net.micode.notes.tool.ResourceParser; import net.micode.notes.ui.NoteEditActivity; import net.micode.notes.ui.NotesListActivity; + +// 抽象的笔记小部件提供者类,继承自 AppWidgetProvider public abstract class NoteWidgetProvider extends AppWidgetProvider { + // 投影数组,用于查询笔记小部件信息时指定要查询的列 public static final String [] PROJECTION = new String [] { NoteColumns.ID, NoteColumns.BG_COLOR_ID, NoteColumns.SNIPPET }; - + // 投影列的索引 public static final int COLUMN_ID = 0; public static final int COLUMN_BG_COLOR_ID = 1; public static final int COLUMN_SNIPPET = 2; - + // 日志标记 private static final String TAG = "NoteWidgetProvider"; - + // 当小部件被删除时调用的方法 @Override public void onDeleted(Context context, int[] appWidgetIds) { + // 创建一个 ContentValues 对象,将 WIDGET_ID 设为无效 ContentValues values = new ContentValues(); values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); + // 遍历要删除的小部件 ID 数组 for (int i = 0; i < appWidgetIds.length; i++) { + // 通过 ContentResolver 更新笔记信息,将对应小部件 ID 的 WIDGET_ID 设为无效 context.getContentResolver().update(Notes.CONTENT_NOTE_URI, values, NoteColumns.WIDGET_ID + "=?", new String[] { String.valueOf(appWidgetIds[i])}); } } - + // 获取笔记小部件信息的私有方法,通过 ContentResolver 查询 private Cursor getNoteWidgetInfo(Context context, int widgetId) { return context.getContentResolver().query(Notes.CONTENT_NOTE_URI, PROJECTION, @@ -64,34 +70,45 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider { new String[] { String.valueOf(widgetId), String.valueOf(Notes.ID_TRASH_FOLER) }, null); } - + // 更新小部件的方法,调用另一个重载的 update 方法 protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { update(context, appWidgetManager, appWidgetIds, false); } - + // 真正执行更新小部件的私有方法 private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, boolean privacyMode) { + // 遍历要更新的小部件 ID 数组 for (int i = 0; i < appWidgetIds.length; i++) { if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) { + // 获取默认背景颜色 ID int bgId = ResourceParser.getDefaultBgId(context); + // 初始化 snippet 为一个空字符串 String snippet = ""; + // 创建一个 Intent,指向 NoteEditActivity Intent intent = new Intent(context, NoteEditActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + // 向 Intent 中添加小部件 ID 和小部件类型信息 intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]); intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType()); - + // 获取小部件的笔记信息 Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]); if (c != null && c.moveToFirst()) { if (c.getCount() > 1) { + // 如果查询结果数量大于 1,打印错误日志并关闭游标 Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]); c.close(); return; } + // 获取 snippet 信息 snippet = c.getString(COLUMN_SNIPPET); + // 获取背景颜色 ID bgId = c.getInt(COLUMN_BG_COLOR_ID); + // 向 Intent 中添加笔记的唯一标识符 intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID)); + // 设置 Intent 的动作 intent.setAction(Intent.ACTION_VIEW); } else { + // 如果没有找到笔记信息,设置默认的 snippet 信息并设置 Intent 动作 snippet = context.getResources().getString(R.string.widget_havenot_content); intent.setAction(Intent.ACTION_INSERT_OR_EDIT); } @@ -99,34 +116,37 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider { if (c != null) { c.close(); } - + // 创建一个 RemoteViews 对象,使用抽象方法 getLayoutId 获取布局 ID RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId()); + // 设置小部件背景图片资源,使用抽象方法 getBgResourceId 获取资源 ID rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId)); + // 向 Intent 中添加背景颜色 ID 信息 intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId); - /** - * Generate the pending intent to start host for the widget - */ + // 创建一个 PendingIntent,根据隐私模式不同创建不同的 PendingIntent PendingIntent pendingIntent = null; if (privacyMode) { + // 在隐私模式下,设置文本视图内容并创建一个指向 NotesListActivity 的 PendingIntent rv.setTextViewText(R.id.widget_text, context.getString(R.string.widget_under_visit_mode)); pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent( context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); } else { + // 正常模式下,设置文本视图内容为 snippet 并创建一个指向 NoteEditActivity 的 PendingIntent rv.setTextViewText(R.id.widget_text, snippet); pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent, PendingIntent.FLAG_UPDATE_CURRENT); } - + // 为小部件的文本视图设置点击事件的 PendingIntent rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent); + // 更新小部件 appWidgetManager.updateAppWidget(appWidgetIds[i], rv); } } } - + // 抽象方法,用于获取背景资源 ID,需要子类实现 protected abstract int getBgResourceId(int bgId); - + // 抽象方法,用于获取布局 ID,需要子类实现 protected abstract int getLayoutId(); - + // 抽象方法,用于获取小部件类型,需要子类实现 protected abstract int getWidgetType(); } diff --git a/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider_2x.java b/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider_2x.java index adcb2f7..6759fa7 100644 --- a/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider_2x.java +++ b/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider_2x.java @@ -23,25 +23,30 @@ import net.micode.notes.R; import net.micode.notes.data.Notes; import net.micode.notes.tool.ResourceParser; - +// 继承自 NoteWidgetProvider 的 2x 笔记小部件提供者类 public class NoteWidgetProvider_2x extends NoteWidgetProvider { + // 当小部件更新时调用此方法 @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + // 调用父类的 update 方法进行更新操作 super.update(context, appWidgetManager, appWidgetIds); } - + // 实现父类的抽象方法,获取布局 ID @Override protected int getLayoutId() { + // 返回 2x 小部件的布局资源 ID return R.layout.widget_2x; } - + // 实现父类的抽象方法,获取背景资源 ID @Override protected int getBgResourceId(int bgId) { + // 使用 ResourceParser 的 WidgetBgResources 类获取 2x 小部件的背景资源 ID return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId); } - + // 实现父类的抽象方法,获取小部件类型 @Override protected int getWidgetType() { + // 返回 2x 小部件的类型 return Notes.TYPE_WIDGET_2X; } } diff --git a/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider_4x.java b/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider_4x.java index c12a02e..a46bb85 100644 --- a/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider_4x.java +++ b/src/Notes-master/src/net/micode/notes/widget/NoteWidgetProvider_4x.java @@ -23,24 +23,29 @@ import net.micode.notes.R; import net.micode.notes.data.Notes; import net.micode.notes.tool.ResourceParser; - +// 继承自 NoteWidgetProvider 的 4x 笔记小部件提供者类 public class NoteWidgetProvider_4x extends NoteWidgetProvider { + // 当小部件更新时调用此方法 @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + // 调用父类的 update 方法进行更新操作 super.update(context, appWidgetManager, appWidgetIds); } - + // 实现父类的抽象方法,获取布局 ID protected int getLayoutId() { + // 返回 4x 小部件的布局资源 ID return R.layout.widget_4x; } - + // 实现父类的抽象方法,获取背景资源 ID @Override protected int getBgResourceId(int bgId) { + // 使用 ResourceParser 的 WidgetBgResources 类获取 4x 小部件的背景资源 ID return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId); } - + // 实现父类的抽象方法,获取小部件类型 @Override protected int getWidgetType() { + // 返回 4x 小部件的类型 return Notes.TYPE_WIDGET_4X; } }