Compare commits

..

7 Commits

@ -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;
import android.database.Cursor;
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;
import org.json.JSONObject;
import java.util.ArrayList;
public class TaskList extends Node {
private static final String TAG = TaskList.class.getSimpleName();
private int mIndex;
private ArrayList<Task> mChildren;
public TaskList() {
super();
mChildren = new ArrayList<Task>();
mIndex = 1;
}
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
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_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_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");
}
return js;
}
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
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());
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) {
try {
// 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) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to get tasklist content from jsonobject");
}
}
}
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.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);
} 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);
else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER)
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE);
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() {
try {
JSONObject js = new JSONObject();
JSONObject folder = new JSONObject();
String folderName = getName();
if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX))
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);
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()) {
// 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())) {
Log.e(TAG, "gtask id doesn't match");
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();
}
return SYNC_ACTION_ERROR;
}
public int getChildTaskCount() {
return mChildren.size();
}
public boolean addChildTask(Task task) {
boolean ret = false;
if (task != null && !mChildren.contains(task)) {
ret = mChildren.add(task);
if (ret) {
// need to set prior sibling and parent
task.setPriorSibling(mChildren.isEmpty() ? null : mChildren
.get(mChildren.size() - 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;
int index = mChildren.indexOf(task);
if (index != -1) {
ret = mChildren.remove(task);
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) {
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) {
for (int i = 0; i < mChildren.size(); i++) {
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) {
for (Task task : mChildren) {
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,361 @@
/*
* 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;
import android.database.Cursor;
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;
import org.json.JSONException;
import org.json.JSONObject;
// 定义一个Task类继承自Node类
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; // 所属的任务列表
// 构造函数
public Task() {
super();
mCompleted = false;
mNotes = null;
mPriorSibling = null;
mParent = null;
mMetaInfo = null;
}
// 获取创建任务所需的JSON对象
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置动作类型为创建任务
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
// 设置动作ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置任务在父列表中的索引位置
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
// 设置实体增量包括任务名称、创建者ID和实体类型
JSONObject entity = new JSONObject();
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);
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
// 设置父任务ID
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());
// 设置目标父类型为任务组
js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
// 设置列表ID为父任务ID
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
// 如果存在前一个兄弟任务则设置其ID
if (mPriorSibling != null) {
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-create jsonobject");
}
}
}
return js;
}
// 定义一个方法,用于生成更新任务所需的 JSON 对象
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置动作类型为 "update"
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
// 设置动作 ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置任务的 ID
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// 创建一个 JSON 对象用于存储实体的增量信息
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
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 task-update jsonobject");
}
return js;
}
// 定义一个方法,用于根据传入的 JSON 对象设置任务的内容
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
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) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to get task content from jsonobject");
}
}
}
// 定义一个方法,用于根据本地 JSON 数据设置任务内容
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
Log.w(TAG, "setContentByLocalJSON: nothing is available");
}
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_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;
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
public JSONObject getLocalJSONFromContent() {
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);
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++) {
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;
if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.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)) {
Log.w(TAG, "remote note id seems to be deleted");
return SYNC_ACTION_UPDATE_LOCAL;
}
// 验证笔记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");
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;
}
// 判断任务是否有价值保存
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;
}
// 设置任务备注信息
public void setNotes(String notes) {
this.mNotes = notes;
}
// 设置前一个兄弟任务
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;
}
// 获取前一个兄弟任务
public Task getPriorSibling() {
return this.mPriorSibling;
}
// 获取父任务列表
public TaskList getParent() {
return this.mParent;
}
}

@ -0,0 +1,505 @@
/*
* 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;
import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import net.micode.notes.tool.ResourceParser;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class SqlNote {
private static final String TAG = SqlNote.class.getSimpleName();
private static final int INVALID_ID = -99999;
public static final String[] PROJECTION_NOTE = new String[] {
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;
public static final int ALERTED_DATE_COLUMN = 1;
public static final int BG_COLOR_ID_COLUMN = 2;
public static final int CREATED_DATE_COLUMN = 3;
public static final int HAS_ATTACHMENT_COLUMN = 4;
public static final int MODIFIED_DATE_COLUMN = 5;
public static final int NOTES_COUNT_COLUMN = 6;
public static final int PARENT_ID_COLUMN = 7;
public static final int SNIPPET_COLUMN = 8;
public static final int TYPE_COLUMN = 9;
public static final int WIDGET_ID_COLUMN = 10;
public static final int WIDGET_TYPE_COLUMN = 11;
public static final int SYNC_ID_COLUMN = 12;
public static final int LOCAL_MODIFIED_COLUMN = 13;
public static final int ORIGIN_PARENT_ID_COLUMN = 14;
public static final int GTASK_ID_COLUMN = 15;
public static final int VERSION_COLUMN = 16;
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) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = true;
mId = INVALID_ID;
mAlertDate = 0;
mBgColorId = ResourceParser.getDefaultBgId(context);
mCreatedDate = System.currentTimeMillis();
mHasAttachment = 0;
mModifiedDate = System.currentTimeMillis();
mParentId = 0;
mSnippet = "";
mType = Notes.TYPE_NOTE;
mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
mOriginParent = 0;
mVersion = 0;
mDiffNoteValues = new ContentValues();
mDataList = new ArrayList<SqlData>();
}
public SqlNote(Context context, Cursor c) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
loadDataContent();
mDiffNoteValues = new ContentValues();
}
public SqlNote(Context context, long id) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(id);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
loadDataContent();
mDiffNoteValues = new ContentValues();
}
private void loadFromCursor(long id) {
Cursor c = null;
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
new String[] {
String.valueOf(id)
}, null);
if (c != null) {
c.moveToNext();
loadFromCursor(c);
} else {
Log.w(TAG, "loadFromCursor: cursor = null");
}
} finally {
if (c != null)
c.close();
}
}
private void loadFromCursor(Cursor c) {
mId = c.getLong(ID_COLUMN);
mAlertDate = c.getLong(ALERTED_DATE_COLUMN);
mBgColorId = c.getInt(BG_COLOR_ID_COLUMN);
mCreatedDate = c.getLong(CREATED_DATE_COLUMN);
mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN);
mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN);
mParentId = c.getLong(PARENT_ID_COLUMN);
mSnippet = c.getString(SNIPPET_COLUMN);
mType = c.getInt(TYPE_COLUMN);
mWidgetId = c.getInt(WIDGET_ID_COLUMN);
mWidgetType = c.getInt(WIDGET_TYPE_COLUMN);
mVersion = c.getLong(VERSION_COLUMN);
}
private void loadDataContent() {
Cursor c = null;
mDataList.clear();
try {
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
"(note_id=?)", new String[] {
String.valueOf(mId)
}, null);
if (c != null) {
if (c.getCount() == 0) {
Log.w(TAG, "it seems that the note has not data");
return;
}
while (c.moveToNext()) {
SqlData data = new SqlData(mContext, c);
mDataList.add(data);
}
} else {
Log.w(TAG, "loadDataContent: cursor = null");
}
} finally {
if (c != null)
c.close();
}
}
public boolean setContent(JSONObject js) {
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
Log.w(TAG, "cannot set system folder");
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {
// for folder we can only update the snnipet and type
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate || !mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type);
}
mType = type;
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID;
if (mIsCreate || mId != id) {
mDiffNoteValues.put(NoteColumns.ID, id);
}
mId = id;
long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note
.getLong(NoteColumns.ALERTED_DATE) : 0;
if (mIsCreate || mAlertDate != alertDate) {
mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate);
}
mAlertDate = alertDate;
int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note
.getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext);
if (mIsCreate || mBgColorId != bgColorId) {
mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId);
}
mBgColorId = bgColorId;
long createDate = note.has(NoteColumns.CREATED_DATE) ? note
.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis();
if (mIsCreate || mCreatedDate != createDate) {
mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate);
}
mCreatedDate = createDate;
int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note
.getInt(NoteColumns.HAS_ATTACHMENT) : 0;
if (mIsCreate || mHasAttachment != hasAttachment) {
mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment);
}
mHasAttachment = hasAttachment;
long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note
.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis();
if (mIsCreate || mModifiedDate != modifiedDate) {
mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate);
}
mModifiedDate = modifiedDate;
long parentId = note.has(NoteColumns.PARENT_ID) ? note
.getLong(NoteColumns.PARENT_ID) : 0;
if (mIsCreate || mParentId != parentId) {
mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId);
}
mParentId = parentId;
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate || !mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type);
}
mType = type;
int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID)
: AppWidgetManager.INVALID_APPWIDGET_ID;
if (mIsCreate || mWidgetId != widgetId) {
mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId);
}
mWidgetId = widgetId;
int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note
.getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE;
if (mIsCreate || mWidgetType != widgetType) {
mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType);
}
mWidgetType = widgetType;
long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note
.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0;
if (mIsCreate || mOriginParent != originParent) {
mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent);
}
mOriginParent = originParent;
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
SqlData sqlData = null;
if (data.has(DataColumns.ID)) {
long dataId = data.getLong(DataColumns.ID);
for (SqlData temp : mDataList) {
if (dataId == temp.getId()) {
sqlData = temp;
}
}
}
if (sqlData == null) {
sqlData = new SqlData(mContext);
mDataList.add(sqlData);
}
sqlData.setContent(data);
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return false;
}
return true;
}
public JSONObject getContent() {
try {
JSONObject js = new JSONObject();
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
JSONObject note = new JSONObject();
if (mType == Notes.TYPE_NOTE) {
note.put(NoteColumns.ID, mId);
note.put(NoteColumns.ALERTED_DATE, mAlertDate);
note.put(NoteColumns.BG_COLOR_ID, mBgColorId);
note.put(NoteColumns.CREATED_DATE, mCreatedDate);
note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment);
note.put(NoteColumns.MODIFIED_DATE, mModifiedDate);
note.put(NoteColumns.PARENT_ID, mParentId);
note.put(NoteColumns.SNIPPET, mSnippet);
note.put(NoteColumns.TYPE, mType);
note.put(NoteColumns.WIDGET_ID, mWidgetId);
note.put(NoteColumns.WIDGET_TYPE, mWidgetType);
note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
JSONArray dataArray = new JSONArray();
for (SqlData sqlData : mDataList) {
JSONObject data = sqlData.getContent();
if (data != null) {
dataArray.put(data);
}
}
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
} else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {
note.put(NoteColumns.ID, mId);
note.put(NoteColumns.TYPE, mType);
note.put(NoteColumns.SNIPPET, mSnippet);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
}
return js;
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
return null;
}
public void setParentId(long id) {
mParentId = id;
mDiffNoteValues.put(NoteColumns.PARENT_ID, id);
}
public void setGtaskId(String gid) {
mDiffNoteValues.put(NoteColumns.GTASK_ID, gid);
}
public void setSyncId(long syncId) {
mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId);
}
public void resetLocalModified() {
mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0);
}
public long getId() {
return mId;
}
public long getParentId() {
return mParentId;
}
public String getSnippet() {
return mSnippet;
}
public boolean isNoteType() {
return mType == Notes.TYPE_NOTE;
}
public void commit(boolean validateVersion) {
if (mIsCreate) {
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
mDiffNoteValues.remove(NoteColumns.ID);
}
Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues);
try {
mId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");
}
if (mId == 0) {
throw new IllegalStateException("Create thread id failed");
}
if (mType == Notes.TYPE_NOTE) {
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, false, -1);
}
}
} else {
if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) {
Log.e(TAG, "No such note");
throw new IllegalStateException("Try to update note with invalid id");
}
if (mDiffNoteValues.size() > 0) {
mVersion ++;
int result = 0;
if (!validateVersion) {
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?)", new String[] {
String.valueOf(mId)
});
} else {
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)",
new String[] {
String.valueOf(mId), String.valueOf(mVersion)
});
}
if (result == 0) {
Log.w(TAG, "there is no update. maybe user updates note when syncing");
}
}
if (mType == Notes.TYPE_NOTE) {
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, validateVersion, mVersion);
}
}
}
// refresh local info
loadFromCursor(mId);
if (mType == Notes.TYPE_NOTE)
loadDataContent();
mDiffNoteValues.clear();
mIsCreate = false;
}
}

@ -0,0 +1,23 @@
[中文]
1. MiCode便签是小米便签的社区开源版由MIUI团队(www.miui.com) 发起并贡献第一批代码遵循NOTICE文件所描述的开源协议
今后为MiCode社区(www.micode.net) 拥有,并由社区发布和维护。
2. Bug反馈和跟踪请访问Github,
https://github.com/MiCode/Notes/issues?sort=created&direction=desc&state=open
3. 功能建议和综合讨论请访问MiCode,
http://micode.net/forum.php?mod=forumdisplay&fid=38
[English]
1. MiCode Notes is open source edition of XM notepad, it's first initiated and sponsored by MIUI team (www.miui.com).
It's opened under license described by NOTICE file. It's owned by the MiCode community (www.micode.net). In future,
the MiCode community will release and maintain this project.
2. Regarding issue tracking, please visit Github,
https://github.com/MiCode/Notes/issues?sort=created&direction=desc&state=open
3. Regarding feature request and general discussion, please visit Micode forum,
http://micode.net/forum.php?mod=forumdisplay&fid=38

@ -35,76 +35,135 @@ import java.util.ArrayList;
public class Note {
// 存储笔记的差异值,使用 ContentValues 类型,可能用于存储一些更新信息
private ContentValues mNoteDiffValues;
// 存储笔记的数据,使用 NoteData 类型
private NoteData mNoteData;
// 日志标签,用于日志输出
private static final String TAG = "Note";
/**
* Create a new note id for adding a new note to databases
* ID 线
*/
public static synchronized long getNewNoteId(Context context, long folderId) {
// Create a new note in the database
// 创建一个新的 ContentValues 对象,用于存储即将插入数据库的数据
ContentValues values = new ContentValues();
// 获取当前系统时间作为创建时间和修改时间
long createdTime = System.currentTimeMillis();
// 将创建时间添加到 ContentValues 中
values.put(NoteColumns.CREATED_DATE, createdTime);
// 将修改时间添加到 ContentValues 中
values.put(NoteColumns.MODIFIED_DATE, createdTime);
// 笔记的类型,这里可能是预定义的 TYPE_NOTE
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
// 标记为本地已修改
values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 父文件夹的 ID
values.put(NoteColumns.PARENT_ID, folderId);
// 通过 ContentResolver 插入数据,并获取插入后的 Uri
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
long noteId = 0;
try {
// 从 Uri 的路径段中获取笔记的 ID这里假定 Uri 的路径段的第二个元素是笔记 ID
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
// 若获取 ID 时出现异常,输出错误日志,并将 noteId 设为 0
Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
}
// 如果笔记 ID 为 -1抛出异常
if (noteId == -1) {
throw new IllegalStateException("Wrong note id:" + noteId);
}
// 返回创建的笔记 ID
return noteId;
}
// 构造函数,初始化 Note 对象
public Note() {
mNoteDiffValues = new ContentValues();
mNoteData = new NoteData();
}
/**
*
* @param key
* @param value
*/
public void setNoteValue(String key, String value) {
// 将键值对添加到 mNoteDiffValues 中
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 mNoteDiffValues mNoteData true false
*/
public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
/**
*
* @param context
* @param noteId ID
* @return true false
*/
public boolean syncNote(Context context, long noteId) {
// 如果笔记 ID 不合法,抛出异常
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 如果笔记未在本地修改,认为同步成功
if (!isLocalModified()) {
return true;
}
@ -113,141 +172,195 @@ public class Note {
* 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
* NoteColumns#LOCAL_MODIFIED NoteColumns#MODIFIED_DATE 使
*/
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
// 不返回,继续执行下面的操作
}
// 清空 mNoteDiffValues可能表示此次修改已同步
mNoteDiffValues.clear();
// 如果 mNoteData 本地修改且将数据推送到 ContentResolver 失败,同步失败
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
return false;
}
// 同步成功
return true;
}
}
// 定义一个名为 Note 的公共类
public class Note {
// 存储笔记差异值的私有变量,使用 ContentValues 类型,可存储键值对数据
private ContentValues mNoteDiffValues;
// 存储笔记数据的私有变量,使用 NoteData 类型
private NoteData mNoteData;
// 用于日志输出的静态常量标签,方便在日志中识别该类的相关信息
private static final String TAG = "Note";
/**
* ID
* 线线
* @param context ContentResolver
* @param folderId ID
* @return ID
*/
public static synchronized long getNewNoteId(Context context, long folderId) {
// 创建一个新的 ContentValues 对象,用于存储插入数据库的数据
ContentValues values = new ContentValues();
// 获取当前系统时间的毫秒数作为笔记的创建时间
long createdTime = System.currentTimeMillis();
// 将创建时间存储在 CREATED_DATE 列中
values.put(NoteColumns.CREATED_DATE, createdTime);
// 将创建时间存储在 MODIFIED_DATE 列中,新笔记的创建时间也是其初始修改时间
values.put(NoteColumns.MODIFIED_DATE, createdTime);
// 存储笔记的类型Notes.TYPE_NOTE 应该是预定义的笔记类型常量
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
// 标记该笔记在本地已修改,可能用于后续的同步或更新操作
values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 存储笔记所属的父文件夹的 ID
values.put(NoteColumns.PARENT_ID, folderId);
// 通过 ContentResolver 插入新的笔记数据到指定的 URI并返回插入后的 URI
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
long noteId = 0;
try {
// 从返回的 URI 中获取笔记的 ID这里假设 URI 的路径部分包含笔记的 ID通常是 URI 的第二个部分
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
// 捕获数字格式异常,打印错误日志,并将 noteId 设置为 0
Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
}
// 如果笔记 ID 为 -1则抛出异常因为这是一个错误的笔记 ID
if (noteId == -1) {
throw new IllegalStateException("Wrong note id:" + noteId);
}
// 返回新创建的笔记的 ID
return noteId;
}
// Note 类的构造函数,用于初始化 Note 对象
public Note() {
// 初始化存储笔记差异值的 ContentValues 对象
mNoteDiffValues = new ContentValues();
// 初始化存储笔记数据的 NoteData 对象
mNoteData = new NoteData();
}
private class NoteData {
private long mTextDataId;
/**
*
*
* @param key
* @param value
*/
public void setNoteValue(String key, String value) {
// 将键值对存储到 mNoteDiffValues 中
mNoteDiffValues.put(key, value);
// 标记该笔记在本地已修改
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记的修改时间为当前系统时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
private ContentValues mTextDataValues;
/**
*
* NoteData
* @param key
* @param value
*/
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);
}
private long mCallDataId;
/**
* ID
* @param id ID
*/
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}
private ContentValues mCallDataValues;
/**
* ID
* @return ID
*/
public long getTextDataId() {
return mNoteData.mTextDataId;
}
private static final String TAG = "NoteData";
/**
* ID
* NoteData ID
* @param id ID
*/
public void setCallDataId(long id) {
mNoteData.setCallDataId(id);
}
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
}
/**
*
* NoteData
* @param key
* @param value
*/
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
/**
*
* mNoteDiffValues NoteData
* @return true false
*/
public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
void setTextDataId(long id) {
if(id <= 0) {
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;
/**
*
* @param context ContentResolver
* @param noteId ID
* @return true false
*/
public boolean syncNote(Context context, long noteId) {
// 检查笔记 ID 是否合法,如果不合法则抛出异常
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
void setCallDataId(long id) {
if (id <= 0) {
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id;
// 如果笔记未在本地修改,认为同步成功
if (!isLocalModified()) {
return true;
}
void setCallData(String key, String value) {
mCallDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
/**
* LOCAL_MODIFIED MODIFIED_DATE
* 使
*/
if (context.getContentResolver().update(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
null) == 0) {
// 如果更新笔记时出现错误,打印错误日志,日志中会标记不应该发生此错误
Log.e(TAG, "Update note error, should not happen");
// 不返回,继续执行后续操作
}
// 清空 mNoteDiffValues可能表示当前的修改已同步到数据库
mNoteDiffValues.clear();
void setTextData(String key, String value) {
mTextDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
// 如果 NoteData 已在本地修改,并且将其数据推送到 ContentResolver 失败,则同步失败
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
return false;
}
Uri pushIntoContentResolver(Context context, long noteId) {
/**
* Check for safety
*/
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = null;
if(mTextDataValues.size() > 0) {
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
if (mTextDataId == 0) {
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mTextDataValues);
try {
setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
Log.e(TAG, "Insert new text data fail with noteId" + noteId);
mTextDataValues.clear();
return null;
}
} else {
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mTextDataId));
builder.withValues(mTextDataValues);
operationList.add(builder.build());
}
mTextDataValues.clear();
}
if(mCallDataValues.size() > 0) {
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
if (mCallDataId == 0) {
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mCallDataValues);
try {
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
Log.e(TAG, "Insert new call data fail with noteId" + noteId);
mCallDataValues.clear();
return null;
}
} else {
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId));
builder.withValues(mCallDataValues);
operationList.add(builder.build());
}
mCallDataValues.clear();
}
if (operationList.size() > 0) {
try {
ContentProviderResult[] results = context.getContentResolver().applyBatch(
Notes.AUTHORITY, operationList);
return (results == null || results.length == 0 || results[0] == null) ? null
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
}
}
return null;
}
// 表示笔记数据已成功同步
return true;
}
}
}

@ -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
// 笔记的唯一标识符
private long mNoteId;
// Note content
// 笔记的内容
private String mContent;
// Note mode
// 笔记的模式
private int mMode;
// 提醒日期
private long mAlertDate;
// 笔记的修改日期
private long mModifiedDate;
// 笔记的背景颜色标识符
private int mBgColorId;
// 小部件的标识符
private int mWidgetId;
// 小部件的类型
private int mWidgetType;
// 文件夹的标识符
private long mFolderId;
// 上下文,可能用于资源访问、数据库操作等
private Context mContext;
// 用于日志输出的标记
private static final String TAG = "WorkingNote";
// 标记笔记是否已删除
private boolean mIsDeleted;
// 笔记设置更改的监听器,当笔记的设置发生变化时,会通知监听器
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
};
// 数据投影中各列的索引,方便从 Cursor 中获取数据
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;
// 笔记投影中各列的索引,方便从 Cursor 中获取数据
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
// 私有构造函数,用于创建新的笔记
// 初始化笔记的一些基本信息,如修改日期、文件夹 ID、创建 Note 对象、标记为未删除等
private WorkingNote(Context context, long folderId) {
mContext = context;
mAlertDate = 0;
@ -114,7 +110,8 @@ public class WorkingNote {
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
}
// Existing note construct
// 私有构造函数,用于加载已存在的笔记
// 根据笔记 ID 和文件夹 ID 加载笔记信息
private WorkingNote(Context context, long noteId, long folderId) {
mContext = context;
mNoteId = noteId;
@ -124,13 +121,16 @@ public class WorkingNote {
loadNote();
}
// 从数据库中加载笔记信息
private void loadNote() {
// 使用 ContentResolver 查询笔记信息
Cursor cursor = mContext.getContentResolver().query(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
null, null);
if (cursor != null) {
if (cursor!= null) {
if (cursor.moveToFirst()) {
// 从 Cursor 中获取笔记的各项信息
mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN);
mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN);
mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN);
@ -140,22 +140,26 @@ public class WorkingNote {
}
cursor.close();
} else {
// 日志输出错误信息并抛出异常,如果没有找到相应的笔记
Log.e(TAG, "No note with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note with id " + mNoteId);
}
loadNoteData();
}
// 从数据库中加载笔记的数据
private void loadNoteData() {
// 使用 ContentResolver 查询笔记的数据信息
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] {
String.valueOf(mNoteId)
}, null);
if (cursor != null) {
if (cursor!= null) {
if (cursor.moveToFirst()) {
do {
String type = cursor.getString(DATA_MIME_TYPE_COLUMN);
// 根据不同的数据类型,处理不同的数据
if (DataConstants.NOTE.equals(type)) {
mContent = cursor.getString(DATA_CONTENT_COLUMN);
mMode = cursor.getInt(DATA_MODE_COLUMN);
@ -169,11 +173,13 @@ public class WorkingNote {
}
cursor.close();
} else {
// 日志输出错误信息并抛出异常,如果没有找到相应的笔记数据
Log.e(TAG, "No data with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId);
}
}
// 创建一个空的笔记
public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId);
@ -183,27 +189,27 @@ 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()) {
// 获取新的笔记 ID如果获取失败记录错误日志
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
Log.e(TAG, "Create new note fail with id:" + mNoteId);
return false;
}
}
// 同步笔记信息到数据库
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) {
// 如果笔记关联了小部件且设置监听器存在,通知小部件更新
if (mWidgetId!= AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType!= Notes.TYPE_WIDGET_INVALIDE
&& mNoteSettingStatusListener!= null) {
mNoteSettingStatusListener.onWidgetChanged();
}
return true;
@ -212,54 +218,62 @@ public class WorkingNote {
}
}
// 检查笔记是否已存在于数据库中
public boolean existInDatabase() {
return mNoteId > 0;
}
// 判断笔记是否值得保存
private boolean isWorthSaving() {
// 如果笔记已删除、不存在且内容为空或者已存在但未被本地修改,则不值得保存
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) {
|| (existInDatabase() &&!mNote.isLocalModified())) {
return false;
} else {
return true;
}
}
// 设置笔记设置更改的监听器
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l;
}
// 设置提醒日期,并通知监听器
public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) {
if (date!= mAlertDate) {
mAlertDate = date;
mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate));
}
if (mNoteSettingStatusListener != null) {
if (mNoteSettingStatusListener!= null) {
mNoteSettingStatusListener.onClockAlertChanged(date, set);
}
}
// 标记笔记是否已删除,并通知监听器
public void markDeleted(boolean mark) {
mIsDeleted = mark;
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
if (mWidgetId!= AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType!= Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener!= null) {
mNoteSettingStatusListener.onWidgetChanged();
}
}
// 设置背景颜色标识符,并通知监听器
public void setBgColorId(int id) {
if (id != mBgColorId) {
if (id!= mBgColorId) {
mBgColorId = id;
if (mNoteSettingStatusListener != null) {
if (mNoteSettingStatusListener!= null) {
mNoteSettingStatusListener.onBackgroundColorChanged();
}
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
}
}
// 设置清单模式,并通知监听器
public void setCheckListMode(int mode) {
if (mMode != mode) {
if (mNoteSettingStatusListener != null) {
if (mMode!= mode) {
if (mNoteSettingStatusListener!= null) {
mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode);
}
mMode = mode;
@ -267,20 +281,23 @@ public class WorkingNote {
}
}
// 设置小部件类型
public void setWidgetType(int type) {
if (type != mWidgetType) {
if (type!= mWidgetType) {
mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
}
}
// 设置小部件标识符
public void setWidgetId(int id) {
if (id != mWidgetId) {
if (id!= mWidgetId) {
mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
}
}
// 设置笔记的工作文本
public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) {
mContent = text;
@ -288,81 +305,82 @@ public class WorkingNote {
}
}
// 将笔记转换为通话笔记
public void convertToCallNote(String phoneNumber, long callDate) {
mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate));
mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber);
mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER));
}
// 判断是否设置了时钟提醒
public boolean hasClockAlert() {
return (mAlertDate > 0 ? true : false);
return (mAlertDate > 0? true : false);
}
// 获取笔记的内容
public String getContent() {
return mContent;
}
// 获取提醒日期
public long getAlertDate() {
return mAlertDate;
}
// 获取修改日期
public long getModifiedDate() {
return mModifiedDate;
}
// 获取背景颜色资源标识符
public int getBgColorResId() {
return NoteBgResources.getNoteBgResource(mBgColorId);
}
// 获取背景颜色标识符
public int getBgColorId() {
return mBgColorId;
}
// 获取标题背景资源标识符
public int getTitleBgResId() {
return NoteBgResources.getNoteTitleBgResource(mBgColorId);
}
// 获取清单模式
public int getCheckListMode() {
return mMode;
}
// 获取笔记的 ID
public long getNoteId() {
return mNoteId;
}
// 获取文件夹的 ID
public long getFolderId() {
return mFolderId;
}
// 获取小部件的 ID
public int getWidgetId() {
return mWidgetId;
}
// 获取小部件的类型
public int getWidgetType() {
return mWidgetType;
}
// 定义一个接口,用于监听笔记设置的更改
public interface NoteSettingChangedListener {
/**
* Called when the background color of current note has just changed
*/
// 当背景颜色改变时调用
void onBackgroundColorChanged();
/**
* Called when user set clock
*/
// 当设置时钟提醒时调用
void onClockAlertChanged(long date, boolean set);
/**
* Call when user create note from widget
*/
// 当小部件改变时调用
void onWidgetChanged();
/**
* Call when switch between check list mode and normal mode
* @param oldMode is previous mode before change
* @param newMode is new mode
*/
// 当切换清单模式时调用
void onCheckListModeChanged(int oldMode, int newMode);
}
}
}

@ -37,68 +37,78 @@ import java.io.PrintStream;
public class BackupUtils {
// 用于日志记录的标记,方便在日志中识别该类的输出
private static final String TAG = "BackupUtils";
// Singleton stuff
// 单例模式使用的静态变量,用于存储该类的唯一实例
private static BackupUtils sInstance;
// 单例模式的获取实例方法,确保在整个应用程序中只有一个 BackupUtils 实例
public static synchronized BackupUtils getInstance(Context context) {
// 如果 sInstance 为空,创建一个新的 BackupUtils 实例并存储在 sInstance 中
if (sInstance == null) {
sInstance = new BackupUtils(context);
}
// 返回 BackupUtils 的唯一实例
return sInstance;
}
/**
* Following states are signs to represents backup or restore
* status
*
*/
// Currently, the sdcard is not mounted
public static final int STATE_SD_CARD_UNMOUONTED = 0;
// The backup file not exist
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
// The data is not well formated, may be changed by other programs
public static final int STATE_DATA_DESTROIED = 2;
// Some run-time exception which causes restore or backup fails
public static final int STATE_SYSTEM_ERROR = 3;
// Backup or restore success
public static final int STATE_SUCCESS = 4;
// 表示 SD 卡未挂载的状态码
public static final int STATE_SD_CARD_UNMOUONTED = 0;
// 表示备份文件不存在的状态码
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
// 表示数据格式被破坏,可能被其他程序修改的数据状态码
public static final int STATE_DATA_DESTROIED = 2;
// 表示由于系统运行时异常导致备份或恢复失败的状态码
public static final int STATE_SYSTEM_ERROR = 3;
// 表示备份或恢复成功的状态码
public static final int STATE_SUCCESS = 4;
// 用于文本导出的 TextExport 对象
private TextExport mTextExport;
// 构造函数,接收 Context 作为参数,并创建一个 TextExport 对象
private BackupUtils(Context context) {
mTextExport = new TextExport(context);
}
// 检查外部存储是否可用,通过检查存储状态是否为已挂载
private static boolean externalStorageAvailable() {
// 比较存储状态是否等于已挂载状态
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
// 调用 TextExport 对象的 exportToText 方法,进行文本导出操作
public int exportToText() {
return mTextExport.exportToText();
}
// 获取导出的文本文件名,调用 TextExport 对象的相应属性
public String getExportedTextFileName() {
return mTextExport.mFileName;
}
// 获取导出的文本文件所在的目录,调用 TextExport 对象的相应属性
public String getExportedTextFileDir() {
return mTextExport.mFileDirectory;
}
// 内部类 TextExport负责具体的文本导出操作
private static class TextExport {
// 用于查询笔记的投影,指定了从数据库中获取笔记信息时需要的列
private static final String[] NOTE_PROJECTION = {
NoteColumns.ID,
NoteColumns.MODIFIED_DATE,
NoteColumns.SNIPPET,
NoteColumns.TYPE
};
// 笔记投影中各列的索引,用于从 Cursor 中准确提取相应信息
private static final int NOTE_COLUMN_ID = 0;
private static final int NOTE_COLUMN_MODIFIED_DATE = 1;
private static final int NOTE_COLUMN_SNIPPET = 2;
// 用于查询数据的投影,指定了从数据库中获取数据时需要的列
private static final String[] DATA_PROJECTION = {
DataColumns.CONTENT,
DataColumns.MIME_TYPE,
@ -107,105 +117,116 @@ public class BackupUtils {
DataColumns.DATA3,
DataColumns.DATA4,
};
// 数据投影中各列的索引,用于从 Cursor 中准确提取相应信息
private static final int DATA_COLUMN_CONTENT = 0;
private static final int DATA_COLUMN_MIME_TYPE = 1;
private static final int DATA_COLUMN_CALL_DATE = 2;
private static final int DATA_COLUMN_PHONE_NUMBER = 4;
private final String [] TEXT_FORMAT;
private static final int FORMAT_FOLDER_NAME = 0;
private static final int FORMAT_NOTE_DATE = 1;
private static final int FORMAT_NOTE_CONTENT = 2;
// 存储文本格式化的字符串数组,包含不同的文本格式
private final String[] TEXT_FORMAT;
// 表示文件夹名称的格式索引
private static final int FORMAT_FOLDER_NAME = 0;
// 表示笔记日期的格式索引
private static final int FORMAT_NOTE_DATE = 1;
// 表示笔记内容的格式索引
private static final int FORMAT_NOTE_CONTENT = 2;
// 上下文对象,用于资源访问和数据库操作等
private Context mContext;
// 导出的文件名
private String mFileName;
// 导出的文件目录
private String mFileDirectory;
// 构造函数,初始化 TextExport 对象
public TextExport(Context context) {
// 从资源中获取存储的文本格式数组
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note);
mContext = context;
mFileName = "";
mFileDirectory = "";
}
// 根据传入的索引获取相应的文本格式
private String getFormat(int id) {
return TEXT_FORMAT[id];
}
/**
* Export the folder identified by folder id to text
*/
// 将指定文件夹的笔记导出为文本,接收文件夹 ID 和打印流作为参数
private void exportFolderToText(String folderId, PrintStream ps) {
// Query notes belong to this folder
// 使用 ContentResolver 查询属于该文件夹的笔记
Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] {
folderId
}, null);
if (notesCursor != null) {
if (notesCursor!= null) {
if (notesCursor.moveToFirst()) {
do {
// Print note's last modified date
// 格式化并打印笔记的最后修改日期
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// Query data belong to this note
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)));
// 获取该笔记的 ID
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
// 调用 exportNoteToText 方法将该笔记导出为文本
exportNoteToText(noteId, ps);
} while (notesCursor.moveToNext());
}
// 关闭 Cursor释放资源
notesCursor.close();
}
}
/**
* Export note identified by id to a print stream
*/
// 将指定笔记导出为文本,接收笔记 ID 和打印流作为参数
private void exportNoteToText(String noteId, PrintStream ps) {
// 使用 ContentResolver 查询属于该笔记的数据
Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI,
DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] {
noteId
}, null);
if (dataCursor != null) {
if (dataCursor!= null) {
if (dataCursor.moveToFirst()) {
do {
// 获取该数据的 MIME 类型
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
if (DataConstants.CALL_NOTE.equals(mimeType)) {
// Print phone number
// 获取电话号码
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER);
// 获取通话日期
long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE);
// 获取位置信息
String location = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(phoneNumber)) {
// 打印电话号码
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
phoneNumber));
}
// Print call date
// 格式化并打印通话日期
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat
.format(mContext.getString(R.string.format_datetime_mdhm),
.format(mContext.getString(R.string.format_datetime_mdhm),
callDate)));
// Print call attachment location
if (!TextUtils.isEmpty(location)) {
// 打印通话附件的位置信息
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
location));
}
} else if (DataConstants.NOTE.equals(mimeType)) {
// 获取笔记的内容
String content = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(content)) {
// 打印笔记内容
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
content));
}
}
} while (dataCursor.moveToNext());
}
// 关闭 Cursor释放资源
dataCursor.close();
}
// print a line separator between note
// 在笔记之间打印行分隔符
try {
ps.write(new byte[] {
Character.LINE_SEPARATOR, Character.LETTER_NUMBER
@ -215,21 +236,21 @@ public class BackupUtils {
}
}
/**
* Note will be exported as text which is user readable
*/
// 导出文本的主要方法,将笔记和文件夹信息导出为文本文件
public int exportToText() {
// 如果外部存储不可用,记录日志并返回相应状态码
if (!externalStorageAvailable()) {
Log.d(TAG, "Media was not mounted");
return STATE_SD_CARD_UNMOUONTED;
}
// 获取导出的打印流
PrintStream ps = getExportToTextPrintStream();
if (ps == null) {
Log.e(TAG, "get print stream error");
return STATE_SYSTEM_ERROR;
}
// First export folder and its notes
// 使用 ContentResolver 查询要导出的文件夹信息
Cursor folderCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
@ -237,55 +258,63 @@ public class BackupUtils {
+ NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null);
if (folderCursor != null) {
if (folderCursor!= null) {
if (folderCursor.moveToFirst()) {
do {
// Print folder's name
// 获取文件夹名称
String folderName = "";
if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
if (folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
folderName = mContext.getString(R.string.call_record_folder_name);
} else {
folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET);
}
if (!TextUtils.isEmpty(folderName)) {
// 打印文件夹名称
ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName));
}
// 获取文件夹的 ID
String folderId = folderCursor.getString(NOTE_COLUMN_ID);
// 调用 exportFolderToText 方法导出该文件夹的笔记
exportFolderToText(folderId, ps);
} while (folderCursor.moveToNext());
}
// 关闭 Cursor释放资源
folderCursor.close();
}
// Export notes in root's folder
// 使用 ContentResolver 查询根文件夹中的笔记信息
Cursor noteCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
+ "=0", null, null);
if (noteCursor != null) {
if (noteCursor!= null) {
if (noteCursor.moveToFirst()) {
do {
// 格式化并打印笔记的修改日期
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// Query data belong to this note
noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)));
// 获取笔记的 ID
String noteId = noteCursor.getString(NOTE_COLUMN_ID);
// 调用 exportNoteToText 方法导出该笔记
exportNoteToText(noteId, ps);
} while (noteCursor.moveToNext());
}
// 关闭 Cursor释放资源
noteCursor.close();
}
// 关闭打印流
ps.close();
// 导出成功,返回成功状态码
return STATE_SUCCESS;
}
/**
* Get a print stream pointed to the file {@generateExportedTextFile}
*/
// 获取导出到文本的打印流
private PrintStream getExportToTextPrintStream() {
// 生成存储在 SD 卡上的文件
File file = generateFileMountedOnSDcard(mContext, R.string.file_path,
R.string.file_name_txt_format);
if (file == null) {
@ -296,7 +325,9 @@ public class BackupUtils {
mFileDirectory = mContext.getString(R.string.file_path);
PrintStream ps = null;
try {
// 创建文件输出流
FileOutputStream fos = new FileOutputStream(file);
// 创建打印流,将数据输出到文件中
ps = new PrintStream(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
@ -309,14 +340,15 @@ public class BackupUtils {
}
}
/**
* Generate the text file to store imported data
*/
// 在 SD 卡上生成存储导入数据的文本文件
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder();
// 获取外部存储目录并添加文件路径
sb.append(Environment.getExternalStorageDirectory());
sb.append(context.getString(filePathResId));
// 创建文件目录对象
File filedir = new File(sb.toString());
// 构建文件名,包含当前日期信息
sb.append(context.getString(
fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd),
@ -324,9 +356,11 @@ public class BackupUtils {
File file = new File(sb.toString());
try {
// 如果目录不存在,创建目录
if (!filedir.exists()) {
filedir.mkdir();
}
// 如果文件不存在,创建文件
if (!file.exists()) {
file.createNewFile();
}
@ -341,4 +375,3 @@ public class BackupUtils {
}
}

@ -36,99 +36,134 @@ import java.util.HashSet;
public class DataUtils {
// 日志标记,用于在日志中标识该类输出的信息
public static final String TAG = "DataUtils";
// 批量删除笔记的方法
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
// 如果 ids 集合为 null打印日志并返回 true
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
}
// 如果 ids 集合大小为 0打印日志并返回 true
if (ids.size() == 0) {
Log.d(TAG, "no id is in the hashset");
return true;
}
// 存储操作列表的 ArrayList用于存储要执行的删除操作
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// 遍历 ids 集合
for (long id : ids) {
if(id == Notes.ID_ROOT_FOLDER) {
// 不允许删除系统根文件夹
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));
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
operationList.add(builder.build());
}
try {
// 应用批量操作,并存储结果
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
// 如果结果为空或结果数组长度为 0 或第一个结果为 null打印日志并返回 false
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()));
}
return false;
}
// 将笔记移动到指定文件夹的方法
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
// 创建 ContentValues 对象存储要更新的值
ContentValues values = new ContentValues();
// 更新目标文件夹 ID
values.put(NoteColumns.PARENT_ID, desFolderId);
// 存储源文件夹 ID
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
// 标记为本地修改
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) {
// 如果 ids 集合为 null打印日志并返回 true
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
}
// 存储操作列表的 ArrayList用于存储要执行的更新操作
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// 遍历 ids 集合
for (long id : ids) {
// 创建一个更新操作的构建器
ContentProviderOperation.Builder builder = ContentProviderOperation
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
// 更新目标文件夹 ID
builder.withValue(NoteColumns.PARENT_ID, folderId);
// 标记为本地修改
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
// 将构建好的操作添加到操作列表中
operationList.add(builder.build());
}
try {
// 应用批量操作,并存储结果
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
// 如果结果为空或结果数组长度为 0 或第一个结果为 null打印日志并返回 false
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()));
// 打印异常信息
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage());
}
return false;
}
/**
* Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}}
* {@link Notes#TYPE_SYSTEM}
*/
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)},
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 以释放资源
cursor.close();
}
}
@ -136,68 +171,86 @@ public class DataUtils {
return count;
}
// 检查笔记是否在笔记数据库中可见
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
// 查询指定类型且不在回收站的笔记
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) {
if (cursor!= null) {
// 若结果集不为空,则表示存在
if (cursor.getCount() > 0) {
exist = true;
}
// 关闭 Cursor 以释放资源
cursor.close();
}
return exist;
}
// 检查笔记是否存在于笔记数据库中
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
// 查询指定笔记 ID 的笔记是否存在
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null, null, null);
boolean exist = false;
if (cursor != null) {
if (cursor!= null) {
// 若结果集不为空,则表示存在
if (cursor.getCount() > 0) {
exist = true;
}
// 关闭 Cursor 以释放资源
cursor.close();
}
return exist;
}
// 检查数据是否存在于数据数据库中
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
// 查询指定数据 ID 的数据是否存在
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
null, null, null, null);
boolean exist = false;
if (cursor != null) {
if (cursor!= null) {
// 若结果集不为空,则表示存在
if (cursor.getCount() > 0) {
exist = true;
}
// 关闭 Cursor 以释放资源
cursor.close();
}
return exist;
}
// 检查可见文件夹名称是否存在
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
// 查询具有指定名称且不在回收站的文件夹是否存在
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?",
new String[] { name }, null);
boolean exist = false;
if(cursor != null) {
if(cursor.getCount() > 0) {
if (cursor!= null) {
// 若结果集不为空,则表示存在
if (cursor.getCount() > 0) {
exist = true;
}
// 关闭 Cursor 以释放资源
cursor.close();
}
return exist;
}
// 获取文件夹中的笔记小部件信息
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
// 查询指定文件夹中的小部件信息
Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
NoteColumns.PARENT_ID + "=?",
@ -205,91 +258,112 @@ public class DataUtils {
null);
HashSet<AppWidgetAttribute> set = null;
if (c != null) {
if (c!= null) {
if (c.moveToFirst()) {
set = new HashSet<AppWidgetAttribute>();
do {
try {
// 创建并存储小部件属性对象
AppWidgetAttribute widget = new AppWidgetAttribute();
widget.widgetId = c.getInt(0);
widget.widgetType = c.getInt(1);
set.add(widget);
} catch (IndexOutOfBoundsException e) {
// 打印异常信息
Log.e(TAG, e.toString());
}
} while (c.moveToNext());
}
// 关闭 Cursor 以释放资源
c.close();
}
return set;
}
// 通过笔记 ID 获取通话号码
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
// 查询指定笔记 ID 的通话号码
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.PHONE_NUMBER },
new String[] { CallNote.PHONE_NUMBER },
CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?",
new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
new String[] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
null);
if (cursor != null && cursor.moveToFirst()) {
if (cursor!= null && cursor.moveToFirst()) {
try {
// 获取通话号码
return cursor.getString(0);
} catch (IndexOutOfBoundsException e) {
// 打印异常信息
Log.e(TAG, "Get call number fails " + e.toString());
} finally {
// 关闭 Cursor 以释放资源
cursor.close();
}
}
return "";
}
// 通过电话号码和通话日期获取笔记 ID
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
// 查询具有指定电话号码和通话日期的笔记 ID
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.NOTE_ID },
new String[] { CallNote.NOTE_ID },
CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL("
+ CallNote.PHONE_NUMBER + ",?)",
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
new String[] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
null);
if (cursor != null) {
if (cursor!= null) {
if (cursor.moveToFirst()) {
try {
// 获取笔记 ID
return cursor.getLong(0);
} catch (IndexOutOfBoundsException e) {
// 打印异常信息
Log.e(TAG, "Get call note id fails " + e.toString());
}
}
// 关闭 Cursor 以释放资源
cursor.close();
}
return 0;
}
// 通过笔记 ID 获取片段
public static String getSnippetById(ContentResolver resolver, long noteId) {
// 查询指定笔记 ID 的片段
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String [] { NoteColumns.SNIPPET },
new String[] { NoteColumns.SNIPPET },
NoteColumns.ID + "=?",
new String [] { String.valueOf(noteId)},
new String[] { String.valueOf(noteId) },
null);
if (cursor != null) {
if (cursor!= null) {
String snippet = "";
if (cursor.moveToFirst()) {
// 获取片段
snippet = cursor.getString(0);
}
// 关闭 Cursor 以释放资源
cursor.close();
return snippet;
}
// 若未找到笔记,抛出异常
throw new IllegalArgumentException("Note is not found with id: " + noteId);
}
// 格式化片段
public static String getFormattedSnippet(String snippet) {
if (snippet != null) {
if (snippet!= null) {
// 去除首尾空格
snippet = snippet.trim();
int index = snippet.indexOf('\n');
if (index != -1) {
if (index!= -1) {
// 截取第一行
snippet = snippet.substring(0, index);
}
}
return snippet;
}
}
}

@ -18,96 +18,96 @@ package net.micode.notes.tool;
public class GTaskStringUtils {
// 表示 GTask JSON 中的 action_id 字段
public final static String GTASK_JSON_ACTION_ID = "action_id";
// 表示 GTask JSON 中的 action_list 字段
public final static String GTASK_JSON_ACTION_LIST = "action_list";
// 表示 GTask JSON 中的 action_type 字段
public final static String GTASK_JSON_ACTION_TYPE = "action_type";
// 表示 GTask JSON 中的 create 操作类型
public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create";
// 表示 GTask JSON 中的 get_all 操作类型
public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all";
// 表示 GTask JSON 中的 move 操作类型
public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move";
// 表示 GTask JSON 中的 update 操作类型
public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update";
// 表示 GTask JSON 中的 creator_id 字段
public final static String GTASK_JSON_CREATOR_ID = "creator_id";
// 表示 GTask JSON 中的 child_entity 字段
public final static String GTASK_JSON_CHILD_ENTITY = "child_entity";
// 表示 GTask JSON 中的 client_version 字段
public final static String GTASK_JSON_CLIENT_VERSION = "client_version";
// 表示 GTask JSON 中的 completed 字段
public final static String GTASK_JSON_COMPLETED = "completed";
// 表示 GTask JSON 中的 current_list_id 字段
public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id";
// 表示 GTask JSON 中的 default_list_id 字段
public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id";
// 表示 GTask JSON 中的 deleted 字段
public final static String GTASK_JSON_DELETED = "deleted";
// 表示 GTask JSON 中的 dest_list 字段
public final static String GTASK_JSON_DEST_LIST = "dest_list";
// 表示 GTask JSON 中的 dest_parent 字段
public final static String GTASK_JSON_DEST_PARENT = "dest_parent";
// 表示 GTask JSON 中的 dest_parent_type 字段
public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type";
// 表示 GTask JSON 中的 entity_delta 字段
public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta";
// 表示 GTask JSON 中的 entity_type 字段
public final static String GTASK_JSON_ENTITY_TYPE = "entity_type";
// 表示 GTask JSON 中的 get_deleted 字段
public final static String GTASK_JSON_GET_DELETED = "get_deleted";
// 表示 GTask JSON 中的 id 字段
public final static String GTASK_JSON_ID = "id";
// 表示 GTask JSON 中的 index 字段
public final static String GTASK_JSON_INDEX = "index";
// 表示 GTask JSON 中的 last_modified 字段
public final static String GTASK_JSON_LAST_MODIFIED = "last_modified";
// 表示 GTask JSON 中的 latest_sync_point 字段
public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point";
// 表示 GTask JSON 中的 list_id 字段
public final static String GTASK_JSON_LIST_ID = "list_id";
// 表示 GTask JSON 中的 lists 字段
public final static String GTASK_JSON_LISTS = "lists";
// 表示 GTask JSON 中的 name 字段
public final static String GTASK_JSON_NAME = "name";
// 表示 GTask JSON 中的 new_id 字段
public final static String GTASK_JSON_NEW_ID = "new_id";
// 表示 GTask JSON 中的 notes 字段
public final static String GTASK_JSON_NOTES = "notes";
// 表示 GTask JSON 中的 parent_id 字段
public final static String GTASK_JSON_PARENT_ID = "parent_id";
// 表示 GTask JSON 中的 prior_sibling_id 字段
public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id";
// 表示 GTask JSON 中的 results 字段
public final static String GTASK_JSON_RESULTS = "results";
// 表示 GTask JSON 中的 source_list 字段
public final static String GTASK_JSON_SOURCE_LIST = "source_list";
// 表示 GTask JSON 中的 tasks 字段
public final static String GTASK_JSON_TASKS = "tasks";
// 表示 GTask JSON 中的 type 字段
public final static String GTASK_JSON_TYPE = "type";
// 表示 GTask JSON 中的 GROUP 类型
public final static String GTASK_JSON_TYPE_GROUP = "GROUP";
// 表示 GTask JSON 中的 TASK 类型
public final static String GTASK_JSON_TYPE_TASK = "TASK";
// 表示 GTask JSON 中的 user 字段
public final static String GTASK_JSON_USER = "user";
// 表示 MIUI 文件夹的前缀
public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]";
// 表示默认文件夹名称
public final static String FOLDER_DEFAULT = "Default";
// 表示通话笔记文件夹名称
public final static String FOLDER_CALL_NOTE = "Call_Note";
// 表示元数据文件夹名称
public final static String FOLDER_META = "METADATA";
// 表示元数据的 GTask ID 头部信息
public final static String META_HEAD_GTASK_ID = "meta_gid";
// 表示元数据的笔记头部信息
public final static String META_HEAD_NOTE = "meta_note";
// 表示元数据的数据头部信息
public final static String META_HEAD_DATA = "meta_data";
// 表示元数据笔记的名称
public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE";
}

@ -24,22 +24,28 @@ import net.micode.notes.ui.NotesPreferenceActivity;
public class ResourceParser {
// 定义一些颜色常量,可能用于表示不同的颜色选项
public static final int YELLOW = 0;
public static final int BLUE = 1;
public static final int WHITE = 2;
public static final int GREEN = 3;
public static final int RED = 4;
// 默认的背景颜色,使用了上面定义的颜色常量 YELLOW
public static final int BG_DEFAULT_COLOR = YELLOW;
// 定义一些字体大小常量,可能用于表示不同的字体大小选项
public static final int TEXT_SMALL = 0;
public static final int TEXT_MEDIUM = 1;
public static final int TEXT_LARGE = 2;
public static final int TEXT_SUPER = 3;
// 默认的字体大小,使用了上面定义的字体大小常量 TEXT_MEDIUM
public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM;
// 内部类 NoteBgResources用于管理笔记背景资源
public static class NoteBgResources {
// 存储不同颜色的笔记编辑界面背景资源的数组,资源由 R.drawable 提供
private final static int [] BG_EDIT_RESOURCES = new int [] {
R.drawable.edit_yellow,
R.drawable.edit_blue,
@ -48,6 +54,7 @@ public class ResourceParser {
R.drawable.edit_red
};
// 存储不同颜色的笔记编辑界面标题背景资源的数组,资源由 R.drawable 提供
private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] {
R.drawable.edit_title_yellow,
R.drawable.edit_title_blue,
@ -56,16 +63,20 @@ public class ResourceParser {
R.drawable.edit_title_red
};
// 根据传入的颜色 ID 获取笔记的背景资源
public static int getNoteBgResource(int id) {
return BG_EDIT_RESOURCES[id];
}
// 根据传入的颜色 ID 获取笔记标题的背景资源
public static int getNoteTitleBgResource(int id) {
return BG_EDIT_TITLE_RESOURCES[id];
}
}
// 根据上下文获取默认的背景颜色 ID
public static int getDefaultBgId(Context context) {
// 检查偏好设置是否开启了背景颜色设置,如果开启,则随机选择一个背景颜色,否则使用默认颜色
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) {
return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length);
@ -74,7 +85,9 @@ public class ResourceParser {
}
}
// 内部类 NoteItemBgResources用于管理笔记项的背景资源
public static class NoteItemBgResources {
// 存储不同颜色的笔记项第一个位置的背景资源的数组,资源由 R.drawable 提供
private final static int [] BG_FIRST_RESOURCES = new int [] {
R.drawable.list_yellow_up,
R.drawable.list_blue_up,
@ -83,6 +96,7 @@ public class ResourceParser {
R.drawable.list_red_up
};
// 存储不同颜色的笔记项正常位置的背景资源的数组,资源由 R.drawable 提供
private final static int [] BG_NORMAL_RESOURCES = new int [] {
R.drawable.list_yellow_middle,
R.drawable.list_blue_middle,
@ -91,6 +105,7 @@ public class ResourceParser {
R.drawable.list_red_middle
};
// 存储不同颜色的笔记项最后一个位置的背景资源的数组,资源由 R.drawable 提供
private final static int [] BG_LAST_RESOURCES = new int [] {
R.drawable.list_yellow_down,
R.drawable.list_blue_down,
@ -99,6 +114,7 @@ public class ResourceParser {
R.drawable.list_red_down,
};
// 存储不同颜色的单个笔记项的背景资源的数组,资源由 R.drawable 提供
private final static int [] BG_SINGLE_RESOURCES = new int [] {
R.drawable.list_yellow_single,
R.drawable.list_blue_single,
@ -107,28 +123,35 @@ public class ResourceParser {
R.drawable.list_red_single
};
// 根据传入的颜色 ID 获取笔记项第一个位置的背景资源
public static int getNoteBgFirstRes(int id) {
return BG_FIRST_RESOURCES[id];
}
// 根据传入的颜色 ID 获取笔记项最后一个位置的背景资源
public static int getNoteBgLastRes(int id) {
return BG_LAST_RESOURCES[id];
}
// 根据传入的颜色 ID 获取单个笔记项的背景资源
public static int getNoteBgSingleRes(int id) {
return BG_SINGLE_RESOURCES[id];
}
// 根据传入的颜色 ID 获取笔记项正常位置的背景资源
public static int getNoteBgNormalRes(int id) {
return BG_NORMAL_RESOURCES[id];
}
// 获取文件夹的背景资源
public static int getFolderBgRes() {
return R.drawable.list_folder;
}
}
// 内部类 WidgetBgResources用于管理小部件的背景资源
public static class WidgetBgResources {
// 存储不同颜色的 2x 小部件的背景资源的数组,资源由 R.drawable 提供
private final static int [] BG_2X_RESOURCES = new int [] {
R.drawable.widget_2x_yellow,
R.drawable.widget_2x_blue,
@ -137,10 +160,12 @@ public class ResourceParser {
R.drawable.widget_2x_red,
};
// 根据传入的颜色 ID 获取 2x 小部件的背景资源
public static int getWidget2xBgResource(int id) {
return BG_2X_RESOURCES[id];
}
// 存储不同颜色的 4x 小部件的背景资源的数组,资源由 R.drawable 提供
private final static int [] BG_4X_RESOURCES = new int [] {
R.drawable.widget_4x_yellow,
R.drawable.widget_4x_blue,
@ -149,12 +174,15 @@ public class ResourceParser {
R.drawable.widget_4x_red
};
// 根据传入的颜色 ID 获取 4x 小部件的背景资源
public static int getWidget4xBgResource(int id) {
return BG_4X_RESOURCES[id];
}
}
// 内部类 TextAppearanceResources用于管理文本外观资源
public static class TextAppearanceResources {
// 存储不同字体大小的文本外观资源的数组,资源由 R.style 提供
private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] {
R.style.TextAppearanceNormal,
R.style.TextAppearanceMedium,
@ -162,11 +190,12 @@ public class ResourceParser {
R.style.TextAppearanceSuper
};
// 根据传入的字体大小 ID 获取文本外观资源
public static int getTexAppearanceResource(int id) {
/**
* HACKME: Fix bug of store the resource id in shared preference.
* The id may larger than the length of resources, in this case,
* return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
* HACKME: ID bug
* ID
* {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
*/
if (id >= TEXTAPPEARANCE_RESOURCES.length) {
return BG_DEFAULT_FONT_SIZE;
@ -174,8 +203,9 @@ public class ResourceParser {
return TEXTAPPEARANCE_RESOURCES[id];
}
// 获取文本外观资源的数量
public static int getResourcesSize() {
return TEXTAPPEARANCE_RESOURCES.length;
}
}
}
}
Loading…
Cancel
Save