@ -1,31 +1,54 @@
/ *
/ *
* Copyright ( c ) 2010 - 2011 , The MiCode Open Source Community ( www . micode . net )
* 版 权 所 有 ( c ) 2010 - 2011 , MiCode 开 源 社 区 ( www . micode . net )
*
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* 根 据 Apache 许 可 证 , 第 2.0 版 ( “ 许 可 证 ” ) 许 可 ;
* you may not use this file except in compliance with the License .
* 除 非 遵 循 许 可 证 , 否 则 不 得 使 用 此 文 件 。
* You may obtain a copy of the License at
* 可 以 在 以 下 网 址 获 取 许 可 证 副 本 :
*
*
* http : //www.apache.org/licenses/LICENSE-2.0
* http : //www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing , software
* 除 非 适 用 于 相 关 法 律 或 书 面 协 议 , 否 则 根 据 许 可 证 分 发 的 软 件
* distributed under the License is distributed on an "AS IS" BASIS ,
* 是 以 “ 原 样 ” 基 础 提 供 , 不 提 供 任 何 形 式 的 保 证 或 条 件 , 无 论 是 明 示 的 还 是 暗 示 的 。
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* 请 参 阅 许 可 证 以 了 解 特 定 语 言 管 理 权 限 和
* See the License for the specific language governing permissions and
* 许 可 证 下 的 限 制 。
* limitations under the License .
* /
* /
// 定义包
package net.micode.notes.gtask.remote ;
package net.micode.notes.gtask.remote ;
import android.app.Activity ;
// 导入需要的类
import android.content.ContentResolver ;
import android.app.Activity ; // 用于活动管理的类
import android.content.ContentUris ;
import android.content.ContentResolver ; // 用于内容提供者的类
import android.content.ContentValues ;
import android.content.ContentUris ; // 处理内容 URI 的工具类
import android.content.Context ;
import android.content.ContentValues ; // 包含 ContentProvider 插入或更新所需值的类
import android.database.Cursor ;
import android.content.Context ; // 应用上下文类
import android.util.Log ;
import android.database.Cursor ; // 数据库查询结果的类
import android.util.Log ; // 记录日志的工具类
// 导入项目中的相关类
import net.micode.notes.R ;
import net.micode.notes.R ;
import net.micode.notes.data.Notes ;
import net.micode.notes.data.Notes ;
< < < < < < < HEAD
import net.micode.notes.data.Notes.DataColumns ; // 数据列常量
import net.micode.notes.data.Notes.NoteColumns ; // 笔记列常量
import net.micode.notes.gtask.data.MetaData ; // 任务元数据类
import net.micode.notes.gtask.data.Node ; // 节点类
import net.micode.notes.gtask.data.SqlNote ; // SQL 笔记类
import net.micode.notes.gtask.data.Task ; // 任务类
import net.micode.notes.gtask.data.TaskList ; // 任务列表类
import net.micode.notes.gtask.exception.ActionFailureException ; // 操作失败异常
import net.micode.notes.gtask.exception.NetworkFailureException ; // 网络失败异常
import net.micode.notes.tool.DataUtils ; // 数据工具类
import net.micode.notes.tool.GTaskStringUtils ; // GTask 字符串工具类
import org.json.JSONArray ; // JSON 数组类
import org.json.JSONException ; // JSON 异常类
import org.json.JSONObject ; // JSON 对象类
import java.util.HashMap ; // 哈希表实现
import java.util.HashSet ; // 哈希集合实现
import java.util.Iterator ; // 迭代器类
= = = = = = =
import net.micode.notes.data.Notes.DataColumns ;
import net.micode.notes.data.Notes.DataColumns ;
import net.micode.notes.data.Notes.NoteColumns ;
import net.micode.notes.data.Notes.NoteColumns ;
import net.micode.notes.gtask.data.MetaData ;
import net.micode.notes.gtask.data.MetaData ;
@ -47,47 +70,49 @@ import java.util.HashSet;
import java.util.Iterator ;
import java.util.Iterator ;
import java.util.Map ;
import java.util.Map ;
// 这是一个管理Google任务同步的类
// GTaskManager类用于管理与Google Tasks的同步操作, 包括初始化任务列表、同步内容、处理各种同步类型的操作等功能
public class GTaskManager {
public class GTaskManager {
private static final String TAG = GTaskManager . class . getSimpleName ( ) ;
private static final String TAG = GTaskManager . class . getSimpleName ( ) ;
// 同步成功状态码
public static final int STATE_SUCCESS = 0 ;
public static final int STATE_SUCCESS = 0 ;
// 网络错误状态码
public static final int STATE_NETWORK_ERROR = 1 ;
public static final int STATE_NETWORK_ERROR = 1 ;
// 内部错误状态码
public static final int STATE_INTERNAL_ERROR = 2 ;
public static final int STATE_INTERNAL_ERROR = 2 ;
// 同步正在进行状态码
public static final int STATE_SYNC_IN_PROGRESS = 3 ;
public static final int STATE_SYNC_IN_PROGRESS = 3 ;
// 同步被取消状态码
public static final int STATE_SYNC_CANCELLED = 4 ;
public static final int STATE_SYNC_CANCELLED = 4 ;
private static GTaskManager mInstance = null ;
private static GTaskManager mInstance = null ;
// 关联的Activity, 用于获取授权令牌等操作
private Activity mActivity ;
private Activity mActivity ;
// 应用上下文
private Context mContext ;
private Context mContext ;
// 用于操作内容提供器,进行数据查询、更新等操作
private ContentResolver mContentResolver ;
private ContentResolver mContentResolver ;
// 标记是否正在同步
private boolean mSyncing ;
private boolean mSyncing ;
// 标记同步是否被取消
private boolean mCancelled ;
private boolean mCancelled ;
// 存储Google Tasks任务列表的哈希表, 以任务列表的全局唯一ID( GID) 为键, 任务列表对象为值
private HashMap < String , TaskList > mGTaskListHashMap ;
private HashMap < String , TaskList > mGTaskListHashMap ;
// 存储Google Tasks节点( 任务、任务列表等) 的哈希表, 以节点的全局唯一ID( GID) 为键, 节点对象为值
private HashMap < String , Node > mGTaskHashMap ;
private HashMap < String , Node > mGTaskHashMap ;
// 存储元数据的哈希表, 以相关的全局唯一ID为键, 元数据对象为值
private HashMap < String , MetaData > mMetaHashMap ;
private HashMap < String , MetaData > mMetaHashMap ;
// 元数据对应的任务列表
private TaskList mMetaList ;
private TaskList mMetaList ;
// 存储本地已删除记录的ID集合, 用于后续清理本地数据
private HashSet < Long > mLocalDeleteIdMap ;
private HashSet < Long > mLocalDeleteIdMap ;
// 存储从Google Tasks的全局唯一ID( GID) 到本地记录ID( NID) 的映射关系
private HashMap < String , Long > mGidToNid ;
private HashMap < String , Long > mGidToNid ;
// 存储从本地记录ID( NID) 到Google Tasks的全局唯一ID( GID) 的映射关系
private HashMap < Long , String > mNidToGid ;
private HashMap < Long , String > mNidToGid ;
// 私有构造函数, 防止外部实例化
// 私有构造函数, 初始化相关成员变量
private GTaskManager ( ) {
private GTaskManager ( ) {
mSyncing = false ;
mSyncing = false ;
mCancelled = false ;
mCancelled = false ;
@ -108,12 +133,13 @@ public class GTaskManager {
return mInstance ;
return mInstance ;
}
}
// 设置 活动上下文,用于获取认证令牌
// 设置 关联的Activity上下文, 主要用于获取授权令牌等相关操作
public synchronized void setActivityContext ( Activity activity ) {
public synchronized void setActivityContext ( Activity activity ) {
// used for getting authtoken
mActivity = activity ;
mActivity = activity ;
}
}
// 同步Google任务与本地数据库
// 执行同步操作, 与Google Tasks进行数据同步
public int sync ( Context context , GTaskASyncTask asyncTask ) {
public int sync ( Context context , GTaskASyncTask asyncTask ) {
if ( mSyncing ) {
if ( mSyncing ) {
Log . d ( TAG , "Sync is in progress" ) ;
Log . d ( TAG , "Sync is in progress" ) ;
@ -123,6 +149,7 @@ public class GTaskManager {
mContentResolver = mContext . getContentResolver ( ) ;
mContentResolver = mContext . getContentResolver ( ) ;
mSyncing = true ;
mSyncing = true ;
mCancelled = false ;
mCancelled = false ;
// 清除之前同步相关的数据缓存, 如任务列表、节点、元数据等的哈希表以及ID映射关系等
mGTaskListHashMap . clear ( ) ;
mGTaskListHashMap . clear ( ) ;
mGTaskHashMap . clear ( ) ;
mGTaskHashMap . clear ( ) ;
mMetaHashMap . clear ( ) ;
mMetaHashMap . clear ( ) ;
@ -134,18 +161,18 @@ public class GTaskManager {
GTaskClient client = GTaskClient . getInstance ( ) ;
GTaskClient client = GTaskClient . getInstance ( ) ;
client . resetUpdateArray ( ) ;
client . resetUpdateArray ( ) ;
// 登录Google 任务
// 登录Google Tasks, 如果取消同步则不再进行登录操作, 如果登录失败则抛出网络异常
if ( ! mCancelled ) {
if ( ! mCancelled ) {
if ( ! client . login ( mActivity ) ) {
if ( ! client . login ( mActivity ) ) {
throw new NetworkFailureException ( "login google task failed" ) ;
throw new NetworkFailureException ( "login google task failed" ) ;
}
}
}
}
// 从Google获取任务列表
// 发布同步进度信息,初始化任务列表阶段
asyncTask . publishProgess ( mContext . getString ( R . string . sync_progress_init_list ) ) ;
asyncTask . publishProgess ( mContext . getString ( R . string . sync_progress_init_list ) ) ;
initGTaskList ( ) ;
initGTaskList ( ) ;
// 同步内容
// 发布 同步进度信息,进行 内容同步阶段
asyncTask . publishProgess ( mContext . getString ( R . string . sync_progress_syncing ) ) ;
asyncTask . publishProgess ( mContext . getString ( R . string . sync_progress_syncing ) ) ;
syncContent ( ) ;
syncContent ( ) ;
} catch ( NetworkFailureException e ) {
} catch ( NetworkFailureException e ) {
@ -159,6 +186,7 @@ public class GTaskManager {
e . printStackTrace ( ) ;
e . printStackTrace ( ) ;
return STATE_INTERNAL_ERROR ;
return STATE_INTERNAL_ERROR ;
} finally {
} finally {
// 无论同步是否成功,最终都清除同步相关的数据缓存
mGTaskListHashMap . clear ( ) ;
mGTaskListHashMap . clear ( ) ;
mGTaskHashMap . clear ( ) ;
mGTaskHashMap . clear ( ) ;
mMetaHashMap . clear ( ) ;
mMetaHashMap . clear ( ) ;
@ -171,26 +199,28 @@ public class GTaskManager {
return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS ;
return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS ;
}
}
// 初始化Google 任务列表
// 初始化Google Tasks 任务列表相关信息,包括获取任务列表、元数据列表以及加载任务等操作
private void initGTaskList ( ) throws NetworkFailureException {
private void initGTaskList ( ) throws NetworkFailureException {
if ( mCancelled )
if ( mCancelled )
return ;
return ;
GTaskClient client = GTaskClient . getInstance ( ) ;
GTaskClient client = GTaskClient . getInstance ( ) ;
try {
try {
// 从Google Tasks获取任务列表信息, 返回JSON数组形式的数据
JSONArray jsTaskLists = client . getTaskLists ( ) ;
JSONArray jsTaskLists = client . getTaskLists ( ) ;
// 初始化元数据列表
// 先 初始化元数据列表,查找名为特定前缀加上"meta"的任务列表作为 元数据列表
mMetaList = null ;
mMetaList = null ;
for ( int i = 0 ; i < jsTaskLists . length ( ) ; i + + ) {
for ( int i = 0 ; i < jsTaskLists . length ( ) ; i + + ) {
JSONObject object = jsTaskLists . getJSONObject ( i ) ;
JSONObject object = jsTaskLists . getJSONObject ( i ) ;
String gid = object . getString ( GTaskStringUtils . GTASK_JSON_ID ) ;
String gid = object . getString ( GTaskStringUtils . GTASK_JSON_ID ) ;
String name = object . getString ( GTaskStringUtils . GTASK_JSON_NAME ) ;
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 = new TaskList ( ) ;
mMetaList . setContentByRemoteJSON ( object ) ;
mMetaList . setContentByRemoteJSON ( object ) ;
// 加载元数据
// 加载元数据 ,获取元数据列表对应的任务列表中的具体元数据信息
JSONArray jsMetas = client . getTaskList ( gid ) ;
JSONArray jsMetas = client . getTaskList ( gid ) ;
for ( int j = 0 ; j < jsMetas . length ( ) ; j + + ) {
for ( int j = 0 ; j < jsMetas . length ( ) ; j + + ) {
object = ( JSONObject ) jsMetas . getJSONObject ( j ) ;
object = ( JSONObject ) jsMetas . getJSONObject ( j ) ;
@ -206,26 +236,29 @@ public class GTaskManager {
}
}
}
}
// 如果元数据列表不存在 则创建
// 如果元数据列表不存在 , 则创建一个新的元数据列表, 并发送到Google Tasks服务器创建对应的任务列表
if ( mMetaList = = null ) {
if ( mMetaList = = null ) {
mMetaList = new TaskList ( ) ;
mMetaList = new TaskList ( ) ;
mMetaList . setName ( GTaskStringUtils . MIUI_FOLDER_PREFFIX + GTaskStringUtils . FOLDER_META ) ;
mMetaList . setName ( GTaskStringUtils . MIUI_FOLDER_PREFFIX
+ GTaskStringUtils . FOLDER_META ) ;
GTaskClient . getInstance ( ) . createTaskList ( mMetaList ) ;
GTaskClient . getInstance ( ) . createTaskList ( mMetaList ) ;
}
}
// 初始化 任务列表
// 初始化 普通 任务列表,遍历获取到的任务列表信息,创建任务列表对象并加载对应的任务信息
for ( int i = 0 ; i < jsTaskLists . length ( ) ; i + + ) {
for ( int i = 0 ; i < jsTaskLists . length ( ) ; i + + ) {
JSONObject object = jsTaskLists . getJSONObject ( i ) ;
JSONObject object = jsTaskLists . getJSONObject ( i ) ;
String gid = object . getString ( GTaskStringUtils . GTASK_JSON_ID ) ;
String gid = object . getString ( GTaskStringUtils . GTASK_JSON_ID ) ;
String name = object . getString ( GTaskStringUtils . GTASK_JSON_NAME ) ;
String name = object . getString ( GTaskStringUtils . GTASK_JSON_NAME ) ;
if ( name . startsWith ( GTaskStringUtils . MIUI_FOLDER_PREFFIX ) & & ! name . equals ( GTaskStringUtils . MIUI_FOLDER_PREFFIX + GTaskStringUtils . FOLDER_META ) ) {
if ( name . startsWith ( GTaskStringUtils . MIUI_FOLDER_PREFFIX )
& & ! name . equals ( GTaskStringUtils . MIUI_FOLDER_PREFFIX
+ GTaskStringUtils . FOLDER_META ) ) {
TaskList tasklist = new TaskList ( ) ;
TaskList tasklist = new TaskList ( ) ;
tasklist . setContentByRemoteJSON ( object ) ;
tasklist . setContentByRemoteJSON ( object ) ;
mGTaskListHashMap . put ( gid , tasklist ) ;
mGTaskListHashMap . put ( gid , tasklist ) ;
mGTaskHashMap . put ( gid , tasklist ) ;
mGTaskHashMap . put ( gid , tasklist ) ;
// 加载任务
// 加载任务 ,获取当前任务列表对应的任务信息
JSONArray jsTasks = client . getTaskList ( gid ) ;
JSONArray jsTasks = client . getTaskList ( gid ) ;
for ( int j = 0 ; j < jsTasks . length ( ) ; j + + ) {
for ( int j = 0 ; j < jsTasks . length ( ) ; j + + ) {
object = ( JSONObject ) jsTasks . getJSONObject ( j ) ;
object = ( JSONObject ) jsTasks . getJSONObject ( j ) ;
@ -247,7 +280,7 @@ public class GTaskManager {
}
}
}
}
// 同步内容到Google任务或本地数据库
// 进行内容同步操作, 处理本地与Google Tasks之间的数据同步, 包括本地删除、文件夹同步、数据库中已有记录的同步等情况
private void syncContent ( ) throws NetworkFailureException {
private void syncContent ( ) throws NetworkFailureException {
int syncType ;
int syncType ;
Cursor c = null ;
Cursor c = null ;
@ -260,9 +293,12 @@ public class GTaskManager {
return ;
return ;
}
}
// 同步本地删除的笔记
// 处理本地已删除的笔记( 记录) , 查询本地回收站文件夹中的记录, 对比Google Tasks中的对应节点进行相应的同步操作
try {
try {
c = mContentResolver . query ( Notes . CONTENT_NOTE_URI , SqlNote . PROJECTION_NOTE , "(type<>? AND parent_id=?)" , new String [ ] { String . valueOf ( Notes . TYPE_SYSTEM ) , String . valueOf ( Notes . ID_TRASH_FOLER ) } , null ) ;
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 ) {
if ( c ! = null ) {
while ( c . moveToNext ( ) ) {
while ( c . moveToNext ( ) ) {
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
@ -284,12 +320,15 @@ public class GTaskManager {
}
}
}
}
// 同步文件夹
// 同步文件夹 相关信息
syncFolder ( ) ;
syncFolder ( ) ;
// 同步本地存在的笔记
// 处理数据库中已存在的笔记( 记录) , 根据其在Google Tasks中的对应情况确定同步类型, 然后进行相应的同步操作
try {
try {
c = mContentResolver . query ( Notes . CONTENT_NOTE_URI , SqlNote . PROJECTION_NOTE , "(type=? AND parent_id<>?)" , new String [ ] { String . valueOf ( Notes . TYPE_NOTE ) , String . valueOf ( Notes . ID_TRASH_FOLER ) } , NoteColumns . TYPE + " DESC" ) ;
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 ) {
if ( c ! = null ) {
while ( c . moveToNext ( ) ) {
while ( c . moveToNext ( ) ) {
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
@ -301,10 +340,10 @@ public class GTaskManager {
syncType = node . getSyncAction ( c ) ;
syncType = node . getSyncAction ( c ) ;
} else {
} else {
if ( c . getString ( SqlNote . GTASK_ID_COLUMN ) . trim ( ) . length ( ) = = 0 ) {
if ( c . getString ( SqlNote . GTASK_ID_COLUMN ) . trim ( ) . length ( ) = = 0 ) {
// 本地新增
// 本地新增 情况
syncType = Node . SYNC_ACTION_ADD_REMOTE ;
syncType = Node . SYNC_ACTION_ADD_REMOTE ;
} else {
} else {
// 远程 删除
// 远程 已 删除情况
syncType = Node . SYNC_ACTION_DEL_LOCAL ;
syncType = Node . SYNC_ACTION_DEL_LOCAL ;
}
}
}
}
@ -321,7 +360,7 @@ public class GTaskManager {
}
}
}
}
// 同步剩余的Google任务
// 处理剩余的在Google Tasks中存在但本地未处理的节点, 进行相应的同步操作( 一般是添加到本地)
Iterator < Map . Entry < String , Node > > iter = mGTaskHashMap . entrySet ( ) . iterator ( ) ;
Iterator < Map . Entry < String , Node > > iter = mGTaskHashMap . entrySet ( ) . iterator ( ) ;
while ( iter . hasNext ( ) ) {
while ( iter . hasNext ( ) ) {
Map . Entry < String , Node > entry = iter . next ( ) ;
Map . Entry < String , Node > entry = iter . next ( ) ;
@ -329,14 +368,14 @@ public class GTaskManager {
doContentSync ( Node . SYNC_ACTION_ADD_LOCAL , node , null ) ;
doContentSync ( Node . SYNC_ACTION_ADD_LOCAL , node , null ) ;
}
}
// 清除本地删除的条目
// mCancelled可能被其他线程设置, 所以需要逐个检查, 清除本地已删除记录的相关数据( 如果同步未取消)
if ( ! mCancelled ) {
if ( ! mCancelled ) {
if ( ! DataUtils . batchDeleteNotes ( mContentResolver , mLocalDeleteIdMap ) ) {
if ( ! DataUtils . batchDeleteNotes ( mContentResolver , mLocalDeleteIdMap ) ) {
throw new ActionFailureException ( "failed to batch-delete local deleted notes" ) ;
throw new ActionFailureException ( "failed to batch-delete local deleted notes" ) ;
}
}
}
}
// 刷新本地同步ID
// 刷新本地同步ID ( 如果同步未取消) , 提交更新并进行相关操作来更新本地记录的同步ID
if ( ! mCancelled ) {
if ( ! mCancelled ) {
GTaskClient . getInstance ( ) . commitUpdate ( ) ;
GTaskClient . getInstance ( ) . commitUpdate ( ) ;
refreshLocalSyncId ( ) ;
refreshLocalSyncId ( ) ;
@ -344,7 +383,7 @@ public class GTaskManager {
}
}
// 同步文件夹 到Google任务或本地数据库
// 同步文件夹 相关信息,包括根文件夹、通话记录文件夹、本地已存在的文件夹以及远程新增的文件夹等情况的处理
private void syncFolder ( ) throws NetworkFailureException {
private void syncFolder ( ) throws NetworkFailureException {
Cursor c = null ;
Cursor c = null ;
String gid ;
String gid ;
@ -355,9 +394,10 @@ public class GTaskManager {
return ;
return ;
}
}
// 同步根文件夹
// 处理根文件夹的同步情况, 根据其在Google Tasks中的对应情况进行相应的同步操作( 添加、更新等)
try {
try {
c = mContentResolver . query ( ContentUris . withAppendedId ( Notes . CONTENT_NOTE_URI , Notes . ID_ROOT_FOLDER ) , SqlNote . PROJECTION_NOTE , null , null , null ) ;
c = mContentResolver . query ( ContentUris . withAppendedId ( Notes . CONTENT_NOTE_URI ,
Notes . ID_ROOT_FOLDER ) , SqlNote . PROJECTION_NOTE , null , null , null ) ;
if ( c ! = null ) {
if ( c ! = null ) {
c . moveToNext ( ) ;
c . moveToNext ( ) ;
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
@ -366,8 +406,9 @@ public class GTaskManager {
mGTaskHashMap . remove ( gid ) ;
mGTaskHashMap . remove ( gid ) ;
mGidToNid . put ( gid , ( long ) Notes . ID_ROOT_FOLDER ) ;
mGidToNid . put ( gid , ( long ) Notes . ID_ROOT_FOLDER ) ;
mNidToGid . put ( ( long ) Notes . ID_ROOT_FOLDER , gid ) ;
mNidToGid . put ( ( long ) Notes . ID_ROOT_FOLDER , gid ) ;
// 更新远程名称(如果需要)
// 对于系统文件夹,仅在必要时更新远程名称
if ( ! node . getName ( ) . equals ( GTaskStringUtils . MIUI_FOLDER_PREFFIX + GTaskStringUtils . FOLDER_DEFAULT ) )
if ( ! node . getName ( ) . equals (
GTaskStringUtils . MIUI_FOLDER_PREFFIX + GTaskStringUtils . FOLDER_DEFAULT ) )
doContentSync ( Node . SYNC_ACTION_UPDATE_REMOTE , node , c ) ;
doContentSync ( Node . SYNC_ACTION_UPDATE_REMOTE , node , c ) ;
} else {
} else {
doContentSync ( Node . SYNC_ACTION_ADD_REMOTE , node , c ) ;
doContentSync ( Node . SYNC_ACTION_ADD_REMOTE , node , c ) ;
@ -382,68 +423,101 @@ public class GTaskManager {
}
}
}
}
// 同步通话记录文件夹
// for call-note文件夹相关的同步操作处理
// 查询通话记录文件夹在本地数据库中的信息, 根据其在Google Tasks中的对应情况进行相应的同步操作( 添加、更新等)
// 如果查询到该文件夹信息存在( 即游标c不为空且能移动到下一条记录) , 则进一步处理
try {
try {
c = mContentResolver . query ( Notes . CONTENT_NOTE_URI , SqlNote . PROJECTION_NOTE , "(_id=?)" , new String [ ] { String . valueOf ( Notes . ID_CALL_RECORD_FOLDER ) } , null ) ;
// 通过ContentResolver查询本地数据库中通话记录文件夹的记录信息, 指定查询条件为_id等于通话记录文件夹的特定ID
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 ! = null ) {
if ( c . moveToNext ( ) ) {
if ( c . moveToNext ( ) ) {
// 获取该文件夹在Google Tasks中对应的全局唯一ID( GID)
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
// 根据GID从存储Google Tasks节点的哈希表中获取对应的节点对象
node = mGTaskHashMap . get ( gid ) ;
node = mGTaskHashMap . get ( gid ) ;
if ( node ! = null ) {
if ( node ! = null ) {
// 如果节点存在,从哈希表中移除该节点(表示已处理)
mGTaskHashMap . remove ( gid ) ;
mGTaskHashMap . remove ( gid ) ;
// 在本地ID到Google Tasks的GID映射表中记录该文件夹的映射关系, 键为GID, 值为通话记录文件夹的本地ID
mGidToNid . put ( gid , ( long ) Notes . ID_CALL_RECORD_FOLDER ) ;
mGidToNid . put ( gid , ( long ) Notes . ID_CALL_RECORD_FOLDER ) ;
// 在Google Tasks的GID到本地ID映射表中记录映射关系, 键为本地ID, 值为GID
mNidToGid . put ( ( long ) Notes . ID_CALL_RECORD_FOLDER , gid ) ;
mNidToGid . put ( ( long ) Notes . ID_CALL_RECORD_FOLDER , gid ) ;
// 更新远程名称(如果需要)
// 对于系统文件夹,仅在其名称与预期的通话记录文件夹名称不一致时(即可能有更新情况),进行远程更新操作
if ( ! node . getName ( ) . equals ( GTaskStringUtils . MIUI_FOLDER_PREFFIX + GTaskStringUtils . FOLDER_CALL_NOTE ) )
if ( ! node . getName ( ) . equals (
GTaskStringUtils . MIUI_FOLDER_PREFFIX
+ GTaskStringUtils . FOLDER_CALL_NOTE ) )
doContentSync ( Node . SYNC_ACTION_UPDATE_REMOTE , node , c ) ;
doContentSync ( Node . SYNC_ACTION_UPDATE_REMOTE , node , c ) ;
} else {
} else {
// 如果节点不存在, 则执行添加远程节点的操作( 意味着本地有该文件夹记录, 但在Google Tasks中还未创建对应节点)
doContentSync ( Node . SYNC_ACTION_ADD_REMOTE , node , c ) ;
doContentSync ( Node . SYNC_ACTION_ADD_REMOTE , node , c ) ;
}
}
}
}
} else {
} else {
// 如果查询失败,打印警告日志
Log . w ( TAG , "failed to query call note folder" ) ;
Log . w ( TAG , "failed to query call note folder" ) ;
}
}
} finally {
} finally {
// 无论查询是否成功,最终都要关闭游标,释放资源,并将游标置空
if ( c ! = null ) {
if ( c ! = null ) {
c . close ( ) ;
c . close ( ) ;
c = null ;
c = null ;
}
}
}
}
// 同步本地存在的文件夹
// 处理本地已存在的文件夹的同步情况
// 查询本地除回收站外的文件夹记录信息, 根据其在Google Tasks中的对应情况进行相应的同步操作
try {
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" ) ;
// 通过ContentResolver查询本地数据库中符合条件的文件夹记录信息, 条件为类型是文件夹且父ID不等于回收站文件夹的ID
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 ) {
if ( c ! = null ) {
while ( c . moveToNext ( ) ) {
while ( c . moveToNext ( ) ) {
// 获取文件夹在Google Tasks中对应的全局唯一ID( GID)
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
// 根据GID从存储Google Tasks节点的哈希表中获取对应的节点对象
node = mGTaskHashMap . get ( gid ) ;
node = mGTaskHashMap . get ( gid ) ;
if ( node ! = null ) {
if ( node ! = null ) {
// 如果节点存在,从哈希表中移除该节点(表示已处理)
mGTaskHashMap . remove ( gid ) ;
mGTaskHashMap . remove ( gid ) ;
// 在本地ID到Google Tasks的GID映射表中记录该文件夹的映射关系, 键为GID, 值为文件夹的本地ID
mGidToNid . put ( gid , c . getLong ( SqlNote . ID_COLUMN ) ) ;
mGidToNid . put ( gid , c . getLong ( SqlNote . ID_COLUMN ) ) ;
// 在Google Tasks的GID到本地ID映射表中记录映射关系, 键为本地ID, 值为GID
mNidToGid . put ( c . getLong ( SqlNote . ID_COLUMN ) , gid ) ;
mNidToGid . put ( c . getLong ( SqlNote . ID_COLUMN ) , gid ) ;
// 获取该节点对应的同步操作类型(根据节点和游标信息判断是添加、更新、删除等哪种类型)
syncType = node . getSyncAction ( c ) ;
syncType = node . getSyncAction ( c ) ;
} else {
} else {
// 如果节点不存在, 根据其GID是否为空字符串判断是本地新增还是远程删除情况, 进而确定同步类型
if ( c . getString ( SqlNote . GTASK_ID_COLUMN ) . trim ( ) . length ( ) = = 0 ) {
if ( c . getString ( SqlNote . GTASK_ID_COLUMN ) . trim ( ) . length ( ) = = 0 ) {
// 本地新增
// 本地新增 情况,同步类型设置为添加远程节点
syncType = Node . SYNC_ACTION_ADD_REMOTE ;
syncType = Node . SYNC_ACTION_ADD_REMOTE ;
} else {
} else {
// 远程删除
// 远程删除 情况,同步类型设置为删除本地节点
syncType = Node . SYNC_ACTION_DEL_LOCAL ;
syncType = Node . SYNC_ACTION_DEL_LOCAL ;
}
}
}
}
// 根据确定的同步类型执行相应的内容同步操作
doContentSync ( syncType , node , c ) ;
doContentSync ( syncType , node , c ) ;
}
}
} else {
} else {
// 如果查询失败,打印警告日志
Log . w ( TAG , "failed to query existing folder" ) ;
Log . w ( TAG , "failed to query existing folder" ) ;
}
}
} finally {
} finally {
// 无论查询是否成功,最终都要关闭游标,释放资源,并将游标置空
if ( c ! = null ) {
if ( c ! = null ) {
c . close ( ) ;
c . close ( ) ;
c = null ;
c = null ;
}
}
}
}
// 同步远程新增的文件夹
// 处理远程新增文件夹的同步情况
// 遍历存储Google Tasks任务列表的哈希表, 对于在Google
// Tasks中存在但本地未处理( 还在mGTaskHashMap中) 的文件夹, 进行添加本地节点的同步操作
Iterator < Map . Entry < String , TaskList > > iter = mGTaskListHashMap . entrySet ( ) . iterator ( ) ;
Iterator < Map . Entry < String , TaskList > > iter = mGTaskListHashMap . entrySet ( ) . iterator ( ) ;
while ( iter . hasNext ( ) ) {
while ( iter . hasNext ( ) ) {
Map . Entry < String , TaskList > entry = iter . next ( ) ;
Map . Entry < String , TaskList > entry = iter . next ( ) ;
@ -455,11 +529,12 @@ public class GTaskManager {
}
}
}
}
// 如果同步未被取消, 提交Google Tasks客户端的更新操作( 将之前暂存的更新操作发送到服务器执行)
if ( ! mCancelled )
if ( ! mCancelled )
GTaskClient . getInstance ( ) . commitUpdate ( ) ;
GTaskClient . getInstance ( ) . commitUpdate ( ) ;
}
}
// 执行内容同步操作
// 根据给定的同步类型 执行具体的 内容同步操作
private void doContentSync ( int syncType , Node node , Cursor c ) throws NetworkFailureException {
private void doContentSync ( int syncType , Node node , Cursor c ) throws NetworkFailureException {
if ( mCancelled ) {
if ( mCancelled ) {
return ;
return ;
@ -467,12 +542,16 @@ public class GTaskManager {
MetaData meta ;
MetaData meta ;
switch ( syncType ) {
switch ( syncType ) {
// 同步类型为添加本地节点,调用相应方法进行本地节点添加操作
case Node . SYNC_ACTION_ADD_LOCAL :
case Node . SYNC_ACTION_ADD_LOCAL :
addLocalNode ( node ) ;
addLocalNode ( node ) ;
break ;
break ;
// 同步类型为添加远程节点,调用相应方法进行远程节点添加操作,并传入节点和游标信息
case Node . SYNC_ACTION_ADD_REMOTE :
case Node . SYNC_ACTION_ADD_REMOTE :
addRemoteNode ( node , c ) ;
addRemoteNode ( node , c ) ;
break ;
break ;
// 同步类型为删除本地节点, 先从元数据哈希表中获取对应的元数据, 若存在则调用Google Tasks客户端删除该元数据节点,
// 同时将本地记录的ID添加到本地已删除记录集合中
case Node . SYNC_ACTION_DEL_LOCAL :
case Node . SYNC_ACTION_DEL_LOCAL :
meta = mMetaHashMap . get ( c . getString ( SqlNote . GTASK_ID_COLUMN ) ) ;
meta = mMetaHashMap . get ( c . getString ( SqlNote . GTASK_ID_COLUMN ) ) ;
if ( meta ! = null ) {
if ( meta ! = null ) {
@ -480,6 +559,8 @@ public class GTaskManager {
}
}
mLocalDeleteIdMap . add ( c . getLong ( SqlNote . ID_COLUMN ) ) ;
mLocalDeleteIdMap . add ( c . getLong ( SqlNote . ID_COLUMN ) ) ;
break ;
break ;
// 同步类型为删除远程节点, 先从元数据哈希表中获取对应节点的元数据, 若存在则调用Google Tasks客户端删除该元数据节点,
// 然后再删除该节点本身
case Node . SYNC_ACTION_DEL_REMOTE :
case Node . SYNC_ACTION_DEL_REMOTE :
meta = mMetaHashMap . get ( node . getGid ( ) ) ;
meta = mMetaHashMap . get ( node . getGid ( ) ) ;
if ( meta ! = null ) {
if ( meta ! = null ) {
@ -487,65 +568,84 @@ public class GTaskManager {
}
}
GTaskClient . getInstance ( ) . deleteNode ( node ) ;
GTaskClient . getInstance ( ) . deleteNode ( node ) ;
break ;
break ;
// 同步类型为更新本地节点,调用相应方法进行本地节点更新操作,并传入节点和游标信息
case Node . SYNC_ACTION_UPDATE_LOCAL :
case Node . SYNC_ACTION_UPDATE_LOCAL :
updateLocalNode ( node , c ) ;
updateLocalNode ( node , c ) ;
break ;
break ;
// 同步类型为更新远程节点,调用相应方法进行远程节点更新操作,并传入节点和游标信息
case Node . SYNC_ACTION_UPDATE_REMOTE :
case Node . SYNC_ACTION_UPDATE_REMOTE :
updateRemoteNode ( node , c ) ;
updateRemoteNode ( node , c ) ;
break ;
break ;
// 同步类型为更新冲突,目前简单采用本地更新的方式(可能后续可以考虑合并修改等更好的处理方式),调用远程节点更新方法
case Node . SYNC_ACTION_UPDATE_CONFLICT :
case Node . SYNC_ACTION_UPDATE_CONFLICT :
// 合并修改可能是更好的做法
// merging both modifications maybe a good idea
// 目前我们简单地使用本地更新
// right now just use local update simply
updateRemoteNode ( node , c ) ;
updateRemoteNode ( node , c ) ;
break ;
break ;
// 同步类型为无操作,直接跳过不做任何处理
case Node . SYNC_ACTION_NONE :
case Node . SYNC_ACTION_NONE :
break ;
break ;
// 同步类型为错误或其他未知类型,抛出操作失败异常,表示遇到了未知的同步操作类型
case Node . SYNC_ACTION_ERROR :
case Node . SYNC_ACTION_ERROR :
default :
default :
throw new ActionFailureException ( "unkown sync action type" ) ;
throw new ActionFailureException ( "unkown sync action type" ) ;
}
}
}
}
// 在本地添加Google任务节点
// 添加本地节点的操作方法
private void addLocalNode ( Node node ) throws NetworkFailureException {
private void addLocalNode ( Node node ) throws NetworkFailureException {
if ( mCancelled ) {
if ( mCancelled ) {
return ;
return ;
}
}
SqlNote sqlNote ;
SqlNote sqlNote ;
// 如果节点是任务列表类型( TaskList)
if ( node instanceof TaskList ) {
if ( node instanceof TaskList ) {
if ( node . getName ( ) . equals ( GTaskStringUtils . MIUI_FOLDER_PREFFIX + GTaskStringUtils . FOLDER_DEFAULT ) ) {
// 如果节点名称是默认根文件夹的名称, 创建一个对应根文件夹的SqlNote对象, 传入上下文和根文件夹的本地ID
if ( node . getName ( ) . equals (
GTaskStringUtils . MIUI_FOLDER_PREFFIX + GTaskStringUtils . FOLDER_DEFAULT ) ) {
sqlNote = new SqlNote ( mContext , Notes . ID_ROOT_FOLDER ) ;
sqlNote = new SqlNote ( mContext , Notes . ID_ROOT_FOLDER ) ;
} else if ( node . getName ( ) . equals ( GTaskStringUtils . MIUI_FOLDER_PREFFIX + GTaskStringUtils . FOLDER_CALL_NOTE ) ) {
} else if ( node . getName ( ) . equals (
GTaskStringUtils . MIUI_FOLDER_PREFFIX + GTaskStringUtils . FOLDER_CALL_NOTE ) ) {
// 如果节点名称是通话记录文件夹的名称, 创建一个对应通话记录文件夹的SqlNote对象, 传入上下文和通话记录文件夹的本地ID
sqlNote = new SqlNote ( mContext , Notes . ID_CALL_RECORD_FOLDER ) ;
sqlNote = new SqlNote ( mContext , Notes . ID_CALL_RECORD_FOLDER ) ;
} else {
} else {
// 其他普通任务列表情况, 创建一个新的SqlNote对象, 传入上下文
sqlNote = new SqlNote ( mContext ) ;
sqlNote = new SqlNote ( mContext ) ;
// 设置SqlNote的内容为节点的本地JSON格式内容( 从节点获取)
sqlNote . setContent ( node . getLocalJSONFromContent ( ) ) ;
sqlNote . setContent ( node . getLocalJSONFromContent ( ) ) ;
// 设置父ID为根文件夹的本地ID
sqlNote . setParentId ( Notes . ID_ROOT_FOLDER ) ;
sqlNote . setParentId ( Notes . ID_ROOT_FOLDER ) ;
}
}
} else {
} else {
// 如果节点是普通任务( Task) 类型, 创建一个新的SqlNote对象, 传入上下文
sqlNote = new SqlNote ( mContext ) ;
sqlNote = new SqlNote ( mContext ) ;
JSONObject js = node . getLocalJSONFromContent ( ) ;
JSONObject js = node . getLocalJSONFromContent ( ) ;
try {
try {
// 如果节点的本地JSON数据中包含特定的笔记头部信息( META_HEAD_NOTE)
if ( js . has ( GTaskStringUtils . META_HEAD_NOTE ) ) {
if ( js . has ( GTaskStringUtils . META_HEAD_NOTE ) ) {
JSONObject note = js . getJSONObject ( GTaskStringUtils . META_HEAD_NOTE ) ;
JSONObject note = js . getJSONObject ( GTaskStringUtils . META_HEAD_NOTE ) ;
if ( note . has ( NoteColumns . ID ) ) {
if ( note . has ( NoteColumns . ID ) ) {
long id = note . getLong ( NoteColumns . ID ) ;
long id = note . getLong ( NoteColumns . ID ) ;
// 检查该笔记ID在本地笔记数据库中是否已存在, 如果存在则移除该ID( 可能需要重新生成新的ID)
if ( DataUtils . existInNoteDatabase ( mContentResolver , id ) ) {
if ( DataUtils . existInNoteDatabase ( mContentResolver , id ) ) {
// ID不可用, 必须创建一个新的
// the id is not available, have to create a new one
note . remove ( NoteColumns . ID ) ;
note . remove ( NoteColumns . ID ) ;
}
}
}
}
}
}
// 如果节点的本地JSON数据中包含特定的数据头部信息( META_HEAD_DATA)
if ( js . has ( GTaskStringUtils . META_HEAD_DATA ) ) {
if ( js . has ( GTaskStringUtils . META_HEAD_DATA ) ) {
JSONArray dataArray = js . getJSONArray ( GTaskStringUtils . META_HEAD_DATA ) ;
JSONArray dataArray = js . getJSONArray ( GTaskStringUtils . META_HEAD_DATA ) ;
for ( int i = 0 ; i < dataArray . length ( ) ; i + + ) {
for ( int i = 0 ; i < dataArray . length ( ) ; i + + ) {
JSONObject data = dataArray . getJSONObject ( i ) ;
JSONObject data = dataArray . getJSONObject ( i ) ;
if ( data . has ( DataColumns . ID ) ) {
if ( data . has ( DataColumns . ID ) ) {
long dataId = data . getLong ( DataColumns . ID ) ;
long dataId = data . getLong ( DataColumns . ID ) ;
// 检查该数据ID在本地数据数据库中是否已存在, 如果存在则移除该ID( 可能需要重新生成新的ID)
if ( DataUtils . existInDataDatabase ( mContentResolver , dataId ) ) {
if ( DataUtils . existInDataDatabase ( mContentResolver , dataId ) ) {
// Data ID不可用, 必须创建一个新的
// the data id is not available, have to create
// a new one
data . remove ( DataColumns . ID ) ;
data . remove ( DataColumns . ID ) ;
}
}
}
}
@ -556,52 +656,61 @@ public class GTaskManager {
Log . w ( TAG , e . toString ( ) ) ;
Log . w ( TAG , e . toString ( ) ) ;
e . printStackTrace ( ) ;
e . printStackTrace ( ) ;
}
}
// 设置SqlNote的内容为处理后的JSON数据
sqlNote . setContent ( js ) ;
sqlNote . setContent ( js ) ;
// 获取任务节点的父节点在本地ID到Google Tasks的GID映射表中的对应父ID, 如果不存在则抛出异常表示找不到本地父ID
Long parentId = mGidToNid . get ( ( ( Task ) node ) . getParent ( ) . getGid ( ) ) ;
Long parentId = mGidToNid . get ( ( ( Task ) node ) . getParent ( ) . getGid ( ) ) ;
if ( parentId = = null ) {
if ( parentId = = null ) {
Log . e ( TAG , "cannot find task's parent id locally" ) ;
Log . e ( TAG , "cannot find task's parent id locally" ) ;
throw new ActionFailureException ( "cannot add local node" ) ;
throw new ActionFailureException ( "cannot add local node" ) ;
}
}
// 设置SqlNote的父ID为获取到的父节点的本地ID
sqlNote . setParentId ( parentId . longValue ( ) ) ;
sqlNote . setParentId ( parentId . longValue ( ) ) ;
}
}
// 创建本地节点
// 设置SqlNote的Google Tasks全局唯一ID( GID) 为节点的GID
sqlNote . setGtaskId ( node . getGid ( ) ) ;
sqlNote . setGtaskId ( node . getGid ( ) ) ;
// 将SqlNote对象提交保存到本地数据库( 传入参数false可能表示不触发某些额外的相关操作)
sqlNote . commit ( false ) ;
sqlNote . commit ( false ) ;
// 更新GID-NID映射
// 在本地ID到Google Tasks的GID映射表中记录该节点的映射关系, 键为节点的GID, 值为SqlNote的本地ID
mGidToNid . put ( node . getGid ( ) , sqlNote . getId ( ) ) ;
mGidToNid . put ( node . getGid ( ) , sqlNote . getId ( ) ) ;
// 在Google Tasks的GID到本地ID映射表中记录映射关系, 键为SqlNote的本地ID, 值为节点的GID
mNidToGid . put ( sqlNote . getId ( ) , node . getGid ( ) ) ;
mNidToGid . put ( sqlNote . getId ( ) , node . getGid ( ) ) ;
// 更新 元数据
// 更新 远程 元数据, 传入节点的GID和对应的SqlNote对象
updateRemoteMeta ( node . getGid ( ) , sqlNote ) ;
updateRemoteMeta ( node . getGid ( ) , sqlNote ) ;
}
}
// 更新本地 Google任务 节点
// 更新本地 节点的操作方法
private void updateLocalNode ( Node node , Cursor c ) throws NetworkFailureException {
private void updateLocalNode ( Node node , Cursor c ) throws NetworkFailureException {
if ( mCancelled ) {
if ( mCancelled ) {
return ;
return ;
}
}
SqlNote sqlNote ;
SqlNote sqlNote ;
// 更新本地笔记
// 根据传入的上下文和游标信息创建一个新的SqlNote对象, 用于更新本地节点信息
sqlNote = new SqlNote ( mContext , c ) ;
sqlNote = new SqlNote ( mContext , c ) ;
// 设置SqlNote的内容为节点的本地JSON格式内容( 从节点获取)
sqlNote . setContent ( node . getLocalJSONFromContent ( ) ) ;
sqlNote . setContent ( node . getLocalJSONFromContent ( ) ) ;
Long parentId = ( node instanceof Task ) ? mGidToNid . get ( ( ( Task ) node ) . getParent ( ) . getGid ( ) ) : new Long ( Notes . ID_ROOT_FOLDER ) ;
Long parentId = ( node instanceof Task ) ? mGidToNid . get ( ( ( Task ) node ) . getParent ( ) . getGid ( ) )
: new Long ( Notes . ID_ROOT_FOLDER ) ;
if ( parentId = = null ) {
if ( parentId = = null ) {
Log . e ( TAG , "cannot find task's parent id locally" ) ;
Log . e ( TAG , "cannot find task's parent id locally" ) ;
throw new ActionFailureException ( "cannot update local node" ) ;
throw new ActionFailureException ( "cannot update local node" ) ;
}
}
// 设置SqlNote的父ID为获取到的父节点的本地ID
sqlNote . setParentId ( parentId . longValue ( ) ) ;
sqlNote . setParentId ( parentId . longValue ( ) ) ;
// 将更新后的SqlNote对象提交保存到本地数据库( 传入参数true可能表示触发某些额外的相关操作)
sqlNote . commit ( true ) ;
sqlNote . commit ( true ) ;
// 更新 元数据信息
// 更新 远程元数据, 传入节点的GID和对应的SqlNote对象
updateRemoteMeta ( node . getGid ( ) , sqlNote ) ;
updateRemoteMeta ( node . getGid ( ) , sqlNote ) ;
}
}
// 在Google任务中添加新的节点
// 添加远程节点的操作方法
private void addRemoteNode ( Node node , Cursor c ) throws NetworkFailureException {
private void addRemoteNode ( Node node , Cursor c ) throws NetworkFailureException {
if ( mCancelled ) {
if ( mCancelled ) {
return ;
return ;
@ -610,9 +719,10 @@ public class GTaskManager {
SqlNote sqlNote = new SqlNote ( mContext , c ) ;
SqlNote sqlNote = new SqlNote ( mContext , c ) ;
Node n ;
Node n ;
// 远程更新
// 如果SqlNote对应的是笔记类型( 即普通任务)
if ( sqlNote . isNoteType ( ) ) {
if ( sqlNote . isNoteType ( ) ) {
Task task = new Task ( ) ;
Task task = new Task ( ) ;
// 设置任务的内容为从本地SqlNote获取的JSON格式内容
task . setContentByLocalJSON ( sqlNote . getContent ( ) ) ;
task . setContentByLocalJSON ( sqlNote . getContent ( ) ) ;
String parentGid = mNidToGid . get ( sqlNote . getParentId ( ) ) ;
String parentGid = mNidToGid . get ( sqlNote . getParentId ( ) ) ;
@ -620,17 +730,20 @@ public class GTaskManager {
Log . e ( TAG , "cannot find task's parent tasklist" ) ;
Log . e ( TAG , "cannot find task's parent tasklist" ) ;
throw new ActionFailureException ( "cannot add remote task" ) ;
throw new ActionFailureException ( "cannot add remote task" ) ;
}
}
// 将任务添加到对应的父任务列表中( 通过本地ID到Google Tasks的GID映射表找到父任务列表)
mGTaskListHashMap . get ( parentGid ) . addChildTask ( task ) ;
mGTaskListHashMap . get ( parentGid ) . addChildTask ( task ) ;
// 通过Google Tasks客户端创建该任务( 发送到服务器创建对应的任务节点)
GTaskClient . getInstance ( ) . createTask ( task ) ;
GTaskClient . getInstance ( ) . createTask ( task ) ;
n = ( Node ) task ;
n = ( Node ) task ;
// 添加元数据
// 更新远程元数据, 传入任务的GID和对应的SqlNote对象
updateRemoteMeta ( task . getGid ( ) , sqlNote ) ;
updateRemoteMeta ( task . getGid ( ) , sqlNote ) ;
} else {
} else {
TaskList tasklist = null ;
TaskList tasklist = null ;
// 如果文件夹已经存在则跳过
// 构建文件夹名称, 先添加特定的前缀, 然后根据SqlNote的本地ID判断是否是根文件夹或通话记录文件夹, 添加相应的后缀名称,
// 否则添加SqlNote的摘要信息作为后缀
String folderName = GTaskStringUtils . MIUI_FOLDER_PREFFIX ;
String folderName = GTaskStringUtils . MIUI_FOLDER_PREFFIX ;
if ( sqlNote . getId ( ) = = Notes . ID_ROOT_FOLDER )
if ( sqlNote . getId ( ) = = Notes . ID_ROOT_FOLDER )
folderName + = GTaskStringUtils . FOLDER_DEFAULT ;
folderName + = GTaskStringUtils . FOLDER_DEFAULT ;
@ -639,131 +752,179 @@ public class GTaskManager {
else
else
folderName + = sqlNote . getSnippet ( ) ;
folderName + = sqlNote . getSnippet ( ) ;
// 遍历存储Google Tasks任务列表的哈希表( mGTaskListHashMap) 的迭代器
Iterator < Map . Entry < String , TaskList > > iter = mGTaskListHashMap . entrySet ( ) . iterator ( ) ;
Iterator < Map . Entry < String , TaskList > > iter = mGTaskListHashMap . entrySet ( ) . iterator ( ) ;
while ( iter . hasNext ( ) ) {
while ( iter . hasNext ( ) ) {
// 获取哈希表中的每一个键值对, 键是任务列表的全局唯一ID( GID) , 值是对应的任务列表对象( TaskList)
Map . Entry < String , TaskList > entry = iter . next ( ) ;
Map . Entry < String , TaskList > entry = iter . next ( ) ;
String gid = entry . getKey ( ) ;
String gid = entry . getKey ( ) ;
TaskList list = entry . getValue ( ) ;
TaskList list = entry . getValue ( ) ;
// 判断当前任务列表的名称是否与之前构建的文件夹名称( folderName) 相等
if ( list . getName ( ) . equals ( folderName ) ) {
if ( list . getName ( ) . equals ( folderName ) ) {
// 如果相等, 说明找到了对应的任务列表, 将其赋值给tasklist变量
tasklist = list ;
tasklist = list ;
// 如果在存储Google Tasks节点的哈希表( mGTaskHashMap) 中包含该任务列表的GID, 说明已经处理过, 将其移除
if ( mGTaskHashMap . containsKey ( gid ) ) {
if ( mGTaskHashMap . containsKey ( gid ) ) {
mGTaskHashMap . remove ( gid ) ;
mGTaskHashMap . remove ( gid ) ;
}
}
// 找到匹配的任务列表后就可以结束循环了
break ;
break ;
}
}
}
}
// 如果 没有匹配项则可以添加
// 如果 经过上述查找没有找到匹配的任务列表( tasklist仍为null) , 则创建一个新的任务列表对象
if ( tasklist = = null ) {
if ( tasklist = = null ) {
tasklist = new TaskList ( ) ;
tasklist = new TaskList ( ) ;
// 设置新任务列表的内容为从本地SqlNote获取的JSON格式内容
tasklist . setContentByLocalJSON ( sqlNote . getContent ( ) ) ;
tasklist . setContentByLocalJSON ( sqlNote . getContent ( ) ) ;
// 通过Google Tasks客户端创建该任务列表( 发送到服务器创建对应的任务列表节点)
GTaskClient . getInstance ( ) . createTaskList ( tasklist ) ;
GTaskClient . getInstance ( ) . createTaskList ( tasklist ) ;
// 将新创建的任务列表添加到存储Google Tasks任务列表的哈希表中, 键为任务列表的GID, 值为任务列表对象
mGTaskListHashMap . put ( tasklist . getGid ( ) , tasklist ) ;
mGTaskListHashMap . put ( tasklist . getGid ( ) , tasklist ) ;
}
}
// 将创建或找到的任务列表对象转换为Node类型并赋值给n( 因为Node是更通用的节点类型, TaskList是一种特殊的Node)
n = ( Node ) tasklist ;
n = ( Node ) tasklist ;
}
}
// 更新本地笔记
// 更新本地笔记相关信息
// 设置本地SqlNote的Google Tasks全局唯一ID( GID) 为n的GID, 即与远程任务列表或任务对应的GID保持一致
sqlNote . setGtaskId ( n . getGid ( ) ) ;
sqlNote . setGtaskId ( n . getGid ( ) ) ;
// 将SqlNote对象提交保存到本地数据库( 传入参数false可能表示不触发某些额外的相关操作, 此处用于保存基本的关联信息等)
sqlNote . commit ( false ) ;
sqlNote . commit ( false ) ;
// 重置本地修改标志(可能表示将本地记录标记为已与远程同步,不再是本地修改状态)
sqlNote . resetLocalModified ( ) ;
sqlNote . resetLocalModified ( ) ;
// 再次提交保存SqlNote对象到本地数据库( 传入参数true可能表示触发一些更新相关的额外操作, 确保修改标志等信息更新成功)
sqlNote . commit ( true ) ;
sqlNote . commit ( true ) ;
// GID-ID映射
// gid-id映射更新
// 在本地ID到Google Tasks的GID映射表( mGidToNid) 中记录该节点( n) 的映射关系, 键为节点的GID, 值为SqlNote的本地ID
mGidToNid . put ( n . getGid ( ) , sqlNote . getId ( ) ) ;
mGidToNid . put ( n . getGid ( ) , sqlNote . getId ( ) ) ;
// 在Google Tasks的GID到本地ID映射表( mNidToGid) 中记录映射关系, 键为SqlNote的本地ID, 值为节点的GID
mNidToGid . put ( sqlNote . getId ( ) , n . getGid ( ) ) ;
mNidToGid . put ( sqlNote . getId ( ) , n . getGid ( ) ) ;
}
}
// 在Google任务中 更新节点
// 更新远程 节点的操作方法
private void updateRemoteNode ( Node node , Cursor c ) throws NetworkFailureException {
private void updateRemoteNode ( Node node , Cursor c ) throws NetworkFailureException {
if ( mCancelled ) {
if ( mCancelled ) {
return ;
return ;
}
}
// 根据传入的上下文和游标信息创建一个新的SqlNote对象, 用于后续操作
SqlNote sqlNote = new SqlNote ( mContext , c ) ;
SqlNote sqlNote = new SqlNote ( mContext , c ) ;
// 远程更新
// 远程更新操作
// 设置远程节点( node) 的内容为从本地SqlNote获取的JSON格式内容, 即将本地修改同步到远程节点
node . setContentByLocalJSON ( sqlNote . getContent ( ) ) ;
node . setContentByLocalJSON ( sqlNote . getContent ( ) ) ;
// 通过Google Tasks客户端将更新后的节点添加到更新队列中( 后续会批量提交更新到服务器)
GTaskClient . getInstance ( ) . addUpdateNode ( node ) ;
GTaskClient . getInstance ( ) . addUpdateNode ( node ) ;
// 更新 元数据
// 更新 远程 元数据, 传入节点的GID和对应的SqlNote对象
updateRemoteMeta ( node . getGid ( ) , sqlNote ) ;
updateRemoteMeta ( node . getGid ( ) , sqlNote ) ;
// 如果 需要移动任务
// 如果 SqlNote对应的是笔记类型( 即普通任务) , 则可能需要处理任务移动相关操作
if ( sqlNote . isNoteType ( ) ) {
if ( sqlNote . isNoteType ( ) ) {
Task task = ( Task ) node ;
Task task = ( Task ) node ;
// 获取任务当前的父任务列表
TaskList preParentList = task . getParent ( ) ;
TaskList preParentList = task . getParent ( ) ;
// 通过本地ID到Google Tasks的GID映射表, 根据本地记录的父ID获取当前任务在远程对应的父任务列表的GID
String curParentGid = mNidToGid . get ( sqlNote . getParentId ( ) ) ;
String curParentGid = mNidToGid . get ( sqlNote . getParentId ( ) ) ;
if ( curParentGid = = null ) {
if ( curParentGid = = null ) {
Log . e ( TAG , "cannot find task's parent tasklist" ) ;
Log . e ( TAG , "cannot find task's parent tasklist" ) ;
throw new ActionFailureException ( "cannot update remote task" ) ;
throw new ActionFailureException ( "cannot update remote task" ) ;
}
}
// 根据获取到的GID从存储Google Tasks任务列表的哈希表中获取当前任务在远程对应的父任务列表对象
TaskList curParentList = mGTaskListHashMap . get ( curParentGid ) ;
TaskList curParentList = mGTaskListHashMap . get ( curParentGid ) ;
// 如果当前任务的前后父任务列表不一致,说明任务需要在远程进行移动操作
if ( preParentList ! = curParentList ) {
if ( preParentList ! = curParentList ) {
// 先从原父任务列表中移除该任务
preParentList . removeChildTask ( task ) ;
preParentList . removeChildTask ( task ) ;
// 将任务添加到新的父任务列表中
curParentList . addChildTask ( task ) ;
curParentList . addChildTask ( task ) ;
// 通过Google Tasks客户端执行任务移动操作, 告知服务器任务在远程的位置变更
GTaskClient . getInstance ( ) . moveTask ( task , preParentList , curParentList ) ;
GTaskClient . getInstance ( ) . moveTask ( task , preParentList , curParentList ) ;
}
}
}
}
// 清除本地修改标志
// 清除本地修改标志 ,标记本地记录已同步到远程,不再处于本地修改状态
sqlNote . resetLocalModified ( ) ;
sqlNote . resetLocalModified ( ) ;
// 将更新后的SqlNote对象提交保存到本地数据库( 传入参数true可能表示触发一些更新相关的额外操作, 确保修改标志等信息更新成功)
sqlNote . commit ( true ) ;
sqlNote . commit ( true ) ;
}
}
// 更新 Google任务中的元数据
// 更新 远程元数据的操作方法
private void updateRemoteMeta ( String gid , SqlNote sqlNote ) throws NetworkFailureException {
private void updateRemoteMeta ( String gid , SqlNote sqlNote ) throws NetworkFailureException {
if ( sqlNote ! = null & & sqlNote . isNoteType ( ) ) {
if ( sqlNote ! = null & & sqlNote . isNoteType ( ) ) {
// 从存储元数据的哈希表( mMetaHashMap) 中根据GID获取对应的元数据对象( MetaData)
MetaData metaData = mMetaHashMap . get ( gid ) ;
MetaData metaData = mMetaHashMap . get ( gid ) ;
if ( metaData ! = null ) {
if ( metaData ! = null ) {
// 如果元数据对象存在, 设置其元数据内容, 传入GID和从本地SqlNote获取的JSON格式内容
metaData . setMeta ( gid , sqlNote . getContent ( ) ) ;
metaData . setMeta ( gid , sqlNote . getContent ( ) ) ;
// 通过Google Tasks客户端将更新后的元数据添加到更新队列中( 后续会批量提交更新到服务器)
GTaskClient . getInstance ( ) . addUpdateNode ( metaData ) ;
GTaskClient . getInstance ( ) . addUpdateNode ( metaData ) ;
} else {
} else {
// 如果元数据对象不存在,则创建一个新的元数据对象
metaData = new MetaData ( ) ;
metaData = new MetaData ( ) ;
// 设置新元数据对象的元数据内容, 传入GID和从本地SqlNote获取的JSON格式内容
metaData . setMeta ( gid , sqlNote . getContent ( ) ) ;
metaData . setMeta ( gid , sqlNote . getContent ( ) ) ;
// 将新创建的元数据对象添加到元数据列表( mMetaList) 中作为子任务( 从逻辑上关联起来)
mMetaList . addChildTask ( metaData ) ;
mMetaList . addChildTask ( metaData ) ;
// 将新创建的元数据对象添加到存储元数据的哈希表中, 键为GID, 值为元数据对象
mMetaHashMap . put ( gid , metaData ) ;
mMetaHashMap . put ( gid , metaData ) ;
// 通过Google Tasks客户端创建该元数据任务( 发送到服务器创建对应的元数据节点)
GTaskClient . getInstance ( ) . createTask ( metaData ) ;
GTaskClient . getInstance ( ) . createTask ( metaData ) ;
}
}
}
}
}
}
// 刷新本地同步ID
// 刷新本地同步ID 的操作方法
private void refreshLocalSyncId ( ) throws NetworkFailureException {
private void refreshLocalSyncId ( ) throws NetworkFailureException {
if ( mCancelled ) {
if ( mCancelled ) {
return ;
return ;
}
}
// 获取最新的Google任务列 表
// 为了获取最新的Google Tasks列表信息, 先清空之前存储相关信息的哈希 表
mGTaskHashMap . clear ( ) ;
mGTaskHashMap . clear ( ) ;
mGTaskListHashMap . clear ( ) ;
mGTaskListHashMap . clear ( ) ;
mMetaHashMap . clear ( ) ;
mMetaHashMap . clear ( ) ;
// 重新初始化Google Tasks列表信息( 重新获取任务列表、元数据等相关内容)
initGTaskList ( ) ;
initGTaskList ( ) ;
Cursor c = null ;
Cursor c = null ;
try {
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" ) ;
// 通过ContentResolver查询本地数据库中除系统类型且不在回收站的笔记记录信息, 按照类型降序排列
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 ) {
if ( c ! = null ) {
while ( c . moveToNext ( ) ) {
while ( c . moveToNext ( ) ) {
// 获取笔记在Google Tasks中对应的全局唯一ID( GID)
String gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
String gid = c . getString ( SqlNote . GTASK_ID_COLUMN ) ;
// 根据GID从存储Google Tasks节点的哈希表中获取对应的节点对象
Node node = mGTaskHashMap . get ( gid ) ;
Node node = mGTaskHashMap . get ( gid ) ;
if ( node ! = null ) {
if ( node ! = null ) {
// 如果节点存在,从哈希表中移除该节点(表示已处理)
mGTaskHashMap . remove ( gid ) ;
mGTaskHashMap . remove ( gid ) ;
// 创建一个ContentValues对象用于存放要更新的数据, 此处将同步ID设置为节点的最后修改时间
ContentValues values = new ContentValues ( ) ;
ContentValues values = new ContentValues ( ) ;
values . put ( NoteColumns . SYNC_ID , node . getLastModified ( ) ) ;
values . put ( NoteColumns . SYNC_ID , node . getLastModified ( ) ) ;
mContentResolver . update ( ContentUris . withAppendedId ( Notes . CONTENT_NOTE_URI , c . getLong ( SqlNote . ID_COLUMN ) ) , values , null , null ) ;
// 通过ContentResolver更新本地数据库中对应笔记的记录, 设置同步ID字段的值
mContentResolver . update ( ContentUris . withAppendedId ( Notes . CONTENT_NOTE_URI ,
c . getLong ( SqlNote . ID_COLUMN ) ) , values , null , null ) ;
} else {
} else {
Log . e ( TAG , "something is missed" ) ;
Log . e ( TAG , "something is missed" ) ;
throw new ActionFailureException ( "some local items don't have gid after sync" ) ;
throw new ActionFailureException (
"some local items don't have gid after sync" ) ;
}
}
}
}
} else {
} else {
Log . w ( TAG , "failed to query local note to refresh sync id" ) ;
Log . w ( TAG , "failed to query local note to refresh sync id" ) ;
}
}
} finally {
} finally {
// 无论查询是否成功,最终都要关闭游标,释放资源,并将游标置空
if ( c ! = null ) {
if ( c ! = null ) {
c . close ( ) ;
c . close ( ) ;
c = null ;
c = null ;
@ -771,13 +932,14 @@ public class GTaskManager {
}
}
}
}
// 获取同步账户
// 获取同步账户 名称的方法, 通过Google Tasks客户端获取同步账户对象, 并返回其名称
public String getSyncAccount ( ) {
public String getSyncAccount ( ) {
return GTaskClient . getInstance ( ) . getSyncAccount ( ) . name ;
return GTaskClient . getInstance ( ) . getSyncAccount ( ) . name ;
}
}
// 取消同步
// 取消同步 的方法, 将表示同步是否取消的标志( mCancelled) 设置为true, 其他相关操作可以根据该标志来判断是否停止执行
public void cancelSync ( ) {
public void cancelSync ( ) {
mCancelled = true ;
mCancelled = true ;
}
}
}
}
> > > > > > > a495b394fa4686564cc2bfe7d054eb66276713ae