|
|
/*
|
|
|
* 版权所有 (c) 2010-2011,MiCode 开源社区 (www.micode.net)
|
|
|
* 根据 Apache 许可证 2.0 版本("许可证")授权;
|
|
|
* 除非符合许可证的规定,否则不得使用本文件。
|
|
|
* 您可以从以下网址获取许可证副本:
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
* 除非适用法律要求或书面同意,本软件按"原样"分发,
|
|
|
* 没有任何明示或暗示的保证或条件。
|
|
|
* 详见许可证中规定的权限和限制。
|
|
|
* (注:这是一份标准的Apache许可证2.0版本的开源声明)
|
|
|
*/
|
|
|
|
|
|
// 定义Google任务远程同步包路径
|
|
|
package net.micode.notes.gtask.remote;
|
|
|
// 导入Android账号管理相关类
|
|
|
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; // 日志工具
|
|
|
// 导入AndroidX注解
|
|
|
import androidx.annotation.NonNull; // 非空参数注解
|
|
|
// 导入Google任务数据模型
|
|
|
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; // Google任务字符串常量工具
|
|
|
import net.micode.notes.ui.NotesPreferenceActivity; // 设置界面Activity
|
|
|
// 导入Apache HTTP组件(已废弃,但部分旧系统仍在使用)
|
|
|
import org.apache.http.HttpEntity; // HTTP消息实体接口
|
|
|
import org.apache.http.HttpResponse; // HTTP响应对象
|
|
|
import org.apache.http.client.entity.UrlEncodedFormEntity; // URL编码表单实体
|
|
|
import org.apache.http.client.methods.HttpGet; // HTTP GET请求方法
|
|
|
import org.apache.http.client.methods.HttpPost; // HTTP POST请求方法
|
|
|
import org.apache.http.cookie.Cookie; // Cookie信息对象
|
|
|
import org.apache.http.impl.client.BasicCookieStore; // 基础Cookie存储
|
|
|
import org.apache.http.impl.client.DefaultHttpClient; // 默认HTTP客户端(已废弃)
|
|
|
import org.apache.http.message.BasicNameValuePair; // 键值对参数对象
|
|
|
import org.apache.http.params.BasicHttpParams; // HTTP参数集合
|
|
|
import org.apache.http.params.HttpConnectionParams; // 连接相关参数
|
|
|
import org.apache.http.params.HttpParams; // HTTP参数接口
|
|
|
import org.apache.http.params.HttpProtocolParams; // 协议相关参数
|
|
|
// 导入JSON处理类
|
|
|
import org.json.JSONArray; // JSON数组处理
|
|
|
import org.json.JSONException; // JSON解析异常
|
|
|
import org.json.JSONObject; // JSON对象处理
|
|
|
// 导入IO流相关类
|
|
|
import java.io.BufferedReader; // 缓冲字符输入流
|
|
|
import java.io.IOException; // IO异常
|
|
|
import java.io.InputStream; // 字节输入流
|
|
|
import java.io.InputStreamReader; // 字节流转字符流
|
|
|
import java.util.LinkedList; // 链表实现
|
|
|
import java.util.List; // 列表接口
|
|
|
// 导入压缩流处理
|
|
|
import java.util.zip.GZIPInputStream; // GZIP解压流
|
|
|
import java.util.zip.Inflater; // 解压器
|
|
|
import java.util.zip.InflaterInputStream; // 解压输入流
|
|
|
|
|
|
// Google任务客户端实现类,负责与Google Tasks API交互
|
|
|
public class GTaskClient {
|
|
|
// 日志标签
|
|
|
private static final String TAG = GTaskClient.class.getSimpleName();
|
|
|
// Google任务基础URL
|
|
|
private static final String GTASK_URL = "https://mail.google.com/tasks/";
|
|
|
// GET请求URL
|
|
|
private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig";
|
|
|
// POST请求URL
|
|
|
private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig";
|
|
|
// 单例实例
|
|
|
private static GTaskClient mInstance = null;
|
|
|
// HTTP客户端(使用已废弃的Apache HTTP Client)
|
|
|
private DefaultHttpClient mHttpClient;
|
|
|
// GET请求实际URL(可能包含自定义域名)
|
|
|
private String mGetUrl;
|
|
|
// POST请求实际URL(可能包含自定义域名)
|
|
|
private String mPostUrl;
|
|
|
// 客户端版本号
|
|
|
private long mClientVersion;
|
|
|
// 登录状态标识
|
|
|
private boolean mLoggedin;
|
|
|
// 上次登录时间戳
|
|
|
private long mLastLoginTime;
|
|
|
// 操作ID计数器
|
|
|
private int mActionId;
|
|
|
// 当前账号信息
|
|
|
private Account mAccount;
|
|
|
// 待提交的更新操作集合
|
|
|
private JSONArray mUpdateArray;
|
|
|
// 私有构造方法(单例模式)
|
|
|
private GTaskClient() {
|
|
|
mHttpClient = null;
|
|
|
mGetUrl = GTASK_GET_URL; // 默认使用官方GET URL
|
|
|
mPostUrl = GTASK_POST_URL; // 默认使用官方POST URL
|
|
|
mClientVersion = -1; // 初始无效版本
|
|
|
mLoggedin = false; // 初始未登录
|
|
|
mLastLoginTime = 0; // 初始时间戳
|
|
|
mActionId = 1; // 操作ID从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分钟毫秒数
|
|
|
if (mLastLoginTime + interval < System.currentTimeMillis()) {
|
|
|
mLoggedin = false; // 标记需要重新登录
|
|
|
}
|
|
|
|
|
|
// 检查账号是否变更
|
|
|
if (mLoggedin && !TextUtils.equals(getSyncAccount().name,
|
|
|
NotesPreferenceActivity.getSyncAccountName(activity))) {
|
|
|
mLoggedin = false; // 账号变更需重新登录
|
|
|
}
|
|
|
|
|
|
// 已登录直接返回
|
|
|
if (mLoggedin) {
|
|
|
Log.d(TAG, "已经登录");
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
mLastLoginTime = System.currentTimeMillis(); // 更新登录时间
|
|
|
String authToken = loginGoogleAccount(activity, false); // 获取认证令牌
|
|
|
if (authToken == null) {
|
|
|
Log.e(TAG, "Google账号登录失败");
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 处理非gmail.com 域名的企业账号
|
|
|
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;
|
|
|
String suffix = mAccount.name.substring(index);
|
|
|
url.append(suffix).append("/");
|
|
|
mGetUrl = url.toString() + "ig"; // 更新GET URL
|
|
|
mPostUrl = url.toString() + "r/ig"; // 更新POST URL
|
|
|
|
|
|
// 尝试用自定义域名登录
|
|
|
if (tryToLoginGtask(activity, authToken)) {
|
|
|
mLoggedin = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 自定义域名登录失败时尝试官方URL
|
|
|
if (!mLoggedin) {
|
|
|
mGetUrl = GTASK_GET_URL; // 恢复默认GET URL
|
|
|
mPostUrl = GTASK_POST_URL; // 恢复默认POST URL
|
|
|
if (!tryToLoginGtask(activity, authToken)) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
mLoggedin = true; // 标记登录成功
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// 获取Google账号认证令牌
|
|
|
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
|
|
|
String authToken;
|
|
|
// 获取账号管理器实例
|
|
|
AccountManager accountManager = AccountManager.get(activity);
|
|
|
// 获取所有Google账号
|
|
|
Account[] accounts = accountManager.getAccountsByType("com.google");
|
|
|
|
|
|
if (accounts.length == 0) {
|
|
|
Log.e(TAG, "没有可用的Google账号");
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
// 获取配置中设置的同步账号名
|
|
|
String accountName = NotesPreferenceActivity.getSyncAccountName(activity);
|
|
|
Account account = null;
|
|
|
// 查找匹配账号
|
|
|
for (Account a : accounts) {
|
|
|
if (a.name.equals(accountName)) {
|
|
|
account = a;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (account != null) {
|
|
|
mAccount = account; // 保存当前账号
|
|
|
} else {
|
|
|
Log.e(TAG, "找不到设置中配置的账号");
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
// 异步获取认证令牌
|
|
|
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) {
|
|
|
accountManager.invalidateAuthToken("com.google", authToken);
|
|
|
loginGoogleAccount(activity, false);
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
Log.e(TAG, "获取认证令牌失败");
|
|
|
authToken = null;
|
|
|
}
|
|
|
|
|
|
return authToken;
|
|
|
}
|
|
|
|
|
|
// 尝试登录Google Tasks服务
|
|
|
private boolean tryToLoginGtask(Activity activity, String authToken) {
|
|
|
if (loginGtask(authToken)) {
|
|
|
// 令牌可能过期,失效后重试
|
|
|
authToken = loginGoogleAccount(activity, true);
|
|
|
if (authToken == null) {
|
|
|
Log.e(TAG, "Google账号登录失败");
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
if (loginGtask(authToken)) {
|
|
|
Log.e(TAG, "Google Tasks登录失败");
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// 实际执行Google Tasks登录
|
|
|
private boolean loginGtask(String authToken) {
|
|
|
// 设置HTTP请求超时(连接10秒,socket15秒)
|
|
|
int timeoutConnection = 10000;
|
|
|
int timeoutSocket = 15000;
|
|
|
HttpParams httpParameters = new BasicHttpParams();
|
|
|
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
|
|
|
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
|
|
|
|
|
|
// 初始化HTTP客户端
|
|
|
mHttpClient = new DefaultHttpClient(httpParameters);
|
|
|
BasicCookieStore localBasicCookieStore = new BasicCookieStore();
|
|
|
mHttpClient.setCookieStore(localBasicCookieStore); // 设置cookie存储
|
|
|
HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);
|
|
|
|
|
|
// 执行登录请求
|
|
|
try {
|
|
|
String loginUrl = mGetUrl + "?auth=" + authToken; // 构造登录URL
|
|
|
HttpGet httpGet = new HttpGet(loginUrl);
|
|
|
HttpResponse response = mHttpClient.execute(httpGet);
|
|
|
|
|
|
// 检查认证cookie
|
|
|
List<Cookie> cookies = mHttpClient.getCookieStore().getCookies();
|
|
|
boolean hasAuthCookie = false;
|
|
|
for (Cookie cookie : cookies) {
|
|
|
if (cookie.getName().contains("GTL")) {
|
|
|
hasAuthCookie = true;
|
|
|
}
|
|
|
}
|
|
|
if (!hasAuthCookie) {
|
|
|
Log.w(TAG, "缺少认证cookie");
|
|
|
}
|
|
|
|
|
|
// 从响应中提取客户端版本号
|
|
|
String resString = getResponseContent(response.getEntity());
|
|
|
String jsBegin = "_setup(";
|
|
|
String jsEnd = ")}</script>";
|
|
|
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);
|
|
|
}
|
|
|
JSONObject js = new JSONObject(jsString);
|
|
|
mClientVersion = js.getLong("v"); // 保存客户端版本
|
|
|
} catch (JSONException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
return true; // 解析失败返回true触发重试
|
|
|
} catch (Exception e) {
|
|
|
Log.e(TAG, "HTTP GET请求失败");
|
|
|
return true; // 网络异常返回true触发重试
|
|
|
}
|
|
|
|
|
|
return false; // 登录成功返回false
|
|
|
}
|
|
|
|
|
|
// 生成递增的操作ID
|
|
|
private int getActionId() {
|
|
|
return mActionId++;
|
|
|
}
|
|
|
|
|
|
// 创建HTTP POST请求对象
|
|
|
private HttpPost createHttpPost() {
|
|
|
HttpPost httpPost = new HttpPost(mPostUrl);
|
|
|
// 设置请求头
|
|
|
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
|
|
|
httpPost.setHeader("AT", "1"); // 认证令牌标识
|
|
|
return httpPost;
|
|
|
}
|
|
|
|
|
|
// 从HTTP实体获取响应内容(支持gzip/deflate压缩)
|
|
|
private String getResponseContent(HttpEntity entity) throws IOException {
|
|
|
String contentEncoding = null;
|
|
|
if (entity.getContentEncoding() != null) {
|
|
|
contentEncoding = entity.getContentEncoding().getValue();
|
|
|
Log.d(TAG, "内容编码: " + contentEncoding);
|
|
|
}
|
|
|
|
|
|
InputStream input = entity.getContent();
|
|
|
// 根据编码类型选择解压方式
|
|
|
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
|
|
|
input = new GZIPInputStream(entity.getContent());
|
|
|
} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
|
|
|
Inflater inflater = new Inflater(true);
|
|
|
input = new InflaterInputStream(entity.getContent(), inflater);
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
// 读取响应内容
|
|
|
InputStreamReader isr = new InputStreamReader(input);
|
|
|
BufferedReader br = new BufferedReader(isr);
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
|
while (true) {
|
|
|
String buff = br.readLine();
|
|
|
if (buff == null) {
|
|
|
return sb.toString(); // 返回完整内容
|
|
|
}
|
|
|
sb = sb.append(buff);
|
|
|
}
|
|
|
} finally {
|
|
|
input.close(); // 确保流关闭
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 执行POST请求并返回JSON响应
|
|
|
private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
|
|
|
if (!mLoggedin) {
|
|
|
Log.e(TAG, "请先登录");
|
|
|
throw new ActionFailureException("未登录");
|
|
|
}
|
|
|
|
|
|
HttpPost httpPost = createHttpPost();
|
|
|
try {
|
|
|
// 构造请求参数
|
|
|
LinkedList<BasicNameValuePair> list = new LinkedList<>();
|
|
|
list.add(new BasicNameValuePair("r", js.toString()));
|
|
|
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
|
|
|
httpPost.setEntity(entity);
|
|
|
|
|
|
// 执行请求并解析响应
|
|
|
HttpResponse response = mHttpClient.execute(httpPost);
|
|
|
String jsString = getResponseContent(response.getEntity());
|
|
|
return new JSONObject(jsString);
|
|
|
|
|
|
} catch (IOException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new NetworkFailureException("POST请求失败");
|
|
|
} catch (JSONException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new ActionFailureException("响应内容转JSON失败");
|
|
|
} catch (Exception e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new ActionFailureException("请求过程中发生错误");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 创建任务
|
|
|
public void createTask(Task task) throws NetworkFailureException {
|
|
|
commitUpdate(); // 先提交待更新操作
|
|
|
try {
|
|
|
JSONObject jsPost = new JSONObject();
|
|
|
JSONArray actionList = new JSONArray();
|
|
|
|
|
|
// 添加创建动作
|
|
|
actionList.put(task.getCreateAction(getActionId()));
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
|
|
|
|
|
|
// 添加客户端版本
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
|
|
|
|
|
|
// 发送请求并处理响应
|
|
|
JSONObject jsResponse = postRequest(jsPost);
|
|
|
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
|
|
|
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
|
|
|
task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
|
|
|
|
|
|
} catch (JSONException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new ActionFailureException("创建任务时处理JSON失败");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 创建任务列表
|
|
|
public void createTaskList(TaskList tasklist) throws NetworkFailureException {
|
|
|
commitUpdate(); // 先提交待更新操作
|
|
|
try {
|
|
|
JSONObject jsPost = new JSONObject();
|
|
|
JSONArray actionList = new JSONArray();
|
|
|
|
|
|
// 添加创建动作
|
|
|
actionList.put(tasklist.getCreateAction(getActionId()));
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
|
|
|
|
|
|
// 添加客户端版本
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
|
|
|
|
|
|
// 发送请求并处理响应
|
|
|
JSONObject jsResponse = postRequest(jsPost);
|
|
|
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
|
|
|
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
|
|
|
tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
|
|
|
|
|
|
} catch (JSONException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new ActionFailureException("创建任务列表时处理JSON失败");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 提交所有待更新操作
|
|
|
public void commitUpdate() throws NetworkFailureException {
|
|
|
if (mUpdateArray != null) { // 有待更新操作时才执行
|
|
|
try {
|
|
|
JSONObject jsPost = new JSONObject();
|
|
|
|
|
|
// 添加动作列表
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);
|
|
|
|
|
|
// 添加客户端版本
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
|
|
|
|
|
|
postRequest(jsPost); // 发送请求
|
|
|
mUpdateArray = null; // 清空待更新操作
|
|
|
} catch (JSONException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new ActionFailureException("提交更新时处理JSON失败");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 添加节点更新操作
|
|
|
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 {
|
|
|
JSONObject jsPost = new JSONObject();
|
|
|
JSONArray actionList = new JSONArray();
|
|
|
JSONObject action = new JSONObject();
|
|
|
|
|
|
// 设置移动动作参数
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
|
|
|
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE);
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid());
|
|
|
|
|
|
// 同列表移动时设置前驱任务ID
|
|
|
if (preParent == curParent && task.getPriorSibling() != null) {
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());
|
|
|
}
|
|
|
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());
|
|
|
|
|
|
// 跨列表移动时设置目标列表ID
|
|
|
if (preParent != curParent) {
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());
|
|
|
}
|
|
|
|
|
|
actionList.put(action);
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
|
|
|
|
|
|
// 添加客户端版本
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
|
|
|
|
|
|
postRequest(jsPost); // 发送请求
|
|
|
|
|
|
} catch (JSONException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new ActionFailureException("移动任务时处理JSON失败");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 删除节点
|
|
|
public void deleteNode(Node node) throws NetworkFailureException {
|
|
|
commitUpdate(); // 先提交待更新操作
|
|
|
try {
|
|
|
JSONObject jsPost = new JSONObject();
|
|
|
JSONArray actionList = new JSONArray();
|
|
|
|
|
|
// 设置删除标记并添加更新动作
|
|
|
node.setDeleted(true);
|
|
|
actionList.put(node.getUpdateAction(getActionId()));
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
|
|
|
|
|
|
// 添加客户端版本
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
|
|
|
|
|
|
postRequest(jsPost); // 发送请求
|
|
|
mUpdateArray = null; // 清空待更新操作
|
|
|
} catch (JSONException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new ActionFailureException("删除节点时处理JSON失败");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 获取所有任务列表
|
|
|
public JSONArray getTaskLists() throws NetworkFailureException {
|
|
|
if (!mLoggedin) {
|
|
|
Log.e(TAG, "请先登录");
|
|
|
throw new ActionFailureException("未登录");
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
HttpGet httpGet = new HttpGet(mGetUrl); // 创建GET请求
|
|
|
HttpResponse response = mHttpClient.execute(httpGet);
|
|
|
|
|
|
// 从响应中提取任务列表数据
|
|
|
String resString = getResponseContent(response.getEntity());
|
|
|
String jsBegin = "_setup(";
|
|
|
String jsEnd = ")}</script>";
|
|
|
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);
|
|
|
}
|
|
|
JSONObject js = new JSONObject(jsString);
|
|
|
return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS);
|
|
|
} catch (IOException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new NetworkFailureException("获取任务列表时HTTP请求失败");
|
|
|
} catch (JSONException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new ActionFailureException("获取任务列表时处理JSON失败");
|
|
|
}
|
|
|
}
|
|
|
// 获取特定任务列表详情
|
|
|
public JSONArray getTaskList(String listGid) throws NetworkFailureException {
|
|
|
commitUpdate(); // 先提交待更新操作
|
|
|
try {
|
|
|
JSONObject jsPost = new JSONObject();
|
|
|
JSONArray actionList = getJsonArray(listGid); // 获取动作数组
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
|
|
|
|
|
|
// 添加客户端版本
|
|
|
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
|
|
|
|
|
|
JSONObject jsResponse = postRequest(jsPost);
|
|
|
return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS);
|
|
|
} catch (JSONException e) {
|
|
|
Log.e(TAG, e.toString());
|
|
|
e.printStackTrace();
|
|
|
throw new ActionFailureException("获取任务列表详情时处理JSON失败");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 构造获取任务列表的动作数组
|
|
|
@NonNull
|
|
|
private JSONArray getJsonArray(String listGid) throws JSONException {
|
|
|
JSONArray actionList = new JSONArray();
|
|
|
JSONObject action = new JSONObject();
|
|
|
// 设置获取全部动作参数
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
|
|
|
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL);
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid);
|
|
|
action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); // 不获取已删除项
|
|
|
actionList.put(action);
|
|
|
return actionList;
|
|
|
}
|
|
|
// 获取当前同步账号
|
|
|
public Account getSyncAccount() {
|
|
|
return mAccount;
|
|
|
}
|
|
|
// 重置待更新操作数组
|
|
|
public void resetUpdateArray() {
|
|
|
mUpdateArray = null;
|
|
|
}
|
|
|
} |