From 449aab321a554fd65630192b28c0741c9ae834c1 Mon Sep 17 00:00:00 2001 From: pbg7l8cy5 <3178482906@qq.com> Date: Thu, 9 Jan 2025 12:03:41 +0800 Subject: [PATCH] 1 --- .../notes/gtask/remote/GTaskASyncTask.java | 58 +- .../notes/gtask/remote/GTaskClient.java | 299 +++-- .../notes/gtask/remote/GTaskManager.java | 1093 +++++++++-------- .../notes/gtask/remote/GTaskSyncService.java | 62 +- 4 files changed, 842 insertions(+), 670 deletions(-) diff --git a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java index b3b61e7..e3accb8 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java +++ b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java @@ -28,89 +28,99 @@ import net.micode.notes.R; import net.micode.notes.ui.NotesListActivity; import net.micode.notes.ui.NotesPreferenceActivity; - +// GTaskASyncTask类继承自AsyncTask,用于在后台执行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; - + // 构造方法,初始化上下文、回调监听器、通知管理器和任务管理器 public GTaskASyncTask(Context context, OnCompleteListener listener) { mContext = context; mOnCompleteListener = listener; mNotifiManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); - mTaskManager = GTaskManager.getInstance(); + .getSystemService(Context.NOTIFICATION_SERVICE);// 从系统服务获取通知管理器 + mTaskManager = GTaskManager.getInstance();// 获取任务管理器的实例 } - + // 取消同步操作 public void cancelSync() { - mTaskManager.cancelSync(); + mTaskManager.cancelSync();// 调用任务管理器的取消同步方法 } - + // 发布进度更新 public void publishProgess(String message) { publishProgress(new String[] { message - }); + });// 调用AsyncTask的publishProgress方法来更新进度 } - - private void showNotification(int tickerId, String content) { + // 显示通知 + 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; + notification.defaults = Notification.DEFAULT_LIGHTS;// 设置通知的默认灯 + notification.flags = Notification.FLAG_AUTO_CANCEL;// 设置通知标志为自动取消 + // 根据通知类型设置不同的PendingIntent PendingIntent pendingIntent; if (tickerId != R.string.ticker_success) { + // 如果不是成功通知,则点击通知后打开NotesPreferenceActivity pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesPreferenceActivity.class), 0); } else { + // 如果是成功通知,则点击通知后打开NotesListActivity 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]); + protected void onProgressUpdate(String... progress) { // 显示同步进行中的通知 + showNotification(R.string.ticker_syncing, progress[0]);// 如果mContext是GTaskSyncService的实例,则通过它发送广播,广播的内容是progress数组的第一个元素 if (mContext instanceof GTaskSyncService) { ((GTaskSyncService) mContext).sendBroadcast(progress[0]); } } @Override - protected void onPostExecute(Integer result) { - if (result == GTaskManager.STATE_SUCCESS) { + protected void onPostExecute(Integer result) {// 根据同步结果(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) { + } 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) { + } 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) { + } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { // 如果同步被取消,显示取消的通知 showNotification(R.string.ticker_cancel, mContext .getString(R.string.error_sync_cancelled)); } +// 如果mOnCompleteListener不为null,启动一个新线程来调用它的onComplete方法 if (mOnCompleteListener != null) { new Thread(new Runnable() { diff --git a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java index c67dfdf..d0b7dab 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java +++ b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java @@ -62,35 +62,37 @@ import java.util.zip.InflaterInputStream; public class GTaskClient { +// 类标签,用于日志输出 private static final String TAG = GTaskClient.class.getSimpleName(); - + // Google Tasks服务的基URL private static final String GTASK_URL = "https://mail.google.com/tasks/"; - + // 用于获取数据的URL private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; - + // 用于提交数据的URL private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; - + // GTaskClient的单例实例 private static GTaskClient mInstance = null; - + // HTTP客户端,用于发送请求 private DefaultHttpClient mHttpClient; - + // 当前使用的获取数据的URL private String mGetUrl; - + // 当前使用的提交数据的URL private String mPostUrl; - + // 客户端版本号 private long mClientVersion; - + // 登录状态 private boolean mLoggedin; - + // 最后一次登录时间 private long mLastLoginTime; - + // 操作ID,用于标识不同的操作 private int mActionId; - + // 当前登录的账户 private Account mAccount; - + // 更新数据数组 private JSONArray mUpdateArray; private GTaskClient() { + mHttpClient = null; mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -109,15 +111,17 @@ public class GTaskClient { return mInstance; } - public boolean login(Activity activity) { + public boolean login(Activity activity) { // 假设cookie在5分钟后过期,需要重新登录 // we suppose that the cookie would expire after 5 minutes // then we need to re-login final long interval = 1000 * 60 * 5; + // 切换账户后需要重新登录 if (mLastLoginTime + interval < System.currentTimeMillis()) { mLoggedin = false; } // need to re-login after account switch + // 如果已经登录,直接返回true if (mLoggedin && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity .getSyncAccountName(activity))) { @@ -128,14 +132,15 @@ public class GTaskClient { Log.d(TAG, "already logged in"); return true; } - + // 更新最后一次登录时间 mLastLoginTime = System.currentTimeMillis(); + // 获取Google账户的认证令牌 String authToken = loginGoogleAccount(activity, false); if (authToken == null) { Log.e(TAG, "login google account failed"); return false; } - +// 如果账户不是gmail.com或googlemail.com,使用自定义域名登录 // login with custom domain if necessary if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() .endsWith("googlemail.com"))) { @@ -159,29 +164,33 @@ public class GTaskClient { return false; } } - + // 设置登录状态为true并返回true表示登录成功 mLoggedin = true; return true; } +// 登录Google账户的函数,接收一个Activity实例和一个标志位来决定是否使当前的token无效 private String loginGoogleAccount(Activity activity, boolean invalidateToken) { - String authToken; - AccountManager accountManager = AccountManager.get(activity); - Account[] accounts = accountManager.getAccountsByType("com.google"); - + String authToken;// 用于存储获取到的认证token + AccountManager accountManager = AccountManager.get(activity);// 获取AccountManager实例 + Account[] accounts = accountManager.getAccountsByType("com.google");// 获取所有Google类型的账户 + // 如果没有可用的Google账户,则记录错误日志并返回null if (accounts.length == 0) { Log.e(TAG, "there is no available google account"); return null; } + // 从设置中获取同步账户的名称 String accountName = NotesPreferenceActivity.getSyncAccountName(activity); Account account = null; + // 遍历所有账户,找到与设置中的账户名匹配的账户 for (Account a : accounts) { if (a.name.equals(accountName)) { account = a; break; } } +// 如果找到了匹配的账户,则将其存储在mAccount变量中,否则记录错误日志并返回null if (account != null) { mAccount = account; } else { @@ -190,60 +199,66 @@ public class GTaskClient { } // 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); + Bundle authTokenBundle = accountManagerFuture.getResult();// 获取结果 + authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);// 从结果中获取token +// 如果需要使token无效,则调用invalidateAuthToken并递归调用loginGoogleAccount以获取新的token if (invalidateToken) { accountManager.invalidateAuthToken("com.google", authToken); loginGoogleAccount(activity, false); } } catch (Exception e) { + // 如果获取token失败,则记录错误日志并将authToken设置为null Log.e(TAG, "get auth token failed"); authToken = null; } - return authToken; + return authToken;// 返回获取到的token } - +// 尝试使用Google账户登录Google Tasks的函数 private boolean tryToLoginGtask(Activity activity, String authToken) { + // 尝试使用提供的token登录Google Tasks if (!loginGtask(authToken)) { +// 如果登录失败,可能是因为token已过期,因此使token无效并尝试重新登录 // maybe the auth token is out of date, now let's invalidate the // token and try again authToken = loginGoogleAccount(activity, true); - if (authToken == null) { + if (authToken == null) {// 如果重新登录失败,则记录错误日志并返回false Log.e(TAG, "login google account failed"); return false; } - +// 使用新的token再次尝试登录Google Tasks if (!loginGtask(authToken)) { Log.e(TAG, "login gtask failed"); return false; } } - return true; + return true;// 登录成功返回true } - +// 使用提供的token登录Google Tasks的函数 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); - BasicCookieStore localBasicCookieStore = new BasicCookieStore(); - mHttpClient.setCookieStore(localBasicCookieStore); - HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); + mHttpClient = new DefaultHttpClient(httpParameters);// 创建HttpClient实例 + BasicCookieStore localBasicCookieStore = new BasicCookieStore();// 创建Cookie存储实例 + mHttpClient.setCookieStore(localBasicCookieStore);// 设置HttpClient的Cookie存储 + HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);// 禁用Expect-Continue握手 - // login gtask + // 构造登录Google Tasks的URL try { String loginUrl = mGetUrl + "?auth=" + authToken; - HttpGet httpGet = new HttpGet(loginUrl); + HttpGet httpGet = new HttpGet(loginUrl);// 创建HttpGet请求 HttpResponse response = null; - response = mHttpClient.execute(httpGet); + response = mHttpClient.execute(httpGet);// 执行HttpGet请求 - // get the cookie now + // 检查响应中的Cookie,看是否有认证Cookie List cookies = mHttpClient.getCookieStore().getCookies(); boolean hasAuthCookie = false; for (Cookie cookie : cookies) { @@ -255,7 +270,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 = ")}"; @@ -265,25 +280,25 @@ public class GTaskClient { if (begin != -1 && end != -1 && begin < end) { jsString = resString.substring(begin + jsBegin.length(), end); } - JSONObject js = new JSONObject(jsString); - mClientVersion = js.getLong("v"); + JSONObject js = new JSONObject(jsString);// 解析JSON字符串 + mClientVersion = js.getLong("v");// 获取客户端版本 } catch (JSONException e) { - Log.e(TAG, e.toString()); + Log.e(TAG, e.toString());// 如果解析JSON时出错,则记录错误日志并返回false e.printStackTrace(); return false; - } catch (Exception e) { + } catch (Exception e) { // 捕获所有异常并记录错误日志,返回false // simply catch all exceptions Log.e(TAG, "httpget gtask_url failed"); return false; } - return true; + return true;// 登录成功返回true } - +// 获取一个唯一的动作ID的函数 private int getActionId() { return mActionId++; } - +// 创建一个HttpPost请求的函数 private HttpPost createHttpPost() { HttpPost httpPost = new HttpPost(mPostUrl); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); @@ -292,89 +307,112 @@ public class GTaskClient { } private String getResponseContent(HttpEntity entity) throws IOException { +// 初始化内容编码变量 + // 获取内容编码,如果存在的话 String contentEncoding = null; if (entity.getContentEncoding() != null) { contentEncoding = entity.getContentEncoding().getValue(); +// 打印内容编码 Log.d(TAG, "encoding: " + contentEncoding); } - + // 获取输入流 InputStream input = entity.getContent(); - if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { + // 根据内容编码进行解压缩 + if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { // 如果是gzip编码,使用GZIPInputStream解压缩 input = new GZIPInputStream(entity.getContent()); - } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { + } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {// 如果是deflate编码,使用InflaterInputStream解压缩 Inflater inflater = new Inflater(true); input = new InflaterInputStream(entity.getContent(), inflater); } + // 读取输入流并转换为字符串 try { + // 创建InputStreamReader,指定UTF-8编码 InputStreamReader isr = new InputStreamReader(input); + // 创建BufferedReader以高效读取文本 BufferedReader br = new BufferedReader(isr); + // 创建StringBuilder以构建响应内容字符串· StringBuilder sb = new StringBuilder(); while (true) { String buff = br.readLine(); if (buff == null) { return sb.toString(); - } + } // 将读取的行追加到StringBuilder sb = sb.append(buff); } - } finally { + } finally { // 确保输入流在完成后被关闭 input.close(); } } - private JSONObject postRequest(JSONObject js) throws NetworkFailureException { + private JSONObject postRequest(JSONObject js) throws NetworkFailureException { // 检查用户是否已登录,如果未登录,则抛出异常 if (!mLoggedin) { Log.e(TAG, "please login first"); throw new ActionFailureException("not logged in"); } - + // 创建HTTP POST请求对象 HttpPost httpPost = createHttpPost(); - try { + try { // 创建参数列表,用于存储请求参数 LinkedList list = new LinkedList(); + // 将JSON对象转换为字符串,并作为参数添加到列表 list.add(new BasicNameValuePair("r", js.toString())); + // 创建UrlEncodedFormEntity对象,用于封装请求参数 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); + // 设置请求的实体内容 httpPost.setEntity(entity); - // execute the post + // 执行HTTP POST请求,获取响应 HttpResponse response = mHttpClient.execute(httpPost); + // 获取响应内容,并将其转换为字符串 String jsString = getResponseContent(response.getEntity()); + // 将响应字符串转换为JSON对象 return new JSONObject(jsString); } catch (ClientProtocolException e) { + // 处理HTTP协议异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new NetworkFailureException("postRequest failed"); } catch (IOException e) { + // 处理I/O异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new NetworkFailureException("postRequest failed"); } catch (JSONException e) { + // 处理JSON解析异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("unable to convert response content to jsonobject"); } catch (Exception e) { + // 处理其他异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("error occurs when posting request"); } } - +// 创建任务的方法 public void createTask(Task task) throws NetworkFailureException { + // 提交之前的更新 commitUpdate(); try { + // 创建用于POST请求的JSON对象 JSONObject jsPost = new JSONObject(); + // 创建动作列表 JSONArray actionList = new JSONArray(); - // action_list + + // 获取任务的创建动作,并添加到动作列表 actionList.put(task.getCreateAction(getActionId())); + // 将动作列表添加到POST请求的JSON对象 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client_version + // 设置客户端版本信息 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - // post + // 发送POST请求,并获取响应 JSONObject jsResponse = postRequest(jsPost); + // 从响应中获取结果,并设置任务的GID JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( GTaskStringUtils.GTASK_JSON_RESULTS).get(0); task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); @@ -387,10 +425,10 @@ public class GTaskClient { } public void createTaskList(TaskList tasklist) throws NetworkFailureException { - commitUpdate(); + commitUpdate(); // 提交之前的更新 try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); + JSONObject jsPost = new JSONObject(); // 创建用于POST请求的JSON对象 + JSONArray actionList = new JSONArray(); // 创建动作列表 // action_list actionList.put(tasklist.getCreateAction(getActionId())); @@ -413,19 +451,21 @@ public class GTaskClient { } public void commitUpdate() throws NetworkFailureException { + // 检查是否有更新数组 if (mUpdateArray != null) { - try { + try { // 创建用于POST请求的JSON对象 JSONObject jsPost = new JSONObject(); - // action_list + // 将更新数组添加到POST请求的JSON对象 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); - - // client_version + // 设置客户端版本信息 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - + // 发送POST请求 postRequest(jsPost); + // 清空更新数组 mUpdateArray = null; } catch (JSONException e) { + // 处理JSON解析异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("commit update: handing jsonobject failed"); @@ -433,40 +473,41 @@ public class GTaskClient { } } - public void addUpdateNode(Node node) throws NetworkFailureException { + 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(); } - + // 如果更新数组为空,则初始化 if (mUpdateArray == null) - mUpdateArray = new JSONArray(); + mUpdateArray = new JSONArray(); // 将节点的更新动作添加到更新数组 mUpdateArray.put(node.getUpdateAction(getActionId())); } } public void moveTask(Task task, TaskList preParent, TaskList curParent) throws NetworkFailureException { - commitUpdate(); + commitUpdate(); // 提交之前的更新 try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); + JSONObject jsPost = new JSONObject(); + // 创建动作列表 + 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) { + action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); // 设置动作ID + action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); // 设置任务ID + if (preParent == curParent && task.getPriorSibling() != null) { // 如果在同一个任务列表内移动且不是第一个任务,则设置前一个兄弟任务的ID // put prioring_sibing_id only if moving within the tasklist and // it is not the first one 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()); + } // 设置源任务列表的GID + action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); // 设置目标父任务的GID + action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); // 如果在不同任务列表间移动,则设置目标任务列表的GID if (preParent != curParent) { // put the dest_list only if moving between tasklists action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); @@ -487,91 +528,99 @@ public class GTaskClient { } public void deleteNode(Node node) throws NetworkFailureException { - commitUpdate(); + commitUpdate();// 先提交之前的所有更新 try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); + JSONObject jsPost = new JSONObject(); // 创建用于POST请求的JSON对象 + JSONArray actionList = new JSONArray(); // 创建动作列表的JSONArray // action_list + // 将节点标记为已删除,并获取更新动作,添加到动作列表中 node.setDeleted(true); - actionList.put(node.getUpdateAction(getActionId())); + actionList.put(node.getUpdateAction(getActionId())); // 将动作列表添加到POST请求的JSON对象中 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - + // 添加客户端版本信息到POST请求的JSON对象中 // client_version jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - + // 发送POST请求 postRequest(jsPost); - mUpdateArray = null; + mUpdateArray = null; // 清空更新数组 } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("delete node: handing jsonobject failed"); + Log.e(TAG, e.toString()); // 如果处理JSON时发生异常,记录错误日志 + e.printStackTrace(); // 打印异常堆栈信息 + throw new ActionFailureException("delete node: handing jsonobject failed"); // 抛出动作失败异常 + } } - public JSONArray getTaskLists() throws NetworkFailureException { + public JSONArray getTaskLists() throws NetworkFailureException { // 检查是否已登录 if (!mLoggedin) { - Log.e(TAG, "please login first"); - throw new ActionFailureException("not logged in"); + Log.e(TAG, "please login first"); // 如果未登录,记录错误日志 + throw new ActionFailureException("not logged in"); // 抛出动作失败异常 } - try { + try { // 创建HTTP GET请求 HttpGet httpGet = new HttpGet(mGetUrl); - HttpResponse response = null; + HttpResponse response = null; // 执行HTTP GET请求,获取响应 response = mHttpClient.execute(httpGet); - + // 获取响应内容 // get the task list - String resString = getResponseContent(response.getEntity()); + String resString = getResponseContent(response.getEntity()); + // 定义JSON字符串的开始和结束标记 String jsBegin = "_setup("; String jsEnd = ")}"; + // 查找JSON字符串的开始和结束位置 int begin = resString.indexOf(jsBegin); int end = resString.lastIndexOf(jsEnd); - String jsString = null; + String jsString = null; // 提取JSON字符串 if (begin != -1 && end != -1 && begin < end) { jsString = resString.substring(begin + jsBegin.length(), end); - } - JSONObject js = new JSONObject(jsString); + } // 将提取的JSON字符串转换为JSONObject. + JSONObject js = new JSONObject(jsString); + // 从JSONObject中获取任务列表的JSONArray return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); - } catch (ClientProtocolException e) { + } catch (ClientProtocolException e) { // 如果HTTP协议错误,记录错误日志 Log.e(TAG, e.toString()); e.printStackTrace(); throw new NetworkFailureException("gettasklists: httpget failed"); } catch (IOException e) { Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("gettasklists: httpget failed"); + e.printStackTrace(); // 打印异常堆栈信息 + throw new NetworkFailureException("gettasklists: httpget failed"); // 抛出网络失败异常 } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("get task lists: handing jasonobject failed"); + Log.e(TAG, e.toString()); // 如果I/O错误,记录错误日志 + e.printStackTrace(); // 打印异常堆栈信息 + throw new ActionFailureException("get task lists: handing jasonobject failed"); // 抛出网络失败异常 } } public JSONArray getTaskList(String listGid) throws NetworkFailureException { - commitUpdate(); + commitUpdate(); // 先提交之前的所有更新 try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); - - // action_list + // 创建用于POST请求的JSON对象 + JSONObject jsPost = new JSONObject(); + // 创建动作列表的JSONArray + JSONArray actionList = new JSONArray(); + // 创建动作的JSONObject + 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()); - action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); - action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); - actionList.put(action); + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); // 设置动作ID + action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); // 设置任务列表ID + action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); // 设置是否获取已删除任务,此处为否 + action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); // 将动作添加到动作列表中 + actionList.put(action); // 将动作列表添加到POST请求的JSON对象中 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client_version + // 添加客户端版本信息 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - - JSONObject jsResponse = postRequest(jsPost); + // 发送POST请求并获取响应 + JSONObject jsResponse = postRequest(jsPost); // 从响应中获取任务数组 return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("get task list: handing jsonobject failed"); + Log.e(TAG, e.toString()); // 记录JSON异常 + e.printStackTrace(); // 打印异常堆栈信息 + throw new ActionFailureException("get task list: handing jsonobject failed"); // 抛出操作失败异常 } } diff --git a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java index d2b4082..cb4f8ed 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java +++ b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java @@ -87,19 +87,20 @@ public class GTaskManager { private HashMap mNidToGid; - private GTaskManager() { - mSyncing = false; - mCancelled = false; - mGTaskListHashMap = new HashMap(); + private GTaskManager() { //对象初始化函数 + mSyncing = false; //正在同步,flase代表未执行 + mCancelled = false; //全局标识,flase代表可以执行 + mGTaskListHashMap = new HashMap(); //<>代表Java的泛型,就是创建一个用类型作为参数的类。 mGTaskHashMap = new HashMap(); mMetaHashMap = new HashMap(); mMetaList = null; mLocalDeleteIdMap = new HashSet(); - mGidToNid = new HashMap(); - mNidToGid = new HashMap(); + mGidToNid = new HashMap(); //GoogleID to NodeID?? + mNidToGid = new HashMap(); //NodeID to GoogleID???通过hashmap散列表建立映射 } - public static synchronized GTaskManager getInstance() { + + public static synchronized GTaskManager getInstance() {//可能运行在多线程环境下,使用语言级同步--synchronized if (mInstance == null) { mInstance = new GTaskManager(); } @@ -107,236 +108,247 @@ public class GTaskManager { } public synchronized void setActivityContext(Activity activity) { - // used for getting authtoken + // 保存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(); - public int sync(Context context, GTaskASyncTask asyncTask) { - if (mSyncing) { - Log.d(TAG, "Sync is in progress"); - return STATE_SYNC_IN_PROGRESS; + // 如果同步未取消,尝试登录Google任务服务 + if (!mCancelled) { + if (!client.login(mActivity)) { + // 登录失败,抛出网络失败异常 + throw new NetworkFailureException("login google task failed"); + } } - mContext = context; - mContentResolver = mContext.getContentResolver(); - mSyncing = true; - mCancelled = false; + + // 发布初始化任务列表的进度信息 + asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); + // 初始化Google任务列表 + 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 { + // 无论是否发生异常,都清空所有映射和列表,并设置同步标志为false mGTaskListHashMap.clear(); mGTaskHashMap.clear(); mMetaHashMap.clear(); mLocalDeleteIdMap.clear(); mGidToNid.clear(); mNidToGid.clear(); - - try { - GTaskClient client = GTaskClient.getInstance(); - client.resetUpdateArray(); - - // login google task - if (!mCancelled) { - if (!client.login(mActivity)) { - throw new NetworkFailureException("login google task failed"); - } - } - - // get the task list from google - asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); - initGTaskList(); - - // do content sync work - 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; + mSyncing = false; } - private void initGTaskList() throws NetworkFailureException { - if (mCancelled) - return; - GTaskClient client = GTaskClient.getInstance(); - try { - JSONArray jsTaskLists = client.getTaskLists(); - - // init meta list first - mMetaList = null; - for (int i = 0; i < jsTaskLists.length(); i++) { - JSONObject object = jsTaskLists.getJSONObject(i); - 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(); - mMetaList.setContentByRemoteJSON(object); - - // load meta data - JSONArray jsMetas = client.getTaskList(gid); - 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); - } + // 根据是否取消同步,返回相应的状态码 + return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; +} +private void initGTaskList() throws NetworkFailureException { + // 如果同步已被取消,直接返回 + if (mCancelled) + return; + // 获取GTaskClient单例 + GTaskClient client = GTaskClient.getInstance(); + try { + // 从客户端获取任务列表的JSONArray + JSONArray jsTaskLists = client.getTaskLists(); + // 首先初始化元数据列表 + mMetaList = null; + for (int i = 0; i < jsTaskLists.length(); i++) { + JSONObject object = jsTaskLists.getJSONObject(i); + 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(); + mMetaList.setContentByRemoteJSON(object); + // 加载元数据 + JSONArray jsMetas = client.getTaskList(gid); + 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); } } } } - - // create meta list if not existed - if (mMetaList == null) { - mMetaList = new TaskList(); - mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META); - GTaskClient.getInstance().createTaskList(mMetaList); - } - - // init task list - for (int i = 0; i < jsTaskLists.length(); i++) { - JSONObject object = jsTaskLists.getJSONObject(i); - 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(); - tasklist.setContentByRemoteJSON(object); - 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); - gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); - Task task = new Task(); - task.setContentByRemoteJSON(object); - if (task.isWorthSaving()) { - task.setMetaInfo(mMetaHashMap.get(gid)); - tasklist.addChildTask(task); - mGTaskHashMap.put(gid, task); - } + } + // 如果元数据列表不存在,则创建它 + 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); + 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(); + 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); + gid = object.getString(GTaskStringUtils.GTASK_JSON_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) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("initGTaskList: handing JSONObject failed"); } + } catch (JSONException e) { + // 捕获JSON解析异常,记录错误日志,打印堆栈跟踪,并抛出操作失败异常 + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("initGTaskList: handing JSONObject failed"); } +} - private void syncContent() throws NetworkFailureException { + private void syncContent() throws NetworkFailureException { // 定义同步类型变量、游标、Google任务ID和节点对象 int syncType; Cursor c = null; String gid; Node node; - + // 清空本地删除的ID映射,为同步做准备 mLocalDeleteIdMap.clear(); - + // 检查同步是否已被取消,如果取消则直接返回,不进行后续操作 if (mCancelled) { return; } - + // 处理本地删除的笔记 // for local deleted note - try { + try { // 查询非系统类型且父ID为垃圾文件夹的笔记,即本地已删除的笔记 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); + while (c.moveToNext()) { // 获取Google任务ID + gid = c.getString(SqlNote.GTASK_ID_COLUMN); // 根据Google任务ID获取节点对象 node = mGTaskHashMap.get(gid); - if (node != null) { + if (node != null) { // 如果节点存在,从映射中移除并执行远程删除同步 mGTaskHashMap.remove(gid); doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c); } - + // 将本地删除的笔记ID添加到映射中,用于后续批量删除 mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); } - } else { + } else { // 如果查询失败,记录警告日志 Log.w(TAG, "failed to query trash folder"); } } finally { + // 确保游标被关闭,避免资源泄漏 if (c != null) { c.close(); c = null; } } - // sync folder first + // 同步文件夹,确保文件夹结构是最新的 syncFolder(); - // for note existing in database - try { + // 处理数据库中现有的笔记 + try { // 查询类型为笔记且父ID不是垃圾文件夹的笔记,即需要同步的现有笔记 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); + while (c.moveToNext()) { // 获取Google任务ID + gid = c.getString(SqlNote.GTASK_ID_COLUMN); // 根据Google任务ID获取节点对象 node = mGTaskHashMap.get(gid); - if (node != null) { + if (node != null) { // 如果节点存在,从映射中移除,并更新GID与NID的映射关系 mGTaskHashMap.remove(gid); mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); - syncType = node.getSyncAction(c); - } else { + syncType = node.getSyncAction(c); // 获取同步类型 + } else { // 如果节点不存在,判断是本地新增还是远程删除 if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add + // local add // 本地新增,需要添加到远程 syncType = Node.SYNC_ACTION_ADD_REMOTE; } else { // remote delete + // 远程删除,需要从本地删除 syncType = Node.SYNC_ACTION_DEL_LOCAL; } } + // 远程删除,需要从本地删除 doContentSync(syncType, node, c); } - } else { + } else { // 如果查询失败,记录警告日志 Log.w(TAG, "failed to query existing note in database"); } - } finally { + } finally { // 确保游标被关闭,避免资源泄漏 if (c != null) { c.close(); c = null; } } - // go through remaining items + // 处理剩余的项目,即那些在本地没有对应项的远程节点 Iterator> iter = mGTaskHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); - node = entry.getValue(); + node = entry.getValue(); // 将这些远程节点添加到本地 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 + // 检查同步是否已被取消,如果未取消,则执行以下操作 if (!mCancelled) { if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { throw new ActionFailureException("failed to batch-delete local deleted notes"); @@ -351,238 +363,270 @@ public class GTaskManager { } - private void syncFolder() throws NetworkFailureException { - Cursor c = null; - String gid; - Node node; - int syncType; +private void syncFolder() throws NetworkFailureException { + Cursor c = null; // 用于数据库查询的游标 + String gid; // Google任务ID + Node node; // 节点对象,代表文件夹或笔记 + int syncType; // 同步类型 - if (mCancelled) { - return; - } + // 检查同步是否已被取消,如果取消则直接返回,不进行后续操作 + if (mCancelled) { + return; + } - // for root folder - 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 = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - 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); - } else { - doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); - } + // 同步根文件夹 + 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 = c.getString(SqlNote.GTASK_ID_COLUMN); // 获取根文件夹的Google任务ID + node = mGTaskHashMap.get(gid); // 根据ID获取对应的节点对象 + if (node != null) { + // 如果节点存在,更新映射关系并检查是否需要更新远程名称 + mGTaskHashMap.remove(gid); + mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER); + mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid); + // 只有在远程名称与预期不符时才更新远程名称 + if (!node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) + doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); } else { - Log.w(TAG, "failed to query root folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; + // 如果节点不存在,添加到远程 + doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); } + } else { + // 如果查询失败,记录警告日志 + Log.w(TAG, "failed to query root folder"); } - - // for call-note folder - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", - new String[] { - String.valueOf(Notes.ID_CALL_RECORD_FOLDER) - }, null); - if (c != null) { - if (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - 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)) - doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); - } else { - doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); - } - } - } else { - Log.w(TAG, "failed to query call note folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; - } + } finally { + // 确保游标被关闭,避免资源泄漏 + if (c != null) { + c.close(); + c = null; } + } - // for local existing folders - 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); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); - mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); - 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; - } - } - doContentSync(syncType, node, c); - } + // 同步通话记录文件夹 + try { + // 查询通话记录文件夹的信息 + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", + new String[] { + String.valueOf(Notes.ID_CALL_RECORD_FOLDER) + }, null); + if (c != null && c.moveToNext()) { + gid = c.getString(SqlNote.GTASK_ID_COLUMN); // 获取通话记录文件夹的Google任务ID + node = mGTaskHashMap.get(gid); // 根据ID获取对应的节点对象 + if (node != null) { + // 如果节点存在,更新映射关系并检查是否需要更新远程名称 + mGTaskHashMap.remove(gid); + mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER); + mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid); + // 只有在远程名称与预期不符时才更新远程名称 + if (!node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + + GTaskStringUtils.FOLDER_CALL_NOTE)) + doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); } else { - Log.w(TAG, "failed to query existing folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; + // 如果节点不存在,添加到远程 + doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); } + } else { + // 如果查询失败,记录警告日志 + Log.w(TAG, "failed to query call note folder"); + } + } finally { + // 确保游标被关闭,避免资源泄漏 + if (c != null) { + c.close(); + c = null; } + } +} - // for remote add folders - Iterator> iter = mGTaskListHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - gid = entry.getKey(); - node = entry.getValue(); - if (mGTaskHashMap.containsKey(gid)) { +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); // 根据ID获取对应的节点对象 + if (node != null) { + // 如果节点存在,更新映射关系并获取同步类型 mGTaskHashMap.remove(gid); - doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); + mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); + mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); + syncType = node.getSyncAction(c); + } else { + // 如果节点不存在,根据GTASK_ID判断是本地新增还是远程删除 + 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 folder"); + } +} finally { + // 确保游标被关闭,避免资源泄漏 + if (c != null) { + c.close(); + c = null; + } +} - if (!mCancelled) - GTaskClient.getInstance().commitUpdate(); +// 同步远程新增的文件夹 +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)) { + // 如果本地映射中包含该ID,说明是远程新增的文件夹 + mGTaskHashMap.remove(gid); + // 执行内容同步,添加到本地 + doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); } +} - private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; - } +// 如果同步未被取消,提交更新 +if (!mCancelled) + GTaskClient.getInstance().commitUpdate(); - 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)); - 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: - // merging both modifications maybe a good idea - // right now just use local update simply - updateRemoteNode(node, c); - break; - case Node.SYNC_ACTION_NONE: - break; - case Node.SYNC_ACTION_ERROR: - default: - throw new ActionFailureException("unkown sync action type"); - } - } - private void addLocalNode(Node node) throws NetworkFailureException { - if (mCancelled) { - return; - } + /** + * 根据同步类型执行具体的同步操作,包括本地和远程的添加、删除、更新等。 + * @param syncType 同步类型,指示执行的操作 + * @param node 需要同步的节点对象 + * @param c 游标,用于读取数据库中的数据 + * @throws NetworkFailureException 如果网络操作失败 + */ +private void doContentSync(int syncType, Node node, Cursor c) 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); - } else if (node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { - sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER); - } else { - sqlNote = new SqlNote(mContext); - sqlNote.setContent(node.getLocalJSONFromContent()); - sqlNote.setParentId(Notes.ID_ROOT_FOLDER); + 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)); + 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); + } else if (node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { + sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_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 - note.remove(NoteColumns.ID); - } + sqlNote.setContent(node.getLocalJSONFromContent()); + sqlNote.setParentId(Notes.ID_ROOT_FOLDER); + } + } else { + // 如果节点是任务,创建新的SqlNote并设置内容 + sqlNote = new SqlNote(mContext); + JSONObject js = node.getLocalJSONFromContent(); + try { + // 检查并处理ID冲突 + 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)) { + // ID不可用,需要创建新的ID + note.remove(NoteColumns.ID); } } + } - if (js.has(GTaskStringUtils.META_HEAD_DATA)) { - JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - 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 - data.remove(DataColumns.ID); - } + if (js.has(GTaskStringUtils.META_HEAD_DATA)) { + JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + for (int i = 0; i < dataArray.length(); i++) { + JSONObject data = dataArray.getJSONObject(i); + if (data.has(DataColumns.ID)) { + long dataId = data.getLong(DataColumns.ID); + if (DataUtils.existInDataDatabase(mContentResolver, dataId)) { + // 数据ID不可用,需要创建新的ID + data.remove(DataColumns.ID); } } - } - } catch (JSONException e) { - Log.w(TAG, e.toString()); - e.printStackTrace(); } - sqlNote.setContent(js); + } catch (JSONException e) { + Log.w(TAG, e.toString()); + e.printStackTrace(); + } + sqlNote.setContent(js); - Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); - if (parentId == null) { - Log.e(TAG, "cannot find task's parent id locally"); - throw new ActionFailureException("cannot add local node"); - } - sqlNote.setParentId(parentId.longValue()); + // 设置父节点ID + Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); + if (parentId == null) { + Log.e(TAG, "cannot find task's parent id locally"); + throw new ActionFailureException("cannot add local node"); } + sqlNote.setParentId(parentId.longValue()); // create the local node sqlNote.setGtaskId(node.getGid()); @@ -596,199 +640,232 @@ public class GTaskManager { 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()); +private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; + } + + SqlNote sqlNote; + // 更新本地笔记 + 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) { + Log.e(TAG, "cannot find task's parent id locally"); + throw new ActionFailureException("cannot update local node"); + } + sqlNote.setParentId(parentId.longValue()); + sqlNote.commit(true); - 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"); - throw new ActionFailureException("cannot update local node"); - } - sqlNote.setParentId(parentId.longValue()); - sqlNote.commit(true); + // 更新远程元信息 + updateRemoteMeta(node.getGid(), sqlNote); +} - // update meta info - updateRemoteMeta(node.getGid(), sqlNote); +/** + * 添加远程节点,将本地节点的更改同步到远程服务器。 + * @param node 需要添加的节点对象 + * @param c 游标,用于读取数据库中的数据 + * @throws NetworkFailureException 如果网络操作失败 + */ +private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; } - private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; + SqlNote sqlNote = new SqlNote(mContext, c); + Node n; + + // 更新远程服务器 + if (sqlNote.isNoteType()) { + Task task = new Task(); + task.setContentByLocalJSON(sqlNote.getContent()); + + // 获取父任务列表的GID + String parentGid = mNidToGid.get(sqlNote.getParentId()); + if (parentGid == null) { + Log.e(TAG, "cannot find task's parent tasklist"); + throw new ActionFailureException("cannot add remote task"); } + mGTaskListHashMap.get(parentGid).addChildTask(task); - SqlNote sqlNote = new SqlNote(mContext, c); - Node n; + GTaskClient.getInstance().createTask(task); + n = (Node) task; - // update remotely - if (sqlNote.isNoteType()) { - Task task = new Task(); - task.setContentByLocalJSON(sqlNote.getContent()); + // 添加元信息 + updateRemoteMeta(task.getGid(), sqlNote); + } else { + TaskList tasklist = null; - String parentGid = mNidToGid.get(sqlNote.getParentId()); - if (parentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); - throw new ActionFailureException("cannot add remote task"); - } - mGTaskListHashMap.get(parentGid).addChildTask(task); + // 跳过已存在的文件夹 + 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(); - GTaskClient.getInstance().createTask(task); - n = (Node) task; + Iterator> iter = mGTaskListHashMap.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + String gid = entry.getKey(); + TaskList list = entry.getValue(); - // 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; - 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(); - TaskList list = entry.getValue(); - - if (list.getName().equals(folderName)) { - tasklist = list; - if (mGTaskHashMap.containsKey(gid)) { - mGTaskHashMap.remove(gid); - } - break; + if (list.getName().equals(folderName)) { + tasklist = list; + if (mGTaskHashMap.containsKey(gid)) { + mGTaskHashMap.remove(gid); } + break; } - - // no match we can add now - if (tasklist == null) { - tasklist = new TaskList(); - tasklist.setContentByLocalJSON(sqlNote.getContent()); - GTaskClient.getInstance().createTaskList(tasklist); - mGTaskListHashMap.put(tasklist.getGid(), tasklist); - } - n = (Node) tasklist; } - // update local note - sqlNote.setGtaskId(n.getGid()); - sqlNote.commit(false); - sqlNote.resetLocalModified(); - sqlNote.commit(true); - - // gid-id mapping - mGidToNid.put(n.getGid(), sqlNote.getId()); - mNidToGid.put(sqlNote.getId(), n.getGid()); + // 如果没有匹配的文件夹,则添加新的任务列表 + if (tasklist == null) { + tasklist = new TaskList(); + tasklist.setContentByLocalJSON(sqlNote.getContent()); + GTaskClient.getInstance().createTaskList(tasklist); + mGTaskListHashMap.put(tasklist.getGid(), tasklist); + } + n = (Node) tasklist; } - private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; - } + // 更新本地笔记 + sqlNote.setGtaskId(n.getGid()); + sqlNote.commit(false); + sqlNote.resetLocalModified(); + sqlNote.commit(true); - SqlNote sqlNote = new SqlNote(mContext, c); + // 更新GID和ID的映射 + mGidToNid.put(n.getGid(), sqlNote.getId()); + mNidToGid.put(sqlNote.getId(), n.getGid()); +} - // update remotely - node.setContentByLocalJSON(sqlNote.getContent()); - GTaskClient.getInstance().addUpdateNode(node); + /** + * 更新远程节点,将本地节点的更改同步到远程服务器。 + * @param node 需要更新的节点对象 + * @param c 游标,用于读取数据库中的数据 + * @throws NetworkFailureException 如果网络操作失败 + */ +private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; + } - // update meta - updateRemoteMeta(node.getGid(), sqlNote); + SqlNote sqlNote = new SqlNote(mContext, c); - // move task if necessary - if (sqlNote.isNoteType()) { - Task task = (Task) node; - TaskList preParentList = task.getParent(); + // 使用本地JSON内容更新远程节点 + node.setContentByLocalJSON(sqlNote.getContent()); + GTaskClient.getInstance().addUpdateNode(node); - String curParentGid = mNidToGid.get(sqlNote.getParentId()); - if (curParentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); - throw new ActionFailureException("cannot update remote task"); - } - TaskList curParentList = mGTaskListHashMap.get(curParentGid); + // 更新远程元信息 + updateRemoteMeta(node.getGid(), sqlNote); - if (preParentList != curParentList) { - preParentList.removeChildTask(task); - curParentList.addChildTask(task); - GTaskClient.getInstance().moveTask(task, preParentList, curParentList); - } + // 如果是笔记类型,可能需要移动任务 + if (sqlNote.isNoteType()) { + Task task = (Task) node; + TaskList preParentList = task.getParent(); + + // 获取当前父任务列表的GID + String curParentGid = mNidToGid.get(sqlNote.getParentId()); + if (curParentGid == null) { + Log.e(TAG, "cannot find task's parent tasklist"); + throw new ActionFailureException("cannot update remote task"); } + TaskList curParentList = mGTaskListHashMap.get(curParentGid); - // clear local modified flag - sqlNote.resetLocalModified(); - sqlNote.commit(true); + // 如果父任务列表发生变化,则移动任务 + if (preParentList != curParentList) { + preParentList.removeChildTask(task); + curParentList.addChildTask(task); + GTaskClient.getInstance().moveTask(task, preParentList, curParentList); + } } - 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); - mMetaHashMap.put(gid, metaData); - GTaskClient.getInstance().createTask(metaData); - } + // 清除本地修改标志并提交更改 + sqlNote.resetLocalModified(); + sqlNote.commit(true); +} + +/** + * 更新远程元信息,确保本地和远程数据的一致性。 + * @param gid 节点的全球唯一标识符 + * @param sqlNote 本地笔记对象 + * @throws NetworkFailureException 如果网络操作失败 + */ +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); + mMetaHashMap.put(gid, metaData); + GTaskClient.getInstance().createTask(metaData); } } +} - private void refreshLocalSyncId() throws NetworkFailureException { - if (mCancelled) { - return; - } - // get the latest gtask list - mGTaskHashMap.clear(); - mGTaskListHashMap.clear(); - mMetaHashMap.clear(); - initGTaskList(); +private void refreshLocalSyncId() throws NetworkFailureException { + if (mCancelled) { + return; + } - 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); - 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, - c.getLong(SqlNote.ID_COLUMN)), values, null, null); - } else { - Log.e(TAG, "something is missed"); - throw new ActionFailureException( - "some local items don't have gid after sync"); - } + // 清除旧的数据映射并重新初始化远程任务列表 + mGTaskHashMap.clear(); + mGTaskListHashMap.clear(); + mMetaHashMap.clear(); + initGTaskList(); + + 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()) { + // 获取笔记的GID + String gid = c.getString(SqlNote.GTASK_ID_COLUMN); + Node node = mGTaskHashMap.get(gid); + if (node != null) { + // 更新本地数据库中的同步ID为远程节点的最后修改时间 + mGTaskHashMap.remove(gid); + ContentValues values = new ContentValues(); + values.put(NoteColumns.SYNC_ID, node.getLastModified()); + mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, + c.getLong(SqlNote.ID_COLUMN)), values, null, null); + } else { + // 如果找不到对应的远程节点,记录错误并抛出异常 + Log.e(TAG, "something is missed"); + throw new ActionFailureException( + "some local items don't have gid after sync"); } - } else { - Log.w(TAG, "failed to query local note to refresh sync id"); - } - } finally { - if (c != null) { - c.close(); - c = null; } + } else { + // 如果查询失败,记录警告 + Log.w(TAG, "failed to query local note to refresh sync id"); + } + } finally { + // 确保游标被关闭以避免资源泄漏 + if (c != null) { + c.close(); + c = null; } } +} + public String getSyncAccount() { return GTaskClient.getInstance().getSyncAccount().name; diff --git a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java index cca36f7..0b3b970 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java +++ b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java @@ -42,17 +42,31 @@ public class GTaskSyncService extends Service { private static String mSyncProgress = ""; +public class GTaskSyncService extends Service { + // 定义广播动作和 extras 的键 + 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.sync_broadcast"; + public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "is_syncing"; + 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(""); // 发送同步完成广播 + stopSelf(); // 停止服务 } }); - sendBroadcast(""); - mSyncTask.execute(); + sendBroadcast(""); // 发送同步开始广播 + mSyncTask.execute(); // 执行同步任务 } } @@ -64,7 +78,7 @@ public class GTaskSyncService extends Service { @Override public void onCreate() { - mSyncTask = null; + mSyncTask = null; // 初始化同步任务为空 } @Override @@ -73,15 +87,15 @@ public class GTaskSyncService extends Service { 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); } @@ -89,40 +103,62 @@ public class GTaskSyncService extends Service { @Override public void onLowMemory() { if (mSyncTask != null) { - mSyncTask.cancelSync(); + mSyncTask.cancelSync(); // 低内存时取消同步任务 } } + @Override public IBinder onBind(Intent intent) { - return null; + return null; // 不支持绑定 } + /** + * 发送广播来通知同步状态和进度。 + * @param msg 进度信息 + */ 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); + sendBroadcast(intent); // 发送广播 } + /** + * 从 Activity 启动同步服务。 + * @param activity Activity 上下文 + */ 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); + activity.startService(intent); // 启动服务 } + /** + * 从 Context 取消同步服务。 + * @param context Context 上下文 + */ 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); + context.startService(intent); // 启动服务以发送取消动作 } + /** + * 检查是否正在同步。 + * @return true 如果正在同步,否则 false + */ public static boolean isSyncing() { return mSyncTask != null; } + /** + * 获取当前的同步进度信息。 + * @return 同步进度信息字符串 + */ public static String getProgressString() { return mSyncProgress; } } +