小米便签精度代码及注释

mr^2
Lwq 2 years ago
parent 5a82222a6c
commit 904833b388

@ -0,0 +1,84 @@
/*
* 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;//声名一个包,包名包含多个层次,每个层次用'.'分割,这是data包用倒置的域名开头
import android.database.Cursor;//引用android.database.Cursor类基于数据库服务的类
import android.util.Log;//日志工具类常用的方法有Log.v() Log.d() Log.i() Log.w() Log.e()
import net.micode.notes.tool.GTaskStringUtils;//引用tool包中的GTaskStringUtils工具类。
import org.json.JSONException;//引用JSON使用失败异常处理类
import org.json.JSONObject;//引用JSON对象库类JsonObject是一种数据格式。其格式为{"key1":value1,"key2",value2....};key必须是字符串。
public class MetaData extends Task {//创建一个继承于Task的类MetaData,主要用于记录数据的变化
private final static String TAG = MetaData.class.getSimpleName();//调用getSimpleName()函数,得到类的简写名称存入字符串TAG中
private String mRelatedGid = null;//创建私有变量mRelatedGid并初始化为null。
public void setMeta(String gid, JSONObject metaInfo) {//调用JSONObject库函数put ()Task类中的setNotes ()和setName ()函数,实现设置数据,即生成元数据库
try {//执行
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);//将这对键值放入metaInfo这个jsonobject对象中
} catch (JSONException e) {//捕捉异常并进行异常处理放入TAG
Log.e(TAG, "failed to put related gid");//输出错误信息TAG为类名即该类无法放入相关联gid信息
}
setNotes(metaInfo.toString());//设置便签将json类的metaInfo转为string
setName(GTaskStringUtils.META_NOTE_NAME);//设置GTask的名字
}
public String getRelatedGid() {
return mRelatedGid;//获取相关联的Gid
}
@Override// @Override 注解是用来指定方法重写的
public boolean isWorthSaving() {
return getNotes() != null;
}//如果getNotes不等于null就返回真如果便签内容非空getNotes就不为null
@Override//表示重写
public void setContentByRemoteJSON(JSONObject js) {//调用父类Task中的setContentByRemoteJSON ()函数使用远程json数据对象设置元数据内容
super.setContentByRemoteJSON(js);//调用函数
if (getNotes() != null) {//如果数据非空
try {//执行
JSONObject metaInfo = new JSONObject(getNotes().trim());//创建新json对象调用trim方法去掉首尾空格
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);//获取关联gid且为字符串类型
} catch (JSONException e) {//进行异常处理
Log.w(TAG, "failed to get related gid");//输出警告信息
mRelatedGid = null;
}
}
}
@Override//表示重写
public void setContentByLocalJSON(JSONObject js) {//使用本地json数据对象设置元数据内容一般不会用到若用到则抛出异常
// this function should not be called
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");//抛出非法参数异常
}
@Override//表示重写
public JSONObject getLocalJSONFromContent() {//从元数据内容中获取本地json对象
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,101 @@
/*
* 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;//声名gtask下的data包
import android.database.Cursor;//引用android.database.Cursor类基于数据库服务的类
import org.json.JSONObject;//引用 JSONObject
public abstract class Node {//同步操作的基础数据类型,定义相关指示同步操作的常量
public static final int SYNC_ACTION_NONE = 0;//不进行操作时=0
public static final int SYNC_ACTION_ADD_REMOTE = 1;//远程云端增加内容=1
public static final int SYNC_ACTION_ADD_LOCAL = 2;//本地增加内容=2
public static final int SYNC_ACTION_DEL_REMOTE = 3;//远程云端删除内容=3
public static final int SYNC_ACTION_DEL_LOCAL = 4;//本地删除内容=4
public static final int SYNC_ACTION_UPDATE_REMOTE = 5;//本地内容更新到远程云端=5
public static final int SYNC_ACTION_UPDATE_LOCAL = 6;//远程云端内容更新到本地=6
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;//同步出现冲突=7
public static final int SYNC_ACTION_ERROR = 8;//同步出现错误=8
private String mGid;//string类型记录gid
private String mName;//string类型记录name
private long mLastModified;//long类型 表明最后一次的修改的时间
private boolean mDeleted;//bool类型判断是否被删除
public Node() {//构造函数,进行初始化
mGid = null;//mgid为空
mName = "";//名字为空
mLastModified = 0;//最后一次修改时间为0
mDeleted = false;//mDeleted为false表示未删除
}
public abstract JSONObject getCreateAction(int actionId);//声明JSONObject对象抽象类并创建操作
public abstract JSONObject getUpdateAction(int actionId);//声明JSONObject对象抽象类获取更新行为
public abstract void setContentByRemoteJSON(JSONObject js);//声明JSONObject对象抽象类从远端JSON中同步设置目录。
public abstract void setContentByLocalJSON(JSONObject js);//声明JSONObject对象抽象类从本地JSON中同步设置目录
public abstract JSONObject getLocalJSONFromContent();//声明JSONObject对象抽象类从目录中获取本地JSON
public abstract int getSyncAction(Cursor c);//声明int抽象类获取同步行为代号
public void setGid(String gid) {//设置 gid
this.mGid = gid;//赋值给mDid
}
public void setName(String name) {//设置名称
this.mName = name;//赋值给mName
}
public void setLastModified(long lastModified) {//设置最新修改时间
this.mLastModified = lastModified;//赋值给mLastModified
}
public void setDeleted(boolean deleted) {//设置删除标识
this.mDeleted = deleted;//赋值给mDeleted
}
public String getGid() {//得到gid
return this.mGid;//返回mGid
}
public String getName() {//获取名称
return this.mName;//返回mName
}
public long getLastModified() {//获取最新修改
return this.mLastModified;
}//返回最新修改
public boolean getDeleted() {//获取删除标识
return this.mDeleted;//返回mDeleted
}
}

@ -0,0 +1,189 @@
/*
* 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;//声名gtask下的data包
import android.content.ContentResolver;//引用android中content的几个类
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;//引用JSON使用失败异常处理类
import org.json.JSONObject;//引用JSON对象库类
public class SqlData {//定义数据库中基本数据类:读取数据、获取数据库中数据、提交数据到数据库
private static final String TAG = SqlData.class.getSimpleName();//调用getSimpleName()函数得到类的简写名称存入字符串TAG中
private static final int INVALID_ID = -99999;//将INVALID_ID初始化为-99999
public static final String[] PROJECTION_DATA = new String[] {//新建一个字符串数组集合了interface DataColumns中所有SF常量
DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,
DataColumns.DATA3//获得数据列idmime类型内容1类型数据3类型数据
};
public static final int DATA_ID_COLUMN = 0;//0号列的名称为DATA_ID_COLUMN
public static final int DATA_MIME_TYPE_COLUMN = 1;//1号列的名称为DATA_MIME_TYPE_COLUMN
public static final int DATA_CONTENT_COLUMN = 2;//2号列的名称为DATA_CONTENT_COLUMN
public static final int DATA_CONTENT_DATA_1_COLUMN = 3;//3号列的名称为DATA_CONTENT_DATA_1_COLUMN
public static final int DATA_CONTENT_DATA_3_COLUMN = 4;//4号列的名称为DATA_CONTENT_DATA_3_COLUMN
private ContentResolver mContentResolver;//定义私有全局变量
private boolean mIsCreate;//mIsCreate用于下文中选择SqlData的生成方式
private long mDataId;//数据ID号
private String mDataMimeType;//数据mime类型
private String mDataContent;//数据内容
private long mDataContentData1;//数据内容中的1类型数据
private String mDataContentData3;//数据内容中的3类型数据
private ContentValues mDiffDataValues;//mDiffDataValues用于构造SqiData操作数据库
public SqlData(Context context) {//构造函数初始化数据参数类型为Context
mContentResolver = context.getContentResolver();//获取ContentResovler对象如果需要查询数据可以直接在mContetResolver上操作
mIsCreate = true;//mIsCreate为TRUE是这种构造方式的标志
mDataId = INVALID_ID;//mDataId 置初始值-99999。
mDataMimeType = DataConstants.NOTE;//设置数据mime类型为note
mDataContent = "";//数据内容
mDataContentData1 = 0;//1数据类型
mDataContentData3 = "";//3数据类型
mDiffDataValues = new ContentValues();//创建内容
}
public SqlData(Context context, Cursor c) {//构造函数初始化数据参数类型分别为Context和Cursor
mContentResolver = context.getContentResolver();//获取ContentProvider提供的数据
mIsCreate = false;//记录当前数据创建方式
loadFromCursor(c);//从光标处载入数据
mDiffDataValues = new ContentValues();
}
private void loadFromCursor(Cursor c) {//从光标c处加载数据帮助实现SqlData的第二种构造将5列的数据赋给该类的对象
mDataId = c.getLong(DATA_ID_COLUMN);//调用cursor类的方法获取数据id参数为id长度
mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);//调用cursor类的方法获取数据mime类型参数为其长度
mDataContent = c.getString(DATA_CONTENT_COLUMN);//调用cursor类的方法获取数据内容参数为其长度
mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);//1类型数据
mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);//3类型数据
}
public void setContent(JSONObject js) throws JSONException {//设置共享数据并且抛出JSON类型的异常处理机制
long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;//如果传入的JSONObject对象有DataColumns.ID这一项则设置dataID为这个ID否则设为INVALID_ID
if (mIsCreate || mDataId != dataId) {//如果采用的是第一种SqlData构造方式或者这个对象的ID不是共享数据ID
mDiffDataValues.put(DataColumns.ID, dataId);//将共享数据ID加入数据库中
}
mDataId = dataId;//共享数据同步后共享数据ID等于该数据ID
String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE)//问号语句若json中有MIME_TYPE这一项则将其获取否则将其定义为notes类中定义的文本类型
: DataConstants.NOTE;
if (mIsCreate || !mDataMimeType.equals(dataMimeType)) {//如果采用的是第一种SqlData构造方式或者这个对象的MimeType不和共享数据一样
mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType);//则将共享数据.MIME_TYPE加入数据库中
}
mDataMimeType = dataMimeType;//共享数据同步后共享数据mime类型等于该数据mime类型
String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : "";//如果传入的JSONObject对象有DataColumn.CONTENT一项那么将其获取否则。将其设置为空
if (mIsCreate || !mDataContent.equals(dataContent)) {//如果是第一种sqldata函数或者该数据内容和共享数据内容不同
mDiffDataValues.put(DataColumns.CONTENT, dataContent);//那么就把这个数据内容添加到数据库这一数据内容列中
}
mDataContent = dataContent;//共享数据同步后,共享数据内容等于该数据内容
long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0;//如果js中有这一列1类型数据则将datacontentdata1设为这个数据 否则设为0
if (mIsCreate || mDataContentData1 != dataContentData1) {//如果是第一种sqldata函数或者该1类型数据和共享1类型数据不同
mDiffDataValues.put(DataColumns.DATA1, dataContentData1);//那么就把这个1类型数据添加到数据库这一1类型数据列中
}
mDataContentData1 = dataContentData1;//共享数据同步后共享1类型数据等于该1类型数据
String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : "";//如果js中有这一列3类型数据则将datacontentdata1设为这个数据 ,否则设为空
if (mIsCreate || !mDataContentData3.equals(dataContentData3)) {//如果是第一种sqldata函数或者该3类型数据和共享3类型数据不同
mDiffDataValues.put(DataColumns.DATA3, dataContentData3);//那么就把这个3类型数据添加到数据库这一3类型数据列中
}
mDataContentData3 = dataContentData3;//共享数据同步后共享3类型数据等于该3类型数据
}
public JSONObject getContent() throws JSONException {//获取共享的数据内容并抛出json异常与处理机制
if (mIsCreate) {//当采用的是第一种SqlData构造方式时
Log.e(TAG, "it seems that we haven't created this in database yet");//在日志中显示错误“没有在数据库中创建这个数据”
return null;//返回null
}
JSONObject js = new JSONObject();//将相关数据放入新创建的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);//将JSON中放入数据这个JSON一共有五个数据对应着SqlData中的五行数据
return js;
}
public void commit(long noteId, boolean validateVersion, long version) {//commit函数把当前所做的修改保存到数据库
if (mIsCreate) {//当采用的是第一种SqlData构造方式时
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {ididid
mDiffDataValues.remove(DataColumns.ID);//则从共享数据中移除ID
}
mDiffDataValues.put(DataColumns.NOTE_ID, noteId);//更新共享数据键为NOTE_ID值为noteId
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);//在note的资源标识下加入data数据并往URI中插入共享数据。
try {
mDataId = Long.valueOf(uri.getPathSegments().get(1));//获取有效便签id并创建
} catch (NumberFormatException e) {//处理异常
Log.e(TAG, "Get note id error :" + e.toString());//获取note id错误e.toString()获取异常类型和异常详细消息
throw new ActionFailureException("create note failed");//抛出异常“创建note失败”
}
} else {//当采用的是第二种SqlData构造方式时
if (mDiffDataValues.size() > 0) {
int result = 0;//若共享数据存在则通过内容解析器更新关于新URI的共享数据
if (!validateVersion) {//如果版本还没确认
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null);//则结果记录下的只是data的ID还有data内容
} else {//如果版本确认了
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)
});//则从数据库中选取对应版本的id进行更新
}
if (result == 0)//{如果更新不存在(或许用户在同步时已经完成更新
Log.w(TAG, "there is no update. maybe user updates note when syncing");//报错
}
}
}
mDiffDataValues.clear();//回到初始化,清空,表示已经更新
mIsCreate = false;
}
public long getId() {
return mDataId;//获取当前id
}
}

@ -0,0 +1,506 @@
/*
* 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;//声名gtask下的data包
import android.appwidget.AppWidgetManager;//引用android中content的几个类
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;//导入json数组类
import org.json.JSONException;//异常处理类
import org.json.JSONObject;//对象类
便
import java.util.ArrayList;//java中向量处理类
public class SqlNote {//用于支持小米便签最底层数据库的相关操作的类
private static final String TAG = SqlNote.class.getSimpleName();//调用getSimpleName ()函数得到类的简写名称存入字符串TAG中
private static final int INVALID_ID = -99999;//将INVALID_ID 初始化为-99999
public static final String[] PROJECTION_NOTE = new String[] {//集合了interface NoteColumns中所有17个SF常量
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
};
public static final int ID_COLUMN = 0;//ID为0
public static final int ALERTED_DATE_COLUMN = 1;//提醒时间为1
public static final int BG_COLOR_ID_COLUMN = 2;//背景颜色为2
public static final int CREATED_DATE_COLUMN = 3;//创建时间为3
public static final int HAS_ATTACHMENT_COLUMN = 4;//有无附件为4
public static final int MODIFIED_DATE_COLUMN = 5;//更改时间为5
public static final int NOTES_COUNT_COLUMN = 6;//便签数为6
public static final int PARENT_ID_COLUMN = 7;//父节点ID为7
public static final int SNIPPET_COLUMN = 8;//文本片段为8
public static final int TYPE_COLUMN = 9;//文件类型为9
public static final int WIDGET_ID_COLUMN = 10;//小部件ID为10
public static final int WIDGET_TYPE_COLUMN = 11;//小部件类型为11
public static final int SYNC_ID_COLUMN = 12;//同步ID为12
public static final int LOCAL_MODIFIED_COLUMN = 13;//本地修改为13
public static final int ORIGIN_PARENT_ID_COLUMN = 14;//原始父文件夹ID为14
public static final int GTASK_ID_COLUMN = 15;//用户ID为15
public static final int VERSION_COLUMN = 16;//版本号为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;
public SqlNote(Context context) {//第一种构造函数参数只有context初始化新建的对象中的所有变量
mContext = context;//获取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;//默认父类ID
mSnippet = "";//文本片段默认为空
mType = Notes.TYPE_NOTE;//默认文件类型为Note的文件类型
mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;//控件ID初始化
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;//控件类型初始化
mOriginParent = 0;//默认原始父文件夹ID
mVersion = 0;//版本号
mDiffNoteValues = new ContentValues();//新建一个NoteValues值用来记录改变的values
mDataList = new ArrayList<SqlData>();//新建一个data的列表
}
public SqlNote(Context context, Cursor c) {//构造函数参数有context和cursor对cursor指向的对象进行初始化
mContext = context;//数据表初始化
mContentResolver = context.getContentResolver();//获取ContentProvider提供的数据
mIsCreate = false;//提示第二种构造方式为false
loadFromCursor(c);//从光标ID处加载数据
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)//如果是数据是便签类型
loadDataContent();//则加载数据内容
mDiffNoteValues = new ContentValues();//新建一个NoteValues值
}
public SqlNote(Context context, long id) {//第三种构造函数参数有Context和id
mContext = context;//数据表初始化
mContentResolver = context.getContentResolver();//获取ContentProvider提供的数据
mIsCreate = false;//第三种构造方式的标识
loadFromCursor(id);//从光标ID处加载数据
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)//如果是数据是便签类型
loadDataContent();//则加载数据内容
mDiffNoteValues = new ContentValues();//新建一个NoteValues值
}
private void loadFromCursor(long id) {//从光标ID处加载数据
Cursor c = null;//没有内容
try {//通过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();//关闭释放cursor
}
}
private void loadFromCursor(Cursor c) {//通过游标从光标处加载数据
mId = c.getLong(ID_COLUMN);//这是loadFromCursor(long id)方法实现时调用的方法以下从cursor指向的那条记录中加载相应的数据从而实现SQLnote和sqldata间的联系实现sqlnote的构造
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);
}
private void loadDataContent() {//通过content机制获取共享数据并加载到数据库当前游标处
Cursor c = null;
mDataList.clear();//清空数据表
try {
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
"(note_id=?)", new String[] {
String.valueOf(mId)
}, null);//获得该ID对应的数据内容
if (c != null) {
if (c.getCount() == 0) {//如果光标处无内容
Log.w(TAG, "it seems that the note has not data");//提示note无数据warning
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();//关闭游标
}
}
public boolean setContent(JSONObject js) {//设置通过content机制用于共享的数据信息
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);//创建一个JSONObject对象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) : "";//如果共享数据存在摘要,则将其赋给声明的 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) {//如果只是通过上下文对note进行数据库操作或者该类型与原类型不相同
mDiffNoteValues.put(NoteColumns.TYPE, type);//将该类型保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mType = type;//将该类型覆盖原类型
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {//如果不是文件夹而是note
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);//获取便签提示日期
long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID;//获取数据的ID
if (mIsCreate || mId != id) {//如果只是通过上下文对note进行数据库操作或者该ID与原ID不相同
mDiffNoteValues.put(NoteColumns.ID, id);//将该ID保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mId = id;//将该ID覆盖原ID
long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note
.getLong(NoteColumns.ALERTED_DATE) : 0;//获取数据的提醒日期
if (mIsCreate || mAlertDate != alertDate) {//如果只是通过上下文对note进行数据库操作或者该提醒日期与原提醒日期不相同
mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate);//将该提醒日期保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mAlertDate = alertDate;//将该提醒日期覆盖原提醒日期
int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note
.getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext);//获取数据的背景颜色
if (mIsCreate || mBgColorId != bgColorId) {//如果只是通过上下文对note进行数据库操作或者该背景颜色与原背景颜色不相同
mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId);//将该背景颜色保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mBgColorId = bgColorId;//将该背景颜色覆盖原背景颜色
long createDate = note.has(NoteColumns.CREATED_DATE) ? note
.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis();//将该背景颜色覆盖原背景颜色
if (mIsCreate || mCreatedDate != createDate) {//如果只是通过上下文对note进行数据库操作或者该创建日期与原创建日期不相同
mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate);//将该创建日期保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mCreatedDate = createDate;//将该创建日期覆盖原创建日期
int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note
.getInt(NoteColumns.HAS_ATTACHMENT) : 0;//获取数据的有无附件的布尔值
if (mIsCreate || mHasAttachment != hasAttachment) {//如果只是通过上下文对note进行数据库操作或者该有无附件的布尔值与原有无附件的布尔值不相同
mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment);//将该有无附件的布尔值保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mHasAttachment = hasAttachment;//将该有无附件的布尔值覆盖原有无附件的布尔值
long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note
.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis();//获取数据的修改日期
if (mIsCreate || mModifiedDate != modifiedDate) {//如果只是通过上下文对note进行数据库操作或者该修改日期与原修改日期不相同
mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate);//将该修改日期保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mModifiedDate = modifiedDate;//将该修改日期覆盖原修改日期
long parentId = note.has(NoteColumns.PARENT_ID) ? note
.getLong(NoteColumns.PARENT_ID) : 0;//获取数据的父节点ID
if (mIsCreate || mParentId != parentId) {//如果只是通过上下文对note进行数据库操作或者该父节点ID与原父节点ID不相同
mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId);//将该父节点ID保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mParentId = parentId;//将该父节点ID覆盖原父节点ID
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : "";//获取数据的文本片段
if (mIsCreate || !mSnippet.equals(snippet)) {//如果只是通过上下文对note进行数据库操作或者该文本片段与原文本片段不相同
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);//将该文本片段保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mSnippet = snippet;//将该文本片段覆盖原文本片段
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;//获取数据的文件类型
if (mIsCreate || mType != type) {//如果只是通过上下文对note进行数据库操作或者该文件类型与原文件类型不相同
mDiffNoteValues.put(NoteColumns.TYPE, type);//将该文件类型保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mType = type;//将该文件类型覆盖原文件类型
int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID)
: AppWidgetManager.INVALID_APPWIDGET_ID;//获取数据的小部件ID
if (mIsCreate || mWidgetId != widgetId) {//如果只是通过上下文对note进行数据库操作或者该小部件ID与原小部件ID不相同
mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId);//将该小部件ID保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mWidgetId = widgetId;//将该小部件ID覆盖原小部件ID
int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note
.getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE;//获取数据的小部件种类
if (mIsCreate || mWidgetType != widgetType) {//如果只是通过上下文对note进行数据库操作或者该小部件种类与原小部件种类不相同
mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType);//将该小部件种类保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mWidgetType = widgetType;//将该小部件种类覆盖原小部件种类
long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note
.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0;//获取数据的原始父文件夹ID
if (mIsCreate || mOriginParent != originParent) {//如果只是通过上下文对note进行数据库操作或者该原始父文件夹ID与原原始父文件夹ID不相同
mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent);//将该原始父文件夹ID保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mOriginParent = originParent;//将该原始父文件夹ID覆盖原原始父文件夹ID
for (int i = 0; i < dataArray.length(); i++) {//遍历dataArray查找id为dataId的数据
JSONObject data = dataArray.getJSONObject(i);//依次获取数据表中的数据ID
SqlData sqlData = null;//如果没有找到,就新建一个并加入到列表中
if (data.has(DataColumns.ID)) {//该数据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) {//如果JSONE出现异常
Log.e(TAG, e.toString());//日志显示错误
e.printStackTrace();//打印堆栈轨迹
return false;
}
return true;
}
public JSONObject getContent() {//获取content机制提供的数据并加载到note中
try {
JSONObject js = new JSONObject();//创建一个新的jsonobject js
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);//设置ID
note.put(NoteColumns.ALERTED_DATE, mAlertDate);//设置提醒时间
note.put(NoteColumns.BG_COLOR_ID, mBgColorId);//设置背景颜色ID
note.put(NoteColumns.CREATED_DATE, mCreatedDate);//创建日期
note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment);//是否有附件
note.put(NoteColumns.MODIFIED_DATE, mModifiedDate);//修改日期
note.put(NoteColumns.PARENT_ID, mParentId);//父节点ID
note.put(NoteColumns.SNIPPET, mSnippet);//文件片段
note.put(NoteColumns.TYPE, mType);//类型
note.put(NoteColumns.WIDGET_ID, mWidgetId);//小部件ID
note.put(NoteColumns.WIDGET_TYPE, mWidgetType);//小部件类型
note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent);//原始父节点ID
js.put(GTaskStringUtils.META_HEAD_NOTE, note);//将这个便签存入元数据中
JSONArray dataArray = new JSONArray();//获取数据库数据,并存入数组中
for (SqlData sqlData : mDataList) {//利用循环将数据链表的数据获取
JSONObject data = sqlData.getContent();//获取内容
if (data != null) {//如果data非空
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);//将id存入jsonobject
note.put(NoteColumns.TYPE, mType);//将类型存入jsonobject
note.put(NoteColumns.SNIPPET, mSnippet);//将文件片段存入jsonobject
js.put(GTaskStringUtils.META_HEAD_NOTE, note);//存入元便签中
}
return js;
} catch (JSONException e) {//json异常处理
Log.e(TAG, e.toString());//提示错误
e.printStackTrace();//打印栈轨迹
}
return null;
}
public void setParentId(long id) {//设置当前ID的父ID
mParentId = id;
mDiffNoteValues.put(NoteColumns.PARENT_ID, id);
}
public void setGtaskId(String gid) {//给当前id设置Gtaskid
mDiffNoteValues.put(NoteColumns.GTASK_ID, gid);
}
public void setSyncId(long syncId) {//给当前id设置同步id
mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId);
}
public void resetLocalModified() {//重新设置本地的修改
mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0);
}
public long getId() {//获得当前id
return mId;
}
public long getParentId() {//获得当前id的父id
return mParentId;
}
public String getSnippet() {//获取用于显示的便签内容片段
return mSnippet;
}
public boolean isNoteType() {//判断是否为note类型
return mType == Notes.TYPE_NOTE;
}
public void commit(boolean validateVersion) {//把当前造作所做的修改保存到数据库
if (mIsCreate) {//采用第一种构造方式
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {//如果是一个无效的id并且还含有这个id
mDiffNoteValues.remove(NoteColumns.ID);//将它移除
}
Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues);//内容解析器中插入该便签的uri
try {
mId = Long.valueOf(uri.getPathSegments().get(1));//强制转换path为idLong型
} catch (NumberFormatException e) {//捕获异常,转换出错
Log.e(TAG, "Get note id error :" + e.toString());//显示错误“获取note的id出现错误”
throw new ActionFailureException("create note failed");//抛出异常,创建 note 失败
}
if (mId == 0) {//id为0
throw new IllegalStateException("Create thread id failed");//创建线程失败
}
if (mType == Notes.TYPE_NOTE) {//如果当前类型是便签类型
for (SqlData sqlData : mDataList) {//直接使用sqldata中的方式遍历
sqlData.commit(mId, false, -1);//引用sqldata的方式实现commit
}
}
} else {
if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) {//如果该便签ID是无效ID
Log.e(TAG, "No such note");//报错:没有这个便签
throw new IllegalStateException("Try to update note with invalid id");//提示尝试去更新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)
});//更新内容解析器存入便签内容uri便签IDmID
} else {//如果是有效版本
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)",//没有更新
new String[] {
String.valueOf(mId), String.valueOf(mVersion)
});//更新不存在,可能用户在同步时更新了 note
}
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);////引用sqldata的commit提交数据
}
}
}
// refresh local info
loadFromCursor(mId);//通过cursor从当前id处加载数据
if (mType == Notes.TYPE_NOTE)//如果是便签类型
loadDataContent();//加载数据内容
mDiffNoteValues.clear();//清空,回到初始化状态
mIsCreate = false;//改变数据库构造模式
}
}

@ -0,0 +1,351 @@
/*
* 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;//声名gtask下的data包
import android.database.Cursor;//引用andriod和JSON中的一些操作以及引用自己的包里的一些类
import android.text.TextUtils;
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.gtask.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONArray;//导入json数组类
import org.json.JSONException;//异常处理类
import org.json.JSONObject;//对象类
public class Task extends Node {//创建Task类继承自父类Node
private static final String TAG = Task.class.getSimpleName();//调用 getSimpleName ()函数来得到类的简写名称并存入字符串TAG中
private boolean mCompleted;//声明布尔类型,判断是否完成
private String mNotes;//页面标签信息
private JSONObject mMetaInfo;//元数据信息
private Task mPriorSibling;//对应的优先兄弟类Task的指针
private TaskList mParent;//任务列表的指针
public Task() {//Task构造方法
super();//调用父类构造方法
mCompleted = false;//对类的变量进行初始化,下同
mNotes = null;
mPriorSibling = null;
mParent = null;
mMetaInfo = null;
}
public JSONObject getCreateAction(int actionId) {//获取创建action
JSONObject js = new JSONObject();//新建一个 JSONObject 的对象用来存放同步过程中所用到的 task 信息
try {
// action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);//共享数据存入动作类型action_ type
// action_id
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);//设置活动的id
// index
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));//设置索引
// entity_delta
JSONObject entity = new JSONObject();//创建实体数据
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());//将name存入数据
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");//将创建者ID存入数据
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_TASK);//将实体类型存入数据
if (getNotes() != null) {//如果有数据
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());//则将数据存放入实体数据中
}
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);//将entity变量作为一个数据存放进js变量中
// parent_id
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());//存入父ID
// dest_parent_type
js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,//存入父类型
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
// list_id
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());//存入列表ID
// prior_sibling_id
if (mPriorSibling != null) {//如果存在优先兄弟task
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());//则将其ID放入js中
}
} catch (JSONException e) {//抛出异常处理机制
Log.e(TAG, e.toString());//e.toString()获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("fail to generate task-create jsonobject");//产生 JSONObject 任务创建操作失败
}
return js;//将这个存储字符串的变量返回
}
public JSONObject getUpdateAction(int actionId) {//获取更新的action
JSONObject js = new JSONObject();//新建一个存储数据的类
try {
// action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
// action_id
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// id
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// entity_delta
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
if (getNotes() != null) {//如果存在 notes
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());//则将其也放入 entity 中
}
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);//导入参数entity和DELTA到js
} catch (JSONException e) {//抛出异常处理机制
Log.e(TAG, e.toString());//e.toString()获取异常类型和异常详细消息
e.printStackTrace();//命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("fail to generate task-update jsonobject");//产生jsonobject任务创建操作失败
}
return js;
}
public void setContentByRemoteJSON(JSONObject js) {//通过远端的jsonobject获取任务内容
if (js != null) {//如果js指向的目标存在
try {
// id
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));//设置ID
}
// last_modified
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));////设置最近修改
}
// name
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));//设置name
}
// notes
if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) {
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES));//设置notes
}
// deleted
if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) {
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED));//设置已删除
}
// completed
if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) {
setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED));//设置已完成
}
} catch (JSONException e) {//异常处理
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("fail to get task content from jsonobject");//产生jsonobject任务创建操作失败
}
}
}
public void setContentByLocalJSON(JSONObject js) {//通过本地的jsonobject获取内容
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {//如果js不存在或者js没有元数据的开头或者js指针没有元数据
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");//那么反馈给用户出错信息
}
try {//否则进行try和catch的异常处理操作
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {//如果note类型匹配失败
Log.e(TAG, "invalid type");//无效类型
return;
}
for (int i = 0; i < dataArray.length(); i++) {//遍历数据数组
JSONObject data = dataArray.getJSONObject(i);//遍历dataArray查找与数据库中DataConstants.NOTE记录信息一致的data
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
setName(data.getString(DataColumns.CONTENT));
break;
}
}
} catch (JSONException e) {//异常处理操作
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//命令行打印异常信息在程序中出错的位置及原因
}
}
public JSONObject getLocalJSONFromContent() {//从Content中获取本地的JSON数据
String name = getName();//获取名称
try {
if (mMetaInfo == null) {//如果元数据不存在,创建一个新的对象
// new task created from web
if (name == null) {//且此名字也不存在
Log.w(TAG, "the note seems to be an empty one");//反馈给用户异常信息
return null;
}
JSONObject js = new JSONObject();//初始化
JSONObject note = new JSONObject();//初始化
JSONArray dataArray = new JSONArray();//初始化
JSONObject data = new JSONObject();//初始化
data.put(DataColumns.CONTENT, name);
dataArray.put(data);
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);//获取metainfo中的head_note
return js;
} else {//否则将元数据同步至数据中
// synced task
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);//同步任务
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);//定义一个数组并进行初始化
for (int i = 0; i < dataArray.length(); i++) {//遍历dataArray查找与数据库中DataConstants.NOTE记录信息一致的data
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
data.put(DataColumns.CONTENT, getName());
break;
}
}
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
return mMetaInfo;
}
} catch (JSONException e) {//异常处理操作
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//命令行打印异常信息在程序中出错的位置及原因
return null;
}
}
public void setMetaInfo(MetaData metaData) {//设置元数据信息
if (metaData != null && metaData.getNotes() != null) {//如果元数据存在且能够获取到文本信息
try {
mMetaInfo = new JSONObject(metaData.getNotes());//进行异常处理,更新数据
} catch (JSONException e) {//异常处理操作
Log.w(TAG, e.toString());//获取异常类型和异常详细消息
mMetaInfo = null;//将元数据的信息置空
}
}
}
public int getSyncAction(Cursor c) {//实现同步操作
try {
JSONObject noteInfo = null;//新建一个JSONObject的对象实体
if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) {//元数据信息不为空并且元数据信息还含有“META_HEAD_NOTE”说明便签存在
noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
}
if (noteInfo == null) {//便签元数据已被删除,不存在
Log.w(TAG, "it seems that note meta has been deleted");//提醒已被删除
return SYNC_ACTION_UPDATE_REMOTE;//返回更新云端数据的同步行为
}
if (!noteInfo.has(NoteColumns.ID)) {//如果远端的数据库中没有它的ID
Log.w(TAG, "remote note id seems to be deleted");//提醒远端数据库中该便签已经被删除
return SYNC_ACTION_UPDATE_LOCAL//返回更新云端数据的同步行为
}
// validate the note id now
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) {//如果ID不同
Log.w(TAG, "note id doesn't match");//提醒信息不匹配
return SYNC_ACTION_UPDATE_LOCAL;//返回更新云端数据的同步行为
}
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {//如果本地的便签数据未修改过,即未更新
// there is no local update
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {//如果修改后的ID匹配成功
// no update both side
return SYNC_ACTION_NONE;//成功则返回无同步操作
} else {//不成功
// apply remote to local
return SYNC_ACTION_UPDATE_LOCAL;//返回本地同步更新操作
}
} else {
// validate gtask id
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {//如果gtask的id与获取的id不匹配
Log.e(TAG, "gtask id doesn't match");//提醒不匹配
return SYNC_ACTION_ERROR;//返回同步操作错误
}
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {//如果本地id与云端id一致
// local modification only
return SYNC_ACTION_UPDATE_REMOTE;//则返回云端更新的同步动作
} else {
return SYNC_ACTION_UPDATE_CONFLICT;//冲突
}
}
} catch (Exception e) {//异常处理操作
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//命令行打印异常信息在程序中出错的位置及原因
}
return SYNC_ACTION_ERROR;//返回同步操作错误
}
public boolean isWorthSaving() {//判断是否值得存放,即当前数据是否有效
return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)
|| (getNotes() != null && getNotes().trim().length() > 0);//若数据非空 或 名字合法存在且去除空格后的名字长度大于零则返回真值
}
public void setCompleted(boolean completed) {
this.mCompleted = completed;//将Task置为修改完毕
}
public void setNotes(String notes) {
this.mNotes = notes;//设定mNotes
}
public void setPriorSibling(Task priorSibling) {
this.mPriorSibling = priorSibling;//设置这个任务的优先兄弟
}
public void setParent(TaskList parent) {
this.mParent = parent;//设置这个任务的父节点
}
public boolean getCompleted() {
return this.mCompleted;//返回是否完成的标志
}
public String getNotes() {
return this.mNotes;//获取成员变量mNotes的信息。
}
public Task getPriorSibling() {
return this.mPriorSibling;//获取优先兄弟列表
}
public TaskList getParent() {
return this.mParent;//获取父节点列表
}
}

@ -0,0 +1,343 @@
/*
* 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;//声名gtask下的data包
import android.database.Cursor;//引用andriod和JSON中的一些操作以及引用自己的包里的一些类
import android.util.Log;
import net.micode.notes.data.Notes;//引用小米便签中的类
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;//导入json异常处理类
import org.json.JSONObject;//对象类
import java.util.ArrayList;
public class TaskList extends Node {//TaskList类继承于Node类
private static final String TAG = TaskList.class.getSimpleName();//调用 getSimpleName ()函数来得到类的简写名称并存入字符串TAG中
private int mIndex;//当前TaskList的指针
private ArrayList<Task> mChildren;//声明了一个ArrayList的动态数组这类数组可以加入不同类型的数据
public TaskList() {//TaskList的构造函数
super();//调用父类构造方法也就是Node类
mChildren = new ArrayList<Task>();//声明arraylist数组
mIndex = 1;//初始化
}
public JSONObject getCreateAction(int actionId) {//定义在Node中定义的一个抽象函数
JSONObject js = new JSONObject();//创建一个新的JSONObject对象
try {
// action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);//指明了操作类型是“create”
// action_id
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);//调用put放入编号
// index
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex);
// entity_delta
JSONObject entity = new JSONObject();//新建一个新的JSONObject对象
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());//getName是父类的一个函数
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");//将创建者的ID设置为空
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);//将实体类型设置为“GROUP”
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("fail to generate tasklist-create jsonobject");//抛出异常,生成更新任务列表的 JSONObject 失败
}
return js;//将已经存储数据的js对象返回
}
public JSONObject getUpdateAction(int actionId) {//获取更新的行为
JSONObject js = new JSONObject();//创建一个JSONObject的实例化对象js
try {
// action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);//初始化js中的类型
// action_id
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);//初始化actionID
// id
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());//初始化ID
// entity_delta
JSONObject entity = new JSONObject();//创建一个 JSONObject 的实例化对象entity
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("fail to generate tasklist-update jsonobject");//抛出异常
}
return js;
}
public void setContentByRemoteJSON(JSONObject js) {//通过远端设置内容
if (js != null) {//js对象不为空
try {
// id
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {//如果传入的对象中含有GTASK_JSON_ID
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));//根据内容进行设置
}
// last_modified
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {//若 js 中存在 GATSK_JSON_LAST_MODIFIED 信息
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));//获取 GTASK_JSON_NAME 字符串并设置为该 js 对象的名称
}
// name
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));//对任务的name进行设置
}
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("fail to get tasklist content from jsonobject");//抛出异常
}
}
}
public void setContentByLocalJSON(JSONObject js) {//通过本地 JSON 数据设置对象 js 内容
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) {//若 js 创建失败或 js 中不存在 META_HEAD_NOTE信息
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");//警告,没有可用资源
}
try {
JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {//若为一般类型的文件夹
String name = folder.getString(NoteColumns.SNIPPET);//获取文件夹片段字符串作为文件夹名称
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name);//设置名称为MIUI系统文件夹前缀+文件夹名称
} else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {//若为系统类型文件夹
if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER)//若为根目录文件夹
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT);//设置名称为MIUI系统文件夹前缀+默认文件夹名称
else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER)//若为通话记录文件夹
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE);//设置名称为MIUI系统文件夹前缀+默认文件夹名称
else
Log.e(TAG, "invalid system folder");//错误,无效的系统文件夹
} else {
Log.e(TAG, "error type");//错误的类型
}
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
}
}
public JSONObject getLocalJSONFromContent() {//通过 Content 机制获取本地 JSON 数据
try {
JSONObject js = new JSONObject();//创建一个 JSONObject 的实例化对象 js
JSONObject folder = new JSONObject();//创建一个 JSONObject 的实例化对象 folder
String folderName = getName();//获取完整的文件名字
if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX))//如果这个文件名字是以"[MIUI_Notes]"开头
folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(),
folderName.length());//文件名字应该去掉这个前缀
folder.put(NoteColumns.SNIPPET, folderName);
if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT)
|| folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE))//当获取的文件夹名称是以"Default"或"Call_Note开头
folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);//则为系统文件夹
else
folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);//否则为一般文件夹
js.put(GTaskStringUtils.META_HEAD_NOTE, folder);
return js;
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
return null;
}
}
public int getSyncAction(Cursor c) {//通过游标类获取同步操作
try {
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {//若本地记录未修改
// there is no local update
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {//最近一次修改的 id 匹配成功
// no update both side
return SYNC_ACTION_NONE;//返回无的同步行为
} else {//匹配失败
// apply remote to local
return SYNC_ACTION_UPDATE_LOCAL;//返回更新本地数据的同步行为
}
} else {
// validate gtask id
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {//如果获取的ID不匹配
Log.e(TAG, "gtask id doesn't match");//错误id不匹配
return SYNC_ACTION_ERROR;//返回同步动作失败
}
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {//如果是最近一次修改的 id
// local modification only
return SYNC_ACTION_UPDATE_REMOTE;//返回云端更新的同步动作
} else {
// for folder conflicts, just apply local modification
return SYNC_ACTION_UPDATE_REMOTE;//返回云端更新的同步动作
}
}
} catch (Exception e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
}
return SYNC_ACTION_ERROR;//返回同步动作失败
}
public int getChildTaskCount() {//获取列表中子任务数量
return mChildren.size();
}
public boolean addChildTask(Task task) {//在当前任务表中添加新的子任务
boolean ret = false;//定义一个布尔型变量初始化为false。
if (task != null && !mChildren.contains(task)) {//任务非空且任务表中不存在该任务
ret = mChildren.add(task);//在mChildren中 添加子任务成功与否返回至ret中保存
if (ret) {//添加子任务成功
// need to set prior sibling and parent
task.setPriorSibling(mChildren.isEmpty() ? null : mChildren
.get(mChildren.size() - 1));//设置兄弟任务优先级,若子任务为空,返回 NULL否则返回子任务数量-1
task.setParent(this);//设置该任务的父任务
}
}
return ret;//返回值为是否成功添加任务
}
public boolean addChildTask(Task task, int index) {//在当前任务表中的索引位置添加新的子任务
if (index < 0 || index > mChildren.size()) {//无效的索引
Log.e(TAG, "add child task: invalid index");//错误,无效的索引导致添加子任务失败
return false;
}
int pos = mChildren.indexOf(task);//获取要添加的任务在列表中的位置
if (task != null && pos == -1) {//任务非空且任务表中不存在该任务
mChildren.add(index, task);//在索引位置添加任务
// update the task list
Task preTask = null;
Task afterTask = null;//更新任务表
if (index != 0)
preTask = mChildren.get(index - 1);
if (index != mChildren.size() - 1)
afterTask = mChildren.get(index + 1);
task.setPriorSibling(preTask);//使得三个任务前后连在一块
if (afterTask != null)//下一个任务设置兄弟任务优先级
afterTask.setPriorSibling(task);
}
return true;
}
public boolean removeChildTask(Task task) {//删除任务表中的子任务
boolean ret = false;//声明布尔类型ret为false
int index = mChildren.indexOf(task);//获取该任务在任务表中的索引
if (index != -1) {//index不等于-1说明任务列表中存在该任务
ret = mChildren.remove(task);//删除mChildren中的任务
if (ret) {//如果删除成功
// reset prior sibling and parent
task.setPriorSibling(null);
task.setParent(null);//就要将该任务的优先兄弟任务和父任务设置为空
// update the task list
if (index != mChildren.size()) {//删除成功后
mChildren.get(index).setPriorSibling(
index == 0 ? null : mChildren.get(index - 1));//对任务列表进行更新
}
}
}
return ret;//返回值是是否删除成功
}
public boolean moveChildTask(Task task, int index) {//将当前TaskList中含有的某个Task移到index位置
if (index < 0 || index >= mChildren.size()) {//目标位置越界,无效
Log.e(TAG, "move child task: invalid index");//错误,无效的索引导致移动子任务失败
return false;
}
int pos = mChildren.indexOf(task);//若所要查找的子任务不存在
if (pos == -1) {
Log.e(TAG, "move child task: the task should in the list");//错误,任务不在列表中导致移动子任务失败
return false;
}
if (pos == index)//当前位置与索引匹配成功
return true;//返回真值
return (removeChildTask(task) && addChildTask(task, index));//不相等则进行删除和添加即移动操作
}
public Task findChildTaskByGid(String gid) {//按gid寻找Task
for (int i = 0; i < mChildren.size(); i++) {//遍历整个任务列表判断任务的gid与传入的gid是否相等
Task t = mChildren.get(i);
if (t.getGid().equals(gid)) {
return t;
}
}
return null;
}
public int getChildTaskIndex(Task task) {//获取子任务索引
return mChildren.indexOf(task);
}
public Task getChildTaskByIndex(int index) {//通过索引获取子任务
if (index < 0 || index >= mChildren.size()) {//指针不在范围内
Log.e(TAG, "getTaskByIndex: invalid index");//错误,无效的索引导致获取任务失败
return null;
}
return mChildren.get(index);
}
public Task getChilTaskByGid(String gid) {//返回指定gid的任务task
for (Task task : mChildren) {//ArrayList的遍历
if (task.getGid().equals(gid))
return task;
}
return null;
}
public ArrayList<Task> getChildTaskList() {//获取子任务列表
return this.mChildren;
}
public void setIndex(int index) {//设置任务索引
this.mIndex = index;
}
public int getIndex() {
return this.mIndex;//获取任务索引
}
}

@ -0,0 +1,32 @@
/*
* 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.exception;//声名gtask下的data包,小米便签行为异常处理
public class ActionFailureException extends RuntimeException {//从RuntimeException类派生出ActionFailureException类用来处理行为异常
private static final long serialVersionUID = 4425249765923293627L;//用来验证版本一致性,如果不一致会导致反序列化的时候版本不一致的异常
public ActionFailureException() {//交给父类的构造函数
super();//指向父类的一个指针
}
public ActionFailureException(String paramString) {//调用父类具有相同形参paramString的构造方法
super(paramString);
}
public ActionFailureException(String paramString, Throwable paramThrowable) {//调用父类具有相同形参paramString和paramThrowable的构造方法
super(paramString, paramThrowable);
}
}

@ -0,0 +1,33 @@
/*
* 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.exception;//声名gtask下的data包,小米便签网络异常处理
public class NetworkFailureException extends Exception {//从Exception类派生出NetworkFailureException类用来处理网络异常
private static final long serialVersionUID = 2107610287180234136L;//用来验证版本一致性,如果不一致会导致反序列化的时候版本不一致的异常
public NetworkFailureException() {//不带参数的构造函数
super();//指向父类的一个指针
}
public NetworkFailureException(String paramString) {//调用父类具有相同形参paramString的构造方法
super(paramString);
}
public NetworkFailureException(String paramString, Throwable paramThrowable) {//调用父类具有相同形参paramString和paramThrowable的构造方法
super(paramString, paramThrowable);
}
}

@ -0,0 +1,123 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.gtask.remote;//声名gtask下的remote包用来实现异步操作
import android.app.Notification;//引用andriod和JSON中的一些操作以及引用自己的包里的一些类
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;
public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {//扩展于AysyncTask类是用来处理GTask的异步任务的类
private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;//static int变量存储GTask同步通知的ID。
public interface OnCompleteListener {//通过interface实现多个接口接口为OnCompleteListener用来初始化异步的功能
void onComplete();//初始化
}
private Context mContext;//文本内容
private NotificationManager mNotifiManager;//通知管理器类的实例化
private GTaskManager mTaskManager;//实例化任务管理器
private OnCompleteListener mOnCompleteListener;//实例化是否完成的监听器
public GTaskASyncTask(Context context, OnCompleteListener listener) {//GTaskASyncTask类的构造函数
mContext = context;//初始化
mOnCompleteListener = listener;//初始化
mNotifiManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);//getSystemService是Activity的一个方法可根据传入的参数获得应服务的对象。这里以Context的NOTIFICATION_SERVICE为对象
mTaskManager = GTaskManager.getInstance();//getInstance ()函数用于使用单例模式创建类的实例
}
public void cancelSync() {//中断同步操作
mTaskManager.cancelSync();//调用类中的同名方法来取消同步
}
public void publishProgess(String message) {//显示消息
publishProgress(new String[] {//String[]创建java数组
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;// PendingIntent 是 Android 提供的一种用于外部程序调起自身程序的能力,生命周期不与主程序相关
if (tickerId != R.string.ticker_success) {//若同步不成功
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesPreferenceActivity.class), 0);//从系统获得一个对象来启动NotesPreferenceActivity
} else {//若同步成功
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesListActivity.class), 0);//从系统取得一个来启动一个NotesListActivity的对象
}
notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
pendingIntent);//设置在通知列表里该通知的显示情况
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);//通过NotificationManager对象的notify方法来执行一个notification的消息
}
@Override//表示重写
protected Integer doInBackground(Void... unused) {//异步执行后台线程将要完成的任务
publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity
.getSyncAccountName(mContext)));//利用getString,将把 getSyncAccountName(mContext)的字符串内容传进sync_progress_login中
return mTaskManager.sync(mContext, this);//进行后台同步具体操作
}
@Override//表示重写
protected void onProgressUpdate(String... progress) {//显示进度的更新
showNotification(R.string.ticker_syncing, progress[0]);//调用显示通知的方法,将第一个进度的通知进行显示
if (mContext instanceof GTaskSyncService) {//如果mContext是GTaskSyncService实例化的对象
((GTaskSyncService) mContext).sendBroadcast(progress[0]);//则发送一个广播
}
}
@Override//表示重写
protected void onPostExecute(Integer result) {//设置任务,比如在用户界面显示一个进度条
if (result == GTaskManager.STATE_SUCCESS) {//若匹配成功
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) {//若因为系统内部原因失败
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) {//若监听器为空
new Thread(new Runnable() {//则创建新进程
public void run() {//执行完后调用然后返回主线程中
mOnCompleteListener.onComplete();
}
}).start();
}
}
}

@ -0,0 +1,585 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.gtask.remote;//声名gtask下的remote包用于自动登录账号并更新消息创建或者获取任务列表
import android.accounts.Account;//引用andriod和JSON中的一些操作以及引用自己的包里的一些类
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import net.micode.notes.gtask.data.Node;//引用小米便签中的类
import net.micode.notes.gtask.data.Task;
import net.micode.notes.gtask.data.TaskList;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.gtask.exception.NetworkFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import net.micode.notes.ui.NotesPreferenceActivity;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
public class GTaskClient {//实现GTask的登录以及创建GTask任务和任务列表从网络上获取任务内容
private static final String TAG = GTaskClient.class.getSimpleName();//设置本类的TAG作用是日志的打印输出和标识此类
private static final String GTASK_URL = "https://mail.google.com/tasks/";//谷歌邮箱的URL
private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig";//传递URL
private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig";//发布的URL
private static GTaskClient mInstance = null;//后续使用的参数以及变量
private DefaultHttpClient mHttpClient;//网络地址客户端
private String mGetUrl;//构造函数:初始化各属性
private String mPostUrl;
private long mClientVersion;
private boolean mLoggedin;
private long mLastLoginTime;
private int mActionId;
private Account mAccount;
private JSONArray mUpdateArray;
private GTaskClient() {//初始化客户端
mHttpClient = null;//初始化
mGetUrl = GTASK_GET_URL;//初始化
mPostUrl = GTASK_POST_URL;//初始化
mClientVersion = -1;//初始化
mLoggedin = false;//初始化
mLastLoginTime = 0;//初始化
mActionId = 1;//初始化
mAccount = null;//初始化
mUpdateArray = null;//初始化
}
public static synchronized GTaskClient getInstance() {//getInstance函数在java中可以使用这种方式使用单例模式创建类的实例
if (mInstance == null) {//若无实例
mInstance = new GTaskClient();//则新建一个
}
return mInstance;
}
public boolean login(Activity activity) {//用于实现登录的方法以activity作为参数
// we suppose that the cookie would expire after 5 minutes
// then we need to re-login
final long interval = 1000 * 60 * 5;//间隔5分钟时间
if (mLastLoginTime + interval < System.currentTimeMillis()) {//距离上次登录的时间间隔若超过5分钟则重置登录状态
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);//用用户提供的账户密码去登陆Google账户
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"))) {//在google账号登陆成功后尝试能否使用用户的域名登陆gtask
StringBuilder url = new StringBuilder(GTASK_URL).append("a/");//append()函数是在文本末添加这里用于新建一个url
int index = mAccount.name.indexOf('@') + 1;//返回@第一次出现的位置并把位置+1后记录在index里
String suffix = mAccount.name.substring(index);//substring() 方法用于提取字符串中介于两个指定下标之间的字符
url.append(suffix + "/");//均为字符串操作来构建url链接
mGetUrl = url.toString() + "ig";//设置用户的getUrl
mPostUrl = url.toString() + "r/ig";//设置用户postURL
if (tryToLoginGtask(activity, authToken)) {
mLoggedin = true;//若不能使用用户域名登录使用google官方url登录
}
}
// try to login with google official url
if (!mLoggedin) {//若前面的尝试失败,则尝试使用官方的域名登陆
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
if (!tryToLoginGtask(activity, authToken)) {//第二次登录失败
return false;//返回false
}
}
mLoggedin = true;//如果没有报错说明登录成功
return true;
}
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {//用以具体实现登录Google账号的方法方法返回账号令牌
String authToken;//使用登录令牌核实用户信息和判断登录状态
AccountManager accountManager = AccountManager.get(activity);//账户管理器集中管理已注册账号和密码
Account[] accounts = accountManager.getAccountsByType("com.google");//将所有以com.google结尾的账号存入accounts数组中
if (accounts.length == 0) {//如果没有这样的账号
Log.e(TAG, "there is no available google account");//信息无有效的google账户
return null;//显示没有谷歌账户
}
String accountName = NotesPreferenceActivity.getSyncAccountName(activity);//匹配活动的账户里是否存在账户
Account account = null;//遍历account数组寻找已登录过的信息
for (Account a : accounts) {//如果找到匹配的就记下来,下次用于自动登录
if (a.name.equals(accountName)) {//没找到,输出例外信息
account = a;
break;
}
}
if (account != null) {//若存在
mAccount = account;//把这个账户记在mAccount中
} else {//不存在
Log.e(TAG, "unable to get an account with the same name in the settings");//显示“不能在设置中获取相同名字的账户”
return null;//若遍历完之后仍没有用户名匹配的账号,则直接返回
}
// get the token now
AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account,
"goanna_mobile", null, activity, null, null);//从账户中获取目标账户的令牌
try {
Bundle authTokenBundle = accountManagerFuture.getResult();//bundle是一个key-value对这里获取目标账户的最终结果集
authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);//这里获取bundle类的对象的String串并赋值给令牌对象
if (invalidateToken) {//如果是非法的令牌
accountManager.invalidateAuthToken("com.google", authToken);//删除存储AccountManager中此账号类型对应的authToken缓存
loginGoogleAccount(activity, false);//登录账号失败
}
} catch (Exception e) {//捕捉令牌获取失败的异常
Log.e(TAG, "get auth token failed");//获取令牌失败
authToken = null;
}
return authToken;
}
private boolean tryToLoginGtask(Activity activity, String authToken) {//用于判断令牌对于登陆gtask账号是否有效
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");//错误,登录 google 帐户失败
return false;
}
if (!loginGtask(authToken)) {//重新获取的令牌再次失效
Log.e(TAG, "login gtask failed");//错误,登录 gtask 失败
return false;
}
}
return true;
}
private boolean loginGtask(String authToken) {//登录gtask的实现函数根据令牌判断是否登陆成功
int timeoutConnection = 10000;//连接超时为10000毫秒即10秒
int timeoutSocket = 15000;//端口超时为15000毫秒即15秒
HttpParams httpParameters = new BasicHttpParams();//申请一个httpParameters参数类的对象
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);//设置连接超时的时间
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);//设置端口超时的时间
mHttpClient = new DefaultHttpClient(httpParameters);//新建一个默认客户端
BasicCookieStore localBasicCookieStore = new BasicCookieStore();//用来存储本地的cookie值
mHttpClient.setCookieStore(localBasicCookieStore);//为新建客户端设置cookie存储
HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);//setUseExpectContinu方法设置http协议1.1中的一个header属性Expect 100 Continue
// login gtask
try {
String loginUrl = mGetUrl + "?auth=" + authToken;
HttpGet httpGet = new HttpGet(loginUrl);//通过令牌与原始的url设置登录的URL
HttpResponse response = null;//通过HttpGet向服务器申请
response = mHttpClient.execute(httpGet);//执行execute()方法之后会返回一个HttpResponse对象,服务器所返回的所有信息就保护在HttpResponse里面
// get the cookie now
List<Cookie> cookies = mHttpClient.getCookieStore().getCookies();//获取cookie
boolean hasAuthCookie = false;//hasauthcookie默认为false
for (Cookie cookie : cookies) {//遍历cookies集合中的每个Cookie对象
if (cookie.getName().contains("GTL")) {//验证cookie信息这里通过GTL标志来验证
hasAuthCookie = true;
}
}
if (!hasAuthCookie) {//若这是未授权的Cookie值
Log.w(TAG, "it seems that there is no auth cookie");//显示没有授权的cookie
}
// get the client version
String resString = getResponseContent(response.getEntity());//获取客户端的内容
String jsBegin = "_setup(";//取得的内容是html语言截取内容为"_setup(" 与 ")}</script>" 中间的部分
String jsEnd = ")}</script>";
int begin = resString.indexOf(jsBegin);//获取jsbegin中begin的序号
int end = resString.lastIndexOf(jsEnd);//获取jsend中end的序号
String jsString = null;
if (begin != -1 && end != -1 && begin < end) {
jsString = resString.substring(begin + jsBegin.length(), end);
}
JSONObject js = new JSONObject(jsString);
mClientVersion = js.getLong("v");//设置客户端版本
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
return false;
} catch (Exception e) {//捕获所有的异常
// simply catch all exceptions
Log.e(TAG, "httpget gtask_url failed");//截取失败打印日志
return false;
}
return true;
}
private int getActionId() {//获取动作的id号码
return mActionId++;
}
private HttpPost createHttpPost() {
HttpPost httpPost = new HttpPost(mPostUrl);//创建一个httppost对象用来保存URL
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");//设置httppost对象的头部
httpPost.setHeader("AT", "1");
return httpPost;
}
private String getResponseContent(HttpEntity entity) throws IOException {//使用getContentEncoding()获取网络上的资源和数据
String contentEncoding = null;
if (entity.getContentEncoding() != null) {//如果获取的内容编码不为空
contentEncoding = entity.getContentEncoding().getValue();//给contentEncoding赋值
Log.d(TAG, "encoding: " + contentEncoding);//打印日志“encoding内容编码”
}
InputStream input = entity.getContent();
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {//如果contentEncoding不为null且contentEncoding与"gzip"相等
input = new GZIPInputStream(entity.getContent());//使用GZIPInputStream对entity内容进行GZIP解压把值赋给InputStream类对象input
} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {//DEFLATE是一个无专利的压缩算法它可以实现无损数据压缩
Inflater inflater = new Inflater(true);
input = new InflaterInputStream(entity.getContent(), inflater);//实现了一个流过滤器用于以“deflate”压缩格式解压缩数据
}
try {
InputStreamReader isr = new InputStreamReader(input);//InputStreamReader类是从字节流到字符流的桥接器它使用指定的字符集读取字节并将它们解码为字符
BufferedReader br = new BufferedReader(isr);//缓存读取类,用于快速的读缓存操作
StringBuilder sb = new StringBuilder();
while (true) {//将BufferedReader类br的内容逐行读取并存储StringBuilder类的sb中。然后返回sb的string格式。
String buff = br.readLine();
if (buff == null) {
return sb.toString();
}
sb = sb.append(buff);
}
} finally {
input.close();
}
}
private JSONObject postRequest(JSONObject js) throws NetworkFailureException {//利用JSON发送请求返回获取的内容
if (!mLoggedin) {//用户未登录
Log.e(TAG, "please login first");//显示请先登录
throw new ActionFailureException("not logged in");//抛出异常没有登录
}
HttpPost httpPost = createHttpPost();//实例化一个httpPost的对象用来向服务器传输数据发送在js里请求的内容
try {
LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>();//LinkedList 类是一个继承于AbstractSequentialList的双向链表
list.add(new BasicNameValuePair("r", js.toString()));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");//普通的键值对"UTF-8"
httpPost.setEntity(entity);//向httpPost对象中添加参数
// execute the post
HttpResponse response = mHttpClient.execute(httpPost);//执行请求
String jsString = getResponseContent(response.getEntity());
return new JSONObject(jsString);
} catch (ClientProtocolException e) {//下面的四个catch是对4种失败情况的处理和抛出异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("postRequest failed");//post请求失败
} catch (IOException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("postRequest failed");
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("unable to convert response content to jsonobject");
} catch (Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("error occurs when posting request");
}
}
public void createTask(Task task) throws NetworkFailureException {//创建单个任务
commitUpdate();//提交更新
try {
JSONObject jsPost = new JSONObject();//用JSON获取Task中的内容并创建相应的jspost
JSONArray actionList = new JSONArray();
// action_list
actionList.put(task.getCreateAction(getActionId()));
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);//将要提交的内容放入jsPost对象中
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);//client的版本号
// post
JSONObject jsResponse = postRequest(jsPost);//通过postRequest获取任务的返回信息
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));//设置任务的id
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("create task: handing jsonobject failed");
}
}
public void createTaskList(TaskList tasklist) throws NetworkFailureException {//创建一个任务列表
commitUpdate();//提交后更新
try {
JSONObject jsPost = new JSONObject();//操作列表
JSONArray actionList = new JSONArray();
// action_list
actionList.put(tasklist.getCreateAction(getActionId()));
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);////客户端版本
// post
JSONObject jsResponse = postRequest(jsPost);//post操作
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("create tasklist: handing jsonobject failed");
}
}
public void commitUpdate() throws NetworkFailureException {//同步更新操作
if (mUpdateArray != null) {//更新列表不为空
try {
JSONObject jsPost = new JSONObject();//更新数据
// action_list
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);
mUpdateArray = null;//更新处理完毕,列表置空
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("commit update: handing jsonobject failed");
}
}
}
public void addUpdateNode(Node node) throws NetworkFailureException {//添加更新节点
if (node != null) {//如果node节点不是空的
// too many update items may result in an error
// set max to 10 items
if (mUpdateArray != null && mUpdateArray.length() > 10) {//判断现在mUpdateArray是否是空的或者满的
commitUpdate();//提交更新
}
if (mUpdateArray == null)//空的则新建一个数组
mUpdateArray = new JSONArray();
mUpdateArray.put(node.getUpdateAction(getActionId()));//将更新节点加入列表
}
}
public void moveTask(Task task, TaskList preParent, TaskList curParent)
throws NetworkFailureException {//把任务移动到指定的列表中
commitUpdate();//提交更新数据
try {//创建新的jsonobject
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
JSONObject action = new JSONObject();
// action_list
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE);
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid());
if (preParent == curParent && task.getPriorSibling() != null) {//当移动发生在同一个任务列表中且该移动不是第一个时
// put prioring_sibing_id only if moving within the tasklist and
// it is not the first one
action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());//设置优先级ID
}
action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());//设置当前列表
action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());
if (preParent != curParent) {//在不同列表间移动时,放入目标列表中去
// put the dest_list only if moving between tasklists
action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());
}
actionList.put(action);
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);//用户版本
postRequest(jsPost);//postRequst()进行更新后的发送
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("move task: handing jsonobject failed");
}
}
public void deleteNode(Node node) throws NetworkFailureException {//删除节点操作
commitUpdate();
try {
JSONObject jsPost = new JSONObject();//新建jsPost把除了node的其他节点都放入jsPost并提交
JSONArray actionList = new JSONArray();
// action_list
node.setDeleted(true);//把要删除的node的成员变量的删除属性设置为true
actionList.put(node.getUpdateAction(getActionId()));//将该节点要更新的操作的id加入操作列表
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);
mUpdateArray = null;
} catch (JSONException e) {//异常处理机制
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("delete node: handing jsonobject failed");
}
}
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);//通过GetURI使用getResponseContent从网上获取初步的数据
HttpResponse response = null;//初始化Httpresponse (回复)为空
response = mHttpClient.execute(httpGet);//用httpGet作消息发给客户端执行并回复消息
// get the task list
String resString = getResponseContent(response.getEntity());//获取任务列表
String jsBegin = "_setup(";//把字符串截取并放入jsStrIng
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);//获取GTASK_JSON_LISTS
} catch (ClientProtocolException e) {//捕捉httpget失败异常
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (IOException e) {//异常处理
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (JSONException e) {//异常处理
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("get task lists: handing jasonobject failed");
}
}
public JSONArray getTaskList(String listGid) throws NetworkFailureException {//获取任务列表
commitUpdate();
try {
JSONObject jsPost = new JSONObject();//设置为传入的listGid
JSONArray actionList = new JSONArray();
JSONObject action = new JSONObject();
// action_list
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,//通过action.put()对JSONObject对象action添加元素
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);//通过jsPost.put()对jsPost添加相关元素
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
JSONObject jsResponse = postRequest(jsPost);//通过postRequest()提交更新后的请求并返回一个JSONObject的对象
return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS);//使用jsResponse.getJSONArray( )获取jsResponse中的JSONArray值并作为函数返回值
} catch (JSONException e) {//异常处理
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因
throw new ActionFailureException("get task list: handing jsonobject failed");
}
}
public Account getSyncAccount() {//获取同步账户
return mAccount;//同步账户
}
public void resetUpdateArray() {//重置更新内容
mUpdateArray = null;//更新内容
}
}
Loading…
Cancel
Save