You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xiaomi-Notes/Task.java

697 lines
33 KiB

3 months ago
/*
* 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.
*/
//包声明:
// 该类属于 net.micode.notes.gtask.data 包,通常表示这是一个与 Google Tasks 或某个任务管理相关的数据模型类。
package net.micode.notes.gtask.data;
//导入 Cursor 类:
// Cursor 是 Android 中用于从数据库中查询数据的接口,通常用于访问 SQLite 数据库中的记录。
import android.database.Cursor;
//导入 TextUtils 类:
// TextUtils 是 Android 提供的工具类,包含了一些常用的字符串操作方法,如判断字符串是否为空或是否匹配某些模式等。
import android.text.TextUtils;
//导入 Log 类:
// Log 类用于 Android 中的日志输出,开发者可以使用它记录调试信息、错误日志等。
import android.util.Log;
//导入 Notes 类:
// 这个类可能是应用中用于表示便签或任务的类。Notes 类中的常量和方法通常用于访问或操作任务和便签相关的数据。
import net.micode.notes.data.Notes;
//导入 DataColumns, DataConstants, NoteColumns
// 这些导入语句表明,这些类包含 Notes 类中的常量和字段,它们可能用于表示与任务或便签相关的列名、常量定义等。
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
//导入 ActionFailureException 类:
// 这个自定义异常类 ActionFailureException 可能用于处理在执行某些操作时发生的错误,表示某些操作失败。
import net.micode.notes.gtask.exception.ActionFailureException;
//导入 GTaskStringUtils 工具类:
// 这个类看起来是与 Google Tasks 相关的字符串工具类,可能包含处理任务相关字符串的实用方法。
import net.micode.notes.tool.GTaskStringUtils;
//导入 org.json 库的类:这些类用于处理 JSON 数据。
// 在任务管理应用中,任务通常是以 JSON 格式存储或传输的JSONArray, JSONException, 和 JSONObject 提供了处理 JSON 数据所需的工具。
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
//类Task 类继承自 Node 类,表示任务的基本模型,包含任务的状态、备注、父任务、优先级等信息。
//Task 类的构造函数:
//初始化了 mCompleted任务是否完成、mNotes任务备注、mPriorSibling前一个兄弟任务
// mParent父任务列表和 mMetaInfo任务的元数据信息等属性。
public class Task extends Node {
// 用于日志输出时标识当前类名
private static final String TAG = Task.class.getSimpleName();
// 任务是否完成
private boolean mCompleted;
// 任务的备注信息
private String mNotes;
// 任务的元数据信息,可能包含额外的任务信息
private JSONObject mMetaInfo;
// 当前任务的前一个兄弟任务
private Task mPriorSibling;
// 当前任务所属的任务列表(父任务列表)
private TaskList mParent;
// 构造函数:初始化 Task 对象的默认值
public Task() {
// 调用父类构造函数(假设父类 Node 也有构造函数)
super();
// 默认任务未完成
mCompleted = false;
// 默认没有备注
mNotes = null;
// 默认没有前一个兄弟任务
mPriorSibling = null;
// 默认没有父任务列表
mParent = null;
// 默认没有元数据
mMetaInfo = null;
}
/**
* JSON
*
* @param actionId ID
* @return JSONObject
*/
/*
getCreateAction(int actionId) JSONObject
getCreateAction(int actionId)
JSONObjectcreate action
JSON ID ID ID
JSONObject JSONObjectjs
action_type
action_id ID actionId
index使 mParent.getChildTaskIndex(this)
entity JSON ID null "task"
mNotes null entity
ID ID
mParent.getGid() ID JSON
ID
mPriorSibling != null ID JSON
JSON JSONException ActionFailureException
JSONException ActionFailureException
JSONException
JSON JSON
ActionFailureException
JSON
使 Log.e(TAG, e.toString()) 便
e.printStackTrace()
*/
public JSONObject getCreateAction(int actionId) {
// 创建一个新的 JSON 对象,用于保存任务的创建信息
JSONObject js = new JSONObject();
try {
// 设置 action_type表示这是一个任务创建的操作
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
// 设置 action_id任务创建动作的唯一 ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置任务在父任务列表中的索引位置
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
// 创建一个 JSON 对象 entity用于表示任务的基本信息任务名称、创建者 ID、任务类型等
JSONObject entity = new JSONObject();
// 设置任务的名称
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
// 设置任务创建者 ID这里默认为 "null"
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_TASK); // 设置任务的类型为 "task"
// 如果任务有备注信息,添加备注到 entity 中
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
// 将任务的 entity 信息放入 JSON 中
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
// 设置任务的父任务 ID当前任务所在的任务列表的 ID
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());
// 设置目标父级类型,这里固定为 "group" 类型
js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
// 设置任务列表的 ID父任务列表的 ID
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
// 如果当前任务有前一个兄弟任务,则设置 prior_sibling_id
if (mPriorSibling != null) {
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());
}
} catch (JSONException e) {
// 如果生成 JSON 时发生错误,记录错误日志,并抛出自定义异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-create jsonobject");
}
// 返回生成的 JSON 对象
return js;
}
}
/*
getUpdateAction(int actionId) JSON JSON ID
actionId ID
JSONObject
js.put()
使 js.put() JSON
put() JSONObject API JSON
GTaskStringUtils.GTASK_JSON_ACTION_TYPE GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE
action_id
使 actionId ID
ID
GTaskStringUtils.GTASK_JSON_ID getGid() IDgetGid() ID
entity JSON
GTaskStringUtils.GTASK_JSON_NAME 使 getName()
getNotes() != null JSON
GTaskStringUtils.GTASK_JSON_DELETED 使 getDeleted()
JSON JSONException ActionFailureException
ActionFailureException "fail to generate task-update jsonobject"
JSONObject JSON
*/
public JSONObject getUpdateAction(int actionId) {
// 创建一个新的 JSON 对象,表示任务更新动作
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使用 `getGid()` 方法获取当前任务的唯一 ID
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// 创建一个 entity 对象,表示任务更新的实际内容(包括任务的名称、备注和删除标记)
JSONObject entity = new JSONObject();
// 设置任务的名称
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
// 如果任务有备注信息,则添加备注字段
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
// 设置任务的删除标记,使用 `getDeleted()` 方法获取任务是否已删除
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
// 将 entity 对象放入 JSON 中,作为任务更新的实际内容
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {
// 捕获 JSON 构建过程中的异常
// 打印错误日志
Log.e(TAG, e.toString());
// 输出堆栈信息
e.printStackTrace();
// 如果发生异常,抛出自定义的更新失败异常
throw new ActionFailureException("fail to generate task-update jsonobject");
}
// 返回生成的任务更新 JSON 对象
return js;
}
/*
`setContentByRemoteJSON(JSONObject js)` JSON
- ****`setContentByRemoteJSON(JSONObject js)` JSON JSON setter
- ****`js` `JSONObject`
- ****
1. ** JSON **
- `js` `null` `null`退
2. ****
- `js.has()` JSON JSON setter
- `GTaskStringUtils` `GTASK_JSON_ID``GTASK_JSON_LAST_MODIFIED``GTASK_JSON_NAME`
3. ****
- ** ID**使 `getString()` ID `setGid()` ID
- ****使 `getLong()` `setLastModified()`
- ****使 `getString()` `setName()`
- ****使 `getString()`
- ****使 `getBoolean()` `setDeleted()`
- ****使 `getBoolean()` `setCompleted()`
4. ****
- JSON `JSONException` `ActionFailureException` JSON
- JSON "fail to get task content from jsonobject"
5. **setter **
- `setGid()`, `setLastModified()`, `setName()`, `setNotes()`, `setDeleted()`, `setCompleted()`
- JSON ID setter
- 使 `js.has()`
- JSON 便
*/
public void setContentByRemoteJSON(JSONObject js) {
// 如果传入的 JSON 对象不为 null
if (js != null) {
try {
// 处理任务 ID获取并设置任务的全局 ID
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
}
// 处理任务的最后修改时间,获取并设置
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
}
// 处理任务名称,获取并设置
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
}
// 处理任务备注,获取并设置
if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) {
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES));
}
// 处理删除标记,获取并设置
if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) {
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED));
}
// 处理完成标记,获取并设置
if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) {
setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED));
}
} catch (JSONException e) {
// 如果解析 JSON 过程中发生异常,打印错误信息并抛出自定义异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to get task content from jsonobject");
}
}
}
/*
JSON JSON name
js JSONObject META_HEAD_NOTE META_HEAD_DATA
*/
public void setContentByLocalJSON(JSONObject js) {
// 检查传入的 JSON 是否为 null且是否包含所需的两个字段
/*
js nullMETA_HEAD_NOTE META_HEAD_DATA
js null
*/
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
// 如果条件不满足,打印警告信息并返回
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
}
try {
/* JSON
JSON META_HEAD_NOTE note META_HEAD_DATA dataArray
*/
// 从 JSON 中提取出 META_HEAD_NOTE 对应的 JSONObject
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
// 从 JSON 中提取出 META_HEAD_DATA 对应的 JSONArray
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
// 检查 note 对象中的 TYPE 是否为 NOTE 类型
//通过 note.getInt(NoteColumns.TYPE) 获取 note 对象中的 TYPE 字段,并与 Notes.TYPE_NOTE 常量进行比较。
// 如果 TYPE 不等于 Notes.TYPE_NOTE假设 Notes.TYPE_NOTE 是预定义的常量,表示有效的 note 类型),
// 则认为该数据无效,打印错误日志并退出方法。
if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {
// 如果 TYPE 不等于 NOTE 类型,打印错误信息并返回
Log.e(TAG, "invalid type");
return;
}
// 遍历 dataArray 数组中的每个 JSONObject
/* dataArray.length() 使 for data
data.getString(DataColumns.MIME_TYPE) MIME_TYPE
DataConstants.NOTE MIME_TYPE NOTE data CONTENT
setName()
data 便使 break
*/
for (int i = 0; i < dataArray.length(); i++) {
// 获取当前遍历的 data 对象
JSONObject data = dataArray.getJSONObject(i);
// 判断 data 中的 MIME_TYPE 是否为 NOTE 类型
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
// 如果 MIME_TYPE 为 NOTE 类型,从 data 中获取 CONTENT 字段的值,并设置为任务的名称
setName(data.getString(DataColumns.CONTENT));
// 找到第一个符合条件的记录后跳出循环
break;
}
}
}
//如果在解析 JSON 数据时发生异常(例如字段缺失或类型不匹配),会捕获 JSONException 并打印错误信息,确保应用不会崩溃。
catch (JSONException e) {
// 如果在解析过程中发生异常,打印错误信息
Log.e(TAG, e.toString());
// 打印堆栈跟踪信息
e.printStackTrace();
}
}
/*
getLocalJSONFromContent() JSON JSONObject
mMetaInfo JSON
*/
public JSONObject getLocalJSONFromContent() {
// 获取当前任务的名称
String name = getName();
try {
// 如果 mMetaInfo 为 null表示任务还未同步或者是一个新任务
if (mMetaInfo == null) {
// new task created from web
// 如果任务的名称为空,输出警告并返回 null
if (name == null) {
Log.w(TAG, "the note seems to be an empty one");
return null;
}
// 创建一个新的 JSON 对象来表示任务的元数据
JSONObject js = new JSONObject();
JSONObject note = new JSONObject();
JSONArray dataArray = new JSONArray();
JSONObject data = new JSONObject();
// 将任务的名称添加到 data 对象中
data.put(DataColumns.CONTENT, name);
// 将 data 对象添加到 dataArray 中
dataArray.put(data);
// 将 dataArray 添加到 js 对象中的 META_HEAD_DATA 字段
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
// 设置 note 对象的 TYPE 字段为 NOTE 类型
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
// 将 note 对象添加到 js 对象中的 META_HEAD_NOTE 字段
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
return js; // 返回生成的 JSON 对象
} else {
// 如果 mMetaInfo 已经存在,表示这是一个已经同步的任务
// 从 mMetaInfo 中获取 META_HEAD_NOTE 和 META_HEAD_DATA
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
// 遍历 dataArray 中的每个 data 对象,更新 MIME_TYPE 为 NOTE 的对象中的 CONTENT 字段
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
// 更新 data 对象中的 CONTENT 字段为当前任务的名称
data.put(DataColumns.CONTENT, getName());
break; // 找到并更新后跳出循环
}
}
// 确保 note 对象中的 TYPE 字段仍然为 NOTE 类型
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
// 返回已经更新的 mMetaInfo 对象
return mMetaInfo;
}
}
// 捕获并处理 JSON 解析过程中的异常
catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
// 如果发生异常,返回 null
return null;
}
}
/*
setMetaInfo(MetaData metaData)
MetaData metaData notes JSONObject mMetaInfo
metaData metaData.getNotes() null getNotes() JSONObject mMetaInfo
JSON JSONException mMetaInfo null
*/
public void setMetaInfo(MetaData metaData) {
if (metaData != null && metaData.getNotes() != null) {
try {
// 将 notes 字符串转换为 JSONObject
mMetaInfo = new JSONObject(metaData.getNotes());
}
catch (JSONException e) { // 如果 JSON 转换失败
// 输出警告日志
Log.w(TAG, e.toString());
// 设置 mMetaInfo 为 null
mMetaInfo = null;
}
}
}
/*
getSyncAction(Cursor c)
mMetaInfo note
Cursor mMetaInfo note
SYNC_ACTION_UPDATE_REMOTE
SYNC_ACTION_UPDATE_LOCAL
SYNC_ACTION_NONE
SYNC_ACTION_UPDATE_CONFLICT
SYNC_ACTION_ERROR
*/
public int getSyncAction(Cursor c) {
try {
JSONObject noteInfo = null;
if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) {
// 获取 note 元数据
noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
}
// 如果没有获取到 note 信息
if (noteInfo == null) {
Log.w(TAG, "it seems that note meta has been deleted");
// 需要从远程更新
return SYNC_ACTION_UPDATE_REMOTE;
}
// 如果 note 缺少 ID 字段
if (!noteInfo.has(NoteColumns.ID)) {
Log.w(TAG, "remote note id seems to be deleted");
// 需要从本地更新
return SYNC_ACTION_UPDATE_LOCAL;
}
// 校验 note ID 是否匹配
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) {
Log.w(TAG, "note id doesn't match");
// 如果不匹配,从本地更新
return SYNC_ACTION_UPDATE_LOCAL;
}
// 如果本地未修改
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// 本地和远程都没有变化
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// 无需操作
return SYNC_ACTION_NONE;
} else { // 远程有更新
// 从远程更新
return SYNC_ACTION_UPDATE_LOCAL;
}
} else { // 本地已修改
// 校验 gtask ID
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
Log.e(TAG, "gtask id doesn't match");
// gtask ID 不匹配,返回错误
return SYNC_ACTION_ERROR;
}
// 本地修改且没有远程修改
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// 将本地修改同步到远程
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;
}
/*
setCompleted(boolean completed)
completed
*/
public void setCompleted(boolean completed) {
//将传入的 completed 参数赋值给任务对象的 mCompleted 属性,用于标识任务是否完成
this.mCompleted = completed;
}
/*
setNotes(String notes)
notes
*/
public void setNotes(String notes) {
//将传入的 notes 参数赋值给任务对象的 mNotes 属性,用于存储任务的备注内容。
this.mNotes = notes;
}
/*
setPriorSibling(Task priorSibling)
priorSibling Task
*/
public void setPriorSibling(Task priorSibling) {
//将传入的 priorSibling 参数赋值给任务对象的 mPriorSibling 属性,表示当前任务在任务列表中的前一个任务。
this.mPriorSibling = priorSibling;
}
/*
setParent(TaskList parent)
parent TaskList
*/
public void setParent(TaskList parent) {
//将传入的 parent 参数赋值给任务对象的 mParent 属性,表示当前任务所属的父任务列表。
this.mParent = parent;
}
/*
getCompleted()
*/
public boolean getCompleted() {
//返回 mCompleted 属性的值,表示任务是否已完成。
return this.mCompleted;
}
/*
getNotes()
*/
public String getNotes() {
//返回 mNotes 属性的值,表示任务的备注或附加说明。
return this.mNotes;
}
/*
getPriorSibling()
Task
*/
public Task getPriorSibling() {
//返回 mPriorSibling 属性的值,表示当前任务在任务列表中的前一个任务。
return this.mPriorSibling;
}
/*
getParent()
TaskList
*/
public TaskList getParent() {
// 返回 mParent 属性的值,表示当前任务所属的父任务列表。
return this.mParent;
}
}