diff --git a/src/一千注释.txt b/src/一千注释.txt deleted file mode 100644 index 114ef4b..0000000 --- a/src/一千注释.txt +++ /dev/null @@ -1,1027 +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.gtask.remote; // Google任务管理功能的包 - -import android.app.Activity; // 导入Activity类 -import android.content.ContentResolver; // 用于访问内容模型的类 -import android.content.ContentUris; // 处理内容URI的实用类 -import android.content.ContentValues; // 用于存储一组键值对 -import android.content.Context; // 应用的基本上下文 -import android.database.Cursor; // 用于遍历数据库行 -import android.util.Log; // 用于记录日志 - -import net.micode.notes.R; // 资源文件的导入 -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.data.MetaData; // Google 任务的元数据 -import net.micode.notes.gtask.data.Node; // 任务的节点结构 -import net.micode.notes.gtask.data.SqlNote; // SQL便签的数据结构 -import net.micode.notes.gtask.data.Task; // 任务数据结构 -import net.micode.notes.gtask.data.TaskList; // 任务列表结构 -import net.micode.notes.gtask.exception.ActionFailureException; // 动作失败的异常 -import net.micode.notes.gtask.exception.NetworkFailureException; // 网络失败的异常 -import net.micode.notes.tool.DataUtils; // 数据处理的工具类 -import net.micode.notes.tool.GTaskStringUtils; // Google 任务字符串的工具类 - -import org.json.JSONArray; // 处理JSON数组的类 -import org.json.JSONException; // JSON操作的异常 -import org.json.JSONObject; // 处理JSON对象的类 - -import java.util.HashMap; // HashMap用于数据存储 -import java.util.HashSet; // HashSet用于存储唯一集合 -import java.util.Iterator; // 用于迭代集合的类 -import java.util.Map; // Map接口 - -public class GTaskManager { - private static final String TAG = GTaskManager.class.getSimpleName(); // 日志标签 - - // 定义状态常量 - public static final int STATE_SUCCESS = 0; // 同步成功的状态 - public static final int STATE_NETWORK_ERROR = 1; // 网络错误的状态 - public static final int STATE_INTERNAL_ERROR = 2; // 内部错误的状态 - public static final int STATE_SYNC_IN_PROGRESS = 3; // 同步正在进行中 - public static final int STATE_SYNC_CANCELLED = 4; // 同步已取消 - - private static GTaskManager mInstance = null; // 单例实例 - - private Activity mActivity; // 当前活动上下文 - private Context mContext; // 应用上下文 - private ContentResolver mContentResolver; // 用于访问数据的内容解析器 - - private boolean mSyncing; // 标记同步是否正在进行 - private boolean mCancelled; // 标记同步是否已取消 - - // 用于管理Google任务和元数据的Map - private HashMap mGTaskListHashMap; // 存储任务列表的映射 - private HashMap mGTaskHashMap; // 存储任务的映射 - private HashMap mMetaHashMap; // 存储元数据的映射 - - private TaskList mMetaList; // 元任务列表 - private HashSet mLocalDeleteIdMap; // 用于跟踪本地删除的ID集合 - private HashMap mGidToNid; // Google ID到便签ID的映射 - private HashMap mNidToGid; // 便签ID到Google ID的映射 - - // 私有构造函数以实现单例模式 - private GTaskManager() { - mSyncing = false; // 初始化为未同步 - mCancelled = false; // 初始化为未取消 - mGTaskListHashMap = new HashMap<>(); // 初始化任务列表映射 - mGTaskHashMap = new HashMap<>(); // 初始化任务映射 - mMetaHashMap = new HashMap<>(); // 初始化元数据映射 - mMetaList = null; // 初始化元列表为null - mLocalDeleteIdMap = new HashSet<>(); // 创建本地删除ID集合 - mGidToNid = new HashMap<>(); // 初始化Google到便签ID的映射 - mNidToGid = new HashMap<>(); // 初始化便签到Google ID的映射 - } - - // 获取单例访问方法 - public static synchronized GTaskManager getInstance() { - if (mInstance == null) { - mInstance = new GTaskManager(); // 如果尚未创建,则创建一个新实例 - } - return mInstance; // 返回单例实例 - } - - // 设置Activity上下文,用于获取认证令牌 - public synchronized void setActivityContext(Activity activity) { - mActivity = activity; // 存储活动上下文 - } - - // 开始同步过程 - public int sync(Context context, GTaskASyncTask asyncTask) { - if (mSyncing) { // 检查同步是否正在进行 - Log.d(TAG, "Sync is in progress"); // 记录同步进行中的信息 - return STATE_SYNC_IN_PROGRESS; // 返回同步进行中状态 - } - mContext = context; // 设置上下文 - mContentResolver = mContext.getContentResolver(); // 获取内容解析器 - mSyncing = true; // 标记同步为进行中 - mCancelled = false; // 标记为未取消 - - // 清空任务和元数据的HashMap - mGTaskListHashMap.clear(); - mGTaskHashMap.clear(); - mMetaHashMap.clear(); - mLocalDeleteIdMap.clear(); - mGidToNid.clear(); - mNidToGid.clear(); - - try { - GTaskClient client = GTaskClient.getInstance(); // 获取Google任务客户端 - client.resetUpdateArray(); // 重置更新数组 - - // 登录Google任务 - if (!mCancelled) { - if (!client.login(mActivity)) { // 如果登录失败 - throw new NetworkFailureException("login google task failed"); // 抛出网络失败异常 - } - } - - // 从Google获取任务列表 - asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); // 发布初始化进度 - initGTaskList(); // 初始化任务列表 - - // 执行内容同步工作 - asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); // 发布同步进度 - syncContent(); // 开始内容同步 - } catch (NetworkFailureException e) { // 捕获网络失败异常 - Log.e(TAG, e.toString()); // 记录错误信息 - return STATE_NETWORK_ERROR; // 返回网络错误状态 - } catch (ActionFailureException e) { // 捕获动作失败异常 - Log.e(TAG, e.toString()); // 记录错误信息 - return STATE_INTERNAL_ERROR; // 返回内部错误状态 - } catch (Exception e) { // 捕获其他异常 - Log.e(TAG, e.toString()); // 记录错误信息 - e.printStackTrace(); // 打印堆栈跟踪 - return STATE_INTERNAL_ERROR; // 返回内部错误状态 - } finally { - // 清空HashMap数据 - mGTaskListHashMap.clear(); - mGTaskHashMap.clear(); - mMetaHashMap.clear(); - mLocalDeleteIdMap.clear(); - mGidToNid.clear(); - mNidToGid.clear(); - mSyncing = false; // 将同步状态标记为未同步 - } - - return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; // 返回结果状态 - } - - // 初始化Google任务列表 - private void initGTaskList() throws NetworkFailureException { - if (mCancelled) // 检查同步是否被取消 - return; // 如果被取消,直接返回 - GTaskClient client = GTaskClient.getInstance(); // 获取Google任务客户端 - try { - JSONArray jsTaskLists = client.getTaskLists(); // 获取任务列表的JSON数组 - - // 首先初始化元数据列表 - mMetaList = null; // 初始化元列表为null - for (int i = 0; i < jsTaskLists.length(); i++) { // 遍历所有任务列表 - JSONObject object = jsTaskLists.getJSONObject(i); // 获取任务列表对象 - String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); // 获取任务列表ID - String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); // 获取任务列表名称 - - // 检查是否为元文件夹 - if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { - mMetaList = new TaskList(); // 实例化元任务列表 - mMetaList.setContentByRemoteJSON(object); // 设置任务列表内容 - - // 加载元数据 - JSONArray jsMetas = client.getTaskList(gid); // 获取元数据的JSON数组 - for (int j = 0; j < jsMetas.length(); j++) { // 遍历每个元数据对象 - object = (JSONObject) jsMetas.getJSONObject(j); // 获取元数据对象 - MetaData metaData = new MetaData(); // 实例化元数据 - metaData.setContentByRemoteJSON(object); // 设置元数据内容 - if (metaData.isWorthSaving()) { // 检查元数据是否值得保存 - mMetaList.addChildTask(metaData); // 添加到元任务列表 - if (metaData.getGid() != null) { - mMetaHashMap.put(metaData.getRelatedGid(), metaData); // 将元数据ID映射到元数据对象 - } - } - } - } - } - - // 如果元数据列表不存在,则创建它 - if (mMetaList == null) { - mMetaList = new TaskList(); // 创建新的任务列表 - mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META); // 设置名称 - GTaskClient.getInstance().createTaskList(mMetaList); // 在Google任务中创建任务列表 - } -// 初始化任务列表 -for (int i = 0; i < jsTaskLists.length(); i++) { // 遍历所有任务列表 - JSONObject object = jsTaskLists.getJSONObject(i); // 获取当前任务列表的JSONObject - String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); // 获取任务列表的ID - String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); // 获取任务列表的名称 - - // 如果任务列表名称以指定前缀开头,并且不是元文件夹 - if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX) - && !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { - TaskList tasklist = new TaskList(); // 创建一个新的任务列表实例 - tasklist.setContentByRemoteJSON(object); // 设置任务列表的内容 - mGTaskListHashMap.put(gid, tasklist); // 将任务列表存入任务列表映射 - mGTaskHashMap.put(gid, tasklist); // 将任务列表存入任务映射 - - // 加载任务 - JSONArray jsTasks = client.getTaskList(gid); // 获取当前任务列表下的任务 - for (int j = 0; j < jsTasks.length(); j++) { // 遍历任务 - object = (JSONObject) jsTasks.getJSONObject(j); // 获取当前任务的JSONObject - gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); // 获取任务ID - Task task = new Task(); // 创建新的任务实例 - task.setContentByRemoteJSON(object); // 设置任务的内容 - if (task.isWorthSaving()) { // 检查任务是否值得保存 - task.setMetaInfo(mMetaHashMap.get(gid)); // 设置任务的元信息 - tasklist.addChildTask(task); // 将任务添加到任务列表中 - mGTaskHashMap.put(gid, task); // 将任务存入任务映射 - } - } - } -} -} catch (JSONException e) { // 处理JSON异常 - Log.e(TAG, e.toString()); // 记录错误信息 - e.printStackTrace(); // 打印堆栈跟踪 - throw new ActionFailureException("initGTaskList: handling JSONObject failed"); // 抛出动作失败异常 -} - -private void syncContent() throws NetworkFailureException { - int syncType; // 同步类型 - Cursor c = null; // 游标用于查询结果 - String gid; // 任务的Google ID - Node node; // 节点对象 - - mLocalDeleteIdMap.clear(); // 清空本地删除ID集合 - - if (mCancelled) { // 检查是否已取消同步 - return; // 如果已取消,直接返回 - } - - // 处理本地删除的便签 - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type<>? AND parent_id=?)", new String[] { - String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) - }, null); // 查询未被删除的便签 - if (c != null) { // 如果查询结果不为空 - while (c.moveToNext()) { // 遍历查询结果 - gid = c.getString(SqlNote.GTASK_ID_COLUMN); // 获取任务ID - node = mGTaskHashMap.get(gid); // 从任务映射中获取节点 - if (node != null) { // 如果节点存在 - mGTaskHashMap.remove(gid); // 从映射中移除该节点 - doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c); // 执行远程删除操作 - } - - mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); // 将本地删除的便签ID添加到集合 - } - } else { - Log.w(TAG, "failed to query trash folder"); // 记录查询回收站失败的警告 - } - } finally { - if (c != null) { // 确保游标关闭 - c.close(); - c = null; // 将游标设为null - } - } - - // 首先同步文件夹 - syncFolder(); - - // 对数据库中存在的便签进行同步 - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type=? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); // 查询系统便签 - if (c != null) { // 如果查询结果不为空 - while (c.moveToNext()) { // 遍历查询结果 - gid = c.getString(SqlNote.GTASK_ID_COLUMN); // 获取任务ID - node = mGTaskHashMap.get(gid); // 从任务映射中获取节点 - if (node != null) { // 如果节点存在 - mGTaskHashMap.remove(gid); // 从映射中移除该节点 - mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); // 将Google ID映射到便签ID - mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); // 将便签ID映射到Google ID - syncType = node.getSyncAction(c); // 获取同步操作类型 - } else { - // 检查便签ID是否为空 - if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // 如果便签ID为空,标记为本地新增 - syncType = Node.SYNC_ACTION_ADD_REMOTE; - } else { - // 否则,标记为远程删除 - syncType = Node.SYNC_ACTION_DEL_LOCAL; - } - } - doContentSync(syncType, node, c); // 执行内容同步 - } - } else { - Log.w(TAG, "failed to query existing note in database"); // 记录查询数据库中现有便签失败的警告 - } - - } -// 针对本地已有的文件夹进行同步 -try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type=? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); // 查询所有类型为文件夹且不在回收站中的便签 - if (c != null) { // 如果查询结果不为空 - while (c.moveToNext()) { // 遍历查询到的文件夹 - gid = c.getString(SqlNote.GTASK_ID_COLUMN); // 获取文件夹的Google ID - node = mGTaskHashMap.get(gid); // 从任务映射中获取相应节点 - if (node != null) { // 如果找到对应的节点 - mGTaskHashMap.remove(gid); // 从任务映射中移除该节点 - mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); // 将Google ID映射到本地ID - mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); // 将本地ID映射到Google ID - syncType = node.getSyncAction(c); // 获取当前节点的同步操作类型 - } else { - // 如果节点不为null,检查Google ID是否为空 - if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // 如果Google ID为空,标记为本地新增 - syncType = Node.SYNC_ACTION_ADD_REMOTE; - } else { - // 否则,标记为远程删除 - syncType = Node.SYNC_ACTION_DEL_LOCAL; - } - } - doContentSync(syncType, node, c); // 执行内容同步逻辑 - } - } else { - Log.w(TAG, "failed to query existing folder"); // 记录查询现有文件夹失败的警告 - } -} finally { - if (c != null) { - c.close(); // 确保游标关闭 - c = null; // 将游标设为null - } -} - -// 针对远程新增的文件夹进行同步 -Iterator> iter = mGTaskListHashMap.entrySet().iterator(); // 遍历任务列表的映射 -while (iter.hasNext()) { // 循环迭代 - Map.Entry entry = iter.next(); // 获取当前条目 - gid = entry.getKey(); // 获取Google ID - node = entry.getValue(); // 获取任务列表对象 - if (mGTaskHashMap.containsKey(gid)) { // 如果任务映射中存在该Google ID - mGTaskHashMap.remove(gid); // 从任务映射中移除该节点 - doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); // 执行本地新增同步 - } -} - -if (!mCancelled) // 如果没有被取消 - GTaskClient.getInstance().commitUpdate(); // 提交更新 - -} - -// 执行内容同步逻辑 -private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { // 检查是否已取消 - return; // 如果已取消,直接返回 - } - - MetaData meta; - switch (syncType) { // 根据同步类型执行不同操作 - case Node.SYNC_ACTION_ADD_LOCAL: // 本地新增 - addLocalNode(node); // 调用方法进行本地新增 - break; - case Node.SYNC_ACTION_ADD_REMOTE: // 远程新增 - addRemoteNode(node, c); // 调用方法进行远程新增 - break; - case Node.SYNC_ACTION_DEL_LOCAL: // 本地删除 - meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN)); // 获取元数据 - if (meta != null) { // 如果元数据不为空 - GTaskClient.getInstance().deleteNode(meta); // 删除远程节点 - } - mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); // 将本地ID添加到删除集合 - break; - case Node.SYNC_ACTION_DEL_REMOTE: // 远程删除 - meta = mMetaHashMap.get(node.getGid()); // 获取对应的元数据 - if (meta != null) { - GTaskClient.getInstance().deleteNode(meta); // 删除元数据 - } - GTaskClient.getInstance().deleteNode(node); // 删除远程节点 - break; - case Node.SYNC_ACTION_UPDATE_LOCAL: // 本地更新 - updateLocalNode(node, c); // 调用方法进行本地更新 - break; - case Node.SYNC_ACTION_UPDATE_REMOTE: // 远程更新 - updateRemoteNode(node, c); // 调用方法进行远程更新 - break; - case Node.SYNC_ACTION_UPDATE_CONFLICT: // 更新冲突 - // 合并两个修改可能是个好主意,这里仅简单使用本地更新 - updateRemoteNode(node, c); // 仅进行远程更新 - break; - case Node.SYNC_ACTION_NONE: // 无操作 - break; - case Node.SYNC_ACTION_ERROR: // 错误 - default: // 默认情况 - throw new ActionFailureException("unknown sync action type"); // 抛出异常,未知同步操作类型 - } -} - -// 添加本地节点 -private void addLocalNode(Node node) throws NetworkFailureException { - if (mCancelled) { // 检查是否已取消 - return; // 如果已取消,直接返回 - } - - SqlNote sqlNote; - if (node instanceof TaskList) { // 如果节点是任务列表 - if (node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) { - sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER); // 创建根文件夹的SqlNote - } else if (node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { - sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER); // 创建通话记录文件夹的SqlNote - } else { - sqlNote = new SqlNote(mContext); // 创建一个新的SqlNote实例 - sqlNote.setContent(node.getLocalJSONFromContent()); // 设置便签内容 - sqlNote.setParentId(Notes.ID_ROOT_FOLDER); // 将父ID设置为根文件夹 - } - } else { - sqlNote = new SqlNote(mContext); // 创建新的SqlNote实例 - JSONObject js = node.getLocalJSONFromContent(); // 获取节点的本地JSON内容 - try { - if (js.has(GTaskStringUtils.META_HEAD_NOTE)) { // 检查是否有元数据 - JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); // 获取元数据对象 - if (note.has(NoteColumns.ID)) { // 如果元数据包含ID - long id = note.getLong(NoteColumns.ID); // 获取ID - if (DataUtils.existInNoteDatabase(mContentResolver, id)) { - // 如果ID在数据库中存在,需要创建一个新的ID - note.remove(NoteColumns.ID); // 从元数据中移除ID - } - } - } - - if (js.has(GTaskStringUtils.META_HEAD_DATA)) { // 检查是否有数据头 -// 初始化SqlNote以便更新便签到本地 -sqlNote = new SqlNote(mContext, c); -sqlNote.setContent(node.getLocalJSONFromContent()); // 设置便签内容为本地JSON数据 - -// 获取父任务ID。如果节点是Task类型,使用映射获取父节点,否则默认使用根文件夹ID -Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()) - : new Long(Notes.ID_ROOT_FOLDER); -if (parentId == null) { - Log.e(TAG, "cannot find task's parent id locally"); // 记录错误,无法找到父节点ID - throw new ActionFailureException("cannot update local node"); // 抛出异常,无法更新本地节点 -} -sqlNote.setParentId(parentId.longValue()); // 设置父节点ID -sqlNote.commit(true); // 提交更新 - -// 更新元数据 -updateRemoteMeta(node.getGid(), sqlNote); // 将远程元数据更新至当前节点 -} - -// 添加远程节点 -private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; // 如果已取消,直接返回 - } - - SqlNote sqlNote = new SqlNote(mContext, c); // 创建SqlNote对象 - Node n; - - // 远程更新节点 - if (sqlNote.isNoteType()) { // 如果是便签类型 - Task task = new Task(); // 创建任务对象 - task.setContentByLocalJSON(sqlNote.getContent()); // 设置任务内容 - - String parentGid = mNidToGid.get(sqlNote.getParentId()); // 获取父任务的Google ID - if (parentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); // 记录错误,无法找到父任务列表 - throw new ActionFailureException("cannot add remote task"); // 抛出异常,无法添加远程任务 - } - mGTaskListHashMap.get(parentGid).addChildTask(task); // 将任务添加到父任务列表中 - - GTaskClient.getInstance().createTask(task); // 创建远程任务 - n = (Node) task; // 将新创建的任务赋值给节点 - - // 更新元数据 - updateRemoteMeta(task.getGid(), sqlNote); // 将元数据更新至当前任务 - } else { - TaskList tasklist = null; // 初始化任务列表指针 - - // 跳过已存在的文件夹 - String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX; // 设置文件夹前缀 - if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) - folderName += GTaskStringUtils.FOLDER_DEFAULT; // 根文件夹 - else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER) - folderName += GTaskStringUtils.FOLDER_CALL_NOTE; // 通话记录文件夹 - else - folderName += sqlNote.getSnippet(); // 默认使用摘要作为文件夹名 - - Iterator> iter = mGTaskListHashMap.entrySet().iterator(); // 遍历任务列表 - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - String gid = entry.getKey(); // 获取Google ID - TaskList list = entry.getValue(); // 获取任务列表 - - if (list.getName().equals(folderName)) { // 如果文件夹名匹配 - tasklist = list; // 替换为匹配的任务列表 - if (mGTaskHashMap.containsKey(gid)) { // 如果映射中存在该Google ID - mGTaskHashMap.remove(gid); // 从映射中移除该ID - } - break; // 跳出循环 - } - } - - // 如果没有匹配的,可以添加新的 - if (tasklist == null) { // 如果没有找到文件夹,则创建新的文件夹 - tasklist = new TaskList(); // 创建新的任务列表 - tasklist.setContentByLocalJSON(sqlNote.getContent()); // 设置任务列表内容 - GTaskClient.getInstance().createTaskList(tasklist); // 创建远程任务列表 - mGTaskListHashMap.put(tasklist.getGid(), tasklist); // 将任务列表添加到映射 - } - n = (Node) tasklist; // 将新创建的任务列表赋值给节点 - } - - // 更新本地便签 - sqlNote.setGtaskId(n.getGid()); // 设置当前节点的Google ID - sqlNote.commit(false); // 提交更新,不会覆盖本地修改 - sqlNote.resetLocalModified(); // 重置本地修改标记 - sqlNote.commit(true); // 再次提交更新 - - // 进行gid-id映射更新 - mGidToNid.put(n.getGid(), sqlNote.getId()); // 将Google ID映射到本地ID - mNidToGid.put(sqlNote.getId(), n.getGid()); // 将本地ID映射到Google ID -} - -// 更新远程节点 -private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; // 如果已取消,直接返回 - } - - SqlNote sqlNote = new SqlNote(mContext, c); // 根据游标创建SqlNote对象 - - // 远程更新逻辑 - node.setContentByLocalJSON(sqlNote.getContent()); // 更新节点内容 - GTaskClient.getInstance().addUpdateNode(node); // 向GTask客户端添加更新 - - // 更新元数据 - updateRemoteMeta(node.getGid(), sqlNote); // 更新远程元数据 - - // 如果需要,移动任务 - if (sqlNote.isNoteType()) { // 如果是便签类型 - Task task = (Task) node; // 转换为任务类型 - TaskList preParentList = task.getParent(); // 获取任务的原父任务列表 - - String curParentGid = mNidToGid.get(sqlNote.getParentId()); // 获取当前父任务的Google ID - if (curParentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); // 记录错误,无法找到父任务列表 - throw new ActionFailureException("cannot update remote task"); // 抛出异常,无法更新远程任务 - } - TaskList curParentList = mGTaskListHashMap.get(curParentGid); // 获取当前父任务列表 - - // 如果父任务列表发生改变 - if (preParentList != curParentList) { - preParentList.removeChildTask(task); // 从原父列表中移除任务 - curParentList.addChildTask(task); // 添加任务到当前父列表 - GTaskClient.getInstance().moveTask(task, preParentList, curParentList); // // 移动任务 - GTaskClient.getInstance().moveTask(task, preParentList, curParentList); // 调用GTaskClient移动任务到新父列表 - } - } - - // 清除本地修改标志 - sqlNote.resetLocalModified(); // 重置本地修改标记 - sqlNote.commit(true); // 提交修改 -} - -// 更新远程元数据 -private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { - if (sqlNote != null && sqlNote.isNoteType()) { // 确保sqlNote不为空且为便签类型 - MetaData metaData = mMetaHashMap.get(gid); // 根据gid获取元数据 - if (metaData != null) { // 如果元数据存在 - metaData.setMeta(gid, sqlNote.getContent()); // 更新元数据内容 - GTaskClient.getInstance().addUpdateNode(metaData); // 向GTask客户端添加更新 - } else { // 如果元数据不存在 - metaData = new MetaData(); // 创建新的元数据实例 - metaData.setMeta(gid, sqlNote.getContent()); // 设置新的元数据内容 - mMetaList.addChildTask(metaData); // 将新的元数据添加到元数据列表 - mMetaHashMap.put(gid, metaData); // 更新元数据映射 - GTaskClient.getInstance().createTask(metaData); // 创建新的任务以同步元数据 - } - } -} - -// 刷新本地同步ID -private void refreshLocalSyncId() throws NetworkFailureException { - if (mCancelled) { - return; // 如果已取消,直接返回 - } - - // 获取最新的Google任务列表 - mGTaskHashMap.clear(); // 清空现有的Google任务映射 - mGTaskListHashMap.clear(); // 清空现有的任务列表映射 - mMetaHashMap.clear(); // 清空现有的元数据映射 - initGTaskList(); // 初始化Google任务列表 - - Cursor c = null; // 初始化游标 - try { - // 查询本地便签,排除系统类型和回收站便签 - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type<>? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); - if (c != null) { - while (c.moveToNext()) { // 遍历查询结果 - String gid = c.getString(SqlNote.GTASK_ID_COLUMN); // 获取Google ID - Node node = mGTaskHashMap.get(gid); // 从映射中查找节点 - if (node != null) { // 如果节点存在 - mGTaskHashMap.remove(gid); // 移除映射中的该节点 - ContentValues values = new ContentValues(); // 创建ContentValues实例 - values.put(NoteColumns.SYNC_ID, node.getLastModified()); // 设置同步ID为节点的最后修改时间 - // 更新数据库 - mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, - c.getLong(SqlNote.ID_COLUMN)), values, null, null); - } else { // 如果节点不存在 - Log.e(TAG, "something is missed"); // 记录错误,某些本地条目缺少gid - throw new ActionFailureException( - "some local items don't have gid after sync"); // 抛出异常,某些本地条目SYNC后没有GID - } - } - } else { - Log.w(TAG, "failed to query local note to refresh sync id"); // 记录警告,查询本地便签失败 - } - } finally { - if (c != null) { - c.close(); // 释放游标资源 - c = null; // 将游标设置为null - } - } -} - -// 获取同步账号的名称 -public String getSyncAccount() { - return GTaskClient.getInstance().getSyncAccount().name; // 返回同步账户的名称 -} - -// 取消同步 -public void cancelSync() { - mCancelled = true; // 将取消标志设为true,表示请求停止同步 -} - - - - - - - - - - - - - - - - - - android:dataExtractionRules="@xml/data_extraction_rules" - android:fullBackupContent="@xml/backup_rules" - android:icon="@mipmap/ic_launcher" - android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" - android:supportsRtl="true" - android:theme="@style/Theme.Notesmaster" - tools:targetApi="31"> - - - - android:configChanges="keyboardHidden|orientation|screenSize" - android:label="@string/app_name" - android:launchMode="singleTop" - android:theme="@style/NoteTheme" - android:uiOptions="splitActionBarWhenNarrow" - android:windowSoftInputMode="adjustPan" - android:exported="true"> - - - - - - - - - - android:configChanges="keyboardHidden|orientation|screenSize" - android:launchMode="singleTop" - android:theme="@style/NoteTheme" - android:exported="true"> - - - - - - - - - - - - - - - - - - - - - - - - - - android:authorities="micode_notes" - android:multiprocess="true" /> - - - - android:label="@string/app_widget2x2" - android:exported="true"> - - - - - - - - - - - android:label="@string/app_widget4x4" - android:exported="true"> - - - - - - - - - - - - - - - - - - - - - - android:label="@string/app_name" - android:launchMode="singleInstance" - android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" > - - - - - android:label="@string/preferences_title" - android:launchMode="singleTop" - android:theme="@android:style/Theme.Holo.Light" /> - - - - - android:exported="false" /> - - - - - - - -/* - * 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.gtask.remote; - -import android.app.Activity; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; - -public class GTaskSyncService extends Service { - // 常量定义 - public final static String ACTION_STRING_NAME = "sync_action_type"; - - public final static int ACTION_START_SYNC = 0; // 启动同步操作的常量 - - public final static int ACTION_CANCEL_SYNC = 1; // 取消同步操作的常量 - - public final static int ACTION_INVALID = 2; // 无效操作的常量 - - public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service"; - - public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing"; // 表示是否正在同步的广播 - - public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg"; // 同步进度消息的广播 - - private static GTaskASyncTask mSyncTask = null; // 存储当前的异步任务实例 - - private static String mSyncProgress = ""; // 存储同步进度消息 - - // 开始同步的方法 - private void startSync() { - if (mSyncTask == null) { - mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { - // 同步完成回调 - public void onComplete() { - mSyncTask = null; // 重置同步任务 - sendBroadcast(""); // 发送广播,更新状态 - stopSelf(); // 停止服务 - } - }); - sendBroadcast(""); // 初始广播 - mSyncTask.execute(); // 执行异步同步任务 - } - } - - // 取消同步的方法 - private void cancelSync() { - if (mSyncTask != null) { - mSyncTask.cancelSync(); // 调用任务的取消方法 - } - } - - @Override - public void onCreate() { - mSyncTask = null; // 服务创建时重置同步任务 - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Bundle bundle = intent.getExtras(); // 获取传递的附加信息 - if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { - // 检查和处理传递过来的动作指令 - switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) { - case ACTION_START_SYNC: - startSync(); // 启动同步 - break; - case ACTION_CANCEL_SYNC: - cancelSync(); // 取消同步 - break; - default: - break; - } - return START_STICKY; // 保持服务运行 - } - return super.onStartCommand(intent, flags, startId); // 调用父类方法 - } - - @Override - public void onLowMemory() { - if (mSyncTask != null) { - mSyncTask.cancelSync(); // 内存不足时取消同步 - } - } - - @Override - public IBinder onBind(Intent intent) { - return null; // 该服务不支持绑定 - } - - // 发送广播的方法 - public void sendBroadcast(String msg) { - mSyncProgress = msg; // 更新同步进度消息 - Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); // 创建广播意图 - intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); // 是否正在同步 - intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); // 添加进度消息 - sendBroadcast(intent); // 发送广播 - } - - // 启动同步的静态方法 - public static void startSync(Activity activity) { - GTaskManager.getInstance().setActivityContext(activity); // 设置活动上下文 - Intent intent = new Intent(activity, GTaskSyncService.class); // 创建意图以启动服务 - intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC); - activity.startService(intent); // 启动服务 - } - - // 取消同步的静态方法 - public static void cancelSync(Context context) { - Intent intent = new Intent(context, GTaskSyncService.class); // 创建意图以取消服务 - intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); - context.startService(intent); // 启动取消服务 - } - - // 检查是否正在同步 - public static boolean isSyncing() { - return mSyncTask != null; // 返回任务是否存在 - } - - // 获取同步进度消息 - public static String getProgressString() { - return mSyncProgress; // 返回当前的同步进度消息 - } -} -package net.micode.notes.gtask.data; - -import android.database.Cursor; -import android.util.Log; -import net.micode.notes.tool.GTaskStringUtils; -import org.json.JSONException; -import org.json.JSONObject; - -public class MetaData extends Task { - private final static String TAG = MetaData.class.getSimpleName(); - - private String mRelatedGid = null; - - // 设置元数据的方法 - public void setMeta(String gid, JSONObject metaInfo) { - try { - metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); // 将 gid 插入到 metaInfo 中 - } catch (JSONException e) { - Log.e(TAG, "failed to put related gid"); // 异常处理,打印错误日志 - } - setNotes(metaInfo.toString()); // 将元数据转换成字符串并设置为笔记内容 - setName(GTaskStringUtils.META_NOTE_NAME); // 设置名称 - } - - // 获取相关 gid 的方法 - public String getRelatedGid() { - return mRelatedGid; // 返回相关 gid - } - - @Override - public boolean isWorthSaving() { - return getNotes() != null; // 如果有笔记内容则视为可保存 - } - - @Override - public void setContentByRemoteJSON(JSONObject js) { - super.setContentByRemoteJSON(js); // 调用父类方法 - if (getNotes() != null) { - try { - JSONObject metaInfo = new JSONObject(getNotes().trim()); // 解析笔记内容为 JSON 对象 - mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); // 获取相关 gid - } catch (JSONException e) { - Log.w(TAG, "failed to get related gid"); // 异常处理 - mRelatedGid = null; // 失败时将相关 gid 设置为 null - } - } - } - - @Override - public void setContentByLocalJSON(JSONObject js) { - // 此方法不应被调用 - throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); - } - - @Override - public JSONObject getLocalJSONFromContent() { - // 此方法不应被调用 - throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); - } - - @Override - public int getSyncAction(Cursor c) { - // 此方法不应被调用 - throw new IllegalAccessError("MetaData:getSyncAction should not be called"); - } -} \ No newline at end of file