From 6317399023462f24cad32148726d20d88b46319b Mon Sep 17 00:00:00 2001 From: bingdawan <3598407655@qq.com> Date: Sat, 23 Mar 2024 16:38:36 +0800 Subject: [PATCH] Client --- GTaskClient.java.docx | Bin 0 -> 11383 bytes GTaskClient.java.txt | 612 +++++++++++++++++++++++++++++++ ~$ass GTaskSyncService.java.docx | Bin 162 -> 0 bytes 3 files changed, 612 insertions(+) create mode 100644 GTaskClient.java.docx create mode 100644 GTaskClient.java.txt delete mode 100644 ~$ass GTaskSyncService.java.docx diff --git a/GTaskClient.java.docx b/GTaskClient.java.docx new file mode 100644 index 0000000000000000000000000000000000000000..d8c872ab07b57485e350ec43b97b2434232e2325 GIT binary patch literal 11383 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 P(EuY)_fs_R`M>`MtvWkm literal 0 HcmV?d00001 diff --git a/GTaskClient.java.txt b/GTaskClient.java.txt new file mode 100644 index 0000000..25b2a6a --- /dev/null +++ b/GTaskClient.java.txt @@ -0,0 +1,612 @@ +package net.micode.notes.gtask.remote; + +/* + * 主要功能:实现GTASK的登录操作,进行GTASK任务的创建,创建任务列表,从网络上获取任务和任务列表的内容 + * 主要使用类或技术:accountManager JSONObject HttpParams authToken Gid + */ +public class GTaskClient { + private static final String TAG = GTaskClient.class.getSimpleName(); + + private static final String GTASK_URL = "https://mail.google.com/tasks/"; //这个是指定的URL + + 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; + } + + /*用来获取的实例化对象 + * 使用 getInstance() + * 返回mInstance这个实例化对象 + */ + public static synchronized GTaskClient getInstance() { + if (mInstance == null) { + mInstance = new GTaskClient(); + } + return mInstance; + } + + /*用来实现登录操作的函数,传入的参数是一个Activity + * 设置登录操作限制时间,如果超时则需要重新登录 + * 有两种登录方式,使用用户自己的URL登录或者使用谷歌官方的URL登录 + * 返回true或者false,即最后是否登陆成功 + */ + 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; //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"; //设置用户对应的getUrl + mPostUrl = url.toString() + "r/ig"; //设置用户对应的postUrl + + if (tryToLoginGtask(activity, authToken)) { + mLoggedin = true; + } + } + + // try to login with google official url + //如果用户账户无法登录,则使用谷歌官方的URI进行登录 + if (!mLoggedin) { + mGetUrl = GTASK_GET_URL; + mPostUrl = GTASK_POST_URL; + if (!tryToLoginGtask(activity, authToken)) { + return false; + } + } + + mLoggedin = true; + return true; + } + + /*具体实现登录谷歌账户的方法 + * 使用令牌机制 + * 使用AccountManager来管理注册账号 + * 返回值是账号的令牌 + */ + private String loginGoogleAccount(Activity activity, boolean invalidateToken) { + String authToken; //令牌,是登录操作保证安全性的一个方法 + AccountManager accountManager = AccountManager.get(activity);//AccountManager这个类给用户提供了集中注册账号的接口 + Account[] accounts = accountManager.getAccountsByType("com.google");//获取全部以com.google结尾的account + + if (accounts.length == 0) { + Log.e(TAG, "there is no available google account"); + return null; + } + + String accountName = NotesPreferenceActivity.getSyncAccountName(activity); + Account account = null; + //遍历获得的accounts信息,寻找已经记录过的账户信息 + 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); + //如果是invalidateToken,那么需要调用invalidateAuthToken(String, String)方法废除这个无效token + if (invalidateToken) { + accountManager.invalidateAuthToken("com.google", authToken); + loginGoogleAccount(activity, false); + } + } catch (Exception e) { + Log.e(TAG, "get auth token failed"); + authToken = null; + } + + return authToken; + } + + //尝试登陆Gtask,这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法 + private boolean tryToLoginGtask(Activity activity, String authToken) { + if (!loginGtask(authToken)) { + // maybe the auth token is out of authTokedate, now let's invalidate the + // token and try again + //删除过一个无效的authToken,申请一个新的后再次尝试登陆 + 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; + } + + //实现登录GTask的具体操作 + private boolean loginGtask(String authToken) { + int timeoutConnection = 10000; + int timeoutSocket = 15000; //socket是一种通信连接实现数据的交换的端口 + HttpParams httpParameters = new BasicHttpParams(); //实例化一个新的HTTP参数类 + HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);//设置连接超时时间 + HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);//设置设置端口超时时间 + mHttpClient = new DefaultHttpClient(httpParameters); + BasicCookieStore localBasicCookieStore = new BasicCookieStore(); //设置本地cookie + mHttpClient.setCookieStore(localBasicCookieStore); + HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); + + // login gtask + try { + String loginUrl = mGetUrl + "?auth=" + authToken; //设置登录的url + HttpGet httpGet = new HttpGet(loginUrl); //通过登录的uri实例化网页上资源的查找 + HttpResponse response = null; + response = mHttpClient.execute(httpGet); + + // get the cookie now + //获取CookieStore里存放的cookie,看如果存有“GTL(不知道什么意思)”,则说明有验证成功的有效的cookie + 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 + //获取client的内容,具体操作是在返回的Content中截取从_setup(开始到)}中间的字符串内容,也就是gtask_url的内容 + 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++; + } + + /*实例化创建一个用于向网络传输数据的对象 + * 使用HttpPost类 + * 返回一个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; + } + + /*通过URL获取响应后返回的数据,也就是网络上的数据和资源 + * 使用getContentEncoding()获取网络上的资源和数据 + * 返回值就是获取到的资源 + */ + private String getResponseContent(HttpEntity entity) throws IOException { + String contentEncoding = null; + if (entity.getContentEncoding() != null) {//通过URL得到HttpEntity对象,如果不为空则使用getContent()方法创建一个流将数据从网络都过来 + contentEncoding = entity.getContentEncoding().getValue(); + Log.d(TAG, "encoding: " + contentEncoding); + } + + InputStream input = entity.getContent(); + if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {//GZIP是使用DEFLATE进行压缩数据的另一个压缩库 + input = new GZIPInputStream(entity.getContent()); + } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {//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(); + } + } + + /*通过JSON发送请求 + * 请求的具体内容在json的实例化对象js中然后传入 + * 利用UrlEncodedFormEntity entity和httpPost.setEntity(entity)方法把js中的内容放置到httpPost中 + * 执行请求后使用getResponseContent方法得到返回的数据和资源 + * 将资源再次放入json后返回 + */ + private JSONObject postRequest(JSONObject js) throws NetworkFailureException { + if (!mLoggedin) {//未登录 + Log.e(TAG, "please login first"); + throw new ActionFailureException("not logged in"); + } + + //实例化一个httpPost的对象用来向服务器传输数据,在这里就是发送请求,而请求的内容在js里 + HttpPost httpPost = createHttpPost(); + try { + LinkedList list = new LinkedList(); + list.add(new BasicNameValuePair("r", js.toString())); + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); //UrlEncodedFormEntity()的形式比较单一,是普通的键值对 + 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"); + } + } + + /*创建单个任务 + * 传入参数是一个.gtask.data.Task包里Task类的对象 + * 利用json获取Task里的内容,并且创建相应的jsPost + * 利用postRequest得到任务的返回信息 + * 使用task.setGid设置task的new_ID + */ + 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"); + } + } + + /* + * 创建一个任务列表,与createTask几乎一样,区别就是最后设置的是tasklist的gid + */ + 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"); + } + } + + /* + * 同步更新操作 + * 使用JSONObject进行数据存储,使用jsPost.put,Put的信息包括UpdateArray和ClientVersion + * 使用postRequest发送这个jspost,进行处理 + */ + 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"); + } + } + } + + /* + * 添加更新的事项 + * 调用commitUpdate()实现 + */ + 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())); + } + } + + /* + * 移动task,比如讲task移动到不同的task列表中去 + * 通过getGid获取task所属列表的gid + * 通过JSONObject.put(String name, Object value)函数设置移动后的task的相关属性值,从而达到移动的目的 + * 最后还是通过postRequest进行更新后的发送 + */ + 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 + //设置优先级ID,只有当移动是发生在文件中 + 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); + //最后将ACTION_LIST加入到jsPost中 + 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"); + } + } + + /* + * 删除操作节点 + * 还是利用JSON + * 删除过后使用postRequest发送删除后的结果 + */ + 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())); //这里会获取到删除操作的ID,加入到actionLiast中 + 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"); + } + } + + /* + * 获取任务列表 + * 首先通过GetURI使用getResponseContent从网上获取数据 + * 然后筛选出"_setup("到)}的部分,并且从中获取GTASK_JSON_LISTS的内容返回 + */ + 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 + //筛选工作,把筛选出的字符串放入jsString + 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); + //获取GTASK_JSON_LISTS + 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"); + } + } + + /* + * 通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务 + */ + 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); //这里设置为传入的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; + } +} \ No newline at end of file diff --git a/~$ass GTaskSyncService.java.docx b/~$ass GTaskSyncService.java.docx deleted file mode 100644 index dabb50a6688743286a232ae5fea69e6200dc66af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 ZcmZQcEG{i(AQiAMBr+5;lmapB0RYR}1Azbl