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

296 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010 - 2011, The MiCode Open Source Community (www.micode.net)
*
* 遵循 Apache 许可证 2.0 版(“许可证”);
* 除非遵守许可证,否则不得使用此文件。
* 你可以在以下网址获取许可证副本:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 除非适用法律要求或书面同意,
* 根据许可证分发的软件按“原样”分发,
* 不附带任何明示或暗示的保证或条件。
* 请参阅许可证,了解具体的权限和限制。
*/
package net.micode.notes.model;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.net.Uri;
import android.os.RemoteException;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import java.util.ArrayList;
// Note 类表示一个笔记,用于管理笔记的基本信息和数据操作,包括创建新笔记、设置笔记内容、同步笔记等功能
public class Note {
// 用于存储笔记的差异值(例如,在本地修改后与原始数据的差异)
private ContentValues mNoteDiffValues;
// 包含笔记的详细数据,如文本数据和通话数据
private NoteData mNoteData;
// 用于日志记录的标签,使用类的简单名称
private static final String TAG = "Note";
// 同步锁,确保在多线程环境下创建新笔记 ID 的操作安全
public static synchronized long getNewNoteId(Context context, long folderId) {
// 创建一个新的 ContentValues 对象,用于存储新笔记的初始数据
ContentValues values = new ContentValues();
// 获取当前系统时间作为创建时间和修改时间
long createdTime = System.currentTimeMillis();
// 设置笔记的创建时间
values.put(NoteColumns.CREATED_DATE, createdTime);
// 设置笔记的修改时间
values.put(NoteColumns.MODIFIED_DATE, createdTime);
// 设置笔记的类型为普通笔记
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
// 标记笔记在本地已修改
values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 设置笔记所属的文件夹 ID
values.put(NoteColumns.PARENT_ID, folderId);
// 将新笔记数据插入到内容提供者的指定 URI 中,并获取返回的 Uri
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
long noteId = 0;
try {
// 从返回的 Uri 中提取笔记 ID
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
}
// 如果获取的笔记 ID 为 -1则抛出异常
if (noteId == -1) {
throw new IllegalStateException("Wrong note id:" + noteId);
}
return noteId;
}
// 笔记类的构造函数,初始化笔记的差异值和数据对象
public Note() {
mNoteDiffValues = new ContentValues();
mNoteData = new NoteData();
}
// 设置笔记的某个属性值,同时标记笔记为本地修改,并更新修改时间
public void setNoteValue(String key, String value) {
mNoteDiffValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 设置笔记的文本数据,同时标记笔记为本地修改,并更新修改时间
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);
}
// 设置笔记的文本数据 ID
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}
// 获取笔记的文本数据 ID
public long getTextDataId() {
return mNoteData.mTextDataId;
}
// 设置笔记的通话数据 ID
public void setCallDataId(long id) {
mNoteData.setCallDataId(id);
}
// 设置笔记的通话数据,同时标记笔记为本地修改,并更新修改时间
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}
// 检查笔记是否在本地被修改,通过检查差异值和数据对象是否有变化来判断
public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
// 同步笔记数据到存储介质(如数据库)
public boolean syncNote(Context context, long noteId) {
// 检查笔记 ID 是否有效,若无效则抛出异常
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 如果笔记没有本地修改,直接返回 true表示无需同步
if (!isLocalModified()) {
return true;
}
/**
* 理论上,一旦数据发生变化,笔记应该在 {@link NoteColumns#LOCAL_MODIFIED} 和
* {@link 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.clear();
// 如果笔记数据有本地修改,并且将数据推送到内容提供者失败,则返回 false表示同步失败
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
return false;
}
return true;
}
// 内部类 NoteData用于管理笔记的详细数据文本数据和通话数据
private class NoteData {
// 文本数据 ID
private long mTextDataId;
// 存储文本数据的 ContentValues 对象
private ContentValues mTextDataValues;
// 通话数据 ID
private long mCallDataId;
// 存储通话数据的 ContentValues 对象
private ContentValues mCallDataValues;
// 用于日志记录的标签,使用类的简单名称
private static final String TAG = "NoteData";
// 构造函数,初始化文本数据和通话数据的相关属性
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
}
// 检查笔记数据是否在本地被修改,通过检查文本数据和通话数据的 ContentValues 对象是否有变化来判断
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
// 设置文本数据 ID检查 ID 是否有效,若无效则抛出异常
void setTextDataId(long id) {
if (id <= 0) {
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;
}
// 设置通话数据 ID检查 ID 是否有效,若无效则抛出异常
void setCallDataId(long id) {
if (id <= 0) {
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id;
}
// 设置通话数据,同时标记笔记为本地修改,并更新修改时间
void setCallData(String key, String value) {
mCallDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 设置文本数据,同时标记笔记为本地修改,并更新修改时间
void setTextData(String key, String value) {
mTextDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 将笔记数据推送到内容提供者中,如果是新数据则插入,否则更新
Uri pushIntoContentResolver(Context context, long noteId) {
/**
* 检查笔记 ID 是否有效,若无效则抛出异常
*/
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);
// 如果文本数据 ID 为 0表示是新数据插入到内容提供者中并获取插入后的 ID
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 {
// 如果文本数据 ID 不为 0表示是已存在的数据构建更新操作
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);
// 如果通话数据 ID 为 0表示是新数据插入到内容提供者中并获取插入后的 ID
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 {
// 如果通话数据 ID 不为 0表示是已存在的数据构建更新操作
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);
// 根据操作结果返回相应的 Uri如果操作失败则返回 null
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;
}
}
}