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

417 lines
15 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";
/**
* 创建一个新的笔记ID并将新笔记添加到数据库中。
*
* @param context 应用程序上下文
* @param folderId 笔记所属文件夹的ID
* @return 新创建的笔记的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 = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
long noteId = 0;
try {
// 从URI中提取笔记的ID
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
// 记录获取笔记ID时的错误信息
Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
}
if (noteId == -1) {
// 如果笔记ID为-1抛出异常表示笔记ID错误
throw new IllegalStateException("Wrong note id:" + noteId);
}
return noteId;
}
/**
* 构造函数,初始化笔记的差异值和笔记数据对象。
*/
public Note() {
mNoteDiffValues = new ContentValues();
mNoteData = new NoteData();
}
/**
* 设置笔记的基本信息值。
*
* @param key 要设置的键
* @param value 要设置的值
*/
public void setNoteValue(String key, String value) {
// 将键值对添加到笔记差异值中
mNoteDiffValues.put(key, value);
// 标记笔记为本地修改过
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记的修改时间为当前时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
* 设置笔记的文本数据值。
*
* @param key 要设置的键
* @param value 要设置的值
*/
public void setTextData(String key, String value) {
// 调用NoteData对象的方法设置文本数据值
mNoteData.setTextData(key, value);
}
/**
* 设置笔记的文本数据ID。
*
* @param id 文本数据的ID
*/
public void setTextDataId(long id) {
// 调用NoteData对象的方法设置文本数据ID
mNoteData.setTextDataId(id);
}
/**
* 获取笔记的文本数据ID。
*
* @return 文本数据的ID
*/
public long getTextDataId() {
return mNoteData.mTextDataId;
}
/**
* 设置笔记的通话数据ID。
*
* @param id 通话数据的ID
*/
public void setCallDataId(long id) {
// 调用NoteData对象的方法设置通话数据ID
mNoteData.setCallDataId(id);
}
/**
* 设置笔记的通话数据值。
*
* @param key 要设置的键
* @param value 要设置的值
*/
public void setCallData(String key, String value) {
// 调用NoteData对象的方法设置通话数据值
mNoteData.setCallData(key, value);
}
/**
* 判断笔记是否有本地修改。
*
* @return 如果有本地修改返回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) {
if (noteId <= 0) {
// 如果笔记ID小于等于0抛出异常表示笔记ID错误
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
if (!isLocalModified()) {
// 如果笔记没有本地修改直接返回true
return true;
}
/**
* 理论上一旦数据发生变化笔记的LOCAL_MODIFIED和MODIFIED_DATE应该更新。
* 为了数据安全,即使更新笔记失败,我们也会更新笔记数据信息。
*/
if (context.getContentResolver().update(
// 构建要更新的笔记的URI
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
null) == 0) {
// 记录更新笔记时的错误信息
Log.e(TAG, "Update note error, should not happen");
// 不返回,继续执行后续操作
}
// 清空笔记差异值
mNoteDiffValues.clear();
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
// 如果笔记数据有本地修改并且将笔记数据推送到内容解析器失败返回false
return false;
}
return true;
}
/**
* 内部类,用于管理笔记的文本数据和通话数据。
*/
private class NoteData {
// 文本数据的ID
private long mTextDataId;
// 用于存储文本数据的键值对
private ContentValues mTextDataValues;
// 通话数据的ID
private long mCallDataId;
// 用于存储通话数据的键值对
private ContentValues mCallDataValues;
// 日志标签,用于在日志中标识该类的相关信息
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() {
// 检查文本数据或通话数据的ContentValues对象是否有数据
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
/**
* 设置文本数据的ID。
*
* @param id 文本数据的ID
*/
void setTextDataId(long id) {
if(id <= 0) {
// 如果文本数据ID小于等于0抛出异常表示ID错误
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;
}
/**
* 设置通话数据的ID。
*
* @param id 通话数据的ID
*/
void setCallDataId(long id) {
if (id <= 0) {
// 如果通话数据ID小于等于0抛出异常表示ID错误
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id;
}
/**
* 设置通话数据的键值对。
*
* @param key 要设置的键
* @param value 要设置的值
*/
void setCallData(String key, String value) {
// 将键值对添加到通话数据的ContentValues对象中
mCallDataValues.put(key, value);
// 标记笔记为本地修改过
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记的修改时间为当前时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
* 设置文本数据的键值对。
*
* @param key 要设置的键
* @param value 要设置的值
*/
void setTextData(String key, String value) {
// 将键值对添加到文本数据的ContentValues对象中
mTextDataValues.put(key, value);
// 标记笔记为本地修改过
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记的修改时间为当前时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
* 将笔记数据推送到内容解析器中。
*
* @param context 应用程序上下文
* @param noteId 笔记的ID
* @return 如果推送成功返回笔记的URI否则返回null
*/
Uri pushIntoContentResolver(Context context, long noteId) {
/**
* 安全检查确保笔记ID大于0。
*/
if (noteId <= 0) {
// 如果笔记ID小于等于0抛出异常表示笔记ID错误
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 创建一个ArrayList用于存储要执行的内容提供者操作
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// 内容提供者操作的构建器
ContentProviderOperation.Builder builder = null;
if(mTextDataValues.size() > 0) {
// 设置文本数据所属的笔记ID
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
if (mTextDataId == 0) {
// 如果文本数据ID为0说明是新的文本数据
// 设置文本数据的MIME类型
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
// 插入新的文本数据到数据库并获取返回的URI
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mTextDataValues);
try {
// 从URI中提取文本数据的ID并设置到mTextDataId中
setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
// 记录插入新文本数据失败的错误信息
Log.e(TAG, "Insert new text data fail with noteId" + noteId);
// 清空文本数据的ContentValues对象
mTextDataValues.clear();
return null;
}
} else {
// 如果文本数据ID不为0说明是更新已有的文本数据
// 创建一个更新操作的构建器
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mTextDataId));
// 设置要更新的值
builder.withValues(mTextDataValues);
// 将更新操作添加到操作列表中
operationList.add(builder.build());
}
// 清空文本数据的ContentValues对象
mTextDataValues.clear();
}
if(mCallDataValues.size() > 0) {
// 设置通话数据所属的笔记ID
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
if (mCallDataId == 0) {
// 如果通话数据ID为0说明是新的通话数据
// 设置通话数据的MIME类型
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
// 插入新的通话数据到数据库并获取返回的URI
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mCallDataValues);
try {
// 从URI中提取通话数据的ID并设置到mCallDataId中
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
// 记录插入新通话数据失败的错误信息
Log.e(TAG, "Insert new call data fail with noteId" + noteId);
// 清空通话数据的ContentValues对象
mCallDataValues.clear();
return null;
}
} else {
// 如果通话数据ID不为0说明是更新已有的通话数据
// 创建一个更新操作的构建器
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId));
// 设置要更新的值
builder.withValues(mCallDataValues);
// 将更新操作添加到操作列表中
operationList.add(builder.build());
}
// 清空通话数据的ContentValues对象
mCallDataValues.clear();
}
if (operationList.size() > 0) {
try {
// 批量执行操作列表中的内容提供者操作
ContentProviderResult[] results = context.getContentResolver().applyBatch(
Notes.AUTHORITY, operationList);
// 如果操作结果为空或长度为0或第一个结果为空返回null否则返回笔记的URI
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;
}
}
}