|
|
|
@ -424,4 +424,555 @@ public class NotesProvider extends ContentProvider {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}package net.micode.notes.data;
|
|
|
|
|
|
|
|
|
|
import android.content.ContentValues;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.database.sqlite.SQLiteDatabase;
|
|
|
|
|
import android.database.sqlite.SQLiteOpenHelper;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.data.Notes.DataColumns;
|
|
|
|
|
import net.micode.notes.data.Notes.DataConstants;
|
|
|
|
|
import net.micode.notes.data.Notes.NoteColumns;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class NotesDatabaseHelper extends SQLiteOpenHelper {
|
|
|
|
|
// 数据库帮助类,用于管理名为 note.db 的 SQLite 数据库。
|
|
|
|
|
// 它继承自 SQLiteOpenHelper 类,这是 Android提供的一个方便的工具类,用于管理数据库的创建和版本更新.
|
|
|
|
|
// 数据库的基本信息;数据库名称和版本信息(在创建实例对象时会用到)
|
|
|
|
|
private static final String DB_NAME = "note.db";
|
|
|
|
|
|
|
|
|
|
private static final int DB_VERSION = 4;
|
|
|
|
|
|
|
|
|
|
//内部接口:个人理解为两个表名,一个note,一个data
|
|
|
|
|
public interface TABLE {
|
|
|
|
|
public static final String NOTE = "note";
|
|
|
|
|
|
|
|
|
|
public static final String DATA = "data";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//一个标签,方便日志输出时识别出信息来自哪里
|
|
|
|
|
private static final String TAG = "NotesDatabaseHelper";
|
|
|
|
|
|
|
|
|
|
//静态所有变量,提供一个全局访问点来获取数据库辅助类的唯一实例,使得在应用的任何地方都可以方便地使用它
|
|
|
|
|
private static NotesDatabaseHelper mInstance;
|
|
|
|
|
|
|
|
|
|
/* 以下都是一些SQL语句,辅助我们来对数据库进行操作 */
|
|
|
|
|
//创建note表的语句,这里的NoteColumns就是我们刚刚在Notes中定义的一个接口,里面定义了一系列静态的数据库表中的列名
|
|
|
|
|
private static final String CREATE_NOTE_TABLE_SQL =
|
|
|
|
|
"CREATE TABLE " + TABLE.NOTE + "(" +
|
|
|
|
|
NoteColumns.ID + " INTEGER PRIMARY KEY," +
|
|
|
|
|
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
|
|
|
|
|
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
|
|
|
|
|
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
|
|
|
|
|
package net.micode.notes.data;
|
|
|
|
|
|
|
|
|
|
import android.content.ContentValues;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.database.sqlite.SQLiteDatabase;
|
|
|
|
|
import android.database.sqlite.SQLiteOpenHelper;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.data.Notes.DataColumns;
|
|
|
|
|
import net.micode.notes.data.Notes.DataConstants;
|
|
|
|
|
import net.micode.notes.data.Notes.NoteColumns;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class NotesDatabaseHelper extends SQLiteOpenHelper {
|
|
|
|
|
// 数据库帮助类,用于管理名为 note.db 的 SQLite 数据库。
|
|
|
|
|
// 它继承自 SQLiteOpenHelper 类,这是 Android提供的一个方便的工具类,用于管理数据库的创建和版本更新.
|
|
|
|
|
// 数据库的基本信息;数据库名称和版本信息(在创建实例对象时会用到)
|
|
|
|
|
private static final String DB_NAME = "note.db";
|
|
|
|
|
|
|
|
|
|
private static final int DB_VERSION = 4;
|
|
|
|
|
|
|
|
|
|
//内部接口:个人理解为两个表名,一个note,一个data
|
|
|
|
|
public interface TABLE {
|
|
|
|
|
public static final String NOTE = "note";
|
|
|
|
|
|
|
|
|
|
public static final String DATA = "data";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//一个标签,方便日志输出时识别出信息来自哪里
|
|
|
|
|
private static final String TAG = "NotesDatabaseHelper";
|
|
|
|
|
|
|
|
|
|
//静态所有变量,提供一个全局访问点来获取数据库辅助类的唯一实例,使得在应用的任何地方都可以方便地使用它
|
|
|
|
|
private static NotesDatabaseHelper mInstance;
|
|
|
|
|
|
|
|
|
|
/* 以下都是一些SQL语句,辅助我们来对数据库进行操作 */
|
|
|
|
|
//创建note表的语句,这里的NoteColumns就是我们刚刚在Notes中定义的一个接口,里面定义了一系列静态的数据库表中的列名
|
|
|
|
|
private static final String CREATE_NOTE_TABLE_SQL =
|
|
|
|
|
"CREATE TABLE " + TABLE.NOTE + "(" +
|
|
|
|
|
NoteColumns.ID + " INTEGER PRIMARY KEY," +
|
|
|
|
|
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
|
|
|
|
|
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
|
|
|
|
|
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
|
|
|
|
|
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
|
|
|
|
|
NoteColupackage net.micode.notes.data;
|
|
|
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
|
|
|
|
import android.provider.ContactsContract.Data;
|
|
|
|
|
import android.telephony.PhoneNumberUtils;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
|
|
|
|
|
public class Contact {
|
|
|
|
|
// 用于处理联系人信息
|
|
|
|
|
// 实现了从联系人数据库中获取指定电话号码对应的联系人姓名的功能
|
|
|
|
|
|
|
|
|
|
//sContactCache:用于缓存电话号码和对应的联系人姓名
|
|
|
|
|
//TAG:用于日志输出的标识
|
|
|
|
|
private static HashMap<String, String> sContactCache;
|
|
|
|
|
private static final String TAG = "Contact";
|
|
|
|
|
|
|
|
|
|
//SQL查询条件( WHERE 后面的语句),用于从联系人数据库中筛选出与给定电话号码匹配的联系人。
|
|
|
|
|
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
|
|
|
|
|
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
|
|
|
|
|
+ " AND " + Data.RAW_CONTACT_ID + " IN "
|
|
|
|
|
+ "(SELECT raw_contact_id "
|
|
|
|
|
+ " FROM phone_lookup"
|
|
|
|
|
+ " WHERE min_match = '+')";
|
|
|
|
|
|
|
|
|
|
//功能简介:用于从Android设备的联系人数据库中获取与给定电话号码对应的联系人姓名。
|
|
|
|
|
//参数:Context对象:用于访问系统服务和应用资源 phoneNumber:需要查询的联系人电话号码
|
|
|
|
|
public static String getContact(Context context, String phoneNumber) {
|
|
|
|
|
// 没映射表就建表,有就查缓存中有没有这个联系人
|
|
|
|
|
if(sContactCache == null) {
|
|
|
|
|
sContactCache = new HashMap<String, String>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(sContactCache.containsKey(phoneNumber)) {
|
|
|
|
|
return sContactCache.get(phoneNumber);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//缓存没有,就查询数据库
|
|
|
|
|
//构造一个SQL查询条件:CALLER_ID_SELECTION中的"+"被替换为电话号码的最小匹配值
|
|
|
|
|
//然后执行查询语句
|
|
|
|
|
String selection = CALLER_ID_SELECTION.replace("+",
|
|
|
|
|
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
|
|
|
|
|
Cursor cursor = context.getContentResolver().query(
|
|
|
|
|
Data.CONTENT_URI,
|
|
|
|
|
new String [] { Phone.DISPLAY_NAME },
|
|
|
|
|
selection,
|
|
|
|
|
new String[] { phoneNumber },
|
|
|
|
|
null);
|
|
|
|
|
|
|
|
|
|
//判断查询结果:
|
|
|
|
|
//查询结果不为空,且能够移动到第一条记录:
|
|
|
|
|
// 那么就尝试从Cursor中获取联系人姓名,并将其存入缓存sContactCache。然后返回联系人姓名。
|
|
|
|
|
// 异常情况:如果在获取字符串时发生数组越界异常,则记录一个错误日志并返回null。
|
|
|
|
|
// 最后都要确保关闭Cursor对象,以避免内存泄漏。
|
|
|
|
|
//如果查询结果为空或者没有记录可以移动到(即没有找到匹配的联系人):
|
|
|
|
|
// 则记录一条调试日志并返回null
|
|
|
|
|
if (cursor != null && cursor.moveToFirst()) {
|
|
|
|
|
try {
|
|
|
|
|
String name = cursor.getString(0);
|
|
|
|
|
sContactCache.put(phoneNumber, name);
|
|
|
|
|
return name;
|
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
|
Log.e(TAG, " Cursor get string error " + e.toString());
|
|
|
|
|
return null;
|
|
|
|
|
} finally {
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Log.d(TAG, "No contact matched with number:" + phoneNumber);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
package net.micode.notes.gtask.data;
|
|
|
|
|
// 定义了 `Task` 类所在的包。
|
|
|
|
|
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.text.TextUtils;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
// 导入 Android SDK 中必要的类:
|
|
|
|
|
// - `Cursor`:用于访问数据库中的数据。
|
|
|
|
|
// - `TextUtils`:用于文本处理的工具类。
|
|
|
|
|
// - `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;
|
|
|
|
|
import org.json.JSONException;
|
|
|
|
|
import org.json.JSONObject;
|
|
|
|
|
// 导入与 JSON 相关的类,用于处理 JSON 数据结构。
|
|
|
|
|
|
|
|
|
|
## Task 类定义
|
|
|
|
|
|
|
|
|
|
public class Task extends Node {
|
|
|
|
|
// 声明 `Task` 类,该类是 `Node` 的子类。这表示 `Task` 继承了 `Node` 的属性和方法。
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 类变量
|
|
|
|
|
|
|
|
|
|
private static final String TAG = Task.class.getSimpleName();
|
|
|
|
|
// - 一个常量字符串,用于记录日志,表示 `Task` 类的名称。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean mCompleted;
|
|
|
|
|
private String mNotes;
|
|
|
|
|
private JSONObject mMetaInfo;
|
|
|
|
|
private Task mPriorSibling;
|
|
|
|
|
private TaskList mParent;
|
|
|
|
|
// 声明实例变量:
|
|
|
|
|
// - `mCompleted`:布尔值,跟踪任务是否已完成。
|
|
|
|
|
// - `mNotes`:字符串,用于保存与任务关联的笔记。
|
|
|
|
|
// - `mMetaInfo`:`JSONObject`,存储有关任务的元数据。
|
|
|
|
|
// - `mPriorSibling`:引用同级中的前一个 `Task`。
|
|
|
|
|
// - `mParent`:引用父级 `TaskList`。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 构造函数
|
|
|
|
|
|
|
|
|
|
public Task() {
|
|
|
|
|
// `Task` 类的构造函数,用于初始化新的任务对象。
|
|
|
|
|
|
|
|
|
|
super();
|
|
|
|
|
// 调用父类 `Node` 的构造函数,确保父类的属性也被初始化。
|
|
|
|
|
|
|
|
|
|
mCompleted = false;
|
|
|
|
|
mNotes = null;
|
|
|
|
|
mPriorSibling = null;
|
|
|
|
|
mParent = null;
|
|
|
|
|
mMetaInfo = null;
|
|
|
|
|
// 初始化实例变量:
|
|
|
|
|
// - 将 `mCompleted` 设置为 `false`,表示任务未完成。
|
|
|
|
|
// - `mNotes`、`mPriorSibling`、`mParent` 和 `mMetaInfo` 初始化为 `null`。
|
|
|
|
|
## 方法:getCreateAction
|
|
|
|
|
|
|
|
|
|
public JSONObject getCreateAction(int actionId) {
|
|
|
|
|
// 定义一个方法,用于生成一个 JSON 对象,描述创建任务的操作。
|
|
|
|
|
|
|
|
|
|
JSONObject js = new JSONObject();
|
|
|
|
|
// 创建一个新的 JSON 对象,用于存储任务的创建信息。
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 开始一个 `try` 块,以处理可能出现的 `JSONException`。
|
|
|
|
|
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
|
|
|
|
|
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
|
|
|
|
|
// 向 JSON 对象中添加操作类型,表示这是一个创建操作。
|
|
|
|
|
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
|
|
|
|
|
// 设置操作 ID,以便跟踪此操作。
|
|
|
|
|
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
|
|
|
|
|
// 将当前任务在父任务列表中的索引添加到 JSON 对象中。
|
|
|
|
|
|
|
|
|
|
JSONObject entity = new JSONObject();
|
|
|
|
|
// 创建一个新的 JSON 对象,用于存储与任务实体相关的信息。
|
|
|
|
|
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
|
|
|
|
|
GTaskStringUtils.GTASK_JSON_TYPE_TASK);
|
|
|
|
|
// 将任务名称、创建者 ID 和实体类型添加到实体 JSON 对象中。
|
|
|
|
|
|
|
|
|
|
if (getNotes() != null) {
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
|
|
|
|
|
}
|
|
|
|
|
// 如果任务有笔记,则将其添加到实体 JSON 对象中。
|
|
|
|
|
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
|
|
|
|
|
// 将实体 JSON 对象添加到主 JSON
|
|
|
|
|
package net.micode.notes.gtask.data;
|
|
|
|
|
定义了 Task 类所在的包。
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.text.TextUtils;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
导入 Android SDK 中必要的类:
|
|
|
|
|
Cursor:用于访问数据库中的数据。
|
|
|
|
|
TextUtils:用于文本处理的工具类。
|
|
|
|
|
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;
|
|
|
|
|
import org.json.JSONException;
|
|
|
|
|
import org.json.JSONObject;
|
|
|
|
|
导入与 JSON 相关的类,用于处理 JSON 数据结构
|
|
|
|
|
private static final String TAG = Task.class.getSimpleName();
|
|
|
|
|
一个常量字符串,用于记录日志,表示 Task 类的名称。
|
|
|
|
|
private boolean mCompleted;
|
|
|
|
|
private String mNotes;
|
|
|
|
|
private JSONObject mMetaInfo;
|
|
|
|
|
private Task mPriorSibling;
|
|
|
|
|
private TaskList mParent;
|
|
|
|
|
声明实例变量:
|
|
|
|
|
mCompleted:布尔值,跟踪任务是否已完成。
|
|
|
|
|
mNotes:字符串,用于保存与任务关联的笔记。
|
|
|
|
|
mMetaInfo:JSONObject,存储有关任务的元数据。
|
|
|
|
|
mPriorSibling:引用同级中的前一个 Task。
|
|
|
|
|
mParent:引用父级 TaskList。
|
|
|
|
|
mCompleted = false;
|
|
|
|
|
mNotes = null;
|
|
|
|
|
mPriorSibling = null;
|
|
|
|
|
mParent = null;
|
|
|
|
|
mMetaInfo = null;
|
|
|
|
|
初始化实例变量:
|
|
|
|
|
将 mCompleted 设置为 false,表示任务未完成。
|
|
|
|
|
mNotes、mPriorSibling、mParent 和 mMetaInfo 初始化为 null。
|
|
|
|
|
try {
|
|
|
|
|
开始一个 try 块,以处理可能出现的 JSONException。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
|
|
|
|
|
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
|
|
|
|
|
向 JSON 对象中添加操作类型,表示这是一个创建操作
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
|
|
|
|
|
设置操作 ID,以便跟踪此操作。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
|
|
|
|
|
将当前任务在父任务列表中的索引添加到 JSON 对象中
|
|
|
|
|
JSONObject entity = new JSONObject();
|
|
|
|
|
创建一个新的 JSON 对象,用于存储与任务实体相关的信息。
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
|
|
|
|
|
GTaskStringUtils.GTASK_JSON_TYPE_TASK);
|
|
|
|
|
将任务名称、创建者 ID 和实体类型添加到实体 JSON 对象中。
|
|
|
|
|
if (getNotes() != null) {
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
|
|
|
|
|
}
|
|
|
|
|
如果任务有笔记,则将其添加到实体 JSON 对象中。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
|
|
|
|
|
将实体 JSON 对象添加到主 JSON 对象中。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());
|
|
|
|
|
添加父任务列表的 ID。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,
|
|
|
|
|
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
|
|
|
|
|
设置目标父级类型为组。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
|
|
|
|
|
添加任务列表的 ID。
|
|
|
|
|
if (mPriorSibling != null) {
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());
|
|
|
|
|
}
|
|
|
|
|
如果有前一个兄弟任务,将其 ID 添加到 JSON 对象中。
|
|
|
|
|
} catch (JSONException e) {
|
|
|
|
|
Log.e(TAG, e.toString());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
throw new ActionFailureException("fail to generate task-create jsonobject");
|
|
|
|
|
}
|
|
|
|
|
捕获 JSON 相关异常,记录错误并抛出一个 ActionFailureException。
|
|
|
|
|
return js;
|
|
|
|
|
返回构建的 JSON 对象,表示创建任务的操作。
|
|
|
|
|
public JSONObject getUpdateAction(int actionId) {
|
|
|
|
|
定义一个方法,用于生成一个 JSON 对象,描述更新任务的操作。
|
|
|
|
|
JSONObject js = new JSONObject();
|
|
|
|
|
创建新的 JSON 对象,用于存储任务的更新信息。
|
|
|
|
|
try {
|
|
|
|
|
开始一个 try 块以处理可能的异常。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
|
|
|
|
|
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
|
|
|
|
|
向 JSON 对象添加操作类型,表示这是一个更新操作。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
|
|
|
|
|
设置操作 ID。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
|
|
|
|
|
添加任务的 ID。
|
|
|
|
|
JSONObject entity = new JSONObject();
|
|
|
|
|
创建一个新的 JSON 对象,存储任务的实体更新信息。
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
|
|
|
|
|
将任务名称添加到实体 JSON 对象中。
|
|
|
|
|
if (getNotes() != null) {
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
|
|
|
|
|
}
|
|
|
|
|
如果有笔记,将其添加到实体 JSON 对象中。
|
|
|
|
|
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
|
|
|
|
|
将任务的删除状态添加到实体 JSON 对象中。
|
|
|
|
|
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
|
|
|
|
|
将实体 JSON 对象添加到主 JSON 对象中。
|
|
|
|
|
} catch (JSONException e) {
|
|
|
|
|
Log.e(TAG, e.toString());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
throw new ActionFailureException("fail to generate task-update jsonobject");
|
|
|
|
|
}
|
|
|
|
|
捕获 JSON 相关异常,记录错误并抛出一个 ActionFailureException。
|
|
|
|
|
return js;
|
|
|
|
|
返回构建的 JSON 对象,表示更新任务的操作。
|
|
|
|
|
方法:setContentByRemoteJSON
|
|
|
|
|
public void setContentByRemoteJSON(JSONObject js) {
|
|
|
|
|
定义一个方法,用于通过远程 JSON 对象设置任务内容。
|
|
|
|
|
if (js != null) {
|
|
|
|
|
检查传入的 JSON 对象是否为 null。
|
|
|
|
|
try {
|
|
|
|
|
开始一个 try 块以处理异常。
|
|
|
|
|
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
|
|
|
|
|
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
|
|
|
|
|
}
|
|
|
|
|
如果 JSON 对象中有任务 ID,则设置任务的 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));
|
|
|
|
|
}
|
|
|
|
|
如果 JSON 对象中有名称,设置任务名称。
|
|
|
|
|
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) {
|
|
|
|
|
Log.e(TAG, e.toString());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
throw new ActionFailureException("fail to get task content from jsonobject");
|
|
|
|
|
}
|
|
|
|
|
捕获 JSON 相关异常,记录错误并抛出一个 ActionFailureException。
|
|
|
|
|
方法:setContentByLocalJSON
|
|
|
|
|
public void setContentByLocalJSON(JSONObject js) {
|
|
|
|
|
定义一个方法,用于通过本地 JSON 对象设置任务内容。
|
|
|
|
|
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|
|
|
|
|
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
|
|
|
|
|
Log.w(TAG, "setContentByLocalJSON: nothing is available");
|
|
|
|
|
}
|
|
|
|
|
如果 JSON 对象为 null 或缺少 "note" 和 "data",记录警告。
|
|
|
|
|
try {
|
|
|
|
|
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
|
|
|
|
|
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
|
|
|
|
|
从 JSON 对象中提取 "note" 和 "data"。
|
|
|
|
|
if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {
|
|
|
|
|
Log.e(TAG, "invalid type");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
检查笔记类型是否有效,如果无效则记录错误并返回。
|
|
|
|
|
for (int i = 0; i < dataArray.length(); i++) {
|
|
|
|
|
JSONObject data = dataArray.getJSONObject(i);
|
|
|
|
|
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
|
|
|
|
|
setName(data.getString(DataColumns.CONTENT));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
遍历数据数组,获取 MIME 类型为 "note" 的数据,设置任务名称。
|
|
|
|
|
} catch (JSONException e) {
|
|
|
|
|
Log.e(TAG, e.toString());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
捕获 JSON 相关异常,记录错误信息。
|
|
|
|
|
方法:getLocalJSONFromContent
|
|
|
|
|
public JSONObject getLocalJSONFromContent() {
|
|
|
|
|
定义一个方法,用于生成描述任务内容的本地 JSON 对象。
|
|
|
|
|
String name = getName();
|
|
|
|
|
获取任务名称。
|
|
|
|
|
try {
|
|
|
|
|
if (mMetaInfo == null) {
|
|
|
|
|
开始一个 try 块,并检查元信息是否为 null。
|
|
|
|
|
if (name == null) {
|
|
|
|
|
Log.w(TAG, "the note seems to be an empty one");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
如果任务名称为空,记录警告并返回 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);
|
|
|
|
|
return js;
|
|
|
|
|
创建一个新的 JSON 对象,构建笔记信息并返回。
|
|
|
|
|
} else {
|
|
|
|
|
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
|
|
|
|
|
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
|
|
|
|
|
否则,从元信息中提取笔记和数据数组。
|
|
|
|
|
for (int i = 0; i < dataArray.length(); i++) {
|
|
|
|
|
JSONObject data = dataArray.getJSONObject(i);
|
|
|
|
|
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
|
|
|
|
|
data.put(DataColumns.CONTENT, getName());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
遍历数据数组,找到 MIME 类型为 "note" 的数据,并更新其内容为任务名称。
|
|
|
|
|
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
|
|
|
|
|
return mMetaInfo;
|
|
|
|
|
设置笔记类型并返回元信息的 JSON 对象。
|
|
|
|
|
} catch (JSONException e) {
|
|
|
|
|
Log.e(TAG, e.toString());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
捕获 JSON 相关异常,记录错误并返回
|
|
|
|
|
public abstract class NoteWidgetProvider extends AppWidgetProvider {
|
|
|
|
|
声明一个名为 NoteWidgetProvider 的抽象类。它继承自 AppWidgetProvider,用于实现 Android 小部件功能的基础类。由于是抽象类,意味着它可以包含未实现的方法,这些方法将在子类中定义。
|
|
|
|
|
public static final String [] PROJECTION = new String [] {
|
|
|
|
|
NoteColumns.ID,
|
|
|
|
|
NoteColumns.BG_COLOR_ID,
|
|
|
|
|
NoteColumns.SNIPPET
|
|
|
|
|
};
|
|
|
|
|
定义一个字符串数组 PROJECTION,包含 SQL 查询时需要的列名。这些列来自 NoteColumns 类,包括笔记的 ID、背景颜色 ID 和内容片段。
|
|
|
|
|
public static final int COLUMN_ID = 0;
|
|
|
|
|
public static final int COLUMN_BG_COLOR_ID = 1;
|
|
|
|
|
public static final int COLUMN_SNIPPET = 2;
|
|
|
|
|
定义常量,用于表示查询结果中列的索引。COLUMN_ID对应第一列(ID),COLUMN_BG_COLOR_ID对应第二列(背景颜色),COLUMN_SNIPPET对应第三列(内容片段)。
|
|
|
|
|
private static final String TAG = "NoteWidgetProvider";
|
|
|
|
|
定义一个用于日志记录的常量 TAG,其值为类名 "NoteWidgetProvider"。在日志中使用此标签时可以明确指出日志来自该类。
|
|
|
|
|
@Override
|
|
|
|
|
public void onDeleted(Context context, int[] appWidgetIds) {
|
|
|
|
|
重写 AppWidgetProvider 类的 onDeleted 方法。该方法在小部件被删除时调用,提供上下文信息和小部件 ID 数组。
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
创建一个 ContentValues 对象 values,用于存储要更新的数据库字段及其值。
|
|
|
|
|
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
|
|
|
|
|
向 values 对象中添加一对键值对,设置 WIDGET_ID 字段的值为无效小部件 ID。这表示当前小部件的 ID 已无效,将在数据库中进行相应更新。
|
|
|
|
|
for (int i = 0; i < appWidgetIds.length; i++) {
|
|
|
|
|
使用 for 循环遍历 appWidgetIds 数组中的每个小部件 ID。
|
|
|
|
|
context.getContentResolver().update(Notes.CONTENT_NOTE_URI,
|
|
|
|
|
values,
|
|
|
|
|
NoteColumns.WIDGET_ID + "=?",
|
|
|
|
|
new String[] { String.valueOf(appWidgetIds[i])});
|
|
|
|
|
使用 ContentResolver 更新 Notes.CONTENT_NOTE_URI(笔记内容 URI)的记录,将小部件 ID 更新为无效值。查询条件是 WIDGET_ID 等于当前 ID。
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
结束 for 循环和 onDeleted 方法的定义。
|
|
|
|
|
private Cursor getNoteWidgetInfo(Context context, int widgetId) {
|
|
|
|
|
定义一个私有方法 getNoteWidgetInfo,接收上下文和小部件 ID 作为参数。该方法返回与指定小部件 ID 相关的数据库游标。
|
|
|
|
|
return context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
|
|
|
|
|
PROJECTION,
|
|
|
|
|
NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?",
|
|
|
|
|
new String[] { String.valueOf(widgetId), String.valueOf(Notes.ID_TRASH_FOLER) },
|
|
|
|
|
null);
|
|
|
|
|
} 使用 ContentResolver 查询 Notes.CONTENT_NOTE_URI,返回与指定 widgetId 相关的笔记信息。PROJECTION 指定需要的列,查询条件是 WIDGET_ID 匹配传入的小部件 ID,并且 PARENT_ID 不等于回收站 ID。
|
|
|
|
|
protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
|
|
|
|
定义一个受保护的方法 update,用于更新指定的小部件。该方法接受上下文、小部件管理器和小部件 ID 数组作为参数。
|
|
|
|
|
update(context, appWidgetManager, appWidgetIds, false);
|
|
|
|
|
}
|
|
|
|
|
调用私有方法 update 的另一个重载版本,将隐私模式参数设置为 false,以进行更新操作。
|
|
|
|
|
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, boolean privacyMode) {
|
|
|
|
|
定义一个私有方法,重载 update 方法,接收上下文、小部件管理器、小部件 ID 数组和隐私模式作为参数。
|
|
|
|
|
for (int i = 0; i < appWidgetIds.length; i++) {
|
|
|
|
|
使用 for 循环遍历小部件 ID 数组。
|
|
|
|
|
if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) {
|
|
|
|
|
检查当前小部件 ID 是否有效(不等于无效小部件 ID)。
|
|
|
|
|
int bgId = ResourceParser.getDefaultBgId(context);
|