Merge branch 'wangmingqiang_branch' of https://bdgit.educoder.net/pxsi3jbgc/Notes into wangmingqiang_branch

pull/11/head
laptoy 12 months ago
commit cbf2534d2e

@ -0,0 +1,216 @@
/**
* @ProiectName:MiNote
* @Package: gtask.remote
* @ClassName: GTaskASyncTask
* @Description:GTaskASyncTaskUI线UI
* 1.线UI线UI
* 2.GTaskASyncTaskpublishProgress()
* UI线onProgressUpdate()便UI
* 3.GTaskASyncTaskUI线UI线onPostExecute()
* UI
* @Author: wmq
*/
package net.micode.notes.gtask.remote;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import net.micode.notes.R;
import net.micode.notes.ui.NotesListActivity;
import net.micode.notes.ui.NotesPreferenceActivity;
/**
* @: GTaskASyncTask
* @ :
* mContext
* mNotifiManager
* mTaskManagerGTaskManager
* mOnCompleteListener
* @:GTaskASyncTask
* 使
*
* @:
* @Author: wmq
*/
public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {//执行的任务可以接收Void类型的输入参数发布String类型的进度信息最终返回Integer类型的结果。
private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;//静态变量用于标识通知的ID。通常用于发送通知时唯一标识通知的标识符。
public interface OnCompleteListener {//内部接口定义了一个回调方法onComplete()。当任务完成时,可以通过实现该接口,在任务完成时进行回调通知。
void onComplete();
}
private Context mContext;
private NotificationManager mNotifiManager;
private GTaskManager mTaskManager;
private OnCompleteListener mOnCompleteListener;
/**
* @: GTaskASyncTask
* @ : context/listener
* @: )
* @:
* @Author: wmq
*/
public GTaskASyncTask(Context context, OnCompleteListener listener) {
mContext = context; //将传入的OnCompleteListener接口的实例赋值给成员变量mOnCompleteListener。用于在任务完成时回调通知调用者。
mOnCompleteListener = listener;
mNotifiManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);//通过上下文对象获取通知管理器的实例。该通知管理器用于发送通知。
mTaskManager = GTaskManager.getInstance();//通过调用GTaskManager类的静态方法getInstance()获取GTaskManager的单例实例。mTaskManager用于管理任务的执行。
}
/**
* @: cancelSync()
* @ :
* @:
* @: mTaskManagercancelSync()
*
* @Author: wmq
*/
public void cancelSync() {
mTaskManager.cancelSync();
}
/**
* @: publishProgess
* @ :message
* @: ,
* publishProgress()UI线onProgressUpdate()
* UI
* @: publishProgessAsyncTaskpublishProgress()
* messageGTaskASyncTask
* publishProgess()
* @Author: wmq
*/
public void publishProgess(String message) {// 发布进度单位系统将会调用onProgressUpdate()方法更新这些值
publishProgress(new String[] {
message
});
}
/* private void showNotification(int tickerId, String content) {
Notification notification = new Notification(R.drawable.notification, mContext
.getString(tickerId), System.currentTimeMillis());
notification.defaults = Notification.DEFAULT_LIGHTS;
notification.flags = Notification.FLAG_AUTO_CANCEL;
PendingIntent pendingIntent;
if (tickerId != R.string.ticker_success) {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesPreferenceActivity.class), 0);
} else {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesListActivity.class), 0);
}
//notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
// pendingIntent);
notification.contentIntent = pendingIntent;
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
}*/
/**
* @: showNotification
* @ :int tickerId / String content
* @:
* tickerId
* 使Notification.Builder
* builder.getNotification()
* 使mNotifiManager.notify()
* @: tickerIdR.string.ticker_success
* NotesPreferenceActivityPendingIntenttickerIdR.string.ticker_success
* NotesListActivityPendingIntent
* @Author: wmq
*/
private void showNotification(int tickerId, String content) {
PendingIntent pendingIntent;
if (tickerId != R.string.ticker_success) {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesPreferenceActivity.class), 0);
} else {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesListActivity.class), 0);
}
Notification.Builder builder = new Notification.Builder(mContext)
.setAutoCancel(true) //设置通知点击后自动取消
.setContentTitle(mContext.getString(R.string.app_name))//设置通知的标题为应用名称。
.setContentText(content)//设置通知的内容为传入的content参数。
.setContentIntent(pendingIntent)//设置通知点击时的跳转意图为之前创建的PendingIntent对象。
.setWhen(System.currentTimeMillis())//时间设置
.setOngoing(true);//用户无法手动清除
Notification notification=builder.getNotification();
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);//将通知显示在系统通知栏中。其中GTASK_SYNC_NOTIFICATION_ID作为通知的ID可以用于标识该通知。
}
/**
* @: doInBackground
* @ : unused
* @:
* @: @OverrideAsyncTask
*publishProgress()
*
* @Author: wmq
*/
@Override
protected void onProgressUpdate(String... progress) {
showNotification(R.string.ticker_syncing, progress[0]);
if (mContext instanceof GTaskSyncService) {
((GTaskSyncService) mContext).sendBroadcast(progress[0]);
}
}
/**
* @: onPostExecute
* @ : result
* @: UI
* @: result
* @Author: wmq
*/
@Override //表示该方法是对父类AsyncTask中的方法进行重写
protected void onPostExecute(Integer result) { //这表示该方法接收一个Integer类型的参数result表示后台操作的结果。
if (result == GTaskManager.STATE_SUCCESS) { //表示同步操作成功那么会显示一个通知更新上次同步时间并执行NotesPreferenceActivity.setLastSyncTime()方法保存最新的同步时间。
showNotification(R.string.ticker_success, mContext.getString(
R.string.success_sync_account, mTaskManager.getSyncAccount()));
NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis());
} else if (result == GTaskManager.STATE_NETWORK_ERROR) { //表示网络错误,会显示一个通知,提示同步时发生网络错误。
showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network));
} else if (result == GTaskManager.STATE_INTERNAL_ERROR) { //表示内部错误会显示一个通知提示同步时发生内部错误。如果result等于
showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal));
} else if (result == GTaskManager.STATE_SYNC_CANCELLED) { //表示同步被取消,会显示一个通知,提示同步被取消。
showNotification(R.string.ticker_cancel, mContext
.getString(R.string.error_sync_cancelled));
}
if (mOnCompleteListener != null) { //如果存在mOnCompleteListener回调函数对象会在新的线程中执行mOnCompleteListener.onComplete()方法。
new Thread(new Runnable() {
public void run() {
mOnCompleteListener.onComplete();
}
}).start();
}
}
}

@ -0,0 +1,767 @@
/**
* @ProiectName:MiNote
* @Package: gtask.remote
* @ClassName: GTaskAClient
* @Description: GTaskGoogle Tasks API使便使Google Tasks
* @Author: wmq
*/
package net.micode.notes.gtask.remote;
//以下内容为引入Android中的各个类
import android.accounts.Account;//引入Android中的Account类代表一个用户账户
import android.accounts.AccountManager;//引入Android中的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;
/**
* @: GTaskClient
* @: GTaskClient
* @: 使GTaskClient
* @Author: wmq
*/
public class GTaskClient {
private static final String TAG = GTaskClient.class.getSimpleName();//TAG是一个常量字符串用于在日志输出中标识GTaskClient类。
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;
/**
* @: GTaskClient()
* @: GTaskClient
* @:
* @Author: wmq
*/
private GTaskClient() {
mHttpClient = null; //将mHttpClient初始化为null表示初始情况下没有可用的HTTP客户端。
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
mClientVersion = -1; //将mClientVersion初始化为-1表示客户端版本号未知。
mLoggedin = false; //将mLoggedin初始化为false表示当前未登录状态。
mLastLoginTime = 0; //将mLastLoginTime初始化为0表示上次登录时间为初始状态。
mActionId = 1;
mAccount = null;
mUpdateArray = null;
}
/**
* @:getInstance
* @ :mInstance
* @:
* @: 使getInstance(),mInstance
* @Author: wmq
*/
public static synchronized GTaskClient getInstance() {
if (mInstance == null) {
mInstance = new GTaskClient();
}
return mInstance;
}
/**
* @: login
* @ : activity
* @: Google TasksTokenURL
* @: ,
*
* @Author: wmq
*/
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);//进行账户登录获取授权Token。
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
/**
*googleURL
*mLoggedintrue
*/
if (!mLoggedin) {
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
if (!tryToLoginGtask(activity, authToken)) {
return false;
}
}
mLoggedin = true;//将登录状态设置为true并返回true表示登录成功。
return true;
}
/**
* @: loginGoogleAccount
* @ : activity()/invalidateToken
* @: GoogleToken
* @: AccountManager
* "com.google"
* Googlenull
*
*
* mAccountnull
* getAuthTokenToken
* accountManagerFuture.getResult()TokenauthToken
* loginGoogleAccount(activity, false)Token
* TokenauthTokennull
* Token
* @Author: wmq
*/
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
String authToken;
AccountManager accountManager = AccountManager.get(activity);//获取系统对象
Account[] accounts = accountManager.getAccountsByType("com.google");//获取类型为"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);
//"goanna_mobile"是用于访问Google服务的令牌类型
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;
}
/**
* @: tryToLoginGtask
* @ : activity() / authToken
* @: 使TokenGoogleGTask
* @: tryToLoginGtaskloginGtask使TokenGTask
* TokenTokenGTask
* @Author: wmq
*/
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;
}
/**
* @: loginGtask
* @ : authToken
* @: GoogleGTask
* @:
* TokenURL
* Cookie"GTL"Cookie
*
* @Author: wmq
*/
//创建了一个DefaultHttpClient对象并设置了一些Http参数
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
//创建一个HttpGet对象并使用mHttpClient.execute(httpGet)发送请求,获取响应
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) { //检查是否存在名为"GTL"的认证Cookie
Log.w(TAG, "it seems that there is no auth cookie");
}
// get the client version
//查找特定字符串来获取JavaScript代码块并将其解析为JSON对象从中提取客户端版本号
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; //返回true表示登录成功
}
/**
* @: getActionId
* @: ,
* @: getActionId()mActionId1
* @Author: wmq
*/
private int getActionId() {
return mActionId++;
}
/**
* @: createHttpPost
* @: HttpPost
* @: HttpPostURLmPostUrl
* Content-Type,httpPost
* @Author: wmq
*/
private HttpPost createHttpPost() {
HttpPost httpPost = new HttpPost(mPostUrl);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
httpPost.setHeader("AT", "1"); //设置了一个名为AT的请求头并将值设置为1
return httpPost;
}
/**
* @: getResponseContent
* @ : HttpEntity entity
* @: HttpEntity
* @: HttpEntity,InputStreamReaderBufferedReader
*
* @Author: wmq
*/
private String getResponseContent(HttpEntity entity) throws IOException {
String contentEncoding = null;
if (entity.getContentEncoding() != null) {
contentEncoding = entity.getContentEncoding().getValue();
Log.d(TAG, "encoding: " + contentEncoding);
}
/**
* "gzip"使GZIPInputStream
* "deflate"使InflaterInputStream
*/
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();//在处理完响应内容后,确保关闭了输入流,以释放资源。
}
}
/**
* @: postRequest
* @ : JSONObject js
* @: POSTJSONObject
* @: HttpPost,JSON
* 0BasicNameValuePair,POST
* @Author: wmq
*/
private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
if (!mLoggedin) {
Log.e(TAG, "please login first");//如果没有登录则抛出ActionFailureException异常并提示用户需要先登录
throw new ActionFailureException("not logged in");
}
HttpPost httpPost = createHttpPost();//创建一个HttpPost对象
try {//设置请求头等参数
LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>();
list.add(new BasicNameValuePair("r", js.toString()));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
httpPost.setEntity(entity);
//将JSON格式的数据放入一个BasicNameValuePair列表中并将列表转换为UrlEncodedFormEntity实体。
// 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");
}
}
/**
* @: createTask
* @ : Task task
* @:
* @: commitUpdate(),JSONObject,postRequest(jsPost)POST,
* IDtask
* @Author: wmq
*/
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
//将actionList放入jsPost中并添加客户端版本信息
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// post
JSONObject jsResponse = postRequest(jsPost);//向服务器发送POST请求并获取服务器返回的响应
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
} catch (JSONException e) { //如果在处理过程中出现JSONException异常则会捕获并打印日志
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("create task: handing jsonobject failed");
}
}
/**
* @: createTaskList.NetworkFailureException
* @ : TaskList tasklist
* @:
* @: commitUpdate(), JSONObject, tasklist.getCreateAction(getActionId())
* ,IDtasklist
* @Author: wmq
*/
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
//将actionList放入jsPost中并添加客户端版本信息
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// post
//调用postRequest(jsPost)方法向服务器发送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) { //处理过程中出现JSONException异常则会捕获并打印日志并抛出ActionFailureException异常表示处理JSON对象失败
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("create tasklist: handing jsonobject failed");
}
}
/**
* @: NetworkFailureException
* @:
* @Author: wmq
*/
public void commitUpdate() throws NetworkFailureException {
if (mUpdateArray != null) {
try {
JSONObject jsPost = new JSONObject();
/**
* mUpdateArrayJSONObjectjsPost
* mUpdateArrayjsPost
*/
// action_list
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);//向服务器发送POST请求将更新的任务数据提交到服务器进行处理
mUpdateArray = null;//mUpdateArray设置为null表示已经提交了所有的任务更新操作
} catch (JSONException e) { //处理过程中出现JSONException异常则会捕获并打印日志
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("commit update: handing jsonobject failed");
}
}
}
/**
* @: NetworkFailureException
* @ : Node node
* @:
* @Author: wmq
*/
public void addUpdateNode(Node node) throws NetworkFailureException {
if (node != null) {
// too many update items may result in an error
// set max to 10 items
/**
* nodemUpdateArray,
* commitUpdate()
*/
if (mUpdateArray != null && mUpdateArray.length() > 10) {
commitUpdate();
}
if (mUpdateArray == null)//如果mUpdateArray仍然为空那么它会创建一个JSONArray对象mUpdateArray用于存储任务更新操作
mUpdateArray = new JSONArray();
mUpdateArray.put(node.getUpdateAction(getActionId()));//获取节点的更新操作并将其添加到mUpdateArray中
}
}
/**
* @: moveTask
* @ : task, preParent, curParent
* @:
* @: jsPost
* @Author: wmq
*/
/**
* commitUpdate()
*/
public void moveTask(Task task, TaskList preParent, TaskList curParent)
throws NetworkFailureException {
commitUpdate();
/**
* JSONArrayactionList
* JSONObjectaction
*/
try {
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
JSONObject action = new JSONObject();
// action_list
//在action中它设置了以下属性
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());
}
//将action添加到actionList中并将actionList添加到jsPost中
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) { //如果在处理过程中出现JSONException异常则会捕获并打印日志
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("move task: handing jsonobject failed");
}
}
/**
* @: deleteNode
* @ : node
* @: Node
* @: JSONObject
* jsPostmUpdateArraynull
* @Author: wmq
*/
public void deleteNode(Node node) throws NetworkFailureException {
commitUpdate();
try {
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
// action_list
/**
* nodedeletedtrue
* node.getUpdateAction(getActionId())JSONObjectactionList
*/
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);
/**
* jsPostpostRequest(jsPost)POST
* JSONException
* ActionFailureExceptionJSON
*/
postRequest(jsPost);
mUpdateArray = null;
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("delete node: handing jsonobject failed");
}
}
/**
* @: getTaskLists
* @ : mLoggedin
* @: Task Lists
* @: HttpGetGET,HttpResponse
* JSONObjectjs
* js"t"GTaskStringUtils.GTASK_JSON_LISTS
* @Author: wmq
*/
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");
}
}
/**
* @: getTaskList
* @ :listGid
* @: Task List
* @: jsPostPOST
* "tasks"
* @Author: wmq
*/
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);//将actionList添加到jsPost中
return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS);
//将客户端版本信息添加到jsPost中并调用postRequest(jsPost)方法向服务器发送POST请求将获取任务列表的操作提交到服务器进行处理。
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("get task list: handing jsonobject failed");
}
}
/**
* @: getSyncAccount
* @:
* @Author: wmq
*/
public Account getSyncAccount() {
return mAccount;
}
/**
* @: resetUpdateArray
* @:
* @: resetUpdateArray()mUpdateArraynull
*
* @Author: wmq
*/
public void resetUpdateArray() {
mUpdateArray = null;
}
}

@ -0,0 +1,100 @@
/**
* @ProiectName:MiNote
* @Package: gtask.remote
* @ClassName: MetaData
* @Description:便
* @Author: wmq
*/
package net.micode.notes.gtask.data;
import android.database.Cursor;
import android.util.Log;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
/**
* @: MetaData extends Task
* @ :
* @: TAG
* @: getSimpleName ()
* @Author: wmq
*/
public class MetaData extends Task {
private final static String TAG = MetaData.class.getSimpleName();
private String mRelatedGid = null;
/**
* @: setMeta
* @ : gid / metaInfo
* @:
* @: JSONObjectput ()TasksetNotes ()setName ()
* @Author: wmq
*/
public void setMeta(String gid, JSONObject metaInfo) {
try {
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);//将这对键值放入metaInfo这个jsonobject对象中
} catch (JSONException e) {
Log.e(TAG, "failed to put related gid");//输出错误信息
}
setNotes(metaInfo.toString());
setName(GTaskStringUtils.META_NOTE_NAME);
}
//功能描述获取相关联的Gid
public String getRelatedGid() {
return mRelatedGid;
}//判断当前数据是否为空,若为空则返回真即值得保存
@Override
public boolean isWorthSaving() {
return getNotes() != null;
}
/**
* @: setContentByRemoteJSON
* @ : JOSN
* @: 使json
* @: TasksetContentByRemoteJSON ()
* @Author: wmq
*/
@Override
public void setContentByRemoteJSON(JSONObject js) {
super.setContentByRemoteJSON(js);
if (getNotes() != null) {
try {
JSONObject metaInfo = new JSONObject(getNotes().trim());
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
} catch (JSONException e) {
Log.w(TAG, "failed to get related gid");
mRelatedGid = null;
}
}
}//使用本地json数据对象设置元数据内容一般不会用到若用到则抛出异常
@Override
public void setContentByLocalJSON(JSONObject js) {
// this function should not be called
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
//传递非法参数异常
}
/**
*
*/
@Override
public JSONObject getLocalJSONFromContent() {
throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");
//传递非法参数异常
}
/**
*
*/
@Override
public int getSyncAction(Cursor c) {
throw new IllegalAccessError("MetaData:getSyncAction should not be called");
}
//传递非法参数异常
}

@ -0,0 +1,269 @@
/**
* @ProiectName:MiNote
* @Package: gtask.data
* @ClassName: SqlData
* @Description:便sqlnotedatanote,SqlData
* @Author: wmq
*/
package net.micode.notes.gtask.data;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
import net.micode.notes.gtask.exception.ActionFailureException;
import org.json.JSONException;
import org.json.JSONObject;
public class SqlData {
/**
* @: TAG
* @: getSimpleName ()
* @Author: wmq
*/
private static final String TAG = SqlData.class.getSimpleName();
private static final int INVALID_ID = -99999;
/*
* NotesDataColumn
*/
// 集合了interface DataColumns中所有SF常量
public static final String[] PROJECTION_DATA = new String[] {
DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,
DataColumns.DATA3
};
// 以下五个变量作为sql表中5列的编号
public static final int DATA_ID_COLUMN = 0;
public static final int DATA_MIME_TYPE_COLUMN = 1;
public static final int DATA_CONTENT_COLUMN = 2;
public static final int DATA_CONTENT_DATA_1_COLUMN = 3;
public static final int DATA_CONTENT_DATA_3_COLUMN = 4;
//以下定义了8个内部的变量
private ContentResolver mContentResolver;
//判断是否直接用Content生成是为true否则为false
private boolean mIsCreate;
private long mDataId;
private String mDataMimeType;
private String mDataContent;
private long mDataContentData1;
private String mDataContentData3;
private ContentValues mDiffDataValues;
/**
* @: SqlData
* @ :context
* @:
* @Author: wmq
*/
public SqlData(Context context) {
//mContentResolver用于获取ContentProvider提供的数据
mContentResolver = context.getContentResolver();
//IsCreate表征当前数据是用哪种方式创建两种构造函数的参数不同
mIsCreate = true;
mDataId = INVALID_ID;//mDataId置初始值-99999
mDataMimeType = DataConstants.NOTE;
mDataContent = "";
mDataContentData1 = 0;
mDataContentData3 = "";
mDiffDataValues = new ContentValues();
}
/**
* @: SqlData
* @ :context / Cursor c
* @: SqlData
* @Author: wmq
*/
public SqlData(Context context, Cursor c) {
/**
* Context访
*/
mContentResolver = context.getContentResolver();
mIsCreate = false;//用于表示是否新建了数据
/**
* CursorCursor便
* SqlData
*/
loadFromCursor(c);
/**
* ContentValuesmDiffDataValues
* 便ContentValues
*
*/
mDiffDataValues = new ContentValues();
}
/**
* @: loadFromCursor
* @ : Cursor c
* @: CursorSqlData
* @:
* CursorID
* CursorMIME
* Cursor
* Cursor1SqlDatamDataContentData1
* @Author: wmq
*/
private void loadFromCursor(Cursor c) {
//直接从一条记录中的获得以下变量的初始值
mDataId = c.getLong(DATA_ID_COLUMN);
mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);
mDataContent = c.getString(DATA_CONTENT_COLUMN);
mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);
mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);
}
/**
* @: setContent
* @ : JSONObject js
* @: JSONObjectSqlData()
* @Author: wmq
*/
public void setContent(JSONObject js) throws JSONException {
long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;//从JSONObject中获取并设置数据ID
if (mIsCreate || mDataId != dataId) {
mDiffDataValues.put(DataColumns.ID, dataId);
}
mDataId = dataId;
String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE)
: DataConstants.NOTE;
if (mIsCreate || !mDataMimeType.equals(dataMimeType)) {
mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType);
}
mDataMimeType = dataMimeType;
String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : "";
if (mIsCreate || !mDataContent.equals(dataContent)) {
mDiffDataValues.put(DataColumns.CONTENT, dataContent);
}
mDataContent = dataContent;
long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0;
/**
* mDiffDataValuesSqlDatamDataContent
*/
if (mIsCreate || mDataContentData1 != dataContentData1) {
mDiffDataValues.put(DataColumns.DATA1, dataContentData1);
}
mDataContentData1 = dataContentData1;//获取并设置附加数据1dataContentData1
String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : "";
/**
* 11mDiffDataValuesSqlDatamDataContentData1
*/
if (mIsCreate || !mDataContentData3.equals(dataContentData3)) {
mDiffDataValues.put(DataColumns.DATA3, dataContentData3);
}
mDataContentData3 = dataContentData3;//取并设置附加数据3dataContentData3
}
/**
* @: getContent
* @: getContent()JSONObjectSqlData
* @:
* mIsCreatetruenull
* JSONObjectSqlDataIDmDataIdMIMEmDataMimeType
* mDataContent1mDataContentData13mDataContentData3
* SqlDataJSONObject
* @Author: wmq
*/
public JSONObject getContent() throws JSONException {
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
//创建JSONObject对象。并将相关数据放入其中并返回。
JSONObject js = new JSONObject();
js.put(DataColumns.ID, mDataId);
js.put(DataColumns.MIME_TYPE, mDataMimeType);
js.put(DataColumns.CONTENT, mDataContent);
js.put(DataColumns.DATA1, mDataContentData1);
js.put(DataColumns.DATA3, mDataContentData3);
return js;
}
// 功能描述:
/**
* @: commit
* @ : noteId / validateVersion / version
* @: commit
* @: SqlDataIDnoteIdmDiffDataValuesContentResolverupdate()
* @Author: wmq
*/
public void commit(long noteId, boolean validateVersion, long version) {
if (mIsCreate) {
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {
mDiffDataValues.remove(DataColumns.ID);
}
mDiffDataValues.put(DataColumns.NOTE_ID, noteId);
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);
try {
mDataId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");
}
} else {
/**
* mDiffDataValues0validateVersion
* 使
*/
if (mDiffDataValues.size() > 0) {
int result = 0;
//如果validateVersion为false表示不需要验证版本直接调用ContentResolver的update()方法更新数据库中对应数据的字段值
if (!validateVersion) {//构造字符串
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null);
} else {
/**
* validateVersiontrueSQL使NoteColumns.IDNoteColumns.VERSION
* IDContentResolverupdate()
*/
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues,
" ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.VERSION + "=?)", new String[] {
String.valueOf(noteId), String.valueOf(version)
});
}
//检查返回的更新结果result是否为0如果是表示没有进行更新操作
if (result == 0) {
Log.w(TAG, "there is no update. maybe user updates note when syncing");
}
}
}
mDiffDataValues.clear();
mIsCreate = false;
}
/**
* @: getId
* @: id
* @Author: wmq
*/
public long getId() {
return mDataId;
}
}

@ -1,150 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.micode.notes"
android:versionCode="1"
android:versionName="0.1" >
<uses-sdk android:minSdkVersion="14" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/icon_app"
android:label="@string/app_name" >
<activity
android:name=".ui.NotesListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustPan" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/NoteTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.INSERT_OR_EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<provider
android:name="net.micode.notes.data.NotesProvider"
android:authorities="micode_notes"
android:multiprocess="true" />
<receiver
android:name=".widget.NoteWidgetProvider_2x"
android:label="@string/app_widget2x2" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_2x_info" />
</receiver>
<receiver
android:name=".widget.NoteWidgetProvider_4x"
android:label="@string/app_widget4x4" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_4x_info" />
</receiver>
<receiver android:name=".ui.AlarmInitReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name="net.micode.notes.ui.AlarmReceiver"
android:process=":remote" >
</receiver>
<activity
android:name=".ui.AlarmAlertActivity"
android:label="@string/app_name"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
</activity>
<activity
android:name="net.micode.notes.ui.NotesPreferenceActivity"
android:label="@string/preferences_title"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Holo.Light" >
</activity>
<service
android:name="net.micode.notes.gtask.remote.GTaskSyncService"
android:exported="false" >
</service>
<meta-data
android:name="android.app.default_searchable"
android:value=".ui.NoteEditActivity" />
</application>
</manifest>
Loading…
Cancel
Save