You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
test1/GTaskClient.java

739 lines
34 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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
*
* 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;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import net.micode.notes.gtask.data.Node;
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.GTaskStringUtils;
import net.micode.notes.ui.NotesPreferenceActivity;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
public class GTaskClient {
private static final String TAG = GTaskClient.class.getSimpleName();
private static final String GTASK_URL = "https://mail.google.com/tasks/";
private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig";
private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig";
private static GTaskClient mInstance = null;
private DefaultHttpClient mHttpClient;
private String mGetUrl;
private String mPostUrl;
private long mClientVersion;
private boolean mLoggedin;
private long mLastLoginTime;
private int mActionId;
private Account mAccount;
private JSONArray mUpdateArray;
private GTaskClient() {
mHttpClient = null;
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
mClientVersion = -1;
mLoggedin = false;
mLastLoginTime = 0;
mActionId = 1;
mAccount = null;
mUpdateArray = null;
}
public static synchronized GTaskClient getInstance() {
if (mInstance == null) {
mInstance = new GTaskClient();
}
return mInstance;
}
public boolean login(Activity activity) {
// 假设cookie在5分钟后过期之后需要重新登录
final long interval = 1000 * 60 * 5; // 5分钟的毫秒数
// 如果最后一次登录时间加上5分钟小于当前时间则认为登录已过期
if (mLastLoginTime + interval < System.currentTimeMillis()) {
mLoggedin = false; // 设置登录状态为未登录
}
// 如果已经登录但同步账号名称与当前活动Activity中设置的同步账号名称不一致则需要重新登录
if (mLoggedin
&& !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity
.getSyncAccountName(activity))) {
mLoggedin = false; // 设置登录状态为未登录
}
// 如果已经登录则直接返回true表示登录成功
if (mLoggedin) {
Log.d(TAG, "already logged in"); // 记录日志:已经登录
return true;
}
// 更新最后一次登录时间为当前时间
mLastLoginTime = System.currentTimeMillis();
// 尝试登录Google账号参数false可能表示某种模式或选项例如不使用静默登录
String authToken = loginGoogleAccount(activity, false);
// 如果获取到的authToken为空表示登录Google账号失败
if (authToken == null) {
Log.e(TAG, "login google account failed"); // 记录错误日志登录Google账号失败
return false; // 返回false表示登录失败
}
// 如果账号名称不以gmail.com或googlemail.com结尾则可能需要使用自定义域的URL进行登录
if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase()
.endsWith("googlemail.com"))) {
// 构建自定义域的URL
StringBuilder url = new StringBuilder(GTASK_URL).append("a/");
int index = mAccount.name.indexOf('@') + 1; // 找到@符号的位置并加1以获取域名部分的开始索引
String suffix = mAccount.name.substring(index); // 获取域名部分
url.append(suffix + "/"); // 拼接域名到URL
mGetUrl = url.toString() + "ig"; // 设置获取数据的URL
mPostUrl = url.toString() + "r/ig"; // 设置提交数据的URL
// 尝试使用自定义域的URL和authToken登录Google任务
if (tryToLoginGtask(activity, authToken)) {
mLoggedin = true; // 如果登录成功,设置登录状态为已登录
}
}
// 如果使用自定义域登录失败或账号是gmail/googlemail则尝试使用Google官方的URL登录
if (!mLoggedin) {
mGetUrl = GTASK_GET_URL; // 设置获取数据的官方URL
mPostUrl = GTASK_POST_URL; // 设置提交数据的官方URL
// 尝试使用官方的URL和authToken登录Google任务
if (!tryToLoginGtask(activity, authToken)) {
return false; // 如果登录失败返回false
}
}
// 无论通过哪种方式只要登录成功就设置登录状态为已登录并返回true
mLoggedin = true;
return true;
}
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
String authToken; // 声明认证令牌变量
// 获取AccountManager实例用于管理账号信息
AccountManager accountManager = AccountManager.get(activity);
// 获取设备上所有类型为"com.google"的账号
Account[] accounts = accountManager.getAccountsByType("com.google");
// 如果没有可用的Google账号则记录错误日志并返回null
if (accounts.length == 0) {
Log.e(TAG, "there is no available google account");
return null;
}
// 从设置中获取同步账号的名称
String accountName = NotesPreferenceActivity.getSyncAccountName(activity);
Account account = null;
// 遍历所有Google账号找到与设置中同步账号名称相匹配的账号
for (Account a : accounts) {
if (a.name.equals(accountName)) {
account = a;
break;
}
}
// 如果找到了匹配的账号则将其赋值给mAccount变量
if (account != null) {
mAccount = account;
} else {
// 如果没有找到匹配的账号则记录错误日志并返回null
Log.e(TAG, "unable to get an account with the same name in the settings");
return null;
}
// 通过AccountManager获取认证令牌
// 注意:"goanna_mobile"可能是一个特定于应用的scope或权限字符串它应该与你在Google API Console中配置的一致
AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account,
"goanna_mobile", null, activity, null, null);
try {
// 获取认证令牌的结果
Bundle authTokenBundle = accountManagerFuture.getResult();
// 从结果中获取认证令牌
authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
// 如果需要使令牌失效(例如,因为令牌可能已过期或不再安全)
if (invalidateToken) {
// 使指定类型的账号的认证令牌失效
// 注意这里应该使用与获取令牌时相同的accountType即"com.google"
// 但由于代码中的这个调用可能是一个错误(因为它使用了"com.google"作为scope而不是accountType
// 在实际应用中应该检查并修正这一点。正确的做法可能是使用与获取令牌时相同的scope或accountType。
// 然而,由于我们不知道"goanna_mobile"的确切含义这里我们假设它应该与getAuthToken调用中的一致。
// 但为了注释的清晰性,我们指出这里可能存在的问题。
accountManager.invalidateAuthToken("com.google", authToken);
// 递归调用loginGoogleAccount方法以获取新的令牌这次不使用invalidateToken标志
// 注意:在实际应用中,递归调用可能不是最佳做法,因为它可能导致堆栈溢出如果调用链太长。
// 一种更好的做法可能是使用循环或重新设计逻辑以避免递归。
loginGoogleAccount(activity, false);
// 注意:由于这个递归调用没有返回值,并且我们也没有在这里处理它的结果,
// 因此这个递归调用实际上对当前的authToken变量没有影响。
// 这可能是一个逻辑错误,需要根据你的应用需求进行修正。
}
} catch (Exception e) {
// 如果获取认证令牌失败则记录错误日志并将authToken设置为null
Log.e(TAG, "get auth token failed");
authToken = null;
}
// 返回认证令牌可能是null如果获取失败
return authToken;
}
// 尝试使用提供的认证令牌登录Google Tasks
private boolean tryToLoginGtask(Activity activity, String authToken) {
// 首先尝试使用传入的认证令牌登录
if (!loginGtask(authToken)) {
// 如果登录失败,可能是因为认证令牌已过期
// 因此,我们先使令牌失效,然后尝试重新获取新的认证令牌
authToken = loginGoogleAccount(activity, true); // true可能表示强制刷新令牌
if (authToken == null) {
// 如果无法获取新的认证令牌记录错误并返回false
Log.e(TAG, "login google account failed");
return false;
}
// 使用新获取的认证令牌再次尝试登录Google Tasks
if (!loginGtask(authToken)) {
// 如果仍然登录失败记录错误并返回false
Log.e(TAG, "login gtask failed");
return false;
}
}
// 如果登录成功返回true
return true;
}
// 使用提供的认证令牌登录Google Tasks
private boolean loginGtask(String authToken) {
// 设置HTTP连接的超时时间
int timeoutConnection = 10000; // 连接超时时间10秒
int timeoutSocket = 15000; // 套接字超时时间15秒
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
mHttpClient = new DefaultHttpClient(httpParameters); // 创建HTTP客户端
// 设置cookie存储
BasicCookieStore localBasicCookieStore = new BasicCookieStore();
mHttpClient.setCookieStore(localBasicCookieStore);
// 禁用“Expect/Continue”握手
HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);
// 构造登录URL并发送HTTP GET请求
try {
String loginUrl = mGetUrl + "?auth=" + authToken; // mGetUrl是Google Tasks的登录URL
HttpGet httpGet = new HttpGet(loginUrl);
HttpResponse response = mHttpClient.execute(httpGet); // 执行请求
// 检查响应中的cookie特别是包含"GTL"的cookie这是Google Tasks的认证cookie
List<Cookie> cookies = mHttpClient.getCookieStore().getCookies();
boolean hasAuthCookie = false;
for (Cookie cookie : cookies) {
if (cookie.getName().contains("GTL")) {
hasAuthCookie = true;
}
}
if (!hasAuthCookie) {
// 如果没有找到认证cookie记录警告
Log.w(TAG, "it seems that there is no auth cookie");
}
// 解析响应内容,获取客户端版本信息
String resString = getResponseContent(response.getEntity()); // 获取响应内容
String jsBegin = "_setup("; // 响应内容中JavaScript对象的开始标记
String jsEnd = ")}</script>"; // 响应内容中JavaScript对象的结束标记
int begin = resString.indexOf(jsBegin);
int end = resString.lastIndexOf(jsEnd);
String jsString = null;
if (begin != -1 && end != -1 && begin < end) {
jsString = resString.substring(begin + jsBegin.length(), end); // 提取JavaScript对象字符串
}
JSONObject js = new JSONObject(jsString); // 将字符串转换为JSON对象
mClientVersion = js.getLong("v"); // 从JSON对象中获取客户端版本信息
} catch (JSONException e) {
// 解析JSON时发生异常记录错误并返回false
Log.e(TAG, e.toString());
e.printStackTrace();
return false;
} catch (Exception e) {
// 捕获所有其他异常记录错误并返回false
Log.e(TAG, "httpget gtask_url failed");
return false;
}
// 如果一切顺利返回true
return true;
}
// 定义一个私有方法用于获取一个动作ID并且每次调用此方法时动作ID自增
private int getActionId() {
return mActionId++; // 返回当前mActionId的值然后将mActionId自增1
}
// 定义一个私有方法用于创建一个HttpPost对象
private HttpPost createHttpPost() {
HttpPost httpPost = new HttpPost(mPostUrl); // 使用成员变量mPostUrl创建一个HttpPost对象
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); // 设置Content-Type头部为表单数据格式字符集为utf-8
httpPost.setHeader("AT", "1"); // 设置AT头部为1可能是用于认证或跟踪请求的自定义头部
return httpPost; // 返回创建好的HttpPost对象
}
// 定义一个私有方法用于从HttpEntity中获取响应内容
private String getResponseContent(HttpEntity entity) throws IOException {
String contentEncoding = null; // 定义一个字符串变量,用于存储内容编码
if (entity.getContentEncoding() != null) { // 如果HttpEntity有内容编码
contentEncoding = entity.getContentEncoding().getValue(); // 获取内容编码的值
Log.d(TAG, "encoding: " + contentEncoding); // 使用Log打印出内容编码
}
InputStream input = entity.getContent(); // 从HttpEntity获取输入流
// 根据内容编码选择合适的输入流处理方式
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
input = new GZIPInputStream(entity.getContent()); // 如果是gzip编码使用GZIPInputStream解压缩
} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
Inflater inflater = new Inflater(true); // 如果是deflate编码创建一个Inflater对象
input = new InflaterInputStream(entity.getContent(), inflater); // 使用InflaterInputStream解压缩
}
try {
InputStreamReader isr = new InputStreamReader(input); // 创建InputStreamReader用于将输入流转换为字符流
BufferedReader br = new BufferedReader(isr); // 创建BufferedReader用于读取字符流
StringBuilder sb = new StringBuilder(); // 创建一个StringBuilder用于拼接读取到的字符
while (true) { // 循环读取字符流直到结束
String buff = br.readLine(); // 读取一行字符
if (buff == null) { // 如果读取到null表示已经读取到流末尾
return sb.toString(); // 返回拼接好的字符串
}
sb = sb.append(buff); // 将读取到的字符追加到StringBuilder中
}
} finally {
input.close(); // 无论是否出现异常,都关闭输入流
}
}
// 定义一个私有方法用于发送POST请求并返回JSON格式的响应
// 参数js是一个包含要发送数据的JSONObject
// 如果网络请求失败或响应无法解析为JSONObject则抛出异常
private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
// 如果未登录则记录错误日志并抛出ActionFailureException异常
if (!mLoggedin) {
Log.e(TAG, "please login first");
throw new ActionFailureException("not logged in");
}
// 创建一个HttpPost对象
HttpPost httpPost = createHttpPost();
try {
// 创建一个LinkedList来存储要发送的表单数据
LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>();
// 将JSONObject转换为字符串并添加到表单数据中
list.add(new BasicNameValuePair("r", js.toString()));
// 使用表单数据和UTF-8编码创建一个UrlEncodedFormEntity对象
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
// 将实体设置到HttpPost对象中
httpPost.setEntity(entity);
// 执行HttpPost请求
HttpResponse response = mHttpClient.execute(httpPost);
// 从响应中获取实体,并转换为字符串
String jsString = getResponseContent(response.getEntity());
// 将字符串解析为JSONObject并返回
return new JSONObject(jsString);
} catch (ClientProtocolException e) {
// 如果客户端协议异常记录错误日志打印堆栈跟踪并抛出NetworkFailureException异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("postRequest failed");
} catch (IOException e) {
// 如果IO异常记录错误日志打印堆栈跟踪并抛出NetworkFailureException异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("postRequest failed");
} catch (JSONException e) {
// 如果JSON解析异常记录错误日志打印堆栈跟踪并抛出ActionFailureException异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("unable to convert response content to jsonobject");
} catch (Exception e) {
// 如果其他异常记录错误日志打印堆栈跟踪并抛出ActionFailureException异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("error occurs when posting request");
}
}
// 定义一个公共方法,用于创建任务
// 参数task是一个Task对象包含了要创建的任务信息
// 如果网络请求失败或JSON处理失败则抛出异常
public void createTask(Task task) throws NetworkFailureException {
// 提交更新(可能是同步数据或检查状态等)
commitUpdate();
try {
// 创建一个JSONObject来存储要发送的数据
JSONObject jsPost = new JSONObject();
// 创建一个JSONArray来存储动作列表
JSONArray actionList = new JSONArray();
// 将任务的创建动作添加到动作列表中
// getActionId()方法用于获取一个唯一的动作ID
actionList.put(task.getCreateAction(getActionId()));
// 将动作列表添加到JSONObject中
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// 将客户端版本添加到JSONObject中
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// 发送POST请求并获取响应
JSONObject jsResponse = postRequest(jsPost);
// 从响应的results数组中获取第一个结果对象
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
// 从结果对象中获取新任务的ID并设置到任务对象中
task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
} catch (JSONException e) {
// 如果JSON处理异常记录错误日志打印堆栈跟踪并抛出ActionFailureException异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("create task: handing jsonobject failed");
}
}
// 定义一个方法用于创建任务列表接收一个TaskList对象作为参数并声明可能抛出NetworkFailureException异常
public void createTaskList(TaskList tasklist) throws NetworkFailureException {
// 调用commitUpdate方法可能抛出NetworkFailureException异常
commitUpdate();
try {
// 创建一个新的JSONObject对象用于存储POST请求的数据
JSONObject jsPost = new JSONObject();
// 创建一个JSONArray对象用于存储动作列表
JSONArray actionList = new JSONArray();
// 将创建任务列表的动作添加到动作列表中getActionId()方法可能用于获取动作的唯一标识符
actionList.put(tasklist.getCreateAction(getActionId()));
// 将动作列表添加到POST数据中键为GTASK_JSON_ACTION_LIST
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// 将客户端版本添加到POST数据中键为GTASK_JSON_CLIENT_VERSION
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// 发送POST请求并接收响应
JSONObject jsResponse = postRequest(jsPost);
// 从响应中提取结果数组的第一个元素并转换为JSONObject
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
// 从结果中提取新创建的任务列表ID并设置给tasklist对象
tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
} catch (JSONException e) {
// 捕获JSON处理异常记录错误日志
Log.e(TAG, e.toString());
e.printStackTrace();
// 抛出自定义的ActionFailureException异常指示处理JSON对象失败
throw new ActionFailureException("create tasklist: handing jsonobject failed");
}
}
// 定义一个方法用于提交更新可能抛出NetworkFailureException异常
public void commitUpdate() throws NetworkFailureException {
// 检查是否有待提交的更新mUpdateArray不为null
if (mUpdateArray != null) {
try {
// 创建一个新的JSONObject对象用于存储POST请求的数据
JSONObject jsPost = new JSONObject();
// 将待提交的更新动作列表添加到POST数据中键为GTASK_JSON_ACTION_LIST
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);
// 将客户端版本添加到POST数据中键为GTASK_JSON_CLIENT_VERSION
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// 发送POST请求提交更新注意这里没有处理响应
postRequest(jsPost);
// 清空待提交的更新数组,表示更新已提交
mUpdateArray = null;
} catch (JSONException e) {
// 捕获JSON处理异常记录错误日志
Log.e(TAG, e.toString());
e.printStackTrace();
// 抛出自定义的ActionFailureException异常指示处理JSON对象失败
throw new ActionFailureException("commit update: handing jsonobject failed");
}
}
}
// 添加一个更新节点到更新数组如果更新数组已满超过10个元素则先提交更新
public void addUpdateNode(Node node) throws NetworkFailureException {
if (node != null) {
// 检查更新数组是否存在且长度超过10
if (mUpdateArray != null && mUpdateArray.length() > 10) {
// 提交当前积累的更新
commitUpdate();
}
// 如果更新数组为空,则初始化它
if (mUpdateArray == null) {
mUpdateArray = new JSONArray();
}
// 将节点的更新动作添加到更新数组中
mUpdateArray.put(node.getUpdateAction(getActionId()));
}
}
// 移动一个任务从一个任务列表到另一个任务列表(或在该任务列表内移动)
public void moveTask(Task task, TaskList preParent, TaskList curParent)
throws NetworkFailureException {
// 提交当前积累的更新
commitUpdate();
try {
// 创建POST请求的JSON对象
JSONObject jsPost = new JSONObject();
// 创建动作列表的JSON数组
JSONArray actionList = new JSONArray();
// 创建动作对象的JSON对象
JSONObject action = new JSONObject();
// 设置动作类型为移动
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE);
// 设置动作ID
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
// 设置要移动的任务ID
action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid());
// 如果是在同一个任务列表内移动且不是第一个任务则设置前一个兄弟任务的ID
if (preParent == curParent && task.getPriorSibling() != null) {
action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());
}
// 设置源任务列表ID
action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());
// 设置目标父任务列表ID
action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());
// 如果是在不同的任务列表之间移动则也设置目标列表ID这里可能有些冗余因为dest_parent通常足以确定位置
if (preParent != curParent) {
action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());
}
// 将动作添加到动作列表中
actionList.put(action);
// 将动作列表添加到POST数据中
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// 设置客户端版本
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// 发送POST请求
postRequest(jsPost);
} catch (JSONException e) {
// 捕获JSON处理异常并记录日志
Log.e(TAG, e.toString());
e.printStackTrace();
// 抛出自定义的ActionFailureException异常
throw new ActionFailureException("move task: handling jsonObject failed");
}
}
// 删除一个节点(可能是任务或其他可删除项)
public void deleteNode(Node node) throws NetworkFailureException {
// 提交当前积累的更新
commitUpdate();
try {
// 创建POST请求的JSON对象
JSONObject jsPost = new JSONObject();
// 创建动作列表的JSON数组
JSONArray actionList = new JSONArray();
// 标记节点为已删除
node.setDeleted(true);
// 将节点的更新动作添加到动作列表中
actionList.put(node.getUpdateAction(getActionId()));
// 将动作列表添加到POST数据中
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// 设置客户端版本
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// 发送POST请求
postRequest(jsPost);
// 清空更新数组,因为更新已提交
mUpdateArray = null;
} catch (JSONException e) {
// 捕获JSON处理异常并记录日志
Log.e(TAG, e.toString());
e.printStackTrace();
// 抛出自定义的ActionFailureException异常
throw new ActionFailureException("delete node: handling jsonObject failed");
}
}
// 获取所有任务列表
public JSONArray getTaskLists() throws NetworkFailureException {
// 检查是否已登录
if (!mLoggedin) {
Log.e(TAG, "please login first");
// 抛出自定义的ActionFailureException异常
throw new ActionFailureException("not logged in");
}
try {
// 创建HTTP GET请求
HttpGet httpGet = new HttpGet(mGetUrl);
// 执行GET请求并获取响应
HttpResponse response = mHttpClient.execute(httpGet);
// 从响应中获取任务列表的JSON字符串
String resString = getResponseContent(response.getEntity());
// 定义JSON字符串的起始和结束标记
String jsBegin = "_setup(";
String jsEnd = ")}</script>";
// 查找起始和结束标记的位置
int begin = resString.indexOf(jsBegin);
int end = resString.lastIndexOf(jsEnd);
// 提取JSON字符串
String jsString = null;
if (begin != -1 && end != -1 && begin < end) {
jsString = resString.substring(begin + jsBegin.length(), end);
}
// 将JSON字符串转换为JSONObject
JSONObject js = new JSONObject(jsString);
// 从JSONObject中获取任务列表的JSONArray
return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS);
} catch (ClientProtocolException e) {
// 捕获HTTP协议异常并记录日志
Log.e(TAG, e.toString());
e.printStackTrace();
// 抛出自定义的NetworkFailureException异常
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (IOException e) {
// 捕获IO异常并记录日志
Log.e(TAG, e.toString());
e.printStackTrace();
// 抛出自定义的NetworkFailureException异常
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (JSONException e) {
// 捕获JSON处理异常并记录日志
Log.e(TAG, e.toString());
e.printStackTrace();
// 抛出自定义的ActionFailureException异常
throw new ActionFailureException("get task lists: handling jsonObject failed");
}
}
// 获取指定任务列表中的所有任务
public JSONArray getTaskList(String listGid) throws NetworkFailureException {
// 提交当前积累的更新
commitUpdate();
try {
// 创建POST请求的JSON对象
JSONObject jsPost = new JSONObject();
// 创建动作列表的JSON数组
JSONArray actionList = new JSONArray();
// 创建动作对象的JSON对象
JSONObject action = new JSONObject();
// 设置动作类型为获取所有任务
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL);
// 设置动作ID
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
// 设置要获取的任务列表ID
action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid);
// 设置是否包含已删除的任务(这里设置为不包含)
action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false);
// 将动作添加到动作列表中
actionList.put(action);
// 将动作列表添加到POST数据中
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// 设置客户端版本
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// 发送POST请求并获取响应
JSONObject jsResponse = postRequest(jsPost);
// 从响应中获取任务的JSONArray
return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS);
} catch (JSONException e) {
// 捕获JSON处理异常并记录日志
Log.e(TAG, e.toString());
e.printStackTrace();
// 抛出自定义的ActionFailureException异常
throw new ActionFailureException("get task list: handling jsonObject failed");
}
}
public Account getSyncAccount() {
return mAccount;
}
public void resetUpdateArray() {
mUpdateArray = null;
}
}