|  |  | @ -15,7 +15,7 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  |  */ |  |  |  |  */ | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | package net.micode.notes.gtask.remote; |  |  |  | package net.micode.notes.gtask.remote; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | //导入Android账户相关类
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | import android.accounts.Account; |  |  |  | import android.accounts.Account; | 
			
		
	
		
		
			
				
					
					|  |  |  | import android.accounts.AccountManager; |  |  |  | import android.accounts.AccountManager; | 
			
		
	
		
		
			
				
					
					|  |  |  | import android.accounts.AccountManagerFuture; |  |  |  | import android.accounts.AccountManagerFuture; | 
			
		
	
	
		
		
			
				
					|  |  | @ -23,7 +23,7 @@ import android.app.Activity; | 
			
		
	
		
		
			
				
					
					|  |  |  | import android.os.Bundle; |  |  |  | import android.os.Bundle; | 
			
		
	
		
		
			
				
					
					|  |  |  | import android.text.TextUtils; |  |  |  | import android.text.TextUtils; | 
			
		
	
		
		
			
				
					
					|  |  |  | import android.util.Log; |  |  |  | import android.util.Log; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | //导入自定义数据结构和工具类
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | import net.micode.notes.gtask.data.Node; |  |  |  | import net.micode.notes.gtask.data.Node; | 
			
		
	
		
		
			
				
					
					|  |  |  | import net.micode.notes.gtask.data.Task; |  |  |  | import net.micode.notes.gtask.data.Task; | 
			
		
	
		
		
			
				
					
					|  |  |  | import net.micode.notes.gtask.data.TaskList; |  |  |  | import net.micode.notes.gtask.data.TaskList; | 
			
		
	
	
		
		
			
				
					|  |  | @ -31,7 +31,7 @@ import net.micode.notes.gtask.exception.ActionFailureException; | 
			
		
	
		
		
			
				
					
					|  |  |  | import net.micode.notes.gtask.exception.NetworkFailureException; |  |  |  | import net.micode.notes.gtask.exception.NetworkFailureException; | 
			
		
	
		
		
			
				
					
					|  |  |  | import net.micode.notes.tool.GTaskStringUtils; |  |  |  | import net.micode.notes.tool.GTaskStringUtils; | 
			
		
	
		
		
			
				
					
					|  |  |  | import net.micode.notes.ui.NotesPreferenceActivity; |  |  |  | import net.micode.notes.ui.NotesPreferenceActivity; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 导入Apache HttpClient相关类
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | import org.apache.http.HttpEntity; |  |  |  | import org.apache.http.HttpEntity; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.apache.http.HttpResponse; |  |  |  | import org.apache.http.HttpResponse; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.apache.http.client.ClientProtocolException; |  |  |  | import org.apache.http.client.ClientProtocolException; | 
			
		
	
	
		
		
			
				
					|  |  | @ -46,10 +46,11 @@ import org.apache.http.params.BasicHttpParams; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.apache.http.params.HttpConnectionParams; |  |  |  | import org.apache.http.params.HttpConnectionParams; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.apache.http.params.HttpParams; |  |  |  | import org.apache.http.params.HttpParams; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.apache.http.params.HttpProtocolParams; |  |  |  | import org.apache.http.params.HttpProtocolParams; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // JSON处理类
 | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.json.JSONArray; |  |  |  | import org.json.JSONArray; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.json.JSONException; |  |  |  | import org.json.JSONException; | 
			
		
	
		
		
			
				
					
					|  |  |  | import org.json.JSONObject; |  |  |  | import org.json.JSONObject; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // Java IO相关类
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | import java.io.BufferedReader; |  |  |  | import java.io.BufferedReader; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.io.IOException; |  |  |  | import java.io.IOException; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.io.InputStream; |  |  |  | import java.io.InputStream; | 
			
		
	
	
		
		
			
				
					|  |  | @ -62,8 +63,9 @@ import java.util.zip.InflaterInputStream; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | public class GTaskClient { |  |  |  | public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   // 日志标签
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     private static final String TAG = GTaskClient.class.getSimpleName(); |  |  |  |     private static final String TAG = GTaskClient.class.getSimpleName(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |   // Google Tasks API地址
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     private static final String GTASK_URL = "https://mail.google.com/tasks/"; |  |  |  |     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_GET_URL = "https://mail.google.com/tasks/ig"; | 
			
		
	
	
		
		
			
				
					|  |  | @ -71,8 +73,8 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |     private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; |  |  |  |     private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     private static GTaskClient mInstance = null; |  |  |  |     private static GTaskClient mInstance = null; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |   // HTTP客户端和相关配置
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     private DefaultHttpClient mHttpClient; |  |  |  |     private DefaultHttpClient mHttpClient;// HTTP客户端实例
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     private String mGetUrl; |  |  |  |     private String mGetUrl; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -89,7 +91,7 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |     private Account mAccount; |  |  |  |     private Account mAccount; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     private JSONArray mUpdateArray; |  |  |  |     private JSONArray mUpdateArray; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |     // 私有构造函数
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     private GTaskClient() { |  |  |  |     private GTaskClient() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         mHttpClient = null; |  |  |  |         mHttpClient = null; | 
			
		
	
		
		
			
				
					
					|  |  |  |         mGetUrl = GTASK_GET_URL; |  |  |  |         mGetUrl = GTASK_GET_URL; | 
			
		
	
	
		
		
			
				
					|  |  | @ -101,7 +103,7 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |         mAccount = null; |  |  |  |         mAccount = null; | 
			
		
	
		
		
			
				
					
					|  |  |  |         mUpdateArray = null; |  |  |  |         mUpdateArray = null; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |     // 获取单例实例
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     public static synchronized GTaskClient getInstance() { |  |  |  |     public static synchronized GTaskClient getInstance() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (mInstance == null) { |  |  |  |         if (mInstance == null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             mInstance = new GTaskClient(); |  |  |  |             mInstance = new GTaskClient(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -112,12 +114,15 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |     public boolean login(Activity activity) { |  |  |  |     public boolean login(Activity activity) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         // we suppose that the cookie would expire after 5 minutes
 |  |  |  |         // we suppose that the cookie would expire after 5 minutes
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // then we need to re-login
 |  |  |  |         // then we need to re-login
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       // 检查登录有效期(5分钟)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         final long interval = 1000 * 60 * 5; |  |  |  |         final long interval = 1000 * 60 * 5; | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (mLastLoginTime + interval < System.currentTimeMillis()) { |  |  |  |         if (mLastLoginTime + interval < System.currentTimeMillis()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             mLoggedin = false;  |  |  |  |             mLoggedin = false;  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |        // 超时需重新登录
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // need to re-login after account switch
 |  |  |  |         // need to re-login after account switch
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       // 检查账户是否变更
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (mLoggedin |  |  |  |         if (mLoggedin | 
			
		
	
		
		
			
				
					
					|  |  |  |                 && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity |  |  |  |                 && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .getSyncAccountName(activity))) { |  |  |  |                         .getSyncAccountName(activity))) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -128,24 +133,26 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.d(TAG, "already logged in"); |  |  |  |             Log.d(TAG, "already logged in"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             return true; |  |  |  |             return true; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 更新最后登录时间
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         mLastLoginTime = System.currentTimeMillis(); |  |  |  |         mLastLoginTime = System.currentTimeMillis(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 获取Google账户授权令牌
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         String authToken = loginGoogleAccount(activity, false); |  |  |  |         String authToken = loginGoogleAccount(activity, false); | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (authToken == null) { |  |  |  |         if (authToken == null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, "login google account failed"); |  |  |  |             Log.e(TAG, "login google account failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             return false; |  |  |  |             return false; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  // 处理自定义域名账户
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | // login with custom domain if necessary
 |  |  |  | // login with custom domain if necessary
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() |  |  |  |         if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() | 
			
		
	
		
		
			
				
					
					|  |  |  |                 .endsWith("googlemail.com"))) { |  |  |  |                 .endsWith("googlemail.com"))) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 构建自定义URL路径
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); |  |  |  |             StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             int index = mAccount.name.indexOf('@') + 1; |  |  |  |             int index = mAccount.name.indexOf('@') + 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |             String suffix = mAccount.name.substring(index); |  |  |  |             String suffix = mAccount.name.substring(index); | 
			
		
	
		
		
			
				
					
					|  |  |  |             url.append(suffix + "/"); |  |  |  |             url.append(suffix + "/"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             mGetUrl = url.toString() + "ig"; |  |  |  |             mGetUrl = url.toString() + "ig"; | 
			
		
	
		
		
			
				
					
					|  |  |  |             mPostUrl = url.toString() + "r/ig"; |  |  |  |             mPostUrl = url.toString() + "r/ig"; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  // 尝试登录自定义域名
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             if (tryToLoginGtask(activity, authToken)) { |  |  |  |             if (tryToLoginGtask(activity, authToken)) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 mLoggedin = true; |  |  |  |                 mLoggedin = true; | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
	
		
		
			
				
					|  |  | @ -166,16 +173,18 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     private String loginGoogleAccount(Activity activity, boolean invalidateToken) { |  |  |  |     private String loginGoogleAccount(Activity activity, boolean invalidateToken) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         String authToken; |  |  |  |         String authToken; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 账户管理器操作
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         AccountManager accountManager = AccountManager.get(activity); |  |  |  |         AccountManager accountManager = AccountManager.get(activity); | 
			
		
	
		
		
			
				
					
					|  |  |  |         Account[] accounts = accountManager.getAccountsByType("com.google"); |  |  |  |         Account[] accounts = accountManager.getAccountsByType("com.google"); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 无可用账户检查
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         if (accounts.length == 0) { |  |  |  |         if (accounts.length == 0) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, "there is no available google account"); |  |  |  |             Log.e(TAG, "there is no available google account"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             return null; |  |  |  |             return null; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 获取配置中的同步账户
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         String accountName = NotesPreferenceActivity.getSyncAccountName(activity); |  |  |  |         String accountName = NotesPreferenceActivity.getSyncAccountName(activity); | 
			
		
	
		
		
			
				
					
					|  |  |  |         Account account = null; |  |  |  |         Account account = null; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 遍历匹配账户名称
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         for (Account a : accounts) { |  |  |  |         for (Account a : accounts) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             if (a.name.equals(accountName)) { |  |  |  |             if (a.name.equals(accountName)) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 account = a; |  |  |  |                 account = a; | 
			
		
	
	
		
		
			
				
					|  |  | @ -183,6 +192,7 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (account != null) { |  |  |  |         if (account != null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           // 设置当前账户
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             mAccount = account; |  |  |  |             mAccount = account; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } else { |  |  |  |         } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, "unable to get an account with the same name in the settings"); |  |  |  |             Log.e(TAG, "unable to get an account with the same name in the settings"); | 
			
		
	
	
		
		
			
				
					|  |  | @ -192,9 +202,11 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |         // get the token now
 |  |  |  |         // get the token now
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account, |  |  |  |         AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account, | 
			
		
	
		
		
			
				
					
					|  |  |  |                 "goanna_mobile", null, activity, null, null); |  |  |  |                 "goanna_mobile", null, activity, null, null); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 获取授权令牌
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Bundle authTokenBundle = accountManagerFuture.getResult(); |  |  |  |             Bundle authTokenBundle = accountManagerFuture.getResult(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); |  |  |  |             authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 需要失效旧令牌时重新获取 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |           if (invalidateToken) { |  |  |  |           if (invalidateToken) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 accountManager.invalidateAuthToken("com.google", authToken); |  |  |  |                 accountManager.invalidateAuthToken("com.google", authToken); | 
			
		
	
		
		
			
				
					
					|  |  |  |                 loginGoogleAccount(activity, false); |  |  |  |                 loginGoogleAccount(activity, false); | 
			
		
	
	
		
		
			
				
					|  |  | @ -208,6 +220,7 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     private boolean tryToLoginGtask(Activity activity, String authToken) { |  |  |  |     private boolean tryToLoginGtask(Activity activity, String authToken) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 首次登录尝试
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (!loginGtask(authToken)) { |  |  |  |         if (!loginGtask(authToken)) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             // maybe the auth token is out of date, now let's invalidate the
 |  |  |  |             // maybe the auth token is out of date, now let's invalidate the
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             // token and try again
 |  |  |  |             // token and try again
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -216,7 +229,7 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 Log.e(TAG, "login google account failed"); |  |  |  |                 Log.e(TAG, "login google account failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return false; |  |  |  |                 return false; | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 使用新令牌再次尝试登录
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             if (!loginGtask(authToken)) { |  |  |  |             if (!loginGtask(authToken)) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 Log.e(TAG, "login gtask failed"); |  |  |  |                 Log.e(TAG, "login gtask failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return false; |  |  |  |                 return false; | 
			
		
	
	
		
		
			
				
					|  |  | @ -226,11 +239,13 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     private boolean loginGtask(String authToken) { |  |  |  |     private boolean loginGtask(String authToken) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 设置HTTP连接参数
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         int timeoutConnection = 10000; |  |  |  |         int timeoutConnection = 10000; | 
			
		
	
		
		
			
				
					
					|  |  |  |         int timeoutSocket = 15000; |  |  |  |         int timeoutSocket = 15000; | 
			
		
	
		
		
			
				
					
					|  |  |  |         HttpParams httpParameters = new BasicHttpParams(); |  |  |  |         HttpParams httpParameters = new BasicHttpParams(); | 
			
		
	
		
		
			
				
					
					|  |  |  |         HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); |  |  |  |         HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); | 
			
		
	
		
		
			
				
					
					|  |  |  |         HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); |  |  |  |         HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 初始化HTTP客户端
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       mHttpClient = new DefaultHttpClient(httpParameters); |  |  |  |       mHttpClient = new DefaultHttpClient(httpParameters); | 
			
		
	
		
		
			
				
					
					|  |  |  |         BasicCookieStore localBasicCookieStore = new BasicCookieStore(); |  |  |  |         BasicCookieStore localBasicCookieStore = new BasicCookieStore(); | 
			
		
	
		
		
			
				
					
					|  |  |  |         mHttpClient.setCookieStore(localBasicCookieStore); |  |  |  |         mHttpClient.setCookieStore(localBasicCookieStore); | 
			
		
	
	
		
		
			
				
					|  |  | @ -238,6 +253,7 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // login gtask
 |  |  |  |         // login gtask
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 构建带认证令牌的登录URL
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             String loginUrl = mGetUrl + "?auth=" + authToken; |  |  |  |             String loginUrl = mGetUrl + "?auth=" + authToken; | 
			
		
	
		
		
			
				
					
					|  |  |  |             HttpGet httpGet = new HttpGet(loginUrl); |  |  |  |             HttpGet httpGet = new HttpGet(loginUrl); | 
			
		
	
		
		
			
				
					
					|  |  |  |             HttpResponse response = null; |  |  |  |             HttpResponse response = null; | 
			
		
	
	
		
		
			
				
					|  |  | @ -256,6 +272,7 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             // get the client version
 |  |  |  |             // get the client version
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 解析响应内容获取客户端版本
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             String resString = getResponseContent(response.getEntity()); |  |  |  |             String resString = getResponseContent(response.getEntity()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             String jsBegin = "_setup("; |  |  |  |             String jsBegin = "_setup("; | 
			
		
	
		
		
			
				
					
					|  |  |  |             String jsEnd = ")}</script>"; |  |  |  |             String jsEnd = ")}</script>"; | 
			
		
	
	
		
		
			
				
					|  |  | @ -286,6 +303,7 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     private HttpPost createHttpPost() { |  |  |  |     private HttpPost createHttpPost() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         HttpPost httpPost = new HttpPost(mPostUrl); |  |  |  |         HttpPost httpPost = new HttpPost(mPostUrl); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 设置请求头信息
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); |  |  |  |         httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         httpPost.setHeader("AT", "1"); |  |  |  |         httpPost.setHeader("AT", "1"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         return httpPost; |  |  |  |         return httpPost; | 
			
		
	
	
		
		
			
				
					|  |  | @ -299,13 +317,14 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         InputStream input = entity.getContent(); |  |  |  |         InputStream input = entity.getContent(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 处理压缩内容
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { |  |  |  |         if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             input = new GZIPInputStream(entity.getContent()); |  |  |  |             input = new GZIPInputStream(entity.getContent()); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { |  |  |  |         } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Inflater inflater = new Inflater(true); |  |  |  |             Inflater inflater = new Inflater(true); | 
			
		
	
		
		
			
				
					
					|  |  |  |             input = new InflaterInputStream(entity.getContent(), inflater); |  |  |  |             input = new InflaterInputStream(entity.getContent(), inflater); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 读取响应内容
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |             InputStreamReader isr = new InputStreamReader(input); |  |  |  |             InputStreamReader isr = new InputStreamReader(input); | 
			
		
	
		
		
			
				
					
					|  |  |  |             BufferedReader br = new BufferedReader(isr); |  |  |  |             BufferedReader br = new BufferedReader(isr); | 
			
		
	
	
		
		
			
				
					|  |  | @ -324,6 +343,7 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     private JSONObject postRequest(JSONObject js) throws NetworkFailureException { |  |  |  |     private JSONObject postRequest(JSONObject js) throws NetworkFailureException { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 登录状态检查
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (!mLoggedin) { |  |  |  |       if (!mLoggedin) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, "please login first"); |  |  |  |             Log.e(TAG, "please login first"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             throw new ActionFailureException("not logged in"); |  |  |  |             throw new ActionFailureException("not logged in"); | 
			
		
	
	
		
		
			
				
					|  |  | @ -331,11 +351,12 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         HttpPost httpPost = createHttpPost(); |  |  |  |         HttpPost httpPost = createHttpPost(); | 
			
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 构建POST参数
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>(); |  |  |  |             LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             list.add(new BasicNameValuePair("r", js.toString())); |  |  |  |             list.add(new BasicNameValuePair("r", js.toString())); | 
			
		
	
		
		
			
				
					
					|  |  |  |             UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); |  |  |  |             UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             httpPost.setEntity(entity); |  |  |  |             httpPost.setEntity(entity); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 执行请求并处理响应
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // execute the post
 |  |  |  |             // execute the post
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             HttpResponse response = mHttpClient.execute(httpPost); |  |  |  |             HttpResponse response = mHttpClient.execute(httpPost); | 
			
		
	
		
		
			
				
					
					|  |  |  |             String jsString = getResponseContent(response.getEntity()); |  |  |  |             String jsString = getResponseContent(response.getEntity()); | 
			
		
	
	
		
		
			
				
					|  |  | @ -362,23 +383,24 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     public void createTask(Task task) throws NetworkFailureException { |  |  |  |     public void createTask(Task task) throws NetworkFailureException { | 
			
		
	
		
		
			
				
					
					|  |  |  |         commitUpdate(); |  |  |  |         commitUpdate(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 提交暂存的更新
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject jsPost = new JSONObject(); |  |  |  |             JSONObject jsPost = new JSONObject(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONArray actionList = new JSONArray(); |  |  |  |             JSONArray actionList = new JSONArray(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 构建创建动作
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // action_list
 |  |  |  |             // action_list
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             actionList.put(task.getCreateAction(getActionId())); |  |  |  |             actionList.put(task.getCreateAction(getActionId())); | 
			
		
	
		
		
			
				
					
					|  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); |  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 添加客户端版本
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // client_version
 |  |  |  |             // client_version
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); |  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 发送请求并处理响应
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // post
 |  |  |  |             // post
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject jsResponse = postRequest(jsPost); |  |  |  |             JSONObject jsResponse = postRequest(jsPost); | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( |  |  |  |             JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( | 
			
		
	
		
		
			
				
					
					|  |  |  |                     GTaskStringUtils.GTASK_JSON_RESULTS).get(0); |  |  |  |                     GTaskStringUtils.GTASK_JSON_RESULTS).get(0); | 
			
		
	
		
		
			
				
					
					|  |  |  |             task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); |  |  |  |             task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 设置服务器生成ID
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         } catch (JSONException e) { |  |  |  |         } catch (JSONException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, e.toString()); |  |  |  |             Log.e(TAG, e.toString()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             e.printStackTrace(); |  |  |  |             e.printStackTrace(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -387,23 +409,23 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     public void createTaskList(TaskList tasklist) throws NetworkFailureException { |  |  |  |     public void createTaskList(TaskList tasklist) throws NetworkFailureException { | 
			
		
	
		
		
			
				
					
					|  |  |  |         commitUpdate(); |  |  |  |         commitUpdate();// 提交暂存的更新
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject jsPost = new JSONObject(); |  |  |  |             JSONObject jsPost = new JSONObject(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONArray actionList = new JSONArray(); |  |  |  |             JSONArray actionList = new JSONArray(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  // 构建创建动作
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // action_list
 |  |  |  |             // action_list
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             actionList.put(tasklist.getCreateAction(getActionId())); |  |  |  |             actionList.put(tasklist.getCreateAction(getActionId())); | 
			
		
	
		
		
			
				
					
					|  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); |  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 添加客户端版本
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // client version
 |  |  |  |             // client version
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); |  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 发送请求并处理响应
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // post
 |  |  |  |             // post
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject jsResponse = postRequest(jsPost); |  |  |  |             JSONObject jsResponse = postRequest(jsPost); | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( |  |  |  |             JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( | 
			
		
	
		
		
			
				
					
					|  |  |  |                     GTaskStringUtils.GTASK_JSON_RESULTS).get(0); |  |  |  |                     GTaskStringUtils.GTASK_JSON_RESULTS).get(0); | 
			
		
	
		
		
			
				
					
					|  |  |  |             tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); |  |  |  |             tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));// 设置服务器生成ID
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         } catch (JSONException e) { |  |  |  |         } catch (JSONException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, e.toString()); |  |  |  |             Log.e(TAG, e.toString()); | 
			
		
	
	
		
		
			
				
					|  |  | @ -411,20 +433,20 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |             throw new ActionFailureException("create tasklist: handing jsonobject failed"); |  |  |  |             throw new ActionFailureException("create tasklist: handing jsonobject failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 提交暂存的更新操作(批量执行队列中的更新)
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     public void commitUpdate() throws NetworkFailureException { |  |  |  |     public void commitUpdate() throws NetworkFailureException { | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (mUpdateArray != null) { |  |  |  |         if (mUpdateArray != null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             try { |  |  |  |             try { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 JSONObject jsPost = new JSONObject(); |  |  |  |                 JSONObject jsPost = new JSONObject(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  // 设置操作列表字段(直接使用暂存的更新数组)
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 // action_list
 |  |  |  |                 // action_list
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); |  |  |  |                 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  // 添加客户端版本号
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 // client_version
 |  |  |  |                 // client_version
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); |  |  |  |                 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 postRequest(jsPost); |  |  |  |                 postRequest(jsPost);// 发送批量更新请求
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 mUpdateArray = null; |  |  |  |                 mUpdateArray = null;// 清空更新队列
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } catch (JSONException e) { |  |  |  |             } catch (JSONException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 Log.e(TAG, e.toString()); |  |  |  |                 Log.e(TAG, e.toString()); | 
			
		
	
		
		
			
				
					
					|  |  |  |                 e.printStackTrace(); |  |  |  |                 e.printStackTrace(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -432,52 +454,58 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 向更新队列添加单个操作(自动处理批量限制)
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     public void addUpdateNode(Node node) throws NetworkFailureException { |  |  |  |     public void addUpdateNode(Node node) throws NetworkFailureException { | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (node != null) { |  |  |  |         if (node != null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             // too many update items may result in an error
 |  |  |  |             // too many update items may result in an error
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             // set max to 10 items
 |  |  |  |             // set max to 10 items
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 限制更新队列最大长度为10(超过则先提交当前队列)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             if (mUpdateArray != null && mUpdateArray.length() > 10) { |  |  |  |             if (mUpdateArray != null && mUpdateArray.length() > 10) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 commitUpdate(); |  |  |  |                 commitUpdate();// 提交当前队列// 初始化更新队列
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             if (mUpdateArray == null) |  |  |  |             if (mUpdateArray == null)// 初始化更新队列
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 mUpdateArray = new JSONArray(); |  |  |  |                 mUpdateArray = new JSONArray(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  // 添加节点的更新操作(调用Node对象生成操作JSON)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             mUpdateArray.put(node.getUpdateAction(getActionId())); |  |  |  |             mUpdateArray.put(node.getUpdateAction(getActionId())); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 移动任务到新位置(支持任务列表间移动和任务排序)
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     public void moveTask(Task task, TaskList preParent, TaskList curParent) |  |  |  |     public void moveTask(Task task, TaskList preParent, TaskList curParent) | 
			
		
	
		
		
			
				
					
					|  |  |  |             throws NetworkFailureException { |  |  |  |             throws NetworkFailureException { | 
			
		
	
		
		
			
				
					
					|  |  |  |         commitUpdate(); |  |  |  |         commitUpdate();// 先提交之前暂存的更新
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject jsPost = new JSONObject(); |  |  |  |             JSONObject jsPost = new JSONObject(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONArray actionList = new JSONArray(); |  |  |  |             JSONArray actionList = new JSONArray(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject action = new JSONObject(); |  |  |  |             JSONObject action = new JSONObject();// 创建移动操作JSON对象
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 设置操作类型为移动
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // action_list
 |  |  |  |             // action_list
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, |  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, | 
			
		
	
		
		
			
				
					
					|  |  |  |                     GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); |  |  |  |                     GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); | 
			
		
	
		
		
			
				
					
					|  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); |  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); |  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 如果在同一任务列表内移动且非第一个任务,设置前置兄弟ID(用于排序)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             if (preParent == curParent && task.getPriorSibling() != null) { |  |  |  |             if (preParent == curParent && task.getPriorSibling() != null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 // put prioring_sibing_id only if moving within the tasklist and
 |  |  |  |                 // put prioring_sibing_id only if moving within the tasklist and
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 // it is not the first one
 |  |  |  |                 // it is not the first one
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); |  |  |  |                 action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 设置源任务列表ID和目标父级ID(目标任务列表ID)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); |  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); |  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 如果跨任务列表移动,额外设置目标列表ID
 | 
			
		
	
		
		
			
				
					
					|  |  |  |           if (preParent != curParent) { |  |  |  |           if (preParent != curParent) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 // put the dest_list only if moving between tasklists
 |  |  |  |                 // put the dest_list only if moving between tasklists
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); |  |  |  |                 action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |             actionList.put(action); |  |  |  |             actionList.put(action); // 添加操作到列表
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); |  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             // client_version
 |  |  |  |             // client_version
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           // 添加客户端版本号
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); |  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             postRequest(jsPost); |  |  |  |             postRequest(jsPost);// 发送移动请求
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         } catch (JSONException e) { |  |  |  |         } catch (JSONException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, e.toString()); |  |  |  |             Log.e(TAG, e.toString()); | 
			
		
	
	
		
		
			
				
					|  |  | @ -485,18 +513,19 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |             throw new ActionFailureException("move task: handing jsonobject failed"); |  |  |  |             throw new ActionFailureException("move task: handing jsonobject failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 删除任务或任务列表(标记为删除并提交更新)
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     public void deleteNode(Node node) throws NetworkFailureException { |  |  |  |     public void deleteNode(Node node) throws NetworkFailureException { | 
			
		
	
		
		
			
				
					
					|  |  |  |         commitUpdate(); |  |  |  |         commitUpdate();// 先提交之前暂存的更新
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject jsPost = new JSONObject(); |  |  |  |             JSONObject jsPost = new JSONObject(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONArray actionList = new JSONArray(); |  |  |  |             JSONArray actionList = new JSONArray(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 标记节点为已删除
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // action_list
 |  |  |  |             // action_list
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             node.setDeleted(true); |  |  |  |             node.setDeleted(true); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           // 添加删除操作
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             actionList.put(node.getUpdateAction(getActionId())); |  |  |  |             actionList.put(node.getUpdateAction(getActionId())); | 
			
		
	
		
		
			
				
					
					|  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); |  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |           // 添加客户端版本号
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // client_version
 |  |  |  |             // client_version
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); |  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -508,18 +537,18 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |             throw new ActionFailureException("delete node: handing jsonobject failed"); |  |  |  |             throw new ActionFailureException("delete node: handing jsonobject failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  // 获取所有任务列表(从Google Tasks获取根任务列表数据)
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     public JSONArray getTaskLists() throws NetworkFailureException { |  |  |  |     public JSONArray getTaskLists() throws NetworkFailureException { | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (!mLoggedin) { |  |  |  |         if (!mLoggedin) {// 未登录检查
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, "please login first"); |  |  |  |             Log.e(TAG, "please login first"); | 
			
		
	
		
		
			
				
					
					|  |  |  |             throw new ActionFailureException("not logged in"); |  |  |  |             throw new ActionFailureException("not logged in"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |             HttpGet httpGet = new HttpGet(mGetUrl); |  |  |  |             HttpGet httpGet = new HttpGet(mGetUrl);// 创建GET请求
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             HttpResponse response = null; |  |  |  |             HttpResponse response = null; | 
			
		
	
		
		
			
				
					
					|  |  |  |             response = mHttpClient.execute(httpGet); |  |  |  |             response = mHttpClient.execute(httpGet); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 解析响应内容
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // get the task list
 |  |  |  |             // get the task list
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             String resString = getResponseContent(response.getEntity()); |  |  |  |             String resString = getResponseContent(response.getEntity()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             String jsBegin = "_setup("; |  |  |  |             String jsBegin = "_setup("; | 
			
		
	
	
		
		
			
				
					|  |  | @ -531,36 +560,40 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 jsString = resString.substring(begin + jsBegin.length(), end); |  |  |  |                 jsString = resString.substring(begin + jsBegin.length(), end); | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject js = new JSONObject(jsString); |  |  |  |             JSONObject js = new JSONObject(jsString); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // 提取任务列表数据
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); |  |  |  |             return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } catch (ClientProtocolException e) { |  |  |  |         } catch (ClientProtocolException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // HTTP协议异常
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, e.toString()); |  |  |  |             Log.e(TAG, e.toString()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             e.printStackTrace(); |  |  |  |             e.printStackTrace(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             throw new NetworkFailureException("gettasklists: httpget failed"); |  |  |  |             throw new NetworkFailureException("gettasklists: httpget failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } catch (IOException e) { |  |  |  |         } catch (IOException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  // IO异常
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, e.toString()); |  |  |  |             Log.e(TAG, e.toString()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             e.printStackTrace(); |  |  |  |             e.printStackTrace(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             throw new NetworkFailureException("gettasklists: httpget failed"); |  |  |  |             throw new NetworkFailureException("gettasklists: httpget failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } catch (JSONException e) { |  |  |  |         } catch (JSONException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // JSON解析异常
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             Log.e(TAG, e.toString()); |  |  |  |             Log.e(TAG, e.toString()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             e.printStackTrace(); |  |  |  |             e.printStackTrace(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             throw new ActionFailureException("get task lists: handing jasonobject failed"); |  |  |  |             throw new ActionFailureException("get task lists: handing jasonobject failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 获取指定任务列表中的任务(支持获取未删除任务)
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     public JSONArray getTaskList(String listGid) throws NetworkFailureException { |  |  |  |     public JSONArray getTaskList(String listGid) throws NetworkFailureException { | 
			
		
	
		
		
			
				
					
					|  |  |  |         commitUpdate(); |  |  |  |         commitUpdate(); | 
			
		
	
		
		
			
				
					
					|  |  |  |         try { |  |  |  |         try { | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject jsPost = new JSONObject(); |  |  |  |             JSONObject jsPost = new JSONObject(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONArray actionList = new JSONArray(); |  |  |  |             JSONArray actionList = new JSONArray(); | 
			
		
	
		
		
			
				
					
					|  |  |  |             JSONObject action = new JSONObject(); |  |  |  |             JSONObject action = new JSONObject(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 设置操作类型为获取所有任务
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             // action_list
 |  |  |  |             // action_list
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, |  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, | 
			
		
	
		
		
			
				
					
					|  |  |  |                     GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); |  |  |  |                     GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); | 
			
		
	
		
		
			
				
					
					|  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); |  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); | 
			
		
	
		
		
			
				
					
					|  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); |  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); | 
			
		
	
		
		
			
				
					
					|  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); |  |  |  |             action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); | 
			
		
	
		
		
			
				
					
					|  |  |  |             actionList.put(action); |  |  |  |             actionList.put(action);// 添加操作到列表
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); |  |  |  |             jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             // client_version
 |  |  |  |             // client_version
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -574,11 +607,11 @@ public class GTaskClient { | 
			
		
	
		
		
			
				
					
					|  |  |  |             throw new ActionFailureException("get task list: handing jsonobject failed"); |  |  |  |             throw new ActionFailureException("get task list: handing jsonobject failed"); | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 获取当前同步账户对象
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     public Account getSyncAccount() { |  |  |  |     public Account getSyncAccount() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         return mAccount; |  |  |  |         return mAccount; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // 重置更新队列(清空待提交的操作)
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     public void resetUpdateArray() { |  |  |  |     public void resetUpdateArray() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         mUpdateArray = null; |  |  |  |         mUpdateArray = null; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |