diff --git a/gtask/GTaskClient.java b/gtask/GTaskClient.java deleted file mode 100644 index 23464e2..0000000 --- a/gtask/GTaskClient.java +++ /dev/null @@ -1,618 +0,0 @@ -/* - * 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; -//导入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; -//导入自定义数据结构和工具类 -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; -// 导入Apache HttpClient相关类 -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; -// JSON处理类 -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -// Java IO相关类 -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(); - // Google Tasks API地址 - 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; - // HTTP客户端和相关配置 - private DefaultHttpClient mHttpClient;// HTTP客户端实例 - - 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) { - // we suppose that the cookie would expire after 5 minutes - // then we need to re-login - // 检查登录有效期(5分钟) - 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(); -// 获取Google账户授权令牌 - 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"))) { -// 构建自定义URL路径 - 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; - } - - 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 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; - } - - 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; - } - - private boolean loginGtask(String authToken) { -// 设置HTTP连接参数 - 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); - HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); - - // login gtask - try { -// 构建带认证令牌的登录URL - String loginUrl = mGetUrl + "?auth=" + authToken; - HttpGet httpGet = new HttpGet(loginUrl); - HttpResponse response = null; - response = mHttpClient.execute(httpGet); - - // get the cookie now - List 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 = ")}"; - 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; - } - - private int getActionId() { - return mActionId++; - } - - 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; - } - - 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(); - } - } - - 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 { -// 构建POST参数 - LinkedList list = new LinkedList(); - 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"); - } - } - - 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)); -// 设置服务器生成ID - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("create task: handing jsonobject failed"); - } - } - - 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));// 设置服务器生成ID - - } catch (JSONException e) { - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new ActionFailureException("create tasklist: handing jsonobject failed"); - } - } -// 提交暂存的更新操作(批量执行队列中的更新) - 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"); - } - } - } -// 向更新队列添加单个操作(自动处理批量限制) - public void addUpdateNode(Node node) throws NetworkFailureException { - if (node != null) { - // too many update items may result in an error - // set max to 10 items -// 限制更新队列最大长度为10(超过则先提交当前队列) - if (mUpdateArray != null && mUpdateArray.length() > 10) { - commitUpdate();// 提交当前队列// 初始化更新队列 - } - - if (mUpdateArray == null)// 初始化更新队列 - mUpdateArray = new JSONArray(); - // 添加节点的更新操作(调用Node对象生成操作JSON) - 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();// 创建移动操作JSON对象 -// 设置操作类型为移动 - // 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()); -// 如果在同一任务列表内移动且非第一个任务,设置前置兄弟ID(用于排序) - 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()); - } -// 设置源任务列表ID和目标父级ID(目标任务列表ID) - action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); - action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); -// 如果跨任务列表移动,额外设置目标列表ID - 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"); - } - } -// 删除任务或任务列表(标记为删除并提交更新) - 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"); - } - } - // 获取所有任务列表(从Google Tasks获取根任务列表数据) - 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);// 创建GET请求 - HttpResponse response = null; - response = mHttpClient.execute(httpGet); -// 解析响应内容 - // get the task list - String resString = getResponseContent(response.getEntity()); - String jsBegin = "_setup("; - String jsEnd = ")}"; - 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) { -// HTTP协议异常 - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("gettasklists: httpget failed"); - } catch (IOException e) { - // IO异常 - Log.e(TAG, e.toString()); - e.printStackTrace(); - throw new NetworkFailureException("gettasklists: httpget failed"); - } catch (JSONException e) { -// JSON解析异常 - 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; - } -}