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.
software/Note.java

383 lines
16 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)
*
* 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.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";
/**
* 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();
//创建一个新的 ContentValues 对象,用于存储笔记的初始值。
long createdTime = System.currentTimeMillis();
//获取当前时间戳,作为笔记的创建时间和修改时间。
values.put(NoteColumns.CREATED_DATE, createdTime);
//将创建时间存储到 ContentValues 对象中。
values.put(NoteColumns.MODIFIED_DATE, createdTime);
//将修改时间存储到 ContentValues 对象中。
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
//将笔记类型存储到 ContentValues 对象中。
values.put(NoteColumns.LOCAL_MODIFIED, 1);
//将本地修改标志设置为 1表示笔记已被修改。
values.put(NoteColumns.PARENT_ID, folderId);
//将文件夹 ID 存储到 ContentValues 对象中。
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
//将 ContentValues 对象插入到数据库中,并返回新创建笔记的 URI。
long noteId = 0;//初始化笔记 ID 变量。
try {
//尝试从 URI 中获取笔记 ID。如果发生 NumberFormatException 异常,则记录错误日志,并将笔记 ID 设置为 0。
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
}
if (noteId == -1) {
//检查笔记 ID 是否为 -1。如果为 -1则抛出 IllegalStateException 异常。
throw new IllegalStateException("Wrong note id:" + noteId);
}
return noteId;//返回新创建的笔记 ID。
}
/*
* 构造函数,初始化笔记的差异值和笔记数据。
*/
public Note() {
//// 初始化笔记的差异值
mNoteDiffValues = new ContentValues();
// // 初始化笔记数据
mNoteData = new NoteData();
}
/*
* 设置笔记的差异值。
* @param key 键
* @param value 值
*/
public void setNoteValue(String key, String value) {
// 将键值对存储到笔记的差异值中
mNoteDiffValues.put(key, value);
// 设置本地修改标志为 1表示笔记已被修改
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 设置修改时间为当前时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/*
* 设置笔记的文本数据。
* @param key 键
* @param value 值
*/
public void setTextData(String key, String value) {
// 调用 NoteData 类的 setTextData 方法,设置文本数据
mNoteData.setTextData(key, value);
}
/*
* 设置笔记的文本数据 ID。
* @param id 文本数据 ID
*/
public void setTextDataId(long id) {
// 调用 NoteData 类的 setTextDataId 方法,设置文本数据 ID
mNoteData.setTextDataId(id);
}
/*
* 获取笔记的文本数据 ID。
* @return 文本数据 ID
*/
public long getTextDataId() {
// 返回 NoteData 类的 mTextDataId 字段
return mNoteData.mTextDataId;
}
/*
* 设置笔记的通话数据 ID。
* @param id 通话数据 ID
*/
public void setCallDataId(long id) {
// 调用 NoteData 类的 setCallDataId 方法,设置通话数据 ID
mNoteData.setCallDataId(id);
}
/*
* 设置调用数据的方法。
* 该方法接受两个参数:一个键和一个值,并将它们传递给 `mNoteData` 对象的 `setCallData` 方法。
* @param key 用于存储数据的键。
* @param value 与键关联的值。
*/
public void setCallData(String key, String value) {
//调用 `mNoteData` 对象的 `setCallData` 方法,并将 `key` 和 `value` 作为参数传递。
mNoteData.setCallData(key, value);
}
/*
* 检查是否有本地修改的方法。
* 该方法返回一个布尔值,指示是否有本地修改。如果有本地修改,则返回 true否则返回 false。
* 本地修改的判断基于两个条件:
* 1. `mNoteDiffValues` 集合的大小是否大于 0。
* 2. `mNoteData` 对象是否报告本地修改。
* @return 如果有本地修改,则返回 true否则返回 false。
*/
public boolean isLocalModified() {
// 检查 `mNoteDiffValues` 集合的大小是否大于 0或者 `mNoteData` 对象是否报告本地修改。
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
/*
* 同步笔记的方法。
* 该方法用于将本地修改的笔记数据同步到内容提供者中。
* @param context 应用程序上下文。
* @param noteId 笔记的唯一标识符。
* @return 如果同步成功,则返回 true否则返回 false。
* @throws IllegalArgumentException 如果 noteId 小于或等于 0则抛出此异常。
*/
public boolean syncNote(Context context, long noteId) {
/// 检查 noteId 是否有效,如果无效则抛出异常。
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 如果没有本地修改,则直接返回 true。
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
* 理论上,一旦数据发生变化,笔记应该在 {@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 集合。
mNoteDiffValues.clear();
// 如果 mNoteData 有本地修改,并且推送数据到内容提供者失败,则返回 false。
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
return false;
}
// 如果所有操作成功,则返回 true。
return true;
}
/*
* 笔记数据类,用于管理笔记的文本数据和通话数据。
*/
private class NoteData {
private long mTextDataId;// 文本数据的唯一标识符
private ContentValues mTextDataValues;// 文本数据的 ContentValues 对象
private long mCallDataId; // 通话数据的唯一标识符
private ContentValues mCallDataValues; // 通话数据的 ContentValues 对象
private static final String TAG = "NoteData";// 日志标签
/*
* 构造函数,初始化文本数据和通话数据的 ContentValues 对象,并将数据 ID 设置为 0。
*/
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
}
/*
* 检查是否有本地修改的方法。
* @return 如果有本地修改,则返回 true否则返回 false。
*/
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
/*
* 设置文本数据的唯一标识符。
* 该方法用于设置文本数据的唯一标识符。如果传入的 id 小于或等于 0则抛出 IllegalArgumentException 异常。
* @param id 文本数据的唯一标识符。
* @throws IllegalArgumentException 如果 id 小于或等于 0则抛出此异常。
*/
void setTextDataId(long id) {
// 检查传入的 id 是否有效,如果无效则抛出异常。
if(id <= 0) {
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;// 设置文本数据的唯一标识符。
}
/*
* 设置通话数据的唯一标识符。
* 该方法用于设置通话数据的唯一标识符。如果传入的 id 小于或等于 0则抛出 IllegalArgumentException 异常。
* @param id 通话数据的唯一标识符。
* @throws IllegalArgumentException 如果 id 小于或等于 0则抛出此异常。
*/
void setCallDataId(long id) {
// 检查传入的 id 是否有效,如果无效则抛出异常。
if (id <= 0) {
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id; // 设置通话数据的唯一标识符。
}
/*
* 设置通话数据的方法。
* 该方法用于将给定的键值对存储到通话数据的 ContentValues 对象中,并更新笔记的本地修改状态和修改日期。
* @param key 通话数据的键。
* @param value 通话数据的值。
*/
void setCallData(String key, String value) {
// 将给定的键值对存储到通话数据的 ContentValues 对象中。
mCallDataValues.put(key, value);
// 更新笔记的本地修改状态为 1表示有本地修改。
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记的修改日期为当前时间。
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/*
*设置文本数据的方法。
* 该方法用于将给定的键值对存储到文本数据的 ContentValues 对象中,并更新笔记的本地修改状态和修改日期。
* @param key 文本数据的键。
* @param value 文本数据的值。
*/
void setTextData(String key, String value) {
// 将给定的键值对存储到文本数据的 ContentValues 对象中。
mTextDataValues.put(key, value);
// 更新笔记的本地修改状态为 1表示有本地修改。
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记的修改日期为当前时间。
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/*
* 将数据推送到内容提供者的方法。
* 该方法用于将文本数据和通话数据推送到内容提供者中。如果文本数据或通话数据有修改,则将其插入或更新到内容提供者中。
* @param context 应用程序上下文。
* @param noteId 笔记的唯一标识符。
* @return 如果推送成功,则返回 Uri否则返回 null。
* @throws IllegalArgumentException 如果 noteId 小于或等于 0则抛出此异常。
*/
Uri pushIntoContentResolver(Context context, long noteId) {
// 这是方法的签名,定义了方法的访问修饰符、返回类型、方法名称和参数列表。
/**
* Check for safety
*/
//检查 noteId 是否有效,如果无效则抛出
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
//创建一个操作列表,用于批量操作。
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = null;
//如果文本数据有修改,处理文本数据。
if(mTextDataValues.size() > 0) {
//将笔记 ID 添加到文本数据的 ContentValues 对象中。
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
//如果文本数据的 ID 为 0表示是新数据插入到内容提供者中。
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;
}
} //如果文本数据的 ID 不为 0表示是已有数据更新到内容提供者中。
else {
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mTextDataId));
builder.withValues(mTextDataValues);
operationList.add(builder.build());
}
mTextDataValues.clear();// 清空文本数据的 ContentValues 对象。
}
// 如果通话数据有修改,处理通话数据。
if(mCallDataValues.size() > 0) {
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
//将笔记 ID 添加到通话数据的 ContentValues 对象中。
//如果通话数据的 ID 为 0表示是新数据插入到内容提供者中。
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;
}
} //如果通话数据的 ID 不为 0表示是已有数据更新到内容提供者中。
else {
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId));
builder.withValues(mCallDataValues);
operationList.add(builder.build());
}
mCallDataValues.clear();//清空通话数据的 ContentValues 对象。
}
//如果操作列表中有操作,执行批量操作。
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;
}
}
}