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.
git.text/src/java/net/micode/notes/gtask/remote/GTaskClient.java

843 lines
30 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;
/**
* <p>Google任务API客户端类。</p>
* <p>设计意图提供与Google任务API交互的核心功能实现任务的创建、更新、删除等操作。</p>
* <p>核心职责:</p>
* <ul>
* <li>处理Google账号的登录认证</li>
* <li>执行Google任务的CRUD操作</li>
* <li>管理API请求的Cookie和会话状态</li>
* <li>处理网络请求和响应,包括压缩数据的解压</li>
* <li>将本地任务模型转换为Google任务API的JSON格式</li>
* </ul>
* <p>关键关联:</p>
* <ul>
* <li>与{@link GTaskManager}配合,提供任务同步的底层支持</li>
* <li>使用{@link Task}和{@link TaskList}类封装Google任务数据</li>
* <li>通过{@link NetworkFailureException}和{@link ActionFailureException}处理异常</li>
* <li>依赖{@link GTaskStringUtils}提供API交互所需的常量</li>
* </ul>
* <p>设计特点:</p>
* <ul>
* <li>采用单例模式确保全局只有一个Google任务API客户端实例</li>
* <li>实现会话管理,避免频繁登录认证</li>
* <li>支持批量更新操作提高API调用效率</li>
* <li>处理不同类型的网络压缩格式gzip、deflate</li>
* </ul>
*/
public class GTaskClient {
/**
* 日志标签,用于调试和错误跟踪
*/
private static final String TAG = GTaskClient.class.getSimpleName();
/**
* Google任务的基本URL
*/
private static final String GTASK_URL = "https://mail.google.com/tasks/";
/**
* Google任务的GET请求URL
*/
private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig";
/**
* Google任务的POST请求URL
*/
private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig";
/**
* GTaskClient的单例实例
*/
private static GTaskClient mInstance = null;
/**
* HTTP客户端用于执行与Google任务API的网络请求
*/
private DefaultHttpClient mHttpClient;
/**
* 当前使用的GET请求URL
*/
private String mGetUrl;
/**
* 当前使用的POST请求URL
*/
private String mPostUrl;
/**
* Google任务客户端版本号
*/
private long mClientVersion;
/**
* 登录状态标志
*/
private boolean mLoggedin;
/**
* 最后一次登录时间
*/
private long mLastLoginTime;
/**
* 请求操作ID用于跟踪API请求
*/
private int mActionId;
/**
* 当前登录的Google账号
*/
private Account mAccount;
/**
* 批量更新的JSON数组用于累积多次更新操作
*/
private JSONArray mUpdateArray;
/**
* <p>私有构造方法。</p>
* <p>设计意图:实现单例模式,防止外部直接实例化。</p>
* <p>初始化所有成员变量,设置默认值。</p>
*/
private GTaskClient() {
mHttpClient = null;
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
mClientVersion = -1;
mLoggedin = false;
mLastLoginTime = 0;
mActionId = 1;
mAccount = null;
mUpdateArray = null;
}
/**
* <p>获取GTaskClient的单例实例。</p>
* <p>业务逻辑:使用双重检查锁定实现线程安全的单例模式。</p>
*
* @return GTaskClient的单例实例
*/
public static synchronized GTaskClient getInstance() {
if (mInstance == null) {
mInstance = new GTaskClient();
}
return mInstance;
}
/**
* <p>登录Google账号并验证Google任务API。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>检查登录状态如果Cookie过期或账号切换则重新登录</li>
* <li>获取Google账号的认证令牌</li>
* <li>如果是自定义域名邮箱使用自定义URL尝试登录</li>
* <li>如果自定义域名登录失败使用官方URL尝试登录</li>
* </ul>
*
* @param activity 当前活动的Activity用于获取账号信息和显示认证界面
* @return true表示登录成功false表示登录失败
*/
public boolean login(Activity activity) {
// we suppose that the cookie would expire after 5 minutes
// then we need to re-login
final long interval = 1000 * 60 * 5;
if (mLastLoginTime + interval < System.currentTimeMillis()) {
mLoggedin = false;
}
// need to re-login after account switch
if (mLoggedin
&& !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity
.getSyncAccountName(activity))) {
mLoggedin = false;
}
if (mLoggedin) {
Log.d(TAG, "already logged in");
return true;
}
mLastLoginTime = System.currentTimeMillis();
String authToken = loginGoogleAccount(activity, false);
if (authToken == null) {
Log.e(TAG, "login google account failed");
return false;
}
// login with custom domain if necessary
if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase()
.endsWith("googlemail.com"))) {
StringBuilder url = new StringBuilder(GTASK_URL).append("a/");
int index = mAccount.name.indexOf('@') + 1;
String suffix = mAccount.name.substring(index);
url.append(suffix + "/");
mGetUrl = url.toString() + "ig";
mPostUrl = url.toString() + "r/ig";
if (tryToLoginGtask(activity, authToken)) {
mLoggedin = true;
}
}
// try to login with google official url
if (!mLoggedin) {
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
if (!tryToLoginGtask(activity, authToken)) {
return false;
}
}
mLoggedin = true;
return true;
}
/**
* <p>登录Google账号并获取认证令牌。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>获取设备上所有的Google账号</li>
* <li>根据设置中选择的账号名查找对应的Account对象</li>
* <li>使用AccountManager获取该账号的认证令牌</li>
* <li>如果需要,可以使现有令牌失效并重新获取</li>
* </ul>
*
* @param activity 当前活动的Activity用于获取AccountManager
* @param invalidateToken 是否使现有令牌失效
* @return 认证令牌字符串如果获取失败则返回null
*/
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
String authToken;
AccountManager accountManager = AccountManager.get(activity);
Account[] accounts = accountManager.getAccountsByType("com.google");
if (accounts.length == 0) {
Log.e(TAG, "there is no available google account");
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, "unable to get an account with the same name in the settings");
return null;
}
// get the token now
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, "get auth token failed");
authToken = null;
}
return authToken;
}
/**
* <p>尝试登录Google任务API。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>首先使用提供的认证令牌尝试登录</li>
* <li>如果登录失败,可能是令牌过期,此时使令牌失效并重新获取</li>
* <li>使用新的认证令牌再次尝试登录</li>
* </ul>
*
* @param activity 当前活动的Activity用于重新获取认证令牌
* @param authToken Google账号的认证令牌
* @return true表示登录成功false表示登录失败
*/
private boolean tryToLoginGtask(Activity activity, String authToken) {
if (!loginGtask(authToken)) {
// maybe the auth token is out of date, now let's invalidate the
// token and try again
authToken = loginGoogleAccount(activity, true);
if (authToken == null) {
Log.e(TAG, "login google account failed");
return false;
}
if (!loginGtask(authToken)) {
Log.e(TAG, "login gtask failed");
return false;
}
}
return true;
}
/**
* <p>登录Google任务API的核心方法。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>配置HTTP客户端的连接和套接字超时时间</li>
* <li>创建Cookie存储以保存认证信息</li>
* <li>发送HTTP GET请求进行登录认证</li>
* <li>检查响应中是否包含认证Cookie</li>
* <li>从响应中解析出客户端版本号</li>
* </ul>
*
* @param authToken Google账号的认证令牌
* @return true表示登录成功false表示登录失败
*/
private boolean loginGtask(String authToken) {
int timeoutConnection = 10000;
int timeoutSocket = 15000;
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
mHttpClient = new DefaultHttpClient(httpParameters);
BasicCookieStore localBasicCookieStore = new BasicCookieStore();
mHttpClient.setCookieStore(localBasicCookieStore);
HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);
// login gtask
try {
String loginUrl = mGetUrl + "?auth=" + authToken;
HttpGet httpGet = new HttpGet(loginUrl);
HttpResponse response = null;
response = mHttpClient.execute(httpGet);
// get the cookie now
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, "it seems that there is no auth cookie");
}
// get the client version
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 false;
} catch (Exception e) {
// simply catch all exceptions
Log.e(TAG, "httpget gtask_url failed");
return false;
}
return true;
}
/**
* <p>获取操作ID。</p>
* <p>业务逻辑返回当前操作ID并自增用于跟踪API请求。</p>
*
* @return 当前操作ID
*/
private int getActionId() {
return mActionId++;
}
/**
* <p>创建HTTP POST请求。</p>
* <p>业务逻辑配置POST请求的URL和请求头。</p>
*
* @return 配置好的HttpPost对象
*/
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;
}
/**
* <p>获取HTTP响应内容。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>检查响应内容的编码方式</li>
* <li>如果是gzip或deflate压缩格式进行解压处理</li>
* <li>将响应内容转换为字符串</li>
* </ul>
*
* @param entity HTTP响应实体
* @return 响应内容字符串
* @throws IOException 如果读取或解压响应内容时发生错误
*/
private String getResponseContent(HttpEntity entity) throws IOException {
String contentEncoding = null;
if (entity.getContentEncoding() != null) {
contentEncoding = entity.getContentEncoding().getValue();
Log.d(TAG, "encoding: " + 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();
}
}
/**
* <p>发送POST请求到Google任务API。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>检查登录状态,未登录则抛出异常</li>
* <li>创建并配置HTTP POST请求</li>
* <li>将JSON数据转换为请求实体</li>
* <li>发送请求并获取响应</li>
* <li>将响应内容转换为JSON对象</li>
* </ul>
*
* @param js 要发送的JSON对象
* @return 响应的JSON对象
* @throws NetworkFailureException 如果网络请求失败
*/
private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
if (!mLoggedin) {
Log.e(TAG, "please login first");
throw new ActionFailureException("not logged in");
}
HttpPost httpPost = createHttpPost();
try {
LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>();
list.add(new BasicNameValuePair("r", js.toString()));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
httpPost.setEntity(entity);
// execute the post
HttpResponse response = mHttpClient.execute(httpPost);
String jsString = getResponseContent(response.getEntity());
return new JSONObject(jsString);
} catch (ClientProtocolException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("postRequest failed");
} catch (IOException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("postRequest failed");
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("unable to convert response content to jsonobject");
} catch (Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("error occurs when posting request");
}
}
/**
* <p>创建新的Google任务。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>提交当前累积的更新操作</li>
* <li>创建任务的JSON表示</li>
* <li>发送创建任务的POST请求</li>
* <li>从响应中获取新创建任务的GID并设置到任务对象中</li>
* </ul>
*
* @param task 要创建的任务对象
* @throws NetworkFailureException 如果网络请求失败
*/
public void createTask(Task task) throws NetworkFailureException {
commitUpdate();
try {
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
// action_list
actionList.put(task.getCreateAction(getActionId()));
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// post
JSONObject jsResponse = postRequest(jsPost);
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("create task: handing jsonobject failed");
}
}
/**
* <p>创建新的Google任务列表。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>提交当前累积的更新操作</li>
* <li>创建任务列表的JSON表示</li>
* <li>发送创建任务列表的POST请求</li>
* <li>从响应中获取新创建任务列表的GID并设置到任务列表对象中</li>
* </ul>
*
* @param tasklist 要创建的任务列表对象
* @throws NetworkFailureException 如果网络请求失败
*/
public void createTaskList(TaskList tasklist) throws NetworkFailureException {
commitUpdate();
try {
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
// action_list
actionList.put(tasklist.getCreateAction(getActionId()));
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// post
JSONObject jsResponse = postRequest(jsPost);
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("create tasklist: handing jsonobject failed");
}
}
/**
* <p>提交累积的更新操作。</p>
* <p>业务逻辑将累积在mUpdateArray中的所有更新操作发送到Google任务API。</p>
*
* @throws NetworkFailureException 如果网络请求失败
*/
public void commitUpdate() throws NetworkFailureException {
if (mUpdateArray != null) {
try {
JSONObject jsPost = new JSONObject();
// action_list
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);
mUpdateArray = null;
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("commit update: handing jsonobject failed");
}
}
}
/**
* <p>添加节点更新操作到累积列表。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>如果累积的更新操作超过10个先提交这些更新</li>
* <li>将节点的更新操作添加到累积列表中</li>
* </ul>
*
* @param node 要更新的节点对象
* @throws NetworkFailureException 如果网络请求失败(当提交累积更新时)
*/
public void addUpdateNode(Node node) throws NetworkFailureException {
if (node != null) {
// too many update items may result in an error
// set max to 10 items
if (mUpdateArray != null && mUpdateArray.length() > 10) {
commitUpdate();
}
if (mUpdateArray == null)
mUpdateArray = new JSONArray();
mUpdateArray.put(node.getUpdateAction(getActionId()));
}
}
/**
* <p>移动任务到新的父任务列表或在同一列表中重新排序。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>提交当前累积的更新操作</li>
* <li>创建移动任务的JSON表示</li>
* <li>如果在同一列表内移动且不是第一个任务设置前一个兄弟任务的ID</li>
* <li>发送移动任务的POST请求</li>
* </ul>
*
* @param task 要移动的任务
* @param preParent 任务的当前父任务列表
* @param curParent 任务的新父任务列表
* @throws NetworkFailureException 如果网络请求失败
*/
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_list
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE);
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid());
if (preParent == curParent && task.getPriorSibling() != null) {
// put prioring_sibing_id only if moving within the tasklist and
// it is not the first one
action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());
}
action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());
action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());
if (preParent != curParent) {
// put the dest_list only if moving between tasklists
action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());
}
actionList.put(action);
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("move task: handing jsonobject failed");
}
}
/**
* <p>删除节点。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>提交当前累积的更新操作</li>
* <li>将节点标记为已删除</li>
* <li>创建删除节点的JSON表示</li>
* <li>发送删除节点的POST请求</li>
* <li>清空累积的更新列表</li>
* </ul>
*
* @param node 要删除的节点
* @throws NetworkFailureException 如果网络请求失败
*/
public void deleteNode(Node node) throws NetworkFailureException {
commitUpdate();
try {
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
// action_list
node.setDeleted(true);
actionList.put(node.getUpdateAction(getActionId()));
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);
mUpdateArray = null;
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("delete node: handing jsonobject failed");
}
}
/**
* <p>获取所有的Google任务列表。</p>
* <p>业务逻辑:</p>
* <ul>
* <li>检查登录状态</li>
* <li>发送获取任务列表的GET请求</li>
* <li>解析响应内容,提取任务列表数据</li>
* </ul>
*
* @return 任务列表的JSON数组
* @throws NetworkFailureException 如果网络请求失败
*/
public JSONArray getTaskLists() throws NetworkFailureException {
if (!mLoggedin) {
Log.e(TAG, "please login first");
throw new ActionFailureException("not logged in");
}
try {
HttpGet httpGet = new HttpGet(mGetUrl);
HttpResponse response = null;
response = mHttpClient.execute(httpGet);
// get the task list
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 (ClientProtocolException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (IOException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("get task lists: handing jasonobject failed");
}
}
public JSONArray getTaskList(String listGid) throws NetworkFailureException {
commitUpdate();
try {
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
JSONObject action = new JSONObject();
// action_list
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL);
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid);
action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false);
actionList.put(action);
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
JSONObject jsResponse = postRequest(jsPost);
return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS);
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("get task list: handing jsonobject failed");
}
}
public Account getSyncAccount() {
return mAccount;
}
public void resetUpdateArray() {
mUpdateArray = null;
}
}