gtask-remote-3

zhonghaoyu
pq5n3hobs 8 months ago
parent 1d7810c1b1
commit 275ae6f597

@ -0,0 +1,443 @@
/*
* Copyright (c) 2010 - 2011, The MiCode Open Source Community (www.micode.net)
*
* Apache 2.0
* 使
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
*
*
*
*/
package net.micode.notes.gtask.remote;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
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;
import net.micode.notes.gtask.data.Node;
import net.micode.notes.gtask.data.SqlNote;
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;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
// GTaskManager 类负责管理与 Google 任务GTask的同步操作包括登录、获取任务列表、同步本地和远程数据等
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;
// GTaskManager 的单例实例
private static GTaskManager mInstance = null;
// 用于获取认证令牌的 Activity
private Activity mActivity;
// 上下文对象
private Context mContext;
// 内容解析器,用于操作本地数据
private ContentResolver mContentResolver;
// 同步是否正在进行的标志
private boolean mSyncing;
// 同步是否被取消的标志
private boolean mCancelled;
// 存储远程任务列表的 HashMap键为任务列表的 GID值为 TaskList 对象
private HashMap<String, TaskList> mGTaskListHashMap;
// 存储远程节点(任务或任务列表)的 HashMap键为节点的 GID值为 Node 对象
private HashMap<String, Node> mGTaskHashMap;
// 存储元数据的 HashMap键为相关的 GID值为 MetaData 对象
private HashMap<String, MetaData> mMetaHashMap;
// 元数据任务列表
private TaskList mMetaList;
// 存储本地已删除笔记 ID 的 HashSet
private HashSet<Long> mLocalDeleteIdMap;
// 从 GID 到本地笔记 ID 的映射 HashMap
private HashMap<String, Long> mGidToNid;
// 从本地笔记 ID 到 GID 的映射 HashMap
private HashMap<Long, String> mNidToGid;
// 私有构造函数,用于初始化 GTaskManager 的成员变量
private GTaskManager() {
mSyncing = false;
mCancelled = false;
mGTaskListHashMap = new HashMap<String, TaskList>();
mGTaskHashMap = new HashMap<String, Node>();
mMetaHashMap = new HashMap<String, MetaData>();
mMetaList = null;
mLocalDeleteIdMap = new HashSet<Long>();
mGidToNid = new HashMap<String, Long>();
mNidToGid = new HashMap<Long, String>();
}
// 获取 GTaskManager 单例实例的方法
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;
// 清空各种存储数据的集合
mGTaskListHashMap.clear();
mGTaskHashMap.clear();
mMetaHashMap.clear();
mLocalDeleteIdMap.clear();
mGidToNid.clear();
mNidToGid.clear();
try {
// 获取 GTaskClient 实例
GTaskClient client = GTaskClient.getInstance();
// 重置更新数组
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 {
// 清空各种存储数据的集合
mGTaskListHashMap.clear();
mGTaskHashMap.clear();
mMetaHashMap.clear();
mLocalDeleteIdMap.clear();
mGidToNid.clear();
mNidToGid.clear();
// 标记同步结束
mSyncing = false;
}
// 返回同步结果状态码
return mCancelled? STATE_SYNC_CANCELLED : STATE_SUCCESS;
}
// 初始化远程任务列表的方法
private void initGTaskList() throws NetworkFailureException {
// 如果同步被取消,直接返回
if (mCancelled)
return;
// 获取 GTaskClient 实例
GTaskClient client = GTaskClient.getInstance();
try {
// 获取远程任务列表的 JSON 数组
JSONArray jsTaskLists = client.getTaskLists();
// 首先初始化元数据任务列表
mMetaList = null;
for (int i = 0; i < jsTaskLists.length(); i++) {
// 获取每个任务列表的 JSONObject
JSONObject object = jsTaskLists.getJSONObject(i);
// 获取任务列表的 GID
String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);
// 获取任务列表的名称
String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);
// 如果是元数据任务列表
if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) {
// 创建元数据任务列表对象
mMetaList = new TaskList();
// 根据远程 JSON 数据设置元数据任务列表的内容
mMetaList.setContentByRemoteJSON(object);
// 加载元数据
JSONArray jsMetas = client.getTaskList(gid);
for (int j = 0; j < jsMetas.length(); j++) {
// 获取每个元数据的 JSONObject
object = (JSONObject) jsMetas.getJSONObject(j);
// 创建元数据对象
MetaData metaData = new MetaData();
// 根据远程 JSON 数据设置元数据的内容
metaData.setContentByRemoteJSON(object);
// 如果元数据值得保存
if (metaData.isWorthSaving()) {
// 将元数据添加到元数据任务列表
mMetaList.addChildTask(metaData);
// 如果元数据有 GID将其添加到元数据 HashMap 中
if (metaData.getGid()!= null) {
mMetaHashMap.put(metaData.getRelatedGid(), metaData);
}
}
}
}
}
// 如果元数据任务列表不存在,创建一个
if (mMetaList == null) {
mMetaList = new TaskList();
mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META);
GTaskClient.getInstance().createTaskList(mMetaList);
}
// 初始化任务列表
for (int i = 0; i < jsTaskLists.length(); i++) {
// 获取每个任务列表的 JSONObject
object = jsTaskLists.getJSONObject(i);
// 获取任务列表的 GID
String gid = object.getString(GTaskStringUtils.GTASK_JSON_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();
// 根据远程 JSON 数据设置任务列表的内容
tasklist.setContentByRemoteJSON(object);
// 将任务列表添加到任务列表 HashMap 中
mGTaskListHashMap.put(gid, tasklist);
// 将任务列表添加到节点 HashMap 中
mGTaskHashMap.put(gid, tasklist);
// 加载任务
JSONArray jsTasks = client.getTaskList(gid);
for (int j = 0; j < jsTasks.length(); j++) {
// 获取每个任务的 JSONObject
object = (JSONObject) jsTasks.getJSONObject(j);
// 获取任务的 GID
gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);
// 创建任务对象
Task task = new Task();
// 根据远程 JSON 数据设置任务的内容
task.setContentByRemoteJSON(object);
// 如果任务值得保存
if (task.isWorthSaving()) {
// 设置任务的元信息
task.setMetaInfo(mMetaHashMap.get(gid));
// 将任务添加到任务列表
tasklist.addChildTask(task);
// 将任务添加到节点 HashMap 中
mGTaskHashMap.put(gid, task);
}
}
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("initGTaskList: handing JSONObject failed");
}
}
// 同步本地和远程内容的方法
private void syncContent() throws NetworkFailureException {
int syncType;
Cursor c = null;
String gid;
Node node;
// 清空本地已删除笔记 ID 的集合
mLocalDeleteIdMap.clear();
// 如果同步被取消,直接返回
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
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
// 获取对应的节点
node = mGTaskHashMap.get(gid);
if (node!= null) {
// 从节点 HashMap 中移除该节点
mGTaskHashMap.remove(gid);
// 执行内容同步操作
doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c);
}
// 将本地已删除笔记的 ID 添加到集合中
mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN));
}
} else {
Log.w(TAG, "failed to query trash folder");
}
} finally {
// 关闭游标
if (c!= null) {
c.close();
c = 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
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
// 获取对应的节点
node = mGTaskHashMap.get(gid);
if (node!= null) {
// 从节点 HashMap 中移除该节点
mGTaskHashMap.remove(gid);
// 记录 GID 与本地笔记 ID 的映射关系
mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN));
mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid);
// 获取同步类型
syncType = node.getSyncAction(c);
} else {
// 如果 GID 为空,说明是本地新增的笔记
if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {
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");
}
} finally {
// 关闭游标
if (c!= null) {
c.close();
c = null;
}
}
// 处理剩余的未处理节点
Iterator<Map.Entry<String, Node>> iter = mGTaskHashMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Node> entry = iter.next();
node = entry.getValue();
// 执行添加到本地的同步操作
doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);
}
// 如果同步未被取消
if (!mCancelled) {
// 批量删除本地已删除的笔记
if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) {
throw new ActionFailureException("failed to batch-delete local deleted notes");
}
}
// 如果同步未被取消
if (!mCancelled) {
// 提交更新
GTaskClient.getInstance().commitUpdate();
// 刷新本地同步 ID
refreshLocalSyncId();
}
}
// 同步文件夹的方法
private void syncFolder() throws NetworkFailureException {
Cursor c = null;
String gid;
Node node;
int syncType;
// 如果同步被取消,直接返回
if (mCancelled) {
return;
}
// 处理根文件夹
try {
// 查询根文件夹的信息
c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,
Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null);
if (c!= null) {
c.moveToNext();
// 获取根文件夹的 GID
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
// 获取对应的节点
node = mGTaskHashMap.get(gid);
if (node!= null) {
// 从节点 HashMap 中移除该节点
m
Loading…
Cancel
Save