// 导入所需的类和接口 import android.appwidget.AppWidgetManager; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.util.Log; import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.gtask.exception.ActionFailureException; import net.micode.notes.tool.GTaskStringUtils; import net.micode.notes.tool.ResourceParser; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; // 声明SqlNote类 public class SqlNote { // 定义日志标签 private static final String TAG = SqlNote.class.getSimpleName(); // 定义无效ID常量 private static final int INVALID_ID = -99999; // 定义从数据库查询Note时需要的列 public static final String[] PROJECTION_NOTE = new String[] { NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID, NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE, NoteColumns.NOTES_COUNT, NoteColumns.PARENT_ID, NoteColumns.SNIPPET, NoteColumns.TYPE, NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.SYNC_ID, NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID, NoteColumns.VERSION }; // 定义各列在PROJECTION_NOTE数组中的索引 public static final int ID_COLUMN = 0; // ... 其他列的索引定义 // 类的成员变量 private Context mContext; // 应用上下文 private ContentResolver mContentResolver; // 内容解析器,用于访问内容提供者 private boolean mIsCreate; // 标记是否是新建 private long mId; // 笔记ID // ... 其他成员变量定义 // 构造函数 public SqlNote(Context context) { mContext = context; // 初始化上下文 mContentResolver = context.getContentResolver(); // 初始化内容解析器 mIsCreate = true; // 标记为新建 mId = INVALID_ID; // 初始化ID为无效ID mAlertDate = 0; // 初始化提醒日期 mBgColorId = ResourceParser.getDefaultBgId(context); // 初始化背景颜色ID mCreatedDate = System.currentTimeMillis(); // 初始化创建日期为当前时间 mHasAttachment = 0; // 初始化是否有附件标记 mModifiedDate = System.currentTimeMillis(); // 初始化修改日期为当前时间 mParentId = 0; // 初始化父ID mSnippet = ""; // 初始化摘要 mType = Notes.TYPE_NOTE; // 初始化类型 mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; // 初始化小部件ID为无效ID mWidgetType = Notes.TYPE_WIDGET_INVALIDE; // 初始化小部件类型 mOriginParent = 0; // 初始化原始父ID mVersion = 0; // 初始化版本 mDiffNoteValues = new ContentValues(); // 初始化差异值存储 mDataList = new ArrayList(); // 初始化数据列表 } // 构造函数,通过上下文和Cursor对象来初始化SqlNote对象 public SqlNote(Context context, Cursor c) { mContext = context; // 保存上下文引用 mContentResolver = context.getContentResolver(); // 获取内容解析器实例,用于与Content Providers交互 mIsCreate = false; // 标记这个对象不是新创建的(即不是通过插入操作创建的) loadFromCursor(c); // 从传入的Cursor加载数据 mDataList = new ArrayList(); // 初始化数据存储列表,用于存储笔记的附加数据 if (mType == Notes.TYPE_NOTE) // 如果笔记类型是普通笔记 loadDataContent(); // 加载笔记的详细内容 mDiffNoteValues = new ContentValues(); // 初始化ContentValues对象,用于存储笔记的更改(可能用于更新操作) } // 构造函数,通过上下文和笔记ID来初始化SqlNote对象 public SqlNote(Context context, long id) { mContext = context; // 保存上下文引用 mContentResolver = context.getContentResolver(); // 获取内容解析器实例 mIsCreate = false; // 标记这个对象不是新创建的 loadFromCursor(id); // 根据笔记ID加载数据 mDataList = new ArrayList(); // 初始化数据存储列表 if (mType == Notes.TYPE_NOTE) // 如果笔记类型是普通笔记 loadDataContent(); // 加载笔记的详细内容 mDiffNoteValues = new ContentValues(); // 初始化ContentValues对象 } // 私有方法,根据传入的笔记ID加载数据 private void loadFromCursor(long id) { Cursor c = null; // 声明Cursor对象 try { // 使用内容解析器查询数据库,获取指定ID的笔记数据 c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", new String[] { String.valueOf(id) }, null); if (c != null) { c.moveToNext(); // 移动到Cursor的第一行(如果存在) loadFromCursor(c); // 从Cursor加载数据 } else { Log.w(TAG, "loadFromCursor: cursor = null"); // 如果Cursor为空,记录警告日志 } } finally { if (c != null) c.close(); // 关闭Cursor } } // 私有方法,从传入的Cursor加载数据到SqlNote对象的属性中 private void loadFromCursor(Cursor c) { mId = c.getLong(ID_COLUMN); // 加载笔记ID mAlertDate = c.getLong(ALERTED_DATE_COLUMN); // 加载提醒日期 mBgColorId = c.getInt(BG_COLOR_ID_COLUMN); // 加载背景颜色ID mCreatedDate = c.getLong(CREATED_DATE_COLUMN); // 加载创建日期 mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN); // 加载是否有附件的标记 mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN); // 加载修改日期 mParentId = c.getLong(PARENT_ID_COLUMN); // 加载父笔记ID mSnippet = c.getString(SNIPPET_COLUMN); // 加载摘要文本 mType = c.getInt(TYPE_COLUMN); // 加载笔记类型 mWidgetId = c.getInt(WIDGET_ID_COLUMN); // 加载小部件ID mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); // 加载小部件类型 mVersion = c.getLong(VERSION_COLUMN); // 加载版本号 } // 私有方法,加载笔记的详细内容(如附加的数据项) private void loadDataContent() { Cursor c = null; // 声明Cursor对象 mDataList.clear(); // 清空数据列表,准备加载新数据 try { // 使用内容解析器查询数据库,获取指定笔记ID的所有数据项 c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, "(note_id=?)", new String[] { String.valueOf(mId) }, null); if (c != null) { if (c.getCount() == 0) { Log.w(TAG, "it seems that the note has not data"); // 如果没有数据项,记录警告日志 return; } while (c.moveToNext()) { // 遍历Cursor,为每一个数据项创建一个SqlData对象并添加到列表中 SqlData data = new SqlData(mContext, c); mDataList.add(data); } } else { Log.w(TAG, "loadDataContent: cursor = null"); // 如果Cursor为空,记录警告日志 } } finally { if (c != null) c.close(); // 关闭Cursor } } // 定义一个方法,接收一个JSONObject参数,返回一个布尔值 public boolean setContent(JSONObject js) { try { // 从传入的JSONObject中获取名为GTaskStringUtils.META_HEAD_NOTE的JSONObject JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); // 判断笔记类型,如果是系统类型,则打印日志并跳过后续操作 if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { Log.w(TAG, "cannot set system folder"); } // 如果是文件夹类型 else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { // 更新snippet和type属性,如果它们是新的或者发生了变化 String snippet = note.has(NoteColumns.SNIPPET) ? note.getString(NoteColumns.SNIPPET) : ""; if (mIsCreate || !mSnippet.equals(snippet)) { mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); } mSnippet = snippet; int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) : Notes.TYPE_NOTE; if (mIsCreate || mType != type) { mDiffNoteValues.put(NoteColumns.TYPE, type); } mType = type; } // 如果是普通笔记类型 else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { // 获取数据数组 JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); // 更新ID属性 long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID; if (mIsCreate || mId != id) { mDiffNoteValues.put(NoteColumns.ID, id); } mId = id; // 更新alertDate属性 long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note.getLong(NoteColumns.ALERTED_DATE) : 0; if (mIsCreate || mAlertDate != alertDate) { mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate); } mAlertDate = alertDate; // 更新bgColorId属性 int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note.getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext); if (mIsCreate || mBgColorId != bgColorId) { mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId); } mBgColorId = bgColorId; // 更新createDate属性 long createDate = note.has(NoteColumns.CREATED_DATE) ? note.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis(); if (mIsCreate || mCreatedDate != createDate) { mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate); } mCreatedDate = createDate; // 更新hasAttachment属性 int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note.getInt(NoteColumns.HAS_ATTACHMENT) : 0; if (mIsCreate || mHasAttachment != hasAttachment) { mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment); } mHasAttachment = hasAttachment; // 更新modifiedDate属性 long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis(); if (mIsCreate || mModifiedDate != modifiedDate) { mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate); } mModifiedDate = modifiedDate; // 更新parentId属性 long parentId = note.has(NoteColumns.PARENT_ID) ? note.getLong(NoteColumns.PARENT_ID) : 0; if (mIsCreate || mParentId != parentId) { mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId); } mParentId = parentId; // 更新snippet属性(对于普通笔记再次处理,可能是因为前面处理文件夹时也用了这个名字的变量) String snippet = note.has(NoteColumns.SNIPPET) ? note.getString(NoteColumns.SNIPPET) : ""; if (mIsCreate || !mSnippet.equals(snippet)) { mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); } mSnippet = snippet; // 更新type属性(对于普通笔记再次处理) int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) : Notes.TYPE_NOTE; if (mIsCreate || mType != type) { mDiffNoteValues.put(NoteColumns.TYPE, type); } mType = type; // 更新widgetId属性 int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID) : AppWidgetManager.INVALID_APPWIDGET_ID; if (mIsCreate || mWidgetId != widgetId) { mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId); } mWidgetId = widgetId; // 更新widgetType属性 int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note.getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE; if (mIsCreate || mWidgetType != widgetType) { mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType); } mWidgetType = widgetType; // 更新originParent属性 long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; if (mIsCreate || mOriginParent != originParent) { mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent); } mOriginParent = originParent; // 遍历数据数组,为每个数据项创建或更新SqlData对象 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); SqlData sqlData = null; // 如果数据项有ID,则尝试在已有数据中查找匹配的SqlData对象 if (data.has(DataColumns.ID)) { long dataId = data.getLong(DataColumns.ID); for (SqlData temp : mDataList) { if (dataId == temp.getId()) { sqlData = temp; } } } // 如果没有找到匹配的SqlData对象,则创建一个新的 if (sqlData == null) { sqlData = new SqlData(mContext); mDataList.add(sqlData); } // 更新SqlData对象的内容 sqlData.setContent(data); } } } catch (JSONException e) { // 捕获JSON异常,打印错误日志 Log.e(TAG, e.toString()); e.printStackTrace(); // 返回false表示处理失败 return false; } // 如果没有异常发生,返回true表示处理成功 return true; } // 定义一个方法,用于获取当前对象的JSON表示 public JSONObject getContent() { try { // 创建一个空的JSONObject用于存储将要返回的数据 JSONObject js = new JSONObject(); // 如果标记为已创建(但数据库中没有记录),则记录日志并返回null if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); return null; } // 创建一个新的JSONObject用于存储笔记信息 JSONObject note = new JSONObject(); // 如果当前对象是笔记类型 if (mType == Notes.TYPE_NOTE) { // 向note对象中添加各种属性 note.put(NoteColumns.ID, mId); note.put(NoteColumns.ALERTED_DATE, mAlertDate); note.put(NoteColumns.BG_COLOR_ID, mBgColorId); note.put(NoteColumns.CREATED_DATE, mCreatedDate); note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment); note.put(NoteColumns.MODIFIED_DATE, mModifiedDate); note.put(NoteColumns.PARENT_ID, mParentId); note.put(NoteColumns.SNIPPET, mSnippet); note.put(NoteColumns.TYPE, mType); note.put(NoteColumns.WIDGET_ID, mWidgetId); note.put(NoteColumns.WIDGET_TYPE, mWidgetType); note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent); // 将note对象添加到js对象中,使用特定的键 js.put(GTaskStringUtils.META_HEAD_NOTE, note); // 创建一个JSONArray用于存储数据列表 JSONArray dataArray = new JSONArray(); // 遍历数据列表,将每个数据项的JSON表示添加到dataArray中 for (SqlData sqlData : mDataList) { JSONObject data = sqlData.getContent(); if (data != null) { dataArray.put(data); } } // 将dataArray添加到js对象中,使用特定的键 js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); } // 如果当前对象是文件夹或系统类型 else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { // 向note对象中添加ID、类型和摘要信息 note.put(NoteColumns.ID, mId); note.put(NoteColumns.TYPE, mType); note.put(NoteColumns.SNIPPET, mSnippet); // 将note对象添加到js对象中,使用特定的键 js.put(GTaskStringUtils.META_HEAD_NOTE, note); } // 返回构建的JSONObject return js; } catch (JSONException e) { // 捕获JSON异常并记录错误日志 Log.e(TAG, e.toString()); e.printStackTrace(); } // 如果发生异常,返回null return null; } // 设置父ID的方法 public void setParentId(long id) { mParentId = id; // 将更改记录到差异映射中,以便稍后提交 mDiffNoteValues.put(NoteColumns.PARENT_ID, id); } // 设置Gtask ID的方法 public void setGtaskId(String gid) { // 将Gtask ID记录到差异映射中 mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); } // 设置同步ID的方法 public void setSyncId(long syncId) { // 将同步ID记录到差异映射中 mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); } // 重置本地修改标记的方法 public void resetLocalModified() { // 将本地修改标记设置为0,表示未修改 mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); } // 获取ID的方法 public long getId() { return mId; } // 获取父ID的方法 public long getParentId() { return mParentId; } // 获取摘要信息的方法 public String getSnippet() { return mSnippet; } // 判断当前对象是否为笔记类型的方法 public boolean isNoteType() { return mType == Notes.TYPE_NOTE; } // 提交更改的方法,包括创建和更新操作 public void commit(boolean validateVersion) { // 如果是创建操作 if (mIsCreate) { // 如果ID无效但差异映射中包含ID,则移除ID if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { mDiffNoteValues.remove(NoteColumns.ID); } // 插入新记录到内容提供者,并获取新记录的ID Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues); try { mId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { // 捕获数字格式异常并记录错误日志 Log.e(TAG, "Get note id error :" + e.toString()); throw new ActionFailureException("create note failed"); } // 如果ID无效,则抛出异常 if (mId == 0) { throw new IllegalStateException("Create thread id failed"); } // 如果是笔记类型,则提交数据列表的更改 if (mType == Notes.TYPE_NOTE) { for (SqlData sqlData : mDataList) { sqlData.commit(mId, false, -1); } } } // 如果是更新操作 else { // 检查ID是否有效 if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) { Log.e(TAG, "No such note"); throw new IllegalStateException("Try to update note with invalid id"); } // 如果有需要更新的属性 if (mDiffNoteValues.size() > 0) { mVersion ++; // 增加版本号 int result = 0; // 根据是否验证版本,执行不同的更新操作 if (!validateVersion) { result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" + NoteColumns.ID + "=?)", new String[] { String.valueOf(mId) }); } else { result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", new String[] { String.valueOf(mId), String.valueOf(mVersion) }); } // 如果没有记录被更新,记录警告日志 if (result == 0) { Log.w(TAG, "there is no update. maybe user updates note when syncing"); } } // 如果是笔记类型,则提交数据列表的更改 if (mType == Notes.TYPE_NOTE) { for (SqlData sqlData : mDataList) { sqlData.commit(mId, validateVersion, mVersion); } } } // 刷新本地信息 loadFromCursor(mId); // 如果是笔记类型,则加载数据内容 if (mType == Notes.TYPE_NOTE) loadDataContent(); // 清空差异映射 mDiffNoteValues.clear(); // 标记为已创建(对于更新操作,实际上是重置为未创建状态) mIsCreate = false; }