diff --git a/doc/小米便签泛读、标注和维护报告.docx b/doc/小米便签泛读、标注和维护报告.docx new file mode 100644 index 0000000..58a4fd9 Binary files /dev/null and b/doc/小米便签泛读、标注和维护报告.docx differ diff --git a/doc/小米便签泛读报告.docx b/doc/小米便签泛读报告.docx deleted file mode 100644 index 29510d5..0000000 Binary files a/doc/小米便签泛读报告.docx and /dev/null differ diff --git a/src/gtask/exception/ActionFailureException.java b/src/gtask/exception/ActionFailureException(1).java similarity index 56% rename from src/gtask/exception/ActionFailureException.java rename to src/gtask/exception/ActionFailureException(1).java index 15504be..1e415ce 100644 --- a/src/gtask/exception/ActionFailureException.java +++ b/src/gtask/exception/ActionFailureException(1).java @@ -16,18 +16,38 @@ package net.micode.notes.gtask.exception; +/** + * ActionFailureException 类 - 动作失败异常 + * + * 功能:表示在Google Tasks同步过程中操作失败的自定义运行时异常 + * 继承自RuntimeException,用于在同步过程中发生不可恢复错误时抛出 + * 用于处理JSON操作失败、网络请求失败、数据转换失败等场景 + */ public class ActionFailureException extends RuntimeException { + // 序列化版本UID,用于对象序列化/反序列化的版本控制 private static final long serialVersionUID = 4425249765923293627L; + /** + * 默认构造函数,创建没有详细消息的异常 + */ public ActionFailureException() { super(); } + /** + * 构造函数,创建带有详细消息的异常 + * @param paramString 异常详细信息,用于调试和日志记录 + */ public ActionFailureException(String paramString) { super(paramString); } + /** + * 构造函数,创建带有详细消息和原因的异常 + * @param paramString 异常详细信息,用于调试和日志记录 + * @param paramThrowable 异常的根本原因(嵌套异常) + */ public ActionFailureException(String paramString, Throwable paramThrowable) { super(paramString, paramThrowable); } -} +} \ No newline at end of file diff --git a/src/gtask/exception/NetworkFailureException.java b/src/gtask/exception/NetworkFailureException(1).java similarity index 55% rename from src/gtask/exception/NetworkFailureException.java rename to src/gtask/exception/NetworkFailureException(1).java index b08cfb1..e8af398 100644 --- a/src/gtask/exception/NetworkFailureException.java +++ b/src/gtask/exception/NetworkFailureException(1).java @@ -16,18 +16,38 @@ package net.micode.notes.gtask.exception; +/** + * NetworkFailureException 类 - 网络故障异常 + * + * 功能:表示在Google Tasks同步过程中因网络问题导致操作失败的自定义异常 + * 继承自Exception(受检异常),用于需要显式处理的网络相关错误 + * 适用于网络连接失败、超时、服务器不可达等场景,要求调用者必须处理此异常 + */ public class NetworkFailureException extends Exception { + // 序列化版本UID,用于对象序列化/反序列化的版本控制 private static final long serialVersionUID = 2107610287180234136L; + /** + * 默认构造函数,创建没有详细消息的异常 + */ public NetworkFailureException() { super(); } + /** + * 构造函数,创建带有详细消息的异常 + * @param paramString 异常详细信息,用于调试和日志记录 + */ public NetworkFailureException(String paramString) { super(paramString); } + /** + * 构造函数,创建带有详细消息和原因的异常 + * @param paramString 异常详细信息,用于调试和日志记录 + * @param paramThrowable 异常的根本原因(嵌套异常) + */ public NetworkFailureException(String paramString, Throwable paramThrowable) { super(paramString, paramThrowable); } -} +} \ No newline at end of file diff --git a/src/gtask/remote/GTaskASyncTask.java b/src/gtask/remote/GTaskASyncTask(1).java similarity index 57% rename from src/gtask/remote/GTaskASyncTask.java rename to src/gtask/remote/GTaskASyncTask(1).java index b3b61e7..744dc52 100644 --- a/src/gtask/remote/GTaskASyncTask.java +++ b/src/gtask/remote/GTaskASyncTask(1).java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * @@ -28,23 +27,39 @@ import net.micode.notes.R; import net.micode.notes.ui.NotesListActivity; import net.micode.notes.ui.NotesPreferenceActivity; - +/** + * GTaskASyncTask 类 - Google Tasks同步异步任务类 + * + * 功能:在后台执行Google Tasks同步操作的AsyncTask实现 + * 继承自AsyncTask,负责处理同步过程的通知显示、进度更新和结果处理 + * 与GTaskManager协作,提供同步的取消功能和进度通知 + */ 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; // Android上下文 + private NotificationManager mNotifiManager; // 通知管理器,用于显示同步通知 + private GTaskManager mTaskManager; // Google Tasks管理器,执行具体同步操作 + private OnCompleteListener mOnCompleteListener; // 同步完成监听器 + /** + * 构造函数 + * @param context Android上下文 + * @param listener 同步完成监听器 + */ public GTaskASyncTask(Context context, OnCompleteListener listener) { mContext = context; mOnCompleteListener = listener; @@ -53,71 +68,112 @@ public class GTaskASyncTask extends AsyncTask { mTaskManager = GTaskManager.getInstance(); } + /** + * 取消同步操作 + */ public void cancelSync() { mTaskManager.cancelSync(); } + /** + * 发布同步进度 + * @param message 进度消息 + */ public void publishProgess(String message) { publishProgress(new String[] { - message + message }); } + /** + * 显示同步通知 + * @param tickerId 通知标题资源ID + * @param 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; PendingIntent pendingIntent; + // 根据同步状态设置不同的点击意图 if (tickerId != R.string.ticker_success) { + // 同步失败或进行中,点击跳转到设置页面 pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesPreferenceActivity.class), 0); - + NotesPreferenceActivity.class), PendingIntent.FLAG_IMMUTABLE); } else { + // 同步成功,点击跳转到便签列表页面 pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesListActivity.class), 0); + NotesListActivity.class), PendingIntent.FLAG_IMMUTABLE); } - notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, - pendingIntent); + // 构建通知(使用兼容性方式) + Notification.Builder builder = new Notification.Builder(mContext) + .setAutoCancel(true) + .setContentTitle(mContext.getString(R.string.app_name)) + .setContentText(content) + .setContentIntent(pendingIntent) + .setWhen(System.currentTimeMillis()) + .setOngoing(true); + Notification notification=builder.getNotification(); + // 显示通知 mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); } + /** + * 后台执行同步任务 + * @param unused 无参数 + * @return 同步结果状态码 + */ @Override protected Integer doInBackground(Void... unused) { + // 发布登录进度 publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity .getSyncAccountName(mContext))); + // 执行同步操作 return mTaskManager.sync(mContext, this); } + /** + * 更新同步进度(在主线程执行) + * @param progress 进度消息数组 + */ @Override protected void onProgressUpdate(String... progress) { + // 显示同步中的通知 showNotification(R.string.ticker_syncing, progress[0]); + // 如果是通过服务调用的,发送广播通知进度 if (mContext instanceof GTaskSyncService) { ((GTaskSyncService) mContext).sendBroadcast(progress[0]); } } + /** + * 同步完成后执行(在主线程执行) + * @param result 同步结果状态码 + */ @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/gtask/remote/GTaskClient.java b/src/gtask/remote/GTaskClient(1).java similarity index 80% rename from src/gtask/remote/GTaskClient.java rename to src/gtask/remote/GTaskClient(1).java index c67dfdf..ec31ce4 100644 --- a/src/gtask/remote/GTaskClient.java +++ b/src/gtask/remote/GTaskClient(1).java @@ -60,36 +60,33 @@ import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; - +/** + * GTask客户端类,用于与Google Tasks API进行交互 + * 提供登录、任务创建、更新、删除、移动等操作功能 + */ public class GTaskClient { - private static final String TAG = GTaskClient.class.getSimpleName(); + private static final String TAG = GTaskClient.class.getSimpleName(); // 日志标签 + // Google Tasks API的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; // Google账户 + private JSONArray mUpdateArray; // 待提交的更新操作数组 + + /** + * 私有构造函数,初始化成员变量 + */ private GTaskClient() { mHttpClient = null; mGetUrl = GTASK_GET_URL; @@ -102,6 +99,10 @@ public class GTaskClient { mUpdateArray = null; } + /** + * 获取GTaskClient单例实例 + * @return GTaskClient单例 + */ public static synchronized GTaskClient getInstance() { if (mInstance == null) { mInstance = new GTaskClient(); @@ -109,18 +110,22 @@ public class GTaskClient { return mInstance; } + /** + * 登录到Google Tasks服务 + * @param activity 当前Activity + * @return 登录是否成功 + */ public boolean login(Activity activity) { - // we suppose that the cookie would expire after 5 minutes - // then we need to re-login + // 检查Cookie是否过期(5分钟) 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))) { + .getSyncAccountName(activity))) { mLoggedin = false; } @@ -136,7 +141,7 @@ public class GTaskClient { return false; } - // login with custom domain if necessary + // 如果是自定义域名,尝试使用自定义URL登录 if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() .endsWith("googlemail.com"))) { StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); @@ -151,7 +156,7 @@ public class GTaskClient { } } - // try to login with google official url + // 如果自定义域名登录失败,尝试使用Google官方URL登录 if (!mLoggedin) { mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -164,6 +169,12 @@ public class GTaskClient { return true; } + /** + * 登录Google账户并获取授权令牌 + * @param activity 当前Activity + * @param invalidateToken 是否使旧令牌失效 + * @return 授权令牌,失败返回null + */ private String loginGoogleAccount(Activity activity, boolean invalidateToken) { String authToken; AccountManager accountManager = AccountManager.get(activity); @@ -189,7 +200,7 @@ public class GTaskClient { return null; } - // get the token now + // 获取授权令牌 AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, "goanna_mobile", null, activity, null, null); try { @@ -207,10 +218,15 @@ public class GTaskClient { return authToken; } + /** + * 尝试登录Google Tasks服务 + * @param activity 当前Activity + * @param authToken 授权令牌 + * @return 登录是否成功 + */ 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 + // 令牌可能过期,尝试刷新令牌后重新登录 authToken = loginGoogleAccount(activity, true); if (authToken == null) { Log.e(TAG, "login google account failed"); @@ -225,6 +241,11 @@ public class GTaskClient { return true; } + /** + * 使用授权令牌登录Google Tasks服务 + * @param authToken 授权令牌 + * @return 登录是否成功 + */ private boolean loginGtask(String authToken) { int timeoutConnection = 10000; int timeoutSocket = 15000; @@ -236,14 +257,14 @@ public class GTaskClient { mHttpClient.setCookieStore(localBasicCookieStore); HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); - // login gtask + // 登录Google Tasks 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 +276,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 +293,6 @@ 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 +300,18 @@ public class GTaskClient { return true; } + /** + * 获取下一个动作ID + * @return 动作ID + */ private int getActionId() { return mActionId++; } + /** + * 创建HTTP POST请求对象 + * @return 配置好的HttpPost对象 + */ private HttpPost createHttpPost() { HttpPost httpPost = new HttpPost(mPostUrl); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); @@ -291,6 +319,12 @@ public class GTaskClient { return httpPost; } + /** + * 从HTTP响应实体中提取内容 + * @param entity HTTP响应实体 + * @return 响应内容字符串 + * @throws IOException 读取失败时抛出 + */ private String getResponseContent(HttpEntity entity) throws IOException { String contentEncoding = null; if (entity.getContentEncoding() != null) { @@ -323,6 +357,12 @@ public class GTaskClient { } } + /** + * 发送POST请求到Google Tasks API + * @param js 要发送的JSON对象 + * @return 响应JSON对象 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private JSONObject postRequest(JSONObject js) throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -336,7 +376,7 @@ public class GTaskClient { 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 +400,25 @@ public class GTaskClient { } } + /** + * 创建新任务 + * @param task 要创建的任务对象 + * @throws NetworkFailureException 网络请求失败时抛出 + */ 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 + // 发送请求 JSONObject jsResponse = postRequest(jsPost); JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( GTaskStringUtils.GTASK_JSON_RESULTS).get(0); @@ -386,20 +431,25 @@ public class GTaskClient { } } + /** + * 创建新任务列表 + * @param tasklist 要创建的任务列表对象 + * @throws NetworkFailureException 网络请求失败时抛出 + */ 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 + // 发送请求 JSONObject jsResponse = postRequest(jsPost); JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( GTaskStringUtils.GTASK_JSON_RESULTS).get(0); @@ -412,15 +462,19 @@ public class GTaskClient { } } + /** + * 提交所有待处理的更新操作 + * @throws NetworkFailureException 网络请求失败时抛出 + */ 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 +487,14 @@ public class GTaskClient { } } + /** + * 添加节点更新操作到待提交队列 + * @param 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(); } @@ -447,6 +505,13 @@ public class GTaskClient { } } + /** + * 移动任务到不同的任务列表或同一列表中的不同位置 + * @param task 要移动的任务 + * @param preParent 原父任务列表 + * @param curParent 目标父任务列表 + * @throws NetworkFailureException 网络请求失败时抛出 + */ public void moveTask(Task task, TaskList preParent, TaskList curParent) throws NetworkFailureException { commitUpdate(); @@ -455,26 +520,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 +550,23 @@ public class GTaskClient { } } + /** + * 删除节点 + * @param node 要删除的节点 + * @throws NetworkFailureException 网络请求失败时抛出 + */ 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 +578,11 @@ public class GTaskClient { } } + /** + * 获取所有任务列表 + * @return 任务列表的JSON数组 + * @throws NetworkFailureException 网络请求失败时抛出 + */ public JSONArray getTaskLists() throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -520,7 +594,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 +621,12 @@ public class GTaskClient { } } + /** + * 获取指定任务列表的所有任务 + * @param listGid 任务列表的全局ID + * @return 任务的JSON数组 + * @throws NetworkFailureException 网络请求失败时抛出 + */ public JSONArray getTaskList(String listGid) throws NetworkFailureException { commitUpdate(); try { @@ -554,7 +634,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 +643,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 +655,18 @@ public class GTaskClient { } } + /** + * 获取当前同步账户 + * @return Google账户对象 + */ public Account getSyncAccount() { return mAccount; } + /** + * 重置更新数组 + */ public void resetUpdateArray() { mUpdateArray = null; } -} +} \ No newline at end of file diff --git a/src/gtask/remote/GTaskManager.java b/src/gtask/remote/GTaskManager(1).java similarity index 79% rename from src/gtask/remote/GTaskManager.java rename to src/gtask/remote/GTaskManager(1).java index d2b4082..19451b9 100644 --- a/src/gtask/remote/GTaskManager.java +++ b/src/gtask/remote/GTaskManager(1).java @@ -47,46 +47,43 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Map; - +/** + * Google Tasks同步管理器 + * 负责协调本地笔记和Google Tasks之间的双向数据同步 + * 包括任务列表、任务和元数据的同步操作 + */ 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 static final String TAG = GTaskManager.class.getSimpleName(); // 日志标签 - private Activity mActivity; + // 同步状态常量 + 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 Context mContext; + private static GTaskManager mInstance = null; // 单例实例 - private ContentResolver mContentResolver; + private Activity mActivity; // 当前Activity + private Context mContext; // 应用上下文 + private ContentResolver mContentResolver; // 内容解析器 - private boolean mSyncing; + private boolean mSyncing; // 同步进行标志 + private boolean mCancelled; // 同步取消标志 - private boolean mCancelled; + // 数据映射存储 + private HashMap mGTaskListHashMap; // Google任务列表映射(GID -> TaskList) + private HashMap mGTaskHashMap; // Google任务节点映射(GID -> Node) + private HashMap mMetaHashMap; // 元数据映射(相关GID -> MetaData) + private TaskList mMetaList; // 元数据任务列表 - private HashMap mGTaskListHashMap; - - private HashMap mGTaskHashMap; - - private HashMap mMetaHashMap; - - private TaskList mMetaList; - - private HashSet mLocalDeleteIdMap; - - private HashMap mGidToNid; - - private HashMap mNidToGid; + private HashSet mLocalDeleteIdMap; // 本地待删除ID集合 + private HashMap mGidToNid; // GID到本地ID的映射 + private HashMap mNidToGid; // 本地ID到GID的映射 + /** + * 私有构造函数,初始化成员变量 + */ private GTaskManager() { mSyncing = false; mCancelled = false; @@ -99,6 +96,10 @@ public class GTaskManager { mNidToGid = new HashMap(); } + /** + * 获取GTaskManager单例实例 + * @return GTaskManager单例 + */ public static synchronized GTaskManager getInstance() { if (mInstance == null) { mInstance = new GTaskManager(); @@ -106,11 +107,20 @@ public class GTaskManager { return mInstance; } + /** + * 设置Activity上下文,用于获取授权令牌 + * @param activity 当前Activity + */ public synchronized void setActivityContext(Activity activity) { - // used for getting authtoken mActivity = activity; } + /** + * 执行Google Tasks同步 + * @param context 应用上下文 + * @param asyncTask 异步任务对象,用于进度更新 + * @return 同步状态码 + */ public int sync(Context context, GTaskASyncTask asyncTask) { if (mSyncing) { Log.d(TAG, "Sync is in progress"); @@ -120,6 +130,8 @@ public class GTaskManager { mContentResolver = mContext.getContentResolver(); mSyncing = true; mCancelled = false; + + // 清理旧数据 mGTaskListHashMap.clear(); mGTaskHashMap.clear(); mMetaHashMap.clear(); @@ -131,18 +143,18 @@ public class GTaskManager { GTaskClient client = GTaskClient.getInstance(); client.resetUpdateArray(); - // login google task + // 登录Google Tasks if (!mCancelled) { if (!client.login(mActivity)) { throw new NetworkFailureException("login google task failed"); } } - // get the task list from google + // 从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) { @@ -156,6 +168,7 @@ public class GTaskManager { e.printStackTrace(); return STATE_INTERNAL_ERROR; } finally { + // 清理数据,无论成功与否 mGTaskListHashMap.clear(); mGTaskHashMap.clear(); mMetaHashMap.clear(); @@ -168,6 +181,11 @@ public class GTaskManager { return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; } + /** + * 初始化Google任务列表数据 + * 从Google Tasks获取所有任务列表和任务,构建本地数据结构 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private void initGTaskList() throws NetworkFailureException { if (mCancelled) return; @@ -175,19 +193,19 @@ public class GTaskManager { 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)) { + // 查找元数据文件夹 + 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); @@ -203,7 +221,7 @@ public class GTaskManager { } } - // create meta list if not existed + // 如果元数据列表不存在,则创建 if (mMetaList == null) { mMetaList = new TaskList(); mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX @@ -211,21 +229,22 @@ public class GTaskManager { 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); + // 只处理MIUI前缀的文件夹(排除元数据文件夹) if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX) && !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META)) { + + 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); @@ -247,6 +266,11 @@ public class GTaskManager { } } + /** + * 执行内容同步 + * 比较本地数据和Google Tasks数据,执行相应的同步操作 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private void syncContent() throws NetworkFailureException { int syncType; Cursor c = null; @@ -259,7 +283,7 @@ public class GTaskManager { return; } - // for local deleted note + // 处理本地已删除的笔记(在回收站中的笔记) try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type<>? AND parent_id=?)", new String[] { @@ -286,10 +310,10 @@ public class GTaskManager { } } - // sync folder first + // 首先同步文件夹 syncFolder(); - // for note existing in database + // 处理数据库中已存在的笔记 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type=? AND parent_id<>?)", new String[] { @@ -306,10 +330,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 + // Google Tasks中已删除的笔记 syncType = Node.SYNC_ACTION_DEL_LOCAL; } } @@ -326,7 +350,7 @@ public class GTaskManager { } } - // go through remaining items + // 处理剩余的Google Tasks项(本地不存在但Google Tasks中存在的项) Iterator> iter = mGTaskHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -334,16 +358,15 @@ 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 + // 检查是否被取消,逐项检查 + // 清理本地删除表 if (!mCancelled) { if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { throw new ActionFailureException("failed to batch-delete local deleted notes"); } } - // refresh local sync id + // 刷新本地同步ID if (!mCancelled) { GTaskClient.getInstance().commitUpdate(); refreshLocalSyncId(); @@ -351,6 +374,10 @@ public class GTaskManager { } + /** + * 同步文件夹结构 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private void syncFolder() throws NetworkFailureException { Cursor c = null; String gid; @@ -361,7 +388,7 @@ public class GTaskManager { return; } - // for root folder + // 同步根文件夹 try { c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); @@ -373,7 +400,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,11 +417,11 @@ public class GTaskManager { } } - // 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) + String.valueOf(Notes.ID_CALL_RECORD_FOLDER) }, null); if (c != null) { if (c.moveToNext()) { @@ -404,8 +431,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 +450,7 @@ public class GTaskManager { } } - // for local existing folders + // 处理本地已存在的文件夹 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type=? AND parent_id<>?)", new String[] { @@ -441,10 +467,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 + // Google Tasks中已删除的文件夹 syncType = Node.SYNC_ACTION_DEL_LOCAL; } } @@ -460,7 +486,7 @@ public class GTaskManager { } } - // for remote add folders + // 处理Google Tasks中新增的文件夹 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -476,6 +502,13 @@ public class GTaskManager { GTaskClient.getInstance().commitUpdate(); } + /** + * 根据同步类型执行具体的同步操作 + * @param syncType 同步类型 + * @param node Google Tasks节点 + * @param c 本地数据库游标 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -484,12 +517,15 @@ public class GTaskManager { MetaData meta; switch (syncType) { case Node.SYNC_ACTION_ADD_LOCAL: + // 在本地添加节点 addLocalNode(node); break; case Node.SYNC_ACTION_ADD_REMOTE: + // 在Google Tasks添加节点 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); @@ -497,6 +533,7 @@ public class GTaskManager { mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); break; case Node.SYNC_ACTION_DEL_REMOTE: + // 删除Google Tasks节点 meta = mMetaHashMap.get(node.getGid()); if (meta != null) { GTaskClient.getInstance().deleteNode(meta); @@ -504,17 +541,19 @@ public class GTaskManager { GTaskClient.getInstance().deleteNode(node); break; case Node.SYNC_ACTION_UPDATE_LOCAL: + // 更新本地节点 updateLocalNode(node, c); break; case Node.SYNC_ACTION_UPDATE_REMOTE: + // 更新Google Tasks节点 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: @@ -522,6 +561,11 @@ public class GTaskManager { } } + /** + * 在本地数据库中添加Google Tasks节点 + * @param node Google Tasks节点 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private void addLocalNode(Node node) throws NetworkFailureException { if (mCancelled) { return; @@ -529,6 +573,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,20 +586,23 @@ public class GTaskManager { sqlNote.setParentId(Notes.ID_ROOT_FOLDER); } } else { + // 处理笔记节点 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)) { - // the id is not available, have to create a new one + // ID不可用,需要创建新ID note.remove(NoteColumns.ID); } } } + // 检查数据ID是否可用 if (js.has(GTaskStringUtils.META_HEAD_DATA)) { JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); for (int i = 0; i < dataArray.length(); i++) { @@ -562,8 +610,7 @@ 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不可用,需要创建新ID data.remove(DataColumns.ID); } } @@ -584,25 +631,31 @@ public class GTaskManager { sqlNote.setParentId(parentId.longValue()); } - // create the local node + // 创建本地节点 sqlNote.setGtaskId(node.getGid()); sqlNote.commit(false); - // update gid-nid mapping + // 更新GID-NID映射 mGidToNid.put(node.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), node.getGid()); - // update meta + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); } + /** + * 使用Google Tasks数据更新本地节点 + * @param node Google Tasks节点 + * @param c 本地数据库游标 + * @throws NetworkFailureException 网络请求失败时抛出 + */ 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()); @@ -615,10 +668,16 @@ public class GTaskManager { sqlNote.setParentId(parentId.longValue()); sqlNote.commit(true); - // update meta info + // 更新元数据信息 updateRemoteMeta(node.getGid(), sqlNote); } + /** + * 在Google Tasks中添加本地节点 + * @param node Google Tasks节点(可能为null) + * @param c 本地数据库游标 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -627,8 +686,9 @@ public class GTaskManager { SqlNote sqlNote = new SqlNote(mContext, c); Node n; - // update remotely + // 在Google Tasks中创建 if (sqlNote.isNoteType()) { + // 创建任务 Task task = new Task(); task.setContentByLocalJSON(sqlNote.getContent()); @@ -642,12 +702,13 @@ public class GTaskManager { 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; @@ -671,7 +732,7 @@ public class GTaskManager { } } - // no match we can add now + // 没有匹配项,现在创建 if (tasklist == null) { tasklist = new TaskList(); tasklist.setContentByLocalJSON(sqlNote.getContent()); @@ -681,17 +742,23 @@ public class GTaskManager { n = (Node) tasklist; } - // update local note + // 更新本地笔记 sqlNote.setGtaskId(n.getGid()); sqlNote.commit(false); sqlNote.resetLocalModified(); sqlNote.commit(true); - // gid-id mapping + // 更新GID-ID映射 mGidToNid.put(n.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), n.getGid()); } + /** + * 使用本地数据更新Google Tasks节点 + * @param node Google Tasks节点 + * @param c 本地数据库游标 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -699,14 +766,14 @@ public class GTaskManager { SqlNote sqlNote = new SqlNote(mContext, c); - // update remotely + // 更新Google Tasks 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(); @@ -725,11 +792,17 @@ public class GTaskManager { } } - // clear local modified flag + // 清除本地修改标志 sqlNote.resetLocalModified(); sqlNote.commit(true); } + /** + * 更新远程元数据 + * @param gid Google Tasks ID + * @param sqlNote 本地笔记对象 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { if (sqlNote != null && sqlNote.isNoteType()) { MetaData metaData = mMetaHashMap.get(gid); @@ -746,12 +819,17 @@ public class GTaskManager { } } + /** + * 刷新本地同步ID + * 从Google Tasks获取最新的修改时间,更新到本地数据库 + * @throws NetworkFailureException 网络请求失败时抛出 + */ private void refreshLocalSyncId() throws NetworkFailureException { if (mCancelled) { return; } - // get the latest gtask list + // 获取最新的Google Tasks列表 mGTaskHashMap.clear(); mGTaskListHashMap.clear(); mMetaHashMap.clear(); @@ -790,11 +868,18 @@ public class GTaskManager { } } + /** + * 获取同步账户名称 + * @return 同步账户名称 + */ public String getSyncAccount() { return GTaskClient.getInstance().getSyncAccount().name; } + /** + * 取消同步 + */ public void cancelSync() { mCancelled = true; } -} +} \ No newline at end of file diff --git a/src/gtask/remote/GTaskSyncService.java b/src/gtask/remote/GTaskSyncService(1).java similarity index 93% rename from src/gtask/remote/GTaskSyncService.java rename to src/gtask/remote/GTaskSyncService(1).java index cca36f7..536ce55 100644 --- a/src/gtask/remote/GTaskSyncService.java +++ b/src/gtask/remote/GTaskSyncService(1).java @@ -23,25 +23,25 @@ import android.content.Intent; import android.os.Bundle; import android.os.IBinder; +/** + * GTaskSyncService - Google Tasks同步服务 + */ public class GTaskSyncService extends Service { public final static String ACTION_STRING_NAME = "sync_action_type"; - public final static int ACTION_START_SYNC = 0; - public final static int ACTION_CANCEL_SYNC = 1; - public final static int ACTION_INVALID = 2; public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service"; - public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing"; - public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg"; private static GTaskASyncTask mSyncTask = null; - private static String mSyncProgress = ""; + /** + * 开始同步操作 + */ private void startSync() { if (mSyncTask == null) { mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { @@ -56,6 +56,9 @@ public class GTaskSyncService extends Service { } } + /** + * 取消同步操作 + */ private void cancelSync() { if (mSyncTask != null) { mSyncTask.cancelSync(); @@ -97,6 +100,9 @@ public class GTaskSyncService extends Service { return null; } + /** + * 发送同步状态广播 + */ public void sendBroadcast(String msg) { mSyncProgress = msg; Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); @@ -105,6 +111,9 @@ public class GTaskSyncService extends Service { sendBroadcast(intent); } + /** + * 启动同步服务 + */ public static void startSync(Activity activity) { GTaskManager.getInstance().setActivityContext(activity); Intent intent = new Intent(activity, GTaskSyncService.class); @@ -112,6 +121,9 @@ 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); @@ -125,4 +137,4 @@ public class GTaskSyncService extends Service { public static String getProgressString() { return mSyncProgress; } -} +} \ No newline at end of file diff --git a/src/model/Note.java b/src/model/Note(1).java similarity index 94% rename from src/model/Note.java rename to src/model/Note(1).java index 6706cf6..2e2723f 100644 --- a/src/model/Note.java +++ b/src/model/Note(1).java @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package net.micode.notes.model; + import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentUris; @@ -33,16 +33,19 @@ import net.micode.notes.data.Notes.TextNote; import java.util.ArrayList; - +/** + * Note - 便签数据模型管理类 + * 负责便签数据的创建、更新和同步操作 + */ public class Note { private ContentValues mNoteDiffValues; private NoteData mNoteData; private static final String TAG = "Note"; + /** - * Create a new note id for adding a new note to databases + * 在数据库中创建新便签并返回其ID */ public static synchronized long getNewNoteId(Context context, long folderId) { - // Create a new note in the database ContentValues values = new ContentValues(); long createdTime = System.currentTimeMillis(); values.put(NoteColumns.CREATED_DATE, createdTime); @@ -50,6 +53,7 @@ public class Note { values.put(NoteColumns.TYPE, Notes.TYPE_NOTE); values.put(NoteColumns.LOCAL_MODIFIED, 1); values.put(NoteColumns.PARENT_ID, folderId); + Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); long noteId = 0; @@ -59,6 +63,7 @@ public class Note { Log.e(TAG, "Get note id error :" + e.toString()); noteId = 0; } + if (noteId == -1) { throw new IllegalStateException("Wrong note id:" + noteId); } @@ -70,6 +75,9 @@ public class Note { mNoteData = new NoteData(); } + /** + * 设置便签的基本属性值 + */ public void setNoteValue(String key, String value) { mNoteDiffValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); @@ -96,10 +104,16 @@ public class Note { mNoteData.setCallData(key, value); } + /** + * 检查便签是否有本地修改 + */ public boolean isLocalModified() { return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); } + /** + * 同步便签数据到数据库 + */ public boolean syncNote(Context context, long noteId) { if (noteId <= 0) { throw new IllegalArgumentException("Wrong note id:" + noteId); @@ -109,16 +123,10 @@ public class Note { return true; } - /** - * In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and - * {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the - * note data info - */ if (context.getContentResolver().update( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null, null) == 0) { Log.e(TAG, "Update note error, should not happen"); - // Do not return, fall through } mNoteDiffValues.clear(); @@ -130,15 +138,15 @@ public class Note { return true; } + /** + * NoteData - 便签数据内部类 + * 管理便签的具体数据内容,包括文本数据和通话记录数据 + */ private class NoteData { private long mTextDataId; - private ContentValues mTextDataValues; - private long mCallDataId; - private ContentValues mCallDataValues; - private static final String TAG = "NoteData"; public NoteData() { @@ -178,10 +186,10 @@ public class Note { mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } + /** + * 将数据变更推送到ContentResolver + */ Uri pushIntoContentResolver(Context context, long noteId) { - /** - * Check for safety - */ if (noteId <= 0) { throw new IllegalArgumentException("Wrong note id:" + noteId); } @@ -250,4 +258,4 @@ public class Note { return null; } } -} +} \ No newline at end of file diff --git a/src/model/WorkingNote.java b/src/model/WorkingNote(1).java similarity index 89% rename from src/model/WorkingNote.java rename to src/model/WorkingNote(1).java index be081e4..3f69a29 100644 --- a/src/model/WorkingNote.java +++ b/src/model/WorkingNote(1).java @@ -31,37 +31,27 @@ import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.TextNote; import net.micode.notes.tool.ResourceParser.NoteBgResources; - +/** + * WorkingNote - 便签编辑状态管理类 + * 管理用户正在编辑的便签状态,作为Note类的上层封装 + */ public class WorkingNote { - // Note for the working note private Note mNote; - // Note Id private long mNoteId; - // Note content private String mContent; - // Note mode private int mMode; - private long mAlertDate; - private long mModifiedDate; - private int mBgColorId; - private int mWidgetId; - private int mWidgetType; - private long mFolderId; - private Context mContext; - private static final String TAG = "WorkingNote"; - private boolean mIsDeleted; - private NoteSettingChangedListener mNoteSettingStatusListener; + // 数据表查询投影列 public static final String[] DATA_PROJECTION = new String[] { DataColumns.ID, DataColumns.CONTENT, @@ -72,6 +62,7 @@ public class WorkingNote { DataColumns.DATA4, }; + // 便签表查询投影列 public static final String[] NOTE_PROJECTION = new String[] { NoteColumns.PARENT_ID, NoteColumns.ALERTED_DATE, @@ -81,27 +72,19 @@ public class WorkingNote { NoteColumns.MODIFIED_DATE }; + // 数据表投影列索引 private static final int DATA_ID_COLUMN = 0; - private static final int DATA_CONTENT_COLUMN = 1; - private static final int DATA_MIME_TYPE_COLUMN = 2; - private static final int DATA_MODE_COLUMN = 3; - + // 便签表投影列索引 private static final int NOTE_PARENT_ID_COLUMN = 0; - private static final int NOTE_ALERTED_DATE_COLUMN = 1; - private static final int NOTE_BG_COLOR_ID_COLUMN = 2; - private static final int NOTE_WIDGET_ID_COLUMN = 3; - private static final int NOTE_WIDGET_TYPE_COLUMN = 4; - private static final int NOTE_MODIFIED_DATE_COLUMN = 5; - // New note construct private WorkingNote(Context context, long folderId) { mContext = context; mAlertDate = 0; @@ -114,7 +97,6 @@ public class WorkingNote { mWidgetType = Notes.TYPE_WIDGET_INVALIDE; } - // Existing note construct private WorkingNote(Context context, long noteId, long folderId) { mContext = context; mNoteId = noteId; @@ -124,6 +106,9 @@ public class WorkingNote { loadNote(); } + /** + * 从数据库加载便签基本属性 + */ private void loadNote() { Cursor cursor = mContext.getContentResolver().query( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, @@ -146,10 +131,13 @@ public class WorkingNote { loadNoteData(); } + /** + * 从数据表加载便签的具体内容 + */ private void loadNoteData() { Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { - String.valueOf(mNoteId) + String.valueOf(mNoteId) }, null); if (cursor != null) { @@ -174,8 +162,11 @@ public class WorkingNote { } } + /** + * 创建空便签 + */ public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, - int widgetType, int defaultBgColorId) { + int widgetType, int defaultBgColorId) { WorkingNote note = new WorkingNote(context, folderId); note.setBgColorId(defaultBgColorId); note.setWidgetId(widgetId); @@ -183,10 +174,16 @@ public class WorkingNote { return note; } + /** + * 从数据库加载便签 + */ public static WorkingNote load(Context context, long id) { return new WorkingNote(context, id, 0); } + /** + * 保存便签到数据库 + */ public synchronized boolean saveNote() { if (isWorthSaving()) { if (!existInDatabase()) { @@ -198,9 +195,7 @@ public class WorkingNote { mNote.syncNote(mContext, mNoteId); - /** - * Update widget content if there exist any widget of this note - */ + // 如果有关联的小部件,则更新小部件内容 if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { @@ -212,10 +207,16 @@ public class WorkingNote { } } + /** + * 判断便签是否已存在于数据库中 + */ public boolean existInDatabase() { return mNoteId > 0; } + /** + * 判断便签是否值得保存 + */ private boolean isWorthSaving() { if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) || (existInDatabase() && !mNote.isLocalModified())) { @@ -225,10 +226,16 @@ public class WorkingNote { } } + /** + * 设置便签设置变更监听器 + */ public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { mNoteSettingStatusListener = l; } + /** + * 设置提醒时间 + */ public void setAlertDate(long date, boolean set) { if (date != mAlertDate) { mAlertDate = date; @@ -239,14 +246,20 @@ public class WorkingNote { } } + /** + * 标记便签为删除状态 + */ public void markDeleted(boolean mark) { mIsDeleted = mark; if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onWidgetChanged(); + mNoteSettingStatusListener.onWidgetChanged(); } } + /** + * 设置背景颜色ID + */ public void setBgColorId(int id) { if (id != mBgColorId) { mBgColorId = id; @@ -257,6 +270,9 @@ public class WorkingNote { } } + /** + * 设置清单模式 + */ public void setCheckListMode(int mode) { if (mMode != mode) { if (mNoteSettingStatusListener != null) { @@ -281,6 +297,9 @@ public class WorkingNote { } } + /** + * 设置便签文本内容 + */ public void setWorkingText(String text) { if (!TextUtils.equals(mContent, text)) { mContent = text; @@ -288,6 +307,9 @@ public class WorkingNote { } } + /** + * 将普通便签转换为通话记录便签 + */ public void convertToCallNote(String phoneNumber, long callDate) { mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); @@ -342,27 +364,13 @@ public class WorkingNote { return mWidgetType; } + /** + * 便签设置变更监听器接口 + */ public interface NoteSettingChangedListener { - /** - * Called when the background color of current note has just changed - */ void onBackgroundColorChanged(); - - /** - * Called when user set clock - */ void onClockAlertChanged(long date, boolean set); - - /** - * Call when user create note from widget - */ void onWidgetChanged(); - - /** - * Call when switch between check list mode and normal mode - * @param oldMode is previous mode before change - * @param newMode is new mode - */ void onCheckListModeChanged(int oldMode, int newMode); } -} +} \ No newline at end of file diff --git a/小米便签泛读报告/小米便签泛读报告.docx b/小米便签泛读报告/小米便签泛读报告.docx deleted file mode 100644 index 9e974ca..0000000 Binary files a/小米便签泛读报告/小米便签泛读报告.docx and /dev/null differ