Compare commits

..

8 Commits

Binary file not shown.

Binary file not shown.

@ -0,0 +1,66 @@
/*
* 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.
*/
/*
* Description便
*/
/**
* @ProjectName: MiNote
* @Package: net.micode.notes.gtask.exception
* @ClassName: ActionFailureException
* @Description: RuntimeException便
* @Author: cyh
*/
package net.micode.notes.gtask.exception;
public class ActionFailureException extends RuntimeException {
private static final long serialVersionUID = 4425249765923293627L;//serialVersionUID相当于java类的身份证。主要用于版本控制。
/**
* @ ActionFailureException()
* @ ActionFailureException
* @ RuntimeException
* @Author:cyh
*/
public ActionFailureException() {
super();
}
/**
* @ActionFailureException(String paramString)
* @String paramString
* @ActionFailureException
* @ RuntimeException paramString
* @Author:cyh
*/
public ActionFailureException(String paramString) {
super(paramString);
}
/**
* @ActionFailureException(String paramString, Throwable paramThrowable)
* @String paramString, Throwable paramThrowable
* @ActionFailureException
* @ RuntimeException paramString paramThrowable
* @Author:cyh
*/
public ActionFailureException(String paramString, Throwable paramThrowable) {
super(paramString, paramThrowable);
}
}

@ -1,216 +0,0 @@
/**
* @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();
}
}
}

@ -1,767 +0,0 @@
/**
* @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,998 @@
/*
* 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.
*/
/**
* @ProjectName: MiNote
* @Package: net.micode.notes.gtask.remote
* @ClassName: GTaskManager
* @Description: Google Google
*
* GTaskManager
* GTaskManager
* Activity
*
* GTaskList Google JSON TaskList
*
* Meta
* ID
* 线
* @Author: cyh
*/
package net.micode.notes.gtask.remote;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.data.MetaData;
import net.micode.notes.gtask.data.Node;
import net.micode.notes.gtask.data.SqlNote;
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.DataUtils;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
public class GTaskManager {
private static final String TAG = GTaskManager.class.getSimpleName();
public static final int STATE_SUCCESS = 0;
public static final int STATE_NETWORK_ERROR = 1;
public static final int STATE_INTERNAL_ERROR = 2;
public static final int STATE_SYNC_IN_PROGRESS = 3;
public static final int STATE_SYNC_CANCELLED = 4;
private static GTaskManager mInstance = null;
private Activity mActivity;
private Context mContext;
private ContentResolver mContentResolver;
private boolean mSyncing;
private boolean mCancelled;
private HashMap<String, TaskList> mGTaskListHashMap;
private HashMap<String, Node> mGTaskHashMap;
private HashMap<String, MetaData> mMetaHashMap;
private TaskList mMetaList;
private HashSet<Long> mLocalDeleteIdMap;
private HashMap<String, Long> mGidToNid;
private HashMap<Long, String> mNidToGid;
/**
* @GTaskManager()
* @ GTaskManager
* @
* @Author:cyh
*/
private GTaskManager() { //对象初始化函数
mSyncing = false; //正在同步,flase代表未执行
mCancelled = false; //全局标识flase代表可以执行
mGTaskListHashMap = new HashMap<String, TaskList>(); //<>代表Java的泛型,就是创建一个用类型作为参数的类。
mGTaskHashMap = new HashMap<String, Node>();
mMetaHashMap = new HashMap<String, MetaData>();
mMetaList = null;
mLocalDeleteIdMap = new HashSet<Long>();
mGidToNid = new HashMap<String, Long>();
mNidToGid = new HashMap<Long, String>(); //通过hashmap散列表建立映射
}
/**
* @GTaskManager getInstance()
* @GTaskManager getInstance() GTaskManager
* @ mInstance null null GTaskManager mInstance null new GTaskManager() GTaskManager mInstance mInstance GTaskManager
* @Author:cyh
*/
public static synchronized GTaskManager getInstance() { //可能运行在多线程环境下,使用语言级同步--synchronized
if (mInstance == null) {
mInstance = new GTaskManager();
}
return mInstance;
}
/**
* @setActivityContext(Activity activity)
* @Activity activity
* @ Activity Activity
* @ activity mActivity
* @Author:cyh
*/
public synchronized void setActivityContext(Activity activity) {
// used for getting authtoken
mActivity = activity;
}
/**
* @sync(Context context, GTaskASyncTask asyncTask)
* @Context context, GTaskASyncTask asyncTask
* @
* @
* mSyncing true STATE_SYNC_IN_PROGRESS
* context mContext ContentResolver
* mSyncing true
* 便
* GTaskClient.getInstance() GTaskClient
* Google NetworkFailureException
* Google TaskList
*
* NetworkFailureException STATE_NETWORK_ERROR
* ActionFailureException STATE_INTERNAL_ERROR
* STATE_INTERNAL_ERROR
* finally mSyncing false
* STATE_SYNC_CANCELLED STATE_SUCCESS
* @Author:cyh
*/
public int sync(Context context, GTaskASyncTask asyncTask) { //核心函数
if (mSyncing) {
Log.d(TAG, "Sync is in progress"); //创建日志文件调试信息debug
return STATE_SYNC_IN_PROGRESS;
}
mContext = context;
mContentResolver = mContext.getContentResolver();
mSyncing = true;
mCancelled = false;
mGTaskListHashMap.clear();
mGTaskHashMap.clear();
mMetaHashMap.clear();
mLocalDeleteIdMap.clear();
mGidToNid.clear();
mNidToGid.clear();
try {
GTaskClient client = GTaskClient.getInstance(); //getInstance即为创建一个实例,client--客户机
client.resetUpdateArray();
// login google task
if (!mCancelled) {
if (!client.login(mActivity)) {
throw new NetworkFailureException("login google task failed");
}
}
// get the task list from google
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list));
initGTaskList(); //获取Google上的JSONtasklist转为本地TaskList
// do content sync work
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing));
syncContent();
} catch (NetworkFailureException e) { //分为两种异常,此类异常为网络异常
Log.e(TAG, e.toString()); //创建日志文件调试信息error
return STATE_NETWORK_ERROR;
} catch (ActionFailureException e) { //此类异常为操作异常
Log.e(TAG, e.toString());
return STATE_INTERNAL_ERROR;
} catch (Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return STATE_INTERNAL_ERROR;
} finally {
mGTaskListHashMap.clear();
mGTaskHashMap.clear();
mMetaHashMap.clear();
mLocalDeleteIdMap.clear();
mGidToNid.clear();
mNidToGid.clear();
mSyncing = false;
}
return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS;
}
/**
* @initGTaskList()
* @GTaskGTask
* @
*GTaskClientJSONJSONTaskListJSONJSONMetaDataJSONisWorthSaving()gidMetaDatamMetaHashMap
* 使GTaskClientcreateTaskList
* JSONTaskListJSONJSONTaskJSONmMetaHashMap使gidTaskmGTaskHashMap
* JSONActionFailureException
* @Author:cyh
*/
private void initGTaskList() throws NetworkFailureException {
if (mCancelled)
return;
GTaskClient client = GTaskClient.getInstance();
try {
//Json对象是Name Value对(即子元素)的无序集合相当于一个Map对象。JsonObject类是bantouyan-json库对Json对象的抽象提供操纵Json对象的各种方法。
//其格式为{"key1":value1,"key2",value2....};key 必须是字符串。
//因为ajax请求不刷新页面但配合js可以实现局部刷新因此json常常被用来作为异步请求的返回对象使用。
JSONArray jsTaskLists = client.getTaskLists();
// init meta list first
mMetaList = null; //TaskList类型
for (int i = 0; i < jsTaskLists.length(); i++) {
JSONObject object = jsTaskLists.getJSONObject(i); //JSONObject与JSONArray一个为对象一个为数组。此处取出单个JASONObject
String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);
String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);
if (name
.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) {
mMetaList = new TaskList(); //MetaList意为元表,Tasklist类型此处为初始化
mMetaList.setContentByRemoteJSON(object); //将JSON中部分数据复制到自己定义的对象中相对应的数据name->mname...
// load meta data
JSONArray jsMetas = client.getTaskList(gid);
for (int j = 0; j < jsMetas.length(); j++) {
object = (JSONObject) jsMetas.getJSONObject(j);
MetaData metaData = new MetaData();
metaData.setContentByRemoteJSON(object);
if (metaData.isWorthSaving()) { //如果不值得保存metadata将不加入mMetaList
mMetaList.addChildTask(metaData);
if (metaData.getGid() != null) {
mMetaHashMap.put(metaData.getRelatedGid(), metaData);
}
}
}
}
}
// create meta list if not existed
if (mMetaList == null) {
mMetaList = new TaskList();
mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_META);
GTaskClient.getInstance().createTaskList(mMetaList);
}
// init task list
for (int i = 0; i < jsTaskLists.length(); i++) {
JSONObject object = jsTaskLists.getJSONObject(i);
String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); //通过getString函数传入本地某个标志数据的名称获取其在远端的名称。
String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);
if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)
&& !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_META)) {
TaskList tasklist = new TaskList(); //继承自Node
tasklist.setContentByRemoteJSON(object);
mGTaskListHashMap.put(gid, tasklist);
mGTaskHashMap.put(gid, tasklist);
// load tasks
JSONArray jsTasks = client.getTaskList(gid);
for (int j = 0; j < jsTasks.length(); j++) {
object = (JSONObject) jsTasks.getJSONObject(j);
gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);
Task task = new Task();
task.setContentByRemoteJSON(object);
if (task.isWorthSaving()) {
task.setMetaInfo(mMetaHashMap.get(gid));
tasklist.addChildTask(task);
mGTaskHashMap.put(gid, task);
}
}
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("initGTaskList: handing JSONObject failed");
}
}
/**
* @syncContent()
* @GTask
* @
* mLocalDeleteIdMapIDHashSet
* mGTaskHashMapgidNodeNodeNodemGTaskHashMapdoContentSyncIDmLocalDeleteIdMap
* syncFolder
* mGTaskHashMapgidNodeNodeNodeNode
* 使IteratormGTaskHashMapNode
* mCancelledtrue
* IDGTask
* @Author:cyh
*/
private void syncContent() throws NetworkFailureException { //本地内容同步操作
int syncType;
Cursor c = null; //数据库指针
String gid;
Node node; //Node包含Sync_Action的不同类型
mLocalDeleteIdMap.clear(); //HashSet<Long>类型
if (mCancelled) {
return;
}
// for local deleted note
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type<>? AND parent_id=?)", new String[] {
String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)
}, null);
if (c != null) {
while (c.moveToNext()) {
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c);
}
mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN));
}
} else {
Log.w(TAG, "failed to query trash folder");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// sync folder first
syncFolder();
// for note existing in database
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type=? AND parent_id<>?)", new String[] {
String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER)
}, NoteColumns.TYPE + " DESC");
if (c != null) {
while (c.moveToNext()) {
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); //通过hashmap建立联系
mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); //通过hashmap建立联系
syncType = node.getSyncAction(c);
} else {
if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {
// local add
syncType = Node.SYNC_ACTION_ADD_REMOTE;
} else {
// remote delete
syncType = Node.SYNC_ACTION_DEL_LOCAL;
}
}
doContentSync(syncType, node, c);
}
} else {
Log.w(TAG, "failed to query existing note in database");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// go through remaining items
Iterator<Map.Entry<String, Node>> iter = mGTaskHashMap.entrySet().iterator(); //Iterator迭代器
while (iter.hasNext()) {
Map.Entry<String, Node> entry = iter.next();
node = entry.getValue();
doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);
}
// mCancelled can be set by another thread, so we neet to check one by //thread----线程
// one
// clear local delete table
if (!mCancelled) {
if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) {
throw new ActionFailureException("failed to batch-delete local deleted notes");
}
}
// refresh local sync id
if (!mCancelled) {
GTaskClient.getInstance().commitUpdate();
refreshLocalSyncId();
}
}
/**
* @syncFolder()
* @
* @root folder call-note folder GTask GTask ID GTask ContentProvider GTask ContentProvider
* @Author:cyh
*/
private void syncFolder() throws NetworkFailureException {
Cursor c = null;
String gid;
Node node;
int syncType;
if (mCancelled) {
return;
}
// for root folder
try {
c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,
Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null);
if (c != null) {
c.moveToNext();
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER);
mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid);
// for system folder, only update remote name if necessary
if (!node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT))
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);
}
} else {
Log.w(TAG, "failed to query root folder");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// for call-note folder
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)",
new String[] {
String.valueOf(Notes.ID_CALL_RECORD_FOLDER)
}, null);
if (c != null) {
if (c.moveToNext()) {
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER);
mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid);
// for system folder, only update remote name if
// necessary
if (!node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE))
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);
}
}
} else {
Log.w(TAG, "failed to query call note folder");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// for local existing folders
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type=? AND parent_id<>?)", new String[] {
String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)
}, NoteColumns.TYPE + " DESC");
if (c != null) {
while (c.moveToNext()) {
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN));
mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid);
syncType = node.getSyncAction(c);
} else {
if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {
// local add
syncType = Node.SYNC_ACTION_ADD_REMOTE;
} else {
// remote delete
syncType = Node.SYNC_ACTION_DEL_LOCAL;
}
}
doContentSync(syncType, node, c);
}
} else {
Log.w(TAG, "failed to query existing folder");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// for remote add folders
Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, TaskList> entry = iter.next();
gid = entry.getKey();
node = entry.getValue();
if (mGTaskHashMap.containsKey(gid)) {
mGTaskHashMap.remove(gid);
doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);
}
}
if (!mCancelled)
GTaskClient.getInstance().commitUpdate();
}
/**
* @doContentSync(int syncType, Node node, Cursor c)
* @int syncType, Node node, Cursor c
* @
* @mCancelled GTask ContentProvider MetaData mMetaHashMap GTask
* @Author:cyh
*/
private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
}
MetaData meta;
switch (syncType) {
case Node.SYNC_ACTION_ADD_LOCAL:
addLocalNode(node);
break;
case Node.SYNC_ACTION_ADD_REMOTE:
addRemoteNode(node, c);
break;
case Node.SYNC_ACTION_DEL_LOCAL:
meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN));
if (meta != null) {
GTaskClient.getInstance().deleteNode(meta);
}
mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN));
break;
case Node.SYNC_ACTION_DEL_REMOTE:
meta = mMetaHashMap.get(node.getGid());
if (meta != null) {
GTaskClient.getInstance().deleteNode(meta);
}
GTaskClient.getInstance().deleteNode(node);
break;
case Node.SYNC_ACTION_UPDATE_LOCAL:
updateLocalNode(node, c);
break;
case Node.SYNC_ACTION_UPDATE_REMOTE:
updateRemoteNode(node, c);
break;
case Node.SYNC_ACTION_UPDATE_CONFLICT:
// merging both modifications maybe a good idea
// right now just use local update simply
updateRemoteNode(node, c);
break;
case Node.SYNC_ACTION_NONE:
break;
case Node.SYNC_ACTION_ERROR:
default:
throw new ActionFailureException("unkown sync action type");
}
}
/**
* @addLocalNode(Node node)
* @Node node
* @Node GTask
* @
* mCancelled
* SqlNote SqlNote
* TaskList SqlNote SqlNote SqlNote SqlNote JSON
* TaskList SqlNote JSON SqlNote parentId ContentProvider Id
* SqlNote GTaskId Gid SqlNote ContentProvider
* mGidToNid mNidToGid GTask Gid ContentProvider Id
* updateRemoteMeta MetaData GTask ContentProvider
* @Author:cyh
*/
private void addLocalNode(Node node) throws NetworkFailureException {
if (mCancelled) {
return;
}
SqlNote sqlNote;
if (node instanceof TaskList) {
if (node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) {
sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER);
} else if (node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) {
sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER);
} else {
sqlNote = new SqlNote(mContext);
sqlNote.setContent(node.getLocalJSONFromContent());
sqlNote.setParentId(Notes.ID_ROOT_FOLDER);
}
} else {
sqlNote = new SqlNote(mContext);
JSONObject js = node.getLocalJSONFromContent();
try {
if (js.has(GTaskStringUtils.META_HEAD_NOTE)) {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (note.has(NoteColumns.ID)) {
long id = note.getLong(NoteColumns.ID);
if (DataUtils.existInNoteDatabase(mContentResolver, id)) {
// the id is not available, have to create a new one
note.remove(NoteColumns.ID);
}
}
}
if (js.has(GTaskStringUtils.META_HEAD_DATA)) {
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (data.has(DataColumns.ID)) {
long dataId = data.getLong(DataColumns.ID);
if (DataUtils.existInDataDatabase(mContentResolver, dataId)) {
// the data id is not available, have to create
// a new one
data.remove(DataColumns.ID);
}
}
}
}
} catch (JSONException e) {
Log.w(TAG, e.toString());
e.printStackTrace();
}
sqlNote.setContent(js);
Long parentId = mGidToNid.get(((Task) node).getParent().getGid());
if (parentId == null) {
Log.e(TAG, "cannot find task's parent id locally");
throw new ActionFailureException("cannot add local node");
}
sqlNote.setParentId(parentId.longValue());
}
// create the local node
sqlNote.setGtaskId(node.getGid());
sqlNote.commit(false);
// update gid-nid mapping
mGidToNid.put(node.getGid(), sqlNote.getId());
mNidToGid.put(sqlNote.getId(), node.getGid());
// update meta
updateRemoteMeta(node.getGid(), sqlNote);
}
/**
* @updateLocalNode(Node node, Cursor c)
* @Node node, Cursor c
* @ GTask ContentProvider
* @
* mCancelled
* Cursor c SqlNote
* JSON SqlNote SqlNote parentId Task GTask Gid mGidToNid ContentProvider Id SqlNote parentId parentId Id
* SqlNote ContentProvider
* updateRemoteMeta MetaData GTask ContentProvider
* @Author:cyh
*/
private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
}
SqlNote sqlNote;
// update the note locally
sqlNote = new SqlNote(mContext, c);
sqlNote.setContent(node.getLocalJSONFromContent());
Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid())
: new Long(Notes.ID_ROOT_FOLDER);
if (parentId == null) {
Log.e(TAG, "cannot find task's parent id locally");
throw new ActionFailureException("cannot update local node");
}
sqlNote.setParentId(parentId.longValue());
sqlNote.commit(true);
// update meta info
updateRemoteMeta(node.getGid(), sqlNote);
}
/**
* @addRemoteNode(Node node, Cursor c)
* @Node node, Cursor c
* @
* @
* mCancelled
* Cursor c SqlNote
* SqlNote Note SqlNote Task Task GTask 使 GTaskClient createTask Task updateRemoteMeta MetaData
* SqlNote Note SqlNote id mGTaskListHashMap tasklist TaskList mGTaskHashMap TaskList 使 GTaskClient createTaskList TaskList
* Gid SqlNote ContentProvider gid-id id-gid
* @Author:cyh
*/
private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
}
SqlNote sqlNote = new SqlNote(mContext, c); //从本地mContext中获取内容
Node n;
// update remotely
if (sqlNote.isNoteType()) {
Task task = new Task();
task.setContentByLocalJSON(sqlNote.getContent());
String parentGid = mNidToGid.get(sqlNote.getParentId());
if (parentGid == null) {
Log.e(TAG, "cannot find task's parent tasklist"); //调试信息
throw new ActionFailureException("cannot add remote task");
}
mGTaskListHashMap.get(parentGid).addChildTask(task); //在本地生成的GTaskList中增加子结点
//登录远程服务器创建Task
GTaskClient.getInstance().createTask(task);
n = (Node) task;
// add meta
updateRemoteMeta(task.getGid(), sqlNote);
} else {
TaskList tasklist = null;
// we need to skip folder if it has already existed
String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX;
if (sqlNote.getId() == Notes.ID_ROOT_FOLDER)
folderName += GTaskStringUtils.FOLDER_DEFAULT;
else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER)
folderName += GTaskStringUtils.FOLDER_CALL_NOTE;
else
folderName += sqlNote.getSnippet();
//iterator迭代器通过统一的接口迭代所有的map元素
Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, TaskList> entry = iter.next();
String gid = entry.getKey();
TaskList list = entry.getValue();
if (list.getName().equals(folderName)) {
tasklist = list;
if (mGTaskHashMap.containsKey(gid)) {
mGTaskHashMap.remove(gid);
}
break;
}
}
// no match we can add now
if (tasklist == null) {
tasklist = new TaskList();
tasklist.setContentByLocalJSON(sqlNote.getContent());
GTaskClient.getInstance().createTaskList(tasklist);
mGTaskListHashMap.put(tasklist.getGid(), tasklist);
}
n = (Node) tasklist;
}
// update local note
sqlNote.setGtaskId(n.getGid());
sqlNote.commit(false);
sqlNote.resetLocalModified();
sqlNote.commit(true);
// gid-id mapping //创建id间的映射
mGidToNid.put(n.getGid(), sqlNote.getId());
mNidToGid.put(sqlNote.getId(), n.getGid());
}
/**
* @updateRemoteNode(Node node, Cursor c)
* @Node node, Cursor c
* @
* @
* mCancelled
* Cursor c SqlNote node 使 GTaskClient addUpdateNode
* updateRemoteMeta
* Note preParentList sqlNote parentId Gid curParentGid curParentGid null curParentGid mGTaskListHashMap TaskList curParentList
* preParentList curParentList preParentList curParentList 使 GTaskClient moveTask
* @Author:cyh
*/
private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
}
SqlNote sqlNote = new SqlNote(mContext, c);
// update remotely
node.setContentByLocalJSON(sqlNote.getContent());
GTaskClient.getInstance().addUpdateNode(node);//GTaskClient用途为从本地登陆远端服务器
// update meta
updateRemoteMeta(node.getGid(), sqlNote);
// move task if necessary
if (sqlNote.isNoteType()) {
Task task = (Task) node;
TaskList preParentList = task.getParent();
//preParentList为通过node获取的父节点列表
String curParentGid = mNidToGid.get(sqlNote.getParentId());
//curParentGid为通过光标在数据库中找到sqlNote的mParentId再通过mNidToGid由long类型转为String类型的Gid
if (curParentGid == null) {
Log.e(TAG, "cannot find task's parent tasklist");
throw new ActionFailureException("cannot update remote task");
}
TaskList curParentList = mGTaskListHashMap.get(curParentGid);
//通过HashMap找到对应Gid的TaskList
if (preParentList != curParentList) {
preParentList.removeChildTask(task);
curParentList.addChildTask(task);
GTaskClient.getInstance().moveTask(task, preParentList, curParentList);
}
}
// clear local modified flag
sqlNote.resetLocalModified();
//commit到本地数据库
sqlNote.commit(true);
}
/**
* @updateRemoteMeta(String gid, SqlNote sqlNote)
* @String gid, SqlNote sqlNote
* @
* @
* sqlNote isNoteType null gid mMetaHashMap metaData
* metaData null sqlNote 使 GTaskClient addUpdateNode
* metaData null MetaData sqlNote metaData mMetaList mMetaHashMap 使 GTaskClient createTask
* @Author:cyh
*/
private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException {
if (sqlNote != null && sqlNote.isNoteType()) {
MetaData metaData = mMetaHashMap.get(gid);
if (metaData != null) {
metaData.setMeta(gid, sqlNote.getContent());
GTaskClient.getInstance().addUpdateNode(metaData);
} else {
metaData = new MetaData();
metaData.setMeta(gid, sqlNote.getContent());
mMetaList.addChildTask(metaData);
mMetaHashMap.put(gid, metaData);
GTaskClient.getInstance().createTask(metaData);
}
}
}
/**
* @refreshLocalSyncId()
* @ID
* @
* mCancelled
* mGTaskHashMapmGTaskListHashMap mMetaHashMap GTaskList
* 使 ContentResolver query Notes.CONTENT_NOTE_URI SqlNote.PROJECTION_NOTE
* null gid mGTaskHashMap node
* node nullID mGTaskHashMap ContentValues valuesID
* 使 ContentResolver update ContentUris.withAppendedId
* node null ActionFailureException
* finally c
* @Author:cyh
*/
private void refreshLocalSyncId() throws NetworkFailureException {
if (mCancelled) {
return;
}
// get the latest gtask list //获取最近的最晚的gtask list
mGTaskHashMap.clear();
mGTaskListHashMap.clear();
mMetaHashMap.clear();
initGTaskList();
Cursor c = null;
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type<>? AND parent_id<>?)", new String[] {
String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)
}, NoteColumns.TYPE + " DESC"); //query语句五个参数NoteColumns.TYPE + " DESC"-----为按类型递减顺序返回查询结果。new String[] {String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)}------为选择参数。"(type<>? AND parent_id<>?)"-------指明返回行过滤器。SqlNote.PROJECTION_NOTE--------应返回的数据列的名字。Notes.CONTENT_NOTE_URI--------contentProvider包含所有数据集所对应的uri
if (c != null) {
while (c.moveToNext()) {
String gid = c.getString(SqlNote.GTASK_ID_COLUMN);
Node node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
ContentValues values = new ContentValues(); //在ContentValues中创建键值对。准备通过contentResolver写入数据
values.put(NoteColumns.SYNC_ID, node.getLastModified());
mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, //进行批量更改选择参数为NULL应该可以用insert替换参数分别为表名和需要更新的value对象。
c.getLong(SqlNote.ID_COLUMN)), values, null, null);
} else {
Log.e(TAG, "something is missed");
throw new ActionFailureException(
"some local items don't have gid after sync");
}
}
} else {
Log.w(TAG, "failed to query local note to refresh sync id");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
}
/**
* @getSyncAccount()
* @
* @ GTaskClient getSyncAccount
* @Author:cyh
*/
public String getSyncAccount() {
return GTaskClient.getInstance().getSyncAccount().name;
}
/**
* @cancelSync()
* @
* @ mCancelled true
* @Author:cyh
*/
public void cancelSync() {
mCancelled = true;
}
}

@ -1,100 +0,0 @@
/**
* @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,127 @@
/*
* 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.data;
/**
* @ProjectName: MiNote
* @Package: net.micode.notes.gtask.data
* @ClassName: Node
* @Description: .
* mGid
* mName
* mLastModified
* mDeleted
*
* getCreateAction(int actionId) IDactionId JSON
* getUpdateAction(int actionId) IDactionId JSON
* setContentByRemoteJSON(JSONObject js)js
* setContentByLocalJSON(JSONObject js)js
* getLocalJSONFromContent() JSON
* getSyncAction(Cursor c)Cursor c ID
* getter setter 访
*
* @Author: cyh
*/
import android.database.Cursor;
import org.json.JSONObject;
public abstract class Node {
//定义了各种用于表征同步状态的常量
public static final int SYNC_ACTION_NONE = 0;// 本地和云端都无可更新内容(即本地和云端内容一致)
public static final int SYNC_ACTION_ADD_REMOTE = 1;// 需要在远程云端增加内容
public static final int SYNC_ACTION_ADD_LOCAL = 2;// 需要在本地增加内容
public static final int SYNC_ACTION_DEL_REMOTE = 3;// 需要在远程云端删除内容
public static final int SYNC_ACTION_DEL_LOCAL = 4;// 需要在本地删除内容
public static final int SYNC_ACTION_UPDATE_REMOTE = 5;// 需要将本地内容更新到远程云端
public static final int SYNC_ACTION_UPDATE_LOCAL = 6;// 需要将远程云端内容更新到本地
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;// 同步出现冲突
public static final int SYNC_ACTION_ERROR = 8;// 同步出现错误
private String mGid;
private String mName;
private long mLastModified;//记录最后一次修改时间
private boolean mDeleted;//表征是否被删除
public Node() {
mGid = null;
mName = "";
mLastModified = 0;
mDeleted = false;
}
public abstract JSONObject getCreateAction(int actionId);
public abstract JSONObject getUpdateAction(int actionId);
public abstract void setContentByRemoteJSON(JSONObject js);
public abstract void setContentByLocalJSON(JSONObject js);
public abstract JSONObject getLocalJSONFromContent();
public abstract int getSyncAction(Cursor c);
public void setGid(String gid) {
this.mGid = gid;
}
public void setName(String name) {
this.mName = name;
}
public void setLastModified(long lastModified) {
this.mLastModified = lastModified;
}
public void setDeleted(boolean deleted) {
this.mDeleted = deleted;
}
public String getGid() {
return this.mGid;
}
public String getName() {
return this.mName;
}
public long getLastModified() {
return this.mLastModified;
}
public boolean getDeleted() {
return this.mDeleted;
}
}

@ -1,269 +0,0 @@
/**
* @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;
}
}

@ -0,0 +1,650 @@
/*
* 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.
*/
/**
* @ProjectName: MiNote
* @Package: net.micode.notes.gtask.data
* @ClassName: SplNote
* @Description: 便sqldatanotedata Java JSON ContentProvider
* @Author: cyh
*/
package net.micode.notes.gtask.data;
import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
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.NoteColumns;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import net.micode.notes.tool.ResourceParser;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class SqlNote {
private static final String TAG = SqlNote.class.getSimpleName();//调用getSimpleName()函数,得到类的简写名称存入字符串TAG中
private static final int INVALID_ID = -99999;
public static final String[] PROJECTION_NOTE = new String[] {// 集合了interface NoteColumns中所有SF常量17个
NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID,
NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE,
NoteColumns.NOTES_COUNT, NoteColumns.PARENT_ID, NoteColumns.SNIPPET, NoteColumns.TYPE,
NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.SYNC_ID,
NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID,
NoteColumns.VERSION
};
//以下设置17个列的编号
public static final int ID_COLUMN = 0;
public static final int ALERTED_DATE_COLUMN = 1;
public static final int BG_COLOR_ID_COLUMN = 2;
public static final int CREATED_DATE_COLUMN = 3;
public static final int HAS_ATTACHMENT_COLUMN = 4;
public static final int MODIFIED_DATE_COLUMN = 5;
public static final int NOTES_COUNT_COLUMN = 6;
public static final int PARENT_ID_COLUMN = 7;
public static final int SNIPPET_COLUMN = 8;
public static final int TYPE_COLUMN = 9;
public static final int WIDGET_ID_COLUMN = 10;
public static final int WIDGET_TYPE_COLUMN = 11;
public static final int SYNC_ID_COLUMN = 12;
public static final int LOCAL_MODIFIED_COLUMN = 13;
public static final int ORIGIN_PARENT_ID_COLUMN = 14;
public static final int GTASK_ID_COLUMN = 15;
public static final int VERSION_COLUMN = 16;
//一下定义了17个内部的变量其中12个可以由content中获得5个需要初始化为0或者new
private Context mContext;
private ContentResolver mContentResolver;
private boolean mIsCreate;
private long mId;
private long mAlertDate;
private int mBgColorId;
private long mCreatedDate;
private int mHasAttachment;
private long mModifiedDate;
private long mParentId;
private String mSnippet;
private int mType;
private int mWidgetId;
private int mWidgetType;
private long mOriginParent;
private long mVersion;
private ContentValues mDiffNoteValues;
private ArrayList<SqlData> mDataList;
/**
* @SqlNote(Context context)
* @
* @mIsCreate
* @Author:cyh
*/
public SqlNote(Context context) {//构造函数只有context对所有的变量进行初始化
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = true;
mId = INVALID_ID;
mAlertDate = 0;
mBgColorId = ResourceParser.getDefaultBgId(context);
mCreatedDate = System.currentTimeMillis();//调用系统函数获得创建时间
mHasAttachment = 0;
mModifiedDate = System.currentTimeMillis();//最后一次修改时间初始化为创建时间
mParentId = 0;
mSnippet = "";
mType = Notes.TYPE_NOTE;
mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
mOriginParent = 0;
mVersion = 0;
mDiffNoteValues = new ContentValues();
mDataList = new ArrayList<SqlData>();
}
/**
* @SqlNote(Context context,Cursor c)
* @
* @mIsCreate
* @Author:cyh
*/
public SqlNote(Context context, Cursor c) {//构造函数有context和一个数据库的cursor多数变量通过cursor指向的一条记录直接进行初始化
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
loadDataContent();
mDiffNoteValues = new ContentValues();
}
/**
* @SqlNote(Context context, long id)
* @,ContextID使SqlNote
* @mIsCreatefalseloadFromCursor()SqlDataContentValuesNotes.TYPE_NOTEloadDataContent()
* @Author:cyh
*/
public SqlNote(Context context, long id) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(id);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
loadDataContent();
mDiffNoteValues = new ContentValues();
}
/**
* @loadFromCursor(long id)
* @
* @使IDCursorCursorfinallyCursor
* @Author:cyh
*/
private void loadFromCursor(long id) {
Cursor c = null;
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
new String[] {
String.valueOf(id)
}, null);//通过id获得对应的ContentResolver中的cursor
if (c != null) {
c.moveToNext();
loadFromCursor(c);//然后加载数据进行初始化,这样函数
} else {
Log.w(TAG, "loadFromCursor: cursor = null");
}
} finally {
if (c != null)
c.close();
}
}
/**
* @loadFromCursor(Cursor c)
* @Cursor c
* @Cursor
* @使CursorgetColumnIndex()ID_COLUMNALERTED_DATE_COLUMN使CursorgetLong()getInt()getString()SqlNote
* @Author:cyh
*/
private void loadFromCursor(Cursor c) {
//直接从一条记录中的获得以下变量的初始值
mId = c.getLong(ID_COLUMN);
mAlertDate = c.getLong(ALERTED_DATE_COLUMN);
mBgColorId = c.getInt(BG_COLOR_ID_COLUMN);
mCreatedDate = c.getLong(CREATED_DATE_COLUMN);
mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN);
mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN);
mParentId = c.getLong(PARENT_ID_COLUMN);
mSnippet = c.getString(SNIPPET_COLUMN);
mType = c.getInt(TYPE_COLUMN);
mWidgetId = c.getInt(WIDGET_ID_COLUMN);
mWidgetType = c.getInt(WIDGET_TYPE_COLUMN);
mVersion = c.getLong(VERSION_COLUMN);
}
/**
* @loadDataContent()
* @
* @使mContentResolvernote_id"note_id=?"mIdCursornullnullCursor0CursorSqlDataSqlDataSqlNotefinallyCursor
* @Author:cyh
*/
private void loadDataContent() {
Cursor c = null;
mDataList.clear();
try {
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
"(note_id=?)", new String[] {
String.valueOf(mId)
}, null);
if (c != null) {
if (c.getCount() == 0) {
Log.w(TAG, "it seems that the note has not data");
return;
}
while (c.moveToNext()) {
SqlData data = new SqlData(mContext, c);
mDataList.add(data);
}
} else {
Log.w(TAG, "loadDataContent: cursor = null");
}
} finally {
if (c != null)
c.close();
}
}
/**
* @setContent(JSONObject js)
* @JSONObject js
* @JSONObjectJSON
* @JSONnotenotemSnippetmTypemIdmAlertDatemBgColorIdmCreatedDatemHasAttachmentmModifiedDatemParentIdmSnippetmTypemWidgetIdmWidgetTypemOriginParentJSONdataArraySqlDataSqlDatasetContentJSONfalsetrue
* @Author:cyh
*/
public boolean setContent(JSONObject js) {
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
Log.w(TAG, "cannot set system folder");
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {
// for folder we can only update the snnipet and type
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate || !mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type);
}
mType = type;
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID;
if (mIsCreate || mId != id) {
mDiffNoteValues.put(NoteColumns.ID, id);
}
mId = id;
long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note
.getLong(NoteColumns.ALERTED_DATE) : 0;
if (mIsCreate || mAlertDate != alertDate) {
mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate);
}
mAlertDate = alertDate;
int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note
.getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext);
if (mIsCreate || mBgColorId != bgColorId) {
mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId);
}
mBgColorId = bgColorId;
long createDate = note.has(NoteColumns.CREATED_DATE) ? note
.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis();
if (mIsCreate || mCreatedDate != createDate) {
mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate);
}
mCreatedDate = createDate;
int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note
.getInt(NoteColumns.HAS_ATTACHMENT) : 0;
if (mIsCreate || mHasAttachment != hasAttachment) {
mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment);
}
mHasAttachment = hasAttachment;
long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note
.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis();
if (mIsCreate || mModifiedDate != modifiedDate) {
mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate);
}
mModifiedDate = modifiedDate;
long parentId = note.has(NoteColumns.PARENT_ID) ? note
.getLong(NoteColumns.PARENT_ID) : 0;
if (mIsCreate || mParentId != parentId) {
mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId);
}
mParentId = parentId;
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate || !mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type);
}
mType = type;
int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID)
: AppWidgetManager.INVALID_APPWIDGET_ID;
if (mIsCreate || mWidgetId != widgetId) {
mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId);
}
mWidgetId = widgetId;
int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note
.getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE;
if (mIsCreate || mWidgetType != widgetType) {
mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType);
}
mWidgetType = widgetType;
long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note
.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0;
if (mIsCreate || mOriginParent != originParent) {
mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent);
}
mOriginParent = originParent;
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
SqlData sqlData = null;
if (data.has(DataColumns.ID)) {
long dataId = data.getLong(DataColumns.ID);
for (SqlData temp : mDataList) {
if (dataId == temp.getId()) {
sqlData = temp;
}
}
}
if (sqlData == null) {
sqlData = new SqlData(mContext);
mDataList.add(sqlData);
}
sqlData.setContent(data);
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return false;
}
return true;
}
/**
* @JSONObject getContent()
* @JSONObject
* @JSONObjectJSONObject
* @Author:cyh
*/
public JSONObject getContent() {
try {
JSONObject js = new JSONObject();
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
JSONObject note = new JSONObject();
if (mType == Notes.TYPE_NOTE) {//类型为note时
note.put(NoteColumns.ID, mId);
note.put(NoteColumns.ALERTED_DATE, mAlertDate);
note.put(NoteColumns.BG_COLOR_ID, mBgColorId);
note.put(NoteColumns.CREATED_DATE, mCreatedDate);
note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment);
note.put(NoteColumns.MODIFIED_DATE, mModifiedDate);
note.put(NoteColumns.PARENT_ID, mParentId);
note.put(NoteColumns.SNIPPET, mSnippet);
note.put(NoteColumns.TYPE, mType);
note.put(NoteColumns.WIDGET_ID, mWidgetId);
note.put(NoteColumns.WIDGET_TYPE, mWidgetType);
note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
JSONArray dataArray = new JSONArray();
for (SqlData sqlData : mDataList) {
JSONObject data = sqlData.getContent();
if (data != null) {
dataArray.put(data);
}
}
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
} else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {
note.put(NoteColumns.ID, mId);
note.put(NoteColumns.TYPE, mType);
note.put(NoteColumns.SNIPPET, mSnippet);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
}
return js;
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
return null;
}
/**
* @setParentId(long id)
* @long id
* @ID
* @longidmParentIdmDiffNoteValues
* @Author:cyh
*/
public void setParentId(long id) {
mParentId = id;
mDiffNoteValues.put(NoteColumns.PARENT_ID, id);
}
/**
* @setGtaskId(String gid)
* @String gid
* @GTASK_ID
* @gidmDiffNoteValues
* @Author:cyh
*/
public void setGtaskId(String gid) {
mDiffNoteValues.put(NoteColumns.GTASK_ID, gid);
}
/**
* @setSyncId(long syncId)
* @long syncId
* @idid
* @ long syncId mDiffNoteValues
* @Author:cyh
*/
public void setSyncId(long syncId) {
mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId);
}
/**
* @resetLocalModified()
* @
* @LOCAL_MODIFIED0
* @Author:cyh
*/
public void resetLocalModified() {
mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0);
}
/**
* @getId()
* @ID
* @ mId
* @Author:cyh
*/
public long getId() {
return mId;
}
/**
* @getParentId()
* @Id
* @ mParentId
* @Author:cyh
*/
public long getParentId() {
return mParentId;
}
/**
* @getSnippet()
* @便
* @ mSnippet
* @Author:cyh
*/
public String getSnippet() {
return mSnippet;
}
/**
* @isNoteType()
* @
* @ TYPE_NOTE true false
* @Author:cyh
*/
public boolean isNoteType() {
return mType == Notes.TYPE_NOTE;
}
/**
* @commit(boolean validateVersion)
* @boolean validateVersion
* @, validateVersion
* @mIsCreate
* IDmId IDINVALID_ID mDiffNoteValues NoteColumns.IDID mDiffNoteValues NoteColumns.ID
* 使 mContentResolver mDiffNoteValues Notes.CONTENT_NOTE_URI URI Uri
* Uri ID mId
* mId 0 IllegalStateException
* Notes.TYPE_NOTE mDataList SqlData commit()
*
* IDmId 0 IDNotes.ID_ROOT_FOLDER Notes.ID_CALL_RECORD_FOLDER IllegalStateException 使 ID
* mDiffNoteValues 0mVersion
* validateVersion 使 mContentResolver Notes.CONTENT_NOTE_URI URI
* 0
* Notes.TYPE_NOTE mDataList SqlData commit()
* mDiffNoteValues mIsCreate false
* @Author:cyh
*/
public void commit(boolean validateVersion) {
if (mIsCreate) {
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
mDiffNoteValues.remove(NoteColumns.ID);
}
Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues);
try {
mId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");
}
if (mId == 0) {
throw new IllegalStateException("Create thread id failed");
}
if (mType == Notes.TYPE_NOTE) {
for (SqlData sqlData : mDataList) {//直接使用sqldata中的实现
sqlData.commit(mId, false, -1);
}
}
} else {
if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) {
Log.e(TAG, "No such note");
throw new IllegalStateException("Try to update note with invalid id");
}
if (mDiffNoteValues.size() > 0) {
mVersion ++;
int result = 0;
if (!validateVersion) {//构造字符串
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?)", new String[] {
String.valueOf(mId)
});
} else {
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)",
new String[] {
String.valueOf(mId), String.valueOf(mVersion)
});
}
if (result == 0) {
Log.w(TAG, "there is no update. maybe user updates note when syncing");
}
}
if (mType == Notes.TYPE_NOTE) {
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, validateVersion, mVersion);
}
}
}
// refresh local info
loadFromCursor(mId);
if (mType == Notes.TYPE_NOTE)
loadDataContent();
mDiffNoteValues.clear();
mIsCreate = false;
}
}

@ -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