diff --git a/src/net/micode/notes/gtask/remote/GTaskASyncTask.java b/src/net/micode/notes/gtask/remote/GTaskASyncTask.java index b3b61e7..c4215ec 100644 --- a/src/net/micode/notes/gtask/remote/GTaskASyncTask.java +++ b/src/net/micode/notes/gtask/remote/GTaskASyncTask.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * @@ -29,95 +28,122 @@ import net.micode.notes.ui.NotesListActivity; import net.micode.notes.ui.NotesPreferenceActivity; +// 用于Google任务同步的异步任务类 public class GTaskASyncTask extends AsyncTask { + // 同步通知的固定ID private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; + // 同步完成监听接口 public interface OnCompleteListener { void onComplete(); } - private Context mContext; - - private NotificationManager mNotifiManager; - - private GTaskManager mTaskManager; - - private OnCompleteListener mOnCompleteListener; + private Context mContext; // 上下文对象 + private NotificationManager mNotifiManager; // 通知管理器 + private GTaskManager mTaskManager; // Google任务管理器 + private OnCompleteListener mOnCompleteListener; // 同步完成监听器 + // 构造函数 public GTaskASyncTask(Context context, OnCompleteListener listener) { mContext = context; mOnCompleteListener = listener; + // 初始化通知管理器 mNotifiManager = (NotificationManager) mContext .getSystemService(Context.NOTIFICATION_SERVICE); + // 获取Google任务管理器实例 mTaskManager = GTaskManager.getInstance(); } + // 取消同步 public void cancelSync() { mTaskManager.cancelSync(); } + // 发布进度更新 public void publishProgess(String message) { publishProgress(new String[] { message }); } + // 显示通知 private void showNotification(int tickerId, String content) { + // 创建通知对象 Notification notification = new Notification(R.drawable.notification, mContext .getString(tickerId), System.currentTimeMillis()); + // 设置默认灯光效果 notification.defaults = Notification.DEFAULT_LIGHTS; + // 设置自动取消标志 notification.flags = Notification.FLAG_AUTO_CANCEL; + PendingIntent pendingIntent; + // 根据通知类型设置不同的跳转页面 if (tickerId != R.string.ticker_success) { + // 失败时跳转到设置页面 pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesPreferenceActivity.class), 0); - } else { + // 成功时跳转到笔记列表页面 pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesListActivity.class), 0); } + // 设置通知详细信息 notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, pendingIntent); + // 显示通知 mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); } + // 后台执行同步任务 @Override protected Integer doInBackground(Void... unused) { + // 发布登录进度信息 publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity .getSyncAccountName(mContext))); + // 执行同步操作 return mTaskManager.sync(mContext, this); } + // 进度更新处理 @Override protected void onProgressUpdate(String... progress) { + // 显示同步中通知 showNotification(R.string.ticker_syncing, progress[0]); + // 如果是服务上下文,发送广播 if (mContext instanceof GTaskSyncService) { ((GTaskSyncService) mContext).sendBroadcast(progress[0]); } } + // 任务执行完成处理 @Override protected void onPostExecute(Integer result) { + // 根据同步结果显示不同通知 if (result == GTaskManager.STATE_SUCCESS) { + // 成功通知 showNotification(R.string.ticker_success, mContext.getString( R.string.success_sync_account, mTaskManager.getSyncAccount())); + // 更新最后同步时间 NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); } else if (result == GTaskManager.STATE_NETWORK_ERROR) { + // 网络错误通知 showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network)); } else if (result == GTaskManager.STATE_INTERNAL_ERROR) { + // 内部错误通知 showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { + // 同步取消通知 showNotification(R.string.ticker_cancel, mContext .getString(R.string.error_sync_cancelled)); } + // 如果有完成监听器,在新线程中执行回调 if (mOnCompleteListener != null) { new Thread(new Runnable() { - public void run() { mOnCompleteListener.onComplete(); } }).start(); } } -} +} \ No newline at end of file diff --git a/src/net/micode/notes/gtask/remote/GTaskClient.java b/src/net/micode/notes/gtask/remote/GTaskClient.java index c67dfdf..f72ddae 100644 --- a/src/net/micode/notes/gtask/remote/GTaskClient.java +++ b/src/net/micode/notes/gtask/remote/GTaskClient.java @@ -61,35 +61,27 @@ import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; +// Google任务客户端类,用于与Google任务服务交互 public class GTaskClient { private static final String TAG = GTaskClient.class.getSimpleName(); + // Google任务服务基础URL private static final String GTASK_URL = "https://mail.google.com/tasks/"; - private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; - private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; - private static GTaskClient mInstance = null; - - private DefaultHttpClient mHttpClient; - - private String mGetUrl; - - private String mPostUrl; - - private long mClientVersion; - - private boolean mLoggedin; - - private long mLastLoginTime; - - private int mActionId; - - private Account mAccount; - - private JSONArray mUpdateArray; - + private static GTaskClient mInstance = null; // 单例实例 + private DefaultHttpClient mHttpClient; // HTTP客户端 + private String mGetUrl; // GET请求URL + private String mPostUrl; // POST请求URL + private long mClientVersion; // 客户端版本号 + private boolean mLoggedin; // 登录状态标志 + private long mLastLoginTime; // 最后登录时间 + private int mActionId; // 操作ID计数器 + private Account mAccount; // 当前同步账户 + private JSONArray mUpdateArray; // 待提交的更新数组 + + // 私有构造函数 private GTaskClient() { mHttpClient = null; mGetUrl = GTASK_GET_URL; @@ -102,6 +94,7 @@ public class GTaskClient { mUpdateArray = null; } + // 获取单例实例 public static synchronized GTaskClient getInstance() { if (mInstance == null) { mInstance = new GTaskClient(); @@ -109,15 +102,15 @@ public class GTaskClient { return mInstance; } + // 登录Google任务服务 public boolean login(Activity activity) { - // we suppose that the cookie would expire after 5 minutes - // then we need to re-login + // 假设cookie5分钟后过期,需要重新登录 final long interval = 1000 * 60 * 5; if (mLastLoginTime + interval < System.currentTimeMillis()) { mLoggedin = false; } - // need to re-login after account switch + // 账户切换后需要重新登录 if (mLoggedin && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity .getSyncAccountName(activity))) { @@ -130,13 +123,14 @@ public class GTaskClient { } mLastLoginTime = System.currentTimeMillis(); + // 获取Google账户认证token String authToken = loginGoogleAccount(activity, false); if (authToken == null) { Log.e(TAG, "login google account failed"); return false; } - // login with custom domain if necessary + // 如果是自定义域名登录 if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() .endsWith("googlemail.com"))) { StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); @@ -146,12 +140,13 @@ public class GTaskClient { mGetUrl = url.toString() + "ig"; mPostUrl = url.toString() + "r/ig"; + // 尝试登录自定义域名任务服务 if (tryToLoginGtask(activity, authToken)) { mLoggedin = true; } } - // try to login with google official url + // 尝试登录Google官方任务服务 if (!mLoggedin) { mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -164,6 +159,7 @@ public class GTaskClient { return true; } + // 登录Google账户获取认证token private String loginGoogleAccount(Activity activity, boolean invalidateToken) { String authToken; AccountManager accountManager = AccountManager.get(activity); @@ -174,6 +170,7 @@ public class GTaskClient { return null; } + // 获取设置中配置的同步账户名 String accountName = NotesPreferenceActivity.getSyncAccountName(activity); Account account = null; for (Account a : accounts) { @@ -189,13 +186,14 @@ public class GTaskClient { return null; } - // get the token now + // 获取认证token AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, "goanna_mobile", null, activity, null, null); try { Bundle authTokenBundle = accountManagerFuture.getResult(); authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); if (invalidateToken) { + // 使token失效并重新获取 accountManager.invalidateAuthToken("com.google", authToken); loginGoogleAccount(activity, false); } @@ -207,10 +205,10 @@ public class GTaskClient { return authToken; } + // 尝试登录Google任务服务 private boolean tryToLoginGtask(Activity activity, String authToken) { if (!loginGtask(authToken)) { - // maybe the auth token is out of date, now let's invalidate the - // token and try again + // 可能是token过期,使token失效并重试 authToken = loginGoogleAccount(activity, true); if (authToken == null) { Log.e(TAG, "login google account failed"); @@ -225,25 +223,28 @@ public class GTaskClient { return true; } + // 执行实际登录Google任务服务的操作 private boolean loginGtask(String authToken) { + // 设置HTTP连接参数 int timeoutConnection = 10000; int timeoutSocket = 15000; HttpParams httpParameters = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); mHttpClient = new DefaultHttpClient(httpParameters); + // 设置cookie存储 BasicCookieStore localBasicCookieStore = new BasicCookieStore(); mHttpClient.setCookieStore(localBasicCookieStore); HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); - // login gtask + // 登录Google任务服务 try { String loginUrl = mGetUrl + "?auth=" + authToken; HttpGet httpGet = new HttpGet(loginUrl); HttpResponse response = null; response = mHttpClient.execute(httpGet); - // get the cookie now + // 获取cookie List cookies = mHttpClient.getCookieStore().getCookies(); boolean hasAuthCookie = false; for (Cookie cookie : cookies) { @@ -255,7 +256,7 @@ public class GTaskClient { Log.w(TAG, "it seems that there is no auth cookie"); } - // get the client version + // 获取客户端版本号 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -272,7 +273,7 @@ public class GTaskClient { e.printStackTrace(); return false; } catch (Exception e) { - // simply catch all exceptions + // 捕获所有异常 Log.e(TAG, "httpget gtask_url failed"); return false; } @@ -280,10 +281,12 @@ public class GTaskClient { return true; } + // 获取操作ID并自增 private int getActionId() { return mActionId++; } + // 创建HTTP POST请求 private HttpPost createHttpPost() { HttpPost httpPost = new HttpPost(mPostUrl); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); @@ -291,6 +294,7 @@ public class GTaskClient { return httpPost; } + // 获取HTTP响应内容 private String getResponseContent(HttpEntity entity) throws IOException { String contentEncoding = null; if (entity.getContentEncoding() != null) { @@ -299,6 +303,7 @@ public class GTaskClient { } InputStream input = entity.getContent(); + // 处理不同的压缩格式 if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { input = new GZIPInputStream(entity.getContent()); } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { @@ -323,6 +328,7 @@ public class GTaskClient { } } + // 发送POST请求并获取JSON响应 private JSONObject postRequest(JSONObject js) throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -331,12 +337,13 @@ public class GTaskClient { HttpPost httpPost = createHttpPost(); try { + // 构建请求参数 LinkedList list = new LinkedList(); list.add(new BasicNameValuePair("r", js.toString())); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); httpPost.setEntity(entity); - // execute the post + // 执行POST请求 HttpResponse response = mHttpClient.execute(httpPost); String jsString = getResponseContent(response.getEntity()); return new JSONObject(jsString); @@ -360,20 +367,21 @@ public class GTaskClient { } } + // 创建新任务 public void createTask(Task task) throws NetworkFailureException { commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); - // action_list + // 添加创建任务的操作 actionList.put(task.getCreateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client_version + // 添加客户端版本号 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - // post + // 发送POST请求 JSONObject jsResponse = postRequest(jsPost); JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( GTaskStringUtils.GTASK_JSON_RESULTS).get(0); @@ -386,20 +394,21 @@ public class GTaskClient { } } + // 创建新任务列表 public void createTaskList(TaskList tasklist) throws NetworkFailureException { commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); - // action_list + // 添加创建任务列表的操作 actionList.put(tasklist.getCreateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client version + // 添加客户端版本号 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - // post + // 发送POST请求 JSONObject jsResponse = postRequest(jsPost); JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( GTaskStringUtils.GTASK_JSON_RESULTS).get(0); @@ -412,15 +421,16 @@ public class GTaskClient { } } + // 提交所有待处理的更新 public void commitUpdate() throws NetworkFailureException { if (mUpdateArray != null) { try { JSONObject jsPost = new JSONObject(); - // action_list + // 添加更新操作列表 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); - // client_version + // 添加客户端版本号 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); postRequest(jsPost); @@ -433,10 +443,10 @@ public class GTaskClient { } } + // 添加待更新的节点 public void addUpdateNode(Node node) throws NetworkFailureException { if (node != null) { - // too many update items may result in an error - // set max to 10 items + // 更新项太多可能导致错误,设置最大10项 if (mUpdateArray != null && mUpdateArray.length() > 10) { commitUpdate(); } @@ -447,6 +457,7 @@ public class GTaskClient { } } + // 移动任务到新位置 public void moveTask(Task task, TaskList preParent, TaskList curParent) throws NetworkFailureException { commitUpdate(); @@ -455,26 +466,25 @@ public class GTaskClient { JSONArray actionList = new JSONArray(); JSONObject action = new JSONObject(); - // action_list + // 构建移动操作 action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); if (preParent == curParent && task.getPriorSibling() != null) { - // put prioring_sibing_id only if moving within the tasklist and - // it is not the first one + // 仅在任务列表内移动且不是第一个任务时,添加前一个兄弟节点ID action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); } action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); if (preParent != curParent) { - // put the dest_list only if moving between tasklists + // 仅在跨任务列表移动时添加目标列表ID action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); } actionList.put(action); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client_version + // 添加客户端版本号 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); postRequest(jsPost); @@ -486,18 +496,19 @@ public class GTaskClient { } } + // 删除节点 public void deleteNode(Node node) throws NetworkFailureException { commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); - // action_list + // 标记节点为已删除并添加更新操作 node.setDeleted(true); actionList.put(node.getUpdateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client_version + // 添加客户端版本号 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); postRequest(jsPost); @@ -509,6 +520,7 @@ public class GTaskClient { } } + // 获取所有任务列表 public JSONArray getTaskLists() throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -520,7 +532,7 @@ public class GTaskClient { HttpResponse response = null; response = mHttpClient.execute(httpGet); - // get the task list + // 解析响应获取任务列表 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -547,6 +559,7 @@ public class GTaskClient { } } + // 获取指定任务列表中的任务 public JSONArray getTaskList(String listGid) throws NetworkFailureException { commitUpdate(); try { @@ -554,7 +567,7 @@ public class GTaskClient { JSONArray actionList = new JSONArray(); JSONObject action = new JSONObject(); - // action_list + // 构建获取所有任务的操作 action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); @@ -563,7 +576,7 @@ public class GTaskClient { actionList.put(action); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client_version + // 添加客户端版本号 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); JSONObject jsResponse = postRequest(jsPost); @@ -575,11 +588,13 @@ public class GTaskClient { } } + // 获取当前同步账户 public Account getSyncAccount() { return mAccount; } + // 重置更新数组 public void resetUpdateArray() { mUpdateArray = null; } -} +} \ No newline at end of file diff --git a/src/net/micode/notes/gtask/remote/GTaskManager.java b/src/net/micode/notes/gtask/remote/GTaskManager.java index d2b4082..b019a2a 100644 --- a/src/net/micode/notes/gtask/remote/GTaskManager.java +++ b/src/net/micode/notes/gtask/remote/GTaskManager.java @@ -48,45 +48,34 @@ import java.util.Iterator; import java.util.Map; +// Google任务管理器类,负责同步逻辑 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; - - private HashMap mGTaskListHashMap; - - private HashMap mGTaskHashMap; - - private HashMap mMetaHashMap; - - private TaskList mMetaList; - - private HashSet mLocalDeleteIdMap; - - private HashMap mGidToNid; - - private HashMap mNidToGid; - + // 同步状态常量 + 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; // Activity上下文(用于获取认证token) + private Context mContext; // 应用上下文 + private ContentResolver mContentResolver; // 内容解析器 + private boolean mSyncing; // 同步状态标志 + private boolean mCancelled; // 取消同步标志 + + // 数据存储相关HashMap + private HashMap mGTaskListHashMap; // 任务列表HashMap + private HashMap mGTaskHashMap; // 节点HashMap + private HashMap mMetaHashMap; // 元数据HashMap + 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; @@ -99,6 +88,7 @@ public class GTaskManager { mNidToGid = new HashMap(); } + // 获取单例实例 public static synchronized GTaskManager getInstance() { if (mInstance == null) { mInstance = new GTaskManager(); @@ -106,11 +96,13 @@ public class GTaskManager { return mInstance; } + // 设置Activity上下文 public synchronized void setActivityContext(Activity activity) { - // used for getting authtoken + // 用于获取认证token mActivity = activity; } + // 执行同步操作 public int sync(Context context, GTaskASyncTask asyncTask) { if (mSyncing) { Log.d(TAG, "Sync is in progress"); @@ -120,6 +112,7 @@ public class GTaskManager { mContentResolver = mContext.getContentResolver(); mSyncing = true; mCancelled = false; + // 清空所有临时数据存储 mGTaskListHashMap.clear(); mGTaskHashMap.clear(); mMetaHashMap.clear(); @@ -131,18 +124,18 @@ public class GTaskManager { GTaskClient client = GTaskClient.getInstance(); client.resetUpdateArray(); - // login google task + // 1. 登录Google任务服务 if (!mCancelled) { if (!client.login(mActivity)) { throw new NetworkFailureException("login google task failed"); } } - // get the task list from google + // 2. 初始化Google任务列表 asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); initGTaskList(); - // do content sync work + // 3. 同步内容 asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); syncContent(); } catch (NetworkFailureException e) { @@ -156,6 +149,7 @@ public class GTaskManager { e.printStackTrace(); return STATE_INTERNAL_ERROR; } finally { + // 清理临时数据 mGTaskListHashMap.clear(); mGTaskHashMap.clear(); mMetaHashMap.clear(); @@ -168,6 +162,7 @@ public class GTaskManager { return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; } + // 初始化Google任务列表 private void initGTaskList() throws NetworkFailureException { if (mCancelled) return; @@ -175,7 +170,7 @@ public class GTaskManager { try { JSONArray jsTaskLists = client.getTaskLists(); - // init meta list first + // 1. 首先初始化元数据列表 mMetaList = null; for (int i = 0; i < jsTaskLists.length(); i++) { JSONObject object = jsTaskLists.getJSONObject(i); @@ -187,7 +182,7 @@ public class GTaskManager { mMetaList = new TaskList(); mMetaList.setContentByRemoteJSON(object); - // load meta data + // 加载元数据 JSONArray jsMetas = client.getTaskList(gid); for (int j = 0; j < jsMetas.length(); j++) { object = (JSONObject) jsMetas.getJSONObject(j); @@ -203,7 +198,7 @@ public class GTaskManager { } } - // create meta list if not existed + // 2. 如果元数据列表不存在,则创建 if (mMetaList == null) { mMetaList = new TaskList(); mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX @@ -211,7 +206,7 @@ public class GTaskManager { GTaskClient.getInstance().createTaskList(mMetaList); } - // init task list + // 3. 初始化其他任务列表 for (int i = 0; i < jsTaskLists.length(); i++) { JSONObject object = jsTaskLists.getJSONObject(i); String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); @@ -225,7 +220,7 @@ public class GTaskManager { mGTaskListHashMap.put(gid, tasklist); mGTaskHashMap.put(gid, tasklist); - // load tasks + // 加载任务 JSONArray jsTasks = client.getTaskList(gid); for (int j = 0; j < jsTasks.length(); j++) { object = (JSONObject) jsTasks.getJSONObject(j); @@ -247,6 +242,7 @@ public class GTaskManager { } } + // 同步内容 private void syncContent() throws NetworkFailureException { int syncType; Cursor c = null; @@ -259,7 +255,7 @@ public class GTaskManager { return; } - // for local deleted note + // 1. 同步本地已删除的笔记 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type<>? AND parent_id=?)", new String[] { @@ -286,10 +282,10 @@ public class GTaskManager { } } - // sync folder first + // 2. 首先同步文件夹 syncFolder(); - // for note existing in database + // 3. 同步数据库中存在的笔记 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type=? AND parent_id<>?)", new String[] { @@ -306,10 +302,10 @@ public class GTaskManager { syncType = node.getSyncAction(c); } else { if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add + // 本地新增 syncType = Node.SYNC_ACTION_ADD_REMOTE; } else { - // remote delete + // 远程删除 syncType = Node.SYNC_ACTION_DEL_LOCAL; } } @@ -326,7 +322,7 @@ public class GTaskManager { } } - // go through remaining items + // 4. 处理剩余的远程新增项 Iterator> iter = mGTaskHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -334,23 +330,21 @@ public class GTaskManager { doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); } - // mCancelled can be set by another thread, so we neet to check one by - // one - // clear local delete table + // 5. 清除本地删除表 if (!mCancelled) { if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { throw new ActionFailureException("failed to batch-delete local deleted notes"); } } - // refresh local sync id + // 6. 刷新本地同步ID if (!mCancelled) { GTaskClient.getInstance().commitUpdate(); refreshLocalSyncId(); } - } + // 同步文件夹 private void syncFolder() throws NetworkFailureException { Cursor c = null; String gid; @@ -361,7 +355,7 @@ public class GTaskManager { return; } - // for root folder + // 1. 同步根文件夹 try { c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); @@ -373,7 +367,7 @@ public class GTaskManager { mGTaskHashMap.remove(gid); mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER); mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid); - // for system folder, only update remote name if necessary + // 对于系统文件夹,仅在必要时更新远程名称 if (!node.getName().equals( GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); @@ -390,7 +384,7 @@ public class GTaskManager { } } - // for call-note folder + // 2. 同步通话记录文件夹 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", new String[] { @@ -404,8 +398,7 @@ public class GTaskManager { mGTaskHashMap.remove(gid); mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER); mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid); - // for system folder, only update remote name if - // necessary + // 对于系统文件夹,仅在必要时更新远程名称 if (!node.getName().equals( GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) @@ -424,7 +417,7 @@ public class GTaskManager { } } - // for local existing folders + // 3. 同步本地存在的文件夹 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type=? AND parent_id<>?)", new String[] { @@ -441,10 +434,10 @@ public class GTaskManager { syncType = node.getSyncAction(c); } else { if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add + // 本地新增 syncType = Node.SYNC_ACTION_ADD_REMOTE; } else { - // remote delete + // 远程删除 syncType = Node.SYNC_ACTION_DEL_LOCAL; } } @@ -460,7 +453,7 @@ public class GTaskManager { } } - // for remote add folders + // 4. 处理远程新增的文件夹 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -476,6 +469,7 @@ public class GTaskManager { GTaskClient.getInstance().commitUpdate(); } + // 执行内容同步操作 private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -510,8 +504,8 @@ public class GTaskManager { updateRemoteNode(node, c); break; case Node.SYNC_ACTION_UPDATE_CONFLICT: - // merging both modifications maybe a good idea - // right now just use local update simply + // 合并修改可能是一个好主意 + // 目前简单使用本地更新 updateRemoteNode(node, c); break; case Node.SYNC_ACTION_NONE: @@ -522,6 +516,7 @@ public class GTaskManager { } } + // 添加本地节点 private void addLocalNode(Node node) throws NetworkFailureException { if (mCancelled) { return; @@ -529,6 +524,7 @@ public class GTaskManager { 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); @@ -541,15 +537,17 @@ public class GTaskManager { sqlNote.setParentId(Notes.ID_ROOT_FOLDER); } } else { + // 处理笔记 sqlNote = new SqlNote(mContext); JSONObject js = node.getLocalJSONFromContent(); try { + // 处理元数据 if (js.has(GTaskStringUtils.META_HEAD_NOTE)) { JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); if (note.has(NoteColumns.ID)) { long id = note.getLong(NoteColumns.ID); if (DataUtils.existInNoteDatabase(mContentResolver, id)) { - // the id is not available, have to create a new one + // ID不可用,需要创建新的 note.remove(NoteColumns.ID); } } @@ -562,13 +560,11 @@ public class GTaskManager { if (data.has(DataColumns.ID)) { long dataId = data.getLong(DataColumns.ID); if (DataUtils.existInDataDatabase(mContentResolver, dataId)) { - // the data id is not available, have to create - // a new one + // 数据ID不可用,需要创建新的 data.remove(DataColumns.ID); } } } - } } catch (JSONException e) { Log.w(TAG, e.toString()); @@ -576,6 +572,7 @@ public class GTaskManager { } sqlNote.setContent(js); + // 设置父文件夹ID Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); if (parentId == null) { Log.e(TAG, "cannot find task's parent id locally"); @@ -584,28 +581,30 @@ public class GTaskManager { sqlNote.setParentId(parentId.longValue()); } - // create the local node + // 创建本地节点 sqlNote.setGtaskId(node.getGid()); sqlNote.commit(false); - // update gid-nid mapping + // 更新ID映射 mGidToNid.put(node.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), node.getGid()); - // update meta + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); } + // 更新本地节点 private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; } SqlNote sqlNote; - // update the note locally + // 更新本地笔记 sqlNote = new SqlNote(mContext, c); sqlNote.setContent(node.getLocalJSONFromContent()); + // 设置父文件夹ID Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()) : new Long(Notes.ID_ROOT_FOLDER); if (parentId == null) { @@ -615,10 +614,11 @@ public class GTaskManager { sqlNote.setParentId(parentId.longValue()); sqlNote.commit(true); - // update meta info + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); } + // 添加远程节点 private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -627,11 +627,13 @@ public class GTaskManager { SqlNote sqlNote = new SqlNote(mContext, c); Node n; - // update remotely + // 远程更新 if (sqlNote.isNoteType()) { + // 处理笔记 Task task = new Task(); task.setContentByLocalJSON(sqlNote.getContent()); + // 获取父文件夹ID String parentGid = mNidToGid.get(sqlNote.getParentId()); if (parentGid == null) { Log.e(TAG, "cannot find task's parent tasklist"); @@ -639,15 +641,17 @@ public class GTaskManager { } mGTaskListHashMap.get(parentGid).addChildTask(task); + // 创建远程任务 GTaskClient.getInstance().createTask(task); n = (Node) task; - // add meta + // 添加元数据 updateRemoteMeta(task.getGid(), sqlNote); } else { + // 处理文件夹 TaskList tasklist = null; - // we need to skip folder if it has already existed + // 跳过已存在的文件夹 String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX; if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) folderName += GTaskStringUtils.FOLDER_DEFAULT; @@ -656,6 +660,7 @@ public class GTaskManager { else folderName += sqlNote.getSnippet(); + // 查找匹配的文件夹 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -671,7 +676,7 @@ public class GTaskManager { } } - // no match we can add now + // 没有匹配项则创建新文件夹 if (tasklist == null) { tasklist = new TaskList(); tasklist.setContentByLocalJSON(sqlNote.getContent()); @@ -681,17 +686,18 @@ public class GTaskManager { n = (Node) tasklist; } - // update local note + // 更新本地笔记 sqlNote.setGtaskId(n.getGid()); sqlNote.commit(false); sqlNote.resetLocalModified(); sqlNote.commit(true); - // gid-id mapping + // 更新ID映射 mGidToNid.put(n.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), n.getGid()); } + // 更新远程节点 private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -699,18 +705,19 @@ public class GTaskManager { SqlNote sqlNote = new SqlNote(mContext, c); - // update remotely + // 更新远程节点 node.setContentByLocalJSON(sqlNote.getContent()); GTaskClient.getInstance().addUpdateNode(node); - // update meta + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); - // move task if necessary + // 如果是笔记,可能需要移动位置 if (sqlNote.isNoteType()) { Task task = (Task) node; TaskList preParentList = task.getParent(); + // 获取当前父文件夹ID String curParentGid = mNidToGid.get(sqlNote.getParentId()); if (curParentGid == null) { Log.e(TAG, "cannot find task's parent tasklist"); @@ -718,6 +725,7 @@ public class GTaskManager { } TaskList curParentList = mGTaskListHashMap.get(curParentGid); + // 如果父文件夹发生变化,移动任务 if (preParentList != curParentList) { preParentList.removeChildTask(task); curParentList.addChildTask(task); @@ -725,18 +733,21 @@ public class GTaskManager { } } - // clear local modified flag + // 清除本地修改标志 sqlNote.resetLocalModified(); sqlNote.commit(true); } + // 更新远程元数据 private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { if (sqlNote != null && sqlNote.isNoteType()) { MetaData metaData = mMetaHashMap.get(gid); if (metaData != null) { + // 更新现有元数据 metaData.setMeta(gid, sqlNote.getContent()); GTaskClient.getInstance().addUpdateNode(metaData); } else { + // 创建新元数据 metaData = new MetaData(); metaData.setMeta(gid, sqlNote.getContent()); mMetaList.addChildTask(metaData); @@ -746,12 +757,13 @@ public class GTaskManager { } } + // 刷新本地同步ID private void refreshLocalSyncId() throws NetworkFailureException { if (mCancelled) { return; } - // get the latest gtask list + // 重新获取Google任务列表 mGTaskHashMap.clear(); mGTaskListHashMap.clear(); mMetaHashMap.clear(); @@ -759,6 +771,7 @@ public class GTaskManager { 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) @@ -769,6 +782,7 @@ public class GTaskManager { Node node = mGTaskHashMap.get(gid); if (node != null) { mGTaskHashMap.remove(gid); + // 更新同步时间戳 ContentValues values = new ContentValues(); values.put(NoteColumns.SYNC_ID, node.getLastModified()); mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, @@ -790,11 +804,13 @@ public class GTaskManager { } } + // 获取当前同步账户 public String getSyncAccount() { return GTaskClient.getInstance().getSyncAccount().name; } + // 取消同步 public void cancelSync() { mCancelled = true; } -} +} \ No newline at end of file diff --git a/src/net/micode/notes/gtask/remote/GTaskSyncService.java b/src/net/micode/notes/gtask/remote/GTaskSyncService.java index cca36f7..9010d32 100644 --- a/src/net/micode/notes/gtask/remote/GTaskSyncService.java +++ b/src/net/micode/notes/gtask/remote/GTaskSyncService.java @@ -23,80 +23,86 @@ import android.content.Intent; import android.os.Bundle; import android.os.IBinder; +// GTask同步服务类,继承自Service 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 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(); + stopSelf(); // 任务完成后停止服务 } }); sendBroadcast(""); - mSyncTask.execute(); + mSyncTask.execute(); // 执行同步任务 } } + // 取消同步方法 private void cancelSync() { if (mSyncTask != null) { - mSyncTask.cancelSync(); + mSyncTask.cancelSync(); // 取消同步任务 } } @Override public void onCreate() { - mSyncTask = null; + mSyncTask = null; // 服务创建时初始化同步任务为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(); + startSync(); // 开始同步 break; case ACTION_CANCEL_SYNC: - cancelSync(); + cancelSync(); // 取消同步 break; default: break; } - return START_STICKY; + return START_STICKY; // 服务被杀死后自动重启 } return super.onStartCommand(intent, flags, startId); } @Override public void onLowMemory() { + // 内存不足时取消同步 if (mSyncTask != null) { mSyncTask.cancelSync(); } } + // 绑定服务时调用,返回null表示不支持绑定 public IBinder onBind(Intent intent) { return null; } + // 发送广播方法,通知同步状态和进度 public void sendBroadcast(String msg) { mSyncProgress = msg; Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); @@ -105,6 +111,7 @@ public class GTaskSyncService extends Service { sendBroadcast(intent); } + // 静态方法,从Activity启动同步 public static void startSync(Activity activity) { GTaskManager.getInstance().setActivityContext(activity); Intent intent = new Intent(activity, GTaskSyncService.class); @@ -112,17 +119,20 @@ public class GTaskSyncService extends Service { 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; } -} +} \ No newline at end of file