付佳代码精读

master
Jia 12 months ago
parent c607dfa504
commit 653753a7bd

@ -26,57 +26,109 @@ import org.json.JSONObject;
public class MetaData extends Task {
// 常量标签,用于日志输出,值为当前类的简单名称
private final static String TAG = MetaData.class.getSimpleName();
// 相关GID的字符串变量初始化为null
private String mRelatedGid = null;
/**
*
*
* @param gid GID
* @param metaInfo JSONObject
*/
public void setMeta(String gid, JSONObject metaInfo) {
try {
// 将GID放入metaInfo中键为GTaskStringUtils.META_HEAD_GTASK_ID
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
} catch (JSONException e) {
// 如果放入GID失败输出错误日志
Log.e(TAG, "failed to put related gid");
}
// 将metaInfo转换为字符串并设置为便签的备注
setNotes(metaInfo.toString());
// 设置便签的名称为预定义的元数据名称
setName(GTaskStringUtils.META_NOTE_NAME);
}
/**
* GID
*
* @return GIDnull
*/
public String getRelatedGid() {
return mRelatedGid;
}
/**
* 便
*
* @return 便truefalse
*/
@Override
public boolean isWorthSaving() {
return getNotes() != null;
}
/**
* JSON便
*
* @param js 便JSONObject
*/
@Override
public void setContentByRemoteJSON(JSONObject js) {
// 调用父类的方法处理JSON对象
super.setContentByRemoteJSON(js);
// 如果便签有备注
if (getNotes() != null) {
try {
// 将备注转换为JSONObject对象
JSONObject metaInfo = new JSONObject(getNotes().trim());
// 从metaInfo中获取相关GID
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
} catch (JSONException e) {
// 如果获取GID失败输出警告日志并将相关GID设置为null
Log.w(TAG, "failed to get related gid");
mRelatedGid = null;
}
}
}
/**
* JSON便
*
* @param js 便JSONObject
* @throws IllegalAccessError
*/
@Override
public void setContentByLocalJSON(JSONObject js) {
// this function should not be called
// 抛出错误,因为此方法不应被调用
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
}
/**
* 便JSON
*
* @return
* @throws IllegalAccessError
*/
@Override
public JSONObject getLocalJSONFromContent() {
// 抛出错误,因为此方法不应被调用
throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");
}
/**
*
*
* @param c
* @return
* @throws IllegalAccessError
*/
@Override
public int getSyncAction(Cursor c) {
// 抛出错误,因为此方法不应被调用
throw new IllegalAccessError("MetaData:getSyncAction should not be called");
}
}

@ -21,79 +21,108 @@ import android.database.Cursor;
import org.json.JSONObject;
public abstract class Node {
public static final int SYNC_ACTION_NONE = 0;
public static final int SYNC_ACTION_ADD_REMOTE = 1;
public static final int SYNC_ACTION_ADD_LOCAL = 2;
public static final int SYNC_ACTION_DEL_REMOTE = 3;
public static final int SYNC_ACTION_DEL_LOCAL = 4;
public static final int SYNC_ACTION_UPDATE_REMOTE = 5;
public static final int SYNC_ACTION_UPDATE_LOCAL = 6;
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;
public static final int SYNC_ACTION_ERROR = 8;
// 同步动作的常量定义,表示不同的同步操作
public static final int SYNC_ACTION_NONE = 0; // 无同步动作
public static final int SYNC_ACTION_ADD_REMOTE = 1; // 远程添加
public static final int SYNC_ACTION_ADD_LOCAL = 2; // 本地添加
public static final int SYNC_ACTION_DEL_REMOTE = 3; // 远程删除
public static final int SYNC_ACTION_DEL_LOCAL = 4; // 本地删除
public static final int SYNC_ACTION_UPDATE_REMOTE = 5; // 远程更新
public static final int SYNC_ACTION_UPDATE_LOCAL = 6; // 本地更新
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; // 更新冲突
public static final int SYNC_ACTION_ERROR = 8; // 同步错误
// 节点的GID全局唯一标识符
private String mGid;
// 节点的名称
private String mName;
// 节点的最后修改时间
private long mLastModified;
// 节点是否被删除的标记
private boolean mDeleted;
// 构造方法,初始化节点的属性
public Node() {
mGid = null;
mName = "";
mLastModified = 0;
mDeleted = false;
mGid = null; // GID初始化为null
mName = ""; // 名称初始化为空字符串
mLastModified = 0; // 最后修改时间初始化为0
mDeleted = false; // 删除标记初始化为false
}
// 抽象方法获取创建动作的JSON对象
// @param actionId 同步动作的ID
// @return 包含创建动作的JSON对象
public abstract JSONObject getCreateAction(int actionId);
// 抽象方法获取更新动作的JSON对象
// @param actionId 同步动作的ID
// @return 包含更新动作的JSON对象
public abstract JSONObject getUpdateAction(int actionId);
// 抽象方法通过远程JSON对象设置节点内容
// @param js 包含节点内容的JSON对象
public abstract void setContentByRemoteJSON(JSONObject js);
// 抽象方法通过本地JSON对象设置节点内容
// @param js 包含节点内容的JSON对象
public abstract void setContentByLocalJSON(JSONObject js);
// 抽象方法从节点内容获取本地JSON对象
// @return 包含节点内容的本地JSON对象
public abstract JSONObject getLocalJSONFromContent();
// 抽象方法,获取同步动作
// @param c 数据库游标,用于获取节点的同步状态
// @return 同步动作的ID
public abstract int getSyncAction(Cursor c);
// 设置节点的GID
// @param gid 要设置的GID
public void setGid(String gid) {
this.mGid = gid;
}
// 设置节点的名称
// @param name 要设置的名称
public void setName(String name) {
this.mName = name;
}
// 设置节点的最后修改时间
// @param lastModified 要设置的最后修改时间
public void setLastModified(long lastModified) {
this.mLastModified = lastModified;
}
// 设置节点的删除标记
// @param deleted 要设置的删除标记
public void setDeleted(boolean deleted) {
this.mDeleted = deleted;
}
// 获取节点的GID
// @return 节点的GID
public String getGid() {
return this.mGid;
}
// 获取节点的名称
// @return 节点的名称
public String getName() {
return this.mName;
}
// 获取节点的最后修改时间
// @return 节点的最后修改时间
public long getLastModified() {
return this.mLastModified;
}
// 获取节点的删除标记
// @return 节点的删除标记
public boolean getDeleted() {
return this.mDeleted;
}

@ -31,41 +31,44 @@ import java.util.ArrayList;
public class TaskList extends Node {
private static final String TAG = TaskList.class.getSimpleName();
private static final String TAG = TaskList.class.getSimpleName(); // 获取当前类的简单名称作为日志标签
private int mIndex;
private int mIndex; // 任务列表的索引
private ArrayList<Task> mChildren;
private ArrayList<Task> mChildren; // 存储子任务的列表
// 构造方法,初始化任务列表和索引
public TaskList() {
super();
mChildren = new ArrayList<Task>();
mIndex = 1;
}
// 生成创建任务的JSON对象
public JSONObject getCreateAction(int actionId) {
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);
// index
// 设置索引
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex);
// entity_delta
// 设置实体变化信息
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务列表名称
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); // 创建者ID这里为空
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
GTaskStringUtils.GTASK_JSON_TYPE_GROUP); // 实体类型为组
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 tasklist-create jsonobject");
@ -74,27 +77,29 @@ public class TaskList extends Node {
return js;
}
// 生成更新任务的JSON对象
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// action_type
// 设置动作类型为更新
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
// action_id
// 设置动作ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// id
// 设置任务列表ID
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// entity_delta
// 设置实体变化信息
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
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) {
// 捕获JSON异常打印错误日志并抛出自定义异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate tasklist-update jsonobject");
@ -103,25 +108,27 @@ public class TaskList extends Node {
return js;
}
// 根据远程JSON对象设置任务列表内容
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
// id
// 设置任务列表ID
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_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));
}
} catch (JSONException e) {
// 捕获JSON异常打印错误日志并抛出自定义异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to get tasklist content from jsonobject");
@ -129,14 +136,16 @@ public class TaskList extends Node {
}
}
// 根据本地JSON对象设置任务列表内容
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); // 本地JSON对象无效或没有头部信息
}
try {
JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
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);
@ -147,16 +156,18 @@ public class TaskList extends Node {
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE);
else
Log.e(TAG, "invalid system folder");
Log.e(TAG, "invalid system folder"); // 无效的系统文件夹
} else {
Log.e(TAG, "error type");
Log.e(TAG, "error type"); // 错误的文件夹类型
}
} catch (JSONException e) {
// 捕获JSON异常打印错误日志
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
// 获取任务列表的本地JSON对象
public JSONObject getLocalJSONFromContent() {
try {
JSONObject js = new JSONObject();
@ -167,6 +178,7 @@ public class TaskList extends Node {
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))
folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
@ -177,38 +189,41 @@ public class TaskList extends Node {
return js;
} catch (JSONException e) {
// 捕获JSON异常打印错误日志并返回null
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()) {
// no update both side
// 远程和本地都没有更新
return SYNC_ACTION_NONE;
} else {
// apply remote to local
// 应用远程更新到本地
return SYNC_ACTION_UPDATE_LOCAL;
}
} else {
// validate gtask id
// 验证任务列表ID
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
Log.e(TAG, "gtask id doesn't match");
Log.e(TAG, "gtask id doesn't match"); // 任务列表ID不匹配
return SYNC_ACTION_ERROR;
}
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// 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();
}
@ -216,10 +231,13 @@ public class TaskList extends Node {
return SYNC_ACTION_ERROR;
}
// 获取子任务数量
public int getChildTaskCount() {
return mChildren.size();
}
// 添加子任务
public boolean addChildTask(Task task) {
boolean ret = false;
if (task != null && !mChildren.contains(task)) {

@ -15,7 +15,7 @@
*/
package net.micode.notes.gtask.exception;
//行为失败后抛出异常
public class ActionFailureException extends RuntimeException {
private static final long serialVersionUID = 4425249765923293627L;

@ -15,7 +15,7 @@
*/
package net.micode.notes.gtask.exception;
//网络连接失败后抛出异常
public class NetworkFailureException extends Exception {
private static final long serialVersionUID = 2107610287180234136L;

@ -23,29 +23,42 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
// 定义一个服务类用于处理Google任务的同步
public class GTaskSyncService extends Service {
// 定义一个字符串常量,表示同步操作的类型
public final static String ACTION_STRING_NAME = "sync_action_type";
// 定义常量,表示开始同步的操作
public final static int ACTION_START_SYNC = 0;
// 定义常量,表示取消同步的操作
public final static int ACTION_CANCEL_SYNC = 1;
// 定义常量,表示无效的操作
public final static int ACTION_INVALID = 2;
// 定义一个广播的名称,用于通知同步状态的变化
public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service";
// 定义广播的附加数据键,表示是否正在同步
public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing";
// 定义广播的附加数据键,表示同步的进度信息
public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg";
// 定义一个异步任务,用于执行同步操作
private static GTaskASyncTask mSyncTask = null;
// 定义一个字符串,用于保存同步的进度信息
private static String mSyncProgress = "";
// 开始同步的方法
private void startSync() {
// 如果当前没有正在执行的同步任务,则创建一个新的异步任务开始同步
if (mSyncTask == null) {
mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() {
public void onComplete() {
// 同步完成后将异步任务设置为null发送一个空消息的广播并停止服务
mSyncTask = null;
sendBroadcast("");
stopSelf();
@ -56,21 +69,27 @@ public class GTaskSyncService extends Service {
}
}
// 取消同步的方法
private void cancelSync() {
// 如果当前有正在执行的同步任务,则取消它
if (mSyncTask != null) {
mSyncTask.cancelSync();
}
}
// 服务创建时调用的方法
@Override
public void onCreate() {
mSyncTask = null;
}
// 服务启动时调用的方法
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 从启动服务的Intent中获取附加数据
Bundle bundle = intent.getExtras();
if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) {
// 根据附加数据中的操作类型,执行相应的操作
switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) {
case ACTION_START_SYNC:
startSync();
@ -81,22 +100,26 @@ public class GTaskSyncService extends Service {
default:
break;
}
return START_STICKY;
return START_STICKY; // 服务被杀死后,系统会尝试重新创建并启动服务
}
return super.onStartCommand(intent, flags, startId);
}
// 系统内存不足时调用的方法
@Override
public void onLowMemory() {
// 如果当前有正在执行的同步任务,则取消它
if (mSyncTask != null) {
mSyncTask.cancelSync();
}
}
// 服务绑定时调用的方法此处直接返回null表示不支持绑定
public IBinder onBind(Intent intent) {
return null;
}
// 发送广播的方法,通知同步状态的变化
public void sendBroadcast(String msg) {
mSyncProgress = msg;
Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME);
@ -105,6 +128,7 @@ public class GTaskSyncService extends Service {
sendBroadcast(intent);
}
// 静态方法用于从Activity中启动同步服务
public static void startSync(Activity activity) {
GTaskManager.getInstance().setActivityContext(activity);
Intent intent = new Intent(activity, GTaskSyncService.class);
@ -112,16 +136,19 @@ public class GTaskSyncService extends Service {
activity.startService(intent);
}
// 静态方法,用于取消同步服务
public static void cancelSync(Context context) {
Intent intent = new Intent(context, GTaskSyncService.class);
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC);
context.startService(intent);
}
// 静态方法,用于判断当前是否有正在执行的同步任务
public static boolean isSyncing() {
return mSyncTask != null;
}
// 静态方法,用于获取同步的进度信息
public static String getProgressString() {
return mSyncProgress;
}

@ -15,6 +15,7 @@
*/
package net.micode.notes.model;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris;
@ -33,16 +34,19 @@ import net.micode.notes.data.Notes.TextNote;
import java.util.ArrayList;
public class Note {
private ContentValues mNoteDiffValues;
private NoteData mNoteData;
private static final String TAG = "Note";
private ContentValues mNoteDiffValues; // 用于存储笔记的差异值
private NoteData mNoteData; // 笔记数据对象
private static final String TAG = "Note"; // 日志标签
/**
* Create a new note id for adding a new note to databases
* ID
* @param context
* @param folderId ID
* @return ID
*/
public static synchronized long getNewNoteId(Context context, long folderId) {
// Create a new note in the database
// 在数据库中创建一个新笔记
ContentValues values = new ContentValues();
long createdTime = System.currentTimeMillis();
values.put(NoteColumns.CREATED_DATE, createdTime);
@ -56,72 +60,109 @@ public class Note {
try {
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
Log.e(TAG, "获取笔记ID出错:" + e.toString());
noteId = 0;
}
if (noteId == -1) {
throw new IllegalStateException("Wrong note id:" + noteId);
throw new IllegalStateException("错误的笔记ID:" + noteId);
}
return noteId;
}
/**
*
*/
public Note() {
mNoteDiffValues = new ContentValues();
mNoteData = new NoteData();
}
/**
*
* @param key
* @param value
*/
public void setNoteValue(String key, String value) {
mNoteDiffValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
*
* @param key
* @param value
*/
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);
}
/**
* ID
* @param id ID
*/
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}
/**
* ID
* @return ID
*/
public long getTextDataId() {
return mNoteData.mTextDataId;
}
/**
* ID
* @param id ID
*/
public void setCallDataId(long id) {
mNoteData.setCallDataId(id);
}
/**
*
* @param key
* @param value
*/
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}
/**
*
* @return truefalse
*/
public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
/**
*
* @param context
* @param noteId ID
* @return truefalse
*/
public boolean syncNote(Context context, long noteId) {
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
throw new IllegalArgumentException("错误的笔记ID:" + noteId);
}
if (!isLocalModified()) {
return true;
}
/**
* In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and
* {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the
* note data info
*/
// 更新笔记的修改状态和修改时间
if (context.getContentResolver().update(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
null) == 0) {
Log.e(TAG, "Update note error, should not happen");
// Do not return, fall through
Log.e(TAG, "更新笔记出错,不应发生");
// 不要返回,继续执行
}
mNoteDiffValues.clear();
// 如果笔记数据被修改且推送到ContentResolver失败则返回false
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
return false;
@ -130,17 +171,19 @@ public class Note {
return true;
}
/**
*
*/
private class NoteData {
private long mTextDataId;
private ContentValues mTextDataValues;
private long mCallDataId;
private ContentValues mCallDataValues;
private static final String TAG = "NoteData";
private long mTextDataId; // 文本数据ID
private ContentValues mTextDataValues; // 文本数据值
private long mCallDataId; // 通话数据ID
private ContentValues mCallDataValues; // 通话数据值
private static final String TAG = "NoteData"; // 日志标签
/**
*
*/
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
@ -148,36 +191,64 @@ public class Note {
mCallDataId = 0;
}
/**
*
* @return truefalse
*/
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
/**
* ID
* @param id ID
*/
void setTextDataId(long id) {
if(id <= 0) {
throw new IllegalArgumentException("Text data id should larger than 0");
throw new IllegalArgumentException("文本数据ID应大于0");
}
mTextDataId = id;
}
/**
* ID
* @param id ID
*/
void setCallDataId(long id) {
if (id <= 0) {
throw new IllegalArgumentException("Call data id should larger than 0");
throw new IllegalArgumentException("通话数据ID应大于0");
}
mCallDataId = id;
}
/**
*
* @param key
* @param value
*/
void setCallData(String key, String value) {
mCallDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
*
* @param key
* @param value
*/
void setTextData(String key, String value) {
mTextDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
* ContentResolver
* @param context
* @param noteId ID
* @return Urinull
*/
Uri pushIntoContentResolver(Context context, long noteId) {
/**
* Check for safety

@ -33,35 +33,36 @@ import net.micode.notes.tool.ResourceParser.NoteBgResources;
public class WorkingNote {
// Note for the working note
// 便签的Note对象
private Note mNote;
// Note Id
// 便签的ID
private long mNoteId;
// Note content
// 便签的内容
private String mContent;
// Note mode
// 便签的模式(可能是检查列表模式等)
private int mMode;
private long mAlertDate;
private long mAlertDate; // 提醒日期
private long mModifiedDate;
private long mModifiedDate; // 修改日期
private int mBgColorId;
private int mBgColorId; // 背景颜色ID
private int mWidgetId;
private int mWidgetId; // 小部件ID
private int mWidgetType;
private int mWidgetType; // 小部件类型
private long mFolderId;
private long mFolderId; // 文件夹ID
private Context mContext;
private Context mContext; // 上下文对象
private static final String TAG = "WorkingNote";
private static final String TAG = "WorkingNote"; // 日志标签
private boolean mIsDeleted;
private boolean mIsDeleted; // 是否已删除
private NoteSettingChangedListener mNoteSettingStatusListener;
private NoteSettingChangedListener mNoteSettingStatusListener; // 便签设置状态监听器
// 数据列的投影,用于数据库查询
public static final String[] DATA_PROJECTION = new String[] {
DataColumns.ID,
DataColumns.CONTENT,
@ -72,6 +73,7 @@ public class WorkingNote {
DataColumns.DATA4,
};
// 便签列的投影,用于数据库查询
public static final String[] NOTE_PROJECTION = new String[] {
NoteColumns.PARENT_ID,
NoteColumns.ALERTED_DATE,
@ -81,27 +83,21 @@ public class WorkingNote {
NoteColumns.MODIFIED_DATE
};
// 数据列在投影中的索引
private static final int DATA_ID_COLUMN = 0;
private static final int DATA_CONTENT_COLUMN = 1;
private static final int DATA_MIME_TYPE_COLUMN = 2;
private static final int DATA_MODE_COLUMN = 3;
// 便签列在投影中的索引
private static final int NOTE_PARENT_ID_COLUMN = 0;
private static final int NOTE_ALERTED_DATE_COLUMN = 1;
private static final int NOTE_BG_COLOR_ID_COLUMN = 2;
private static final int NOTE_WIDGET_ID_COLUMN = 3;
private static final int NOTE_WIDGET_TYPE_COLUMN = 4;
private static final int NOTE_MODIFIED_DATE_COLUMN = 5;
// New note construct
// 新建便签的构造函数
private WorkingNote(Context context, long folderId) {
mContext = context;
mAlertDate = 0;
@ -111,19 +107,20 @@ public class WorkingNote {
mNoteId = 0;
mIsDeleted = false;
mMode = 0;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE; // 无效的小部件类型
}
// Existing note construct
// 现有便签的构造函数
private WorkingNote(Context context, long noteId, long folderId) {
mContext = context;
mNoteId = noteId;
mFolderId = folderId;
mIsDeleted = false;
mNote = new Note();
loadNote();
loadNote(); // 加载便签数据
}
// 从数据库中加载便签数据
private void loadNote() {
Cursor cursor = mContext.getContentResolver().query(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
@ -143,13 +140,14 @@ public class WorkingNote {
Log.e(TAG, "No note with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note with id " + mNoteId);
}
loadNoteData();
loadNoteData(); // 加载便签的具体内容
}
// 从数据库中加载便签的具体内容
private void loadNoteData() {
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] {
String.valueOf(mNoteId)
String.valueOf(mNoteId)
}, null);
if (cursor != null) {
@ -174,8 +172,9 @@ public class WorkingNote {
}
}
// 创建一个空的便签
public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
int widgetType, int defaultBgColorId) {
int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId);
note.setBgColorId(defaultBgColorId);
note.setWidgetId(widgetId);
@ -183,10 +182,12 @@ public class WorkingNote {
return note;
}
// 加载一个已存在的便签
public static WorkingNote load(Context context, long id) {
return new WorkingNote(context, id, 0);
}
// 保存便签
public synchronized boolean saveNote() {
if (isWorthSaving()) {
if (!existInDatabase()) {
@ -198,9 +199,7 @@ public class WorkingNote {
mNote.syncNote(mContext, mNoteId);
/**
* Update widget content if there exist any widget of this note
*/
// 如果存在与此便签相关的小部件,则更新小部件内容
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE
&& mNoteSettingStatusListener != null) {
@ -212,10 +211,12 @@ public class WorkingNote {
}
}
// 检查便签是否存在于数据库中
public boolean existInDatabase() {
return mNoteId > 0;
}
// 检查便签是否值得保存
private boolean isWorthSaving() {
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) {
@ -225,10 +226,12 @@ public class WorkingNote {
}
}
// 设置便签设置状态监听器
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l;
}
// 设置提醒日期
public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) {
mAlertDate = date;
@ -238,6 +241,7 @@ public class WorkingNote {
mNoteSettingStatusListener.onClockAlertChanged(date, set);
}
}
// 标记便签为已删除或未删除
public void markDeleted(boolean mark) {
mIsDeleted = mark;

@ -36,123 +36,208 @@ import java.util.HashSet;
public class DataUtils {
// 常量标签,用于日志输出
public static final String TAG = "DataUtils";
/**
*
*
* @param resolver 访
* @param ids ID
* @return truefalse
*/
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
// 如果ID集合为空则直接返回true表示删除成功实际未进行删除操作
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
}
// 如果ID集合大小为0也直接返回true
if (ids.size() == 0) {
Log.d(TAG, "no id is in the hashset");
return true;
}
// 创建一个内容提供者操作列表
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// 遍历ID集合构建删除操作
for (long id : ids) {
// 如果是系统根文件夹,则跳过删除操作,并输出错误日志
if(id == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Don't delete system folder root");
continue;
}
// 构建删除操作,并添加到操作列表
ContentProviderOperation.Builder builder = ContentProviderOperation
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
operationList.add(builder.build());
}
try {
// 批量执行操作,并获取结果
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
// 如果结果为空或长度为0或第一个结果为空则认为删除失败
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
}
// 删除成功
return true;
} catch (RemoteException e) {
// 捕获远程异常,并输出错误日志
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
// 捕获操作应用异常,并输出错误日志
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
// 发生异常返回false
return false;
}
/**
*
*
* @param resolver 访
* @param id ID
* @param srcFolderId ID
* @param desFolderId ID
*/
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
// 创建内容值对象,用于存储要更新的字段及其新值
ContentValues values = new ContentValues();
// 设置目标文件夹ID
values.put(NoteColumns.PARENT_ID, desFolderId);
// 设置源文件夹ID
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
// 设置本地修改标志为1
values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记信息
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
}
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
long folderId) {
/**
*
*
* @param resolver 访
* @param ids ID
* @param folderId ID
* @return truefalse
*/
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids, long folderId) {
// 如果ID集合为空则直接返回true表示移动成功实际未进行移动操作
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
}
// 创建一个内容提供者操作列表
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// 遍历ID集合构建更新操作
for (long id : ids) {
ContentProviderOperation.Builder builder = ContentProviderOperation
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
// 设置目标文件夹ID
builder.withValue(NoteColumns.PARENT_ID, folderId);
// 设置本地修改标志为1
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
// 将构建的操作添加到操作列表
operationList.add(builder.build());
}
try {
// 批量执行操作,并获取结果
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
// 如果结果为空或长度为0或第一个结果为空则认为移动失败
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
}
// 移动成功
return true;
} catch (RemoteException e) {
// 捕获远程异常,并输出错误日志
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
// 捕获操作应用异常,并输出错误日志
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
// 发生异常返回false
return false;
}
/**
* Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}}
*
*
* @param resolver 访
* @return
*/
public static int getUserFolderCount(ContentResolver resolver) {
Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI,
// 查询非系统文件夹且非垃圾文件夹的数量
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { "COUNT(*)" },
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
null);
int count = 0;
if(cursor != null) {
if(cursor.moveToFirst()) {
// 如果游标不为空
if (cursor != null) {
// 移动到结果集的第一条记录
if (cursor.moveToFirst()) {
try {
// 获取文件夹数量
count = cursor.getInt(0);
} catch (IndexOutOfBoundsException e) {
// 捕获索引越界异常,并输出错误日志
Log.e(TAG, "get folder count failed:" + e.toString());
} finally {
// 关闭游标
cursor.close();
}
}
}
// 返回文件夹数量
return count;
}
/**
*
*
* @param resolver 访
* @param noteId ID
* @param type
* @return truefalse
*/
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
// 查询指定ID和类型的笔记且不在垃圾文件夹中
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null,
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
new String [] {String.valueOf(type)},
new String[] { String.valueOf(type) },
null);
boolean exist = false;
// 如果游标不为空
if (cursor != null) {
// 如果查询结果的数量大于0则表示笔记存在
if (cursor.getCount() > 0) {
exist = true;
}
// 关闭游标
cursor.close();
}
// 返回笔记是否存在
return exist;
}
/**
*
*
* @param resolver 访
* @param noteId ID
* @return truefalse
*/
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null, null, null);

@ -32,23 +32,31 @@ import net.micode.notes.tool.ResourceParser;
import net.micode.notes.ui.NoteEditActivity;
import net.micode.notes.ui.NotesListActivity;
// 这是一个抽象类,用于提供笔记小部件的功能
public abstract class NoteWidgetProvider extends AppWidgetProvider {
// 定义查询数据库时需要获取的列
public static final String [] PROJECTION = new String [] {
NoteColumns.ID,
NoteColumns.BG_COLOR_ID,
NoteColumns.SNIPPET
NoteColumns.ID, // 笔记ID
NoteColumns.BG_COLOR_ID, // 笔记背景颜色ID
NoteColumns.SNIPPET // 笔记摘要
};
// 定义列索引常量,方便后续通过索引获取数据
public static final int COLUMN_ID = 0;
public static final int COLUMN_BG_COLOR_ID = 1;
public static final int COLUMN_SNIPPET = 2;
// 定义日志标签
private static final String TAG = "NoteWidgetProvider";
// 当小部件被删除时调用此方法
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
// 创建一个ContentValues对象用于更新数据库中的数据
ContentValues values = new ContentValues();
// 将小部件ID设置为无效ID
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
// 遍历所有被删除的小部件ID并更新数据库中对应的数据
for (int i = 0; i < appWidgetIds.length; i++) {
context.getContentResolver().update(Notes.CONTENT_NOTE_URI,
values,
@ -57,7 +65,9 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
}
}
// 私有方法用于获取指定小部件ID的笔记信息
private Cursor getNoteWidgetInfo(Context context, int widgetId) {
// 查询数据库获取指定小部件ID且不在垃圾箱中的笔记信息
return context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?",
@ -65,47 +75,61 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
null);
}
// 保护方法,用于更新小部件,不开启隐私模式
protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
update(context, appWidgetManager, appWidgetIds, false);
}
// 私有方法,用于更新小部件,可选择是否开启隐私模式
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds,
boolean privacyMode) {
boolean privacyMode) {
// 遍历所有需要更新的小部件ID
for (int i = 0; i < appWidgetIds.length; i++) {
// 如果小部件ID有效
if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) {
// 初始化背景颜色ID和摘要
int bgId = ResourceParser.getDefaultBgId(context);
String snippet = "";
// 创建一个指向NoteEditActivity的Intent用于点击小部件时跳转
Intent intent = new Intent(context, NoteEditActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType());
// 获取指定小部件ID的笔记信息
Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]);
// 如果获取到笔记信息
if (c != null && c.moveToFirst()) {
// 如果有多条笔记信息使用相同的小部件ID记录错误日志并返回
if (c.getCount() > 1) {
Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]);
c.close();
return;
}
// 获取摘要和背景颜色ID并设置到Intent中
snippet = c.getString(COLUMN_SNIPPET);
bgId = c.getInt(COLUMN_BG_COLOR_ID);
intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID));
intent.setAction(Intent.ACTION_VIEW);
} else {
// 如果没有获取到笔记信息设置默认摘要并设置Intent动作为插入或编辑
snippet = context.getResources().getString(R.string.widget_havenot_content);
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
}
// 关闭Cursor
if (c != null) {
c.close();
}
// 创建一个RemoteViews对象用于设置小部件的UI
RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId());
// 设置背景图片
rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId));
// 将背景颜色ID设置到Intent中
intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId);
/**
* Generate the pending intent to start host for the widget
*/
// 根据是否开启隐私模式,设置不同的文本和点击行为
PendingIntent pendingIntent = null;
if (privacyMode) {
rv.setTextViewText(R.id.widget_text,
@ -118,15 +142,20 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
PendingIntent.FLAG_UPDATE_CURRENT);
}
// 设置小部件的点击行为
rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent);
// 更新小部件的UI
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
}
}
// 抽象方法由子类实现用于获取背景资源ID
protected abstract int getBgResourceId(int bgId);
// 抽象方法由子类实现用于获取布局ID
protected abstract int getLayoutId();
// 抽象方法,由子类实现,用于获取小部件类型
protected abstract int getWidgetType();
}

@ -24,24 +24,34 @@ import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser;
// 这是一个名为NoteWidgetProvider_2x的类它继承自NoteWidgetProvider类
public class NoteWidgetProvider_2x extends NoteWidgetProvider {
// 重写父类的onUpdate方法用于更新小部件
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// 调用父类的update方法来进行实际的更新操作传递上下文、小部件管理器和小部件ID数组
super.update(context, appWidgetManager, appWidgetIds);
}
// 重写父类的getLayoutId方法用于获取小部件的布局ID
@Override
protected int getLayoutId() {
// 返回widget_2x布局资源的ID
return R.layout.widget_2x;
}
// 重写父类的getBgResourceId方法用于根据背景ID获取对应的资源ID
@Override
protected int getBgResourceId(int bgId) {
// 使用ResourceParser.WidgetBgResources的getWidget2xBgResource方法根据传入的背景ID获取对应的2x小部件背景资源ID
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);
}
// 重写父类的getWidgetType方法用于获取小部件的类型
@Override
protected int getWidgetType() {
// 返回表示2x类型小部件的常量值
return Notes.TYPE_WIDGET_2X;
}
}
}
Loading…
Cancel
Save