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.

376 lines
14 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 {
// 用于存储便签差异值的 ContentValues 对象
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 = 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抛出异常
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) {
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 被修改返回 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 不合法,抛出异常
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
if (!isLocalModified()) {
// 若便签未被修改,直接返回 true
return true;
}
/**
* 理论上,一旦数据发生变化,便签的 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.clear();
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
// 若便签数据被修改且同步失败,返回 false
return false;
}
return true;
}
/**
* 内部类,用于管理便签的数据,包括文本数据和通话数据。
*/
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";
/**
* 构造函数,初始化文本数据和通话数据的 ContentValues 对象。
*/
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。
* @param id 文本数据的 ID
*/
void setTextDataId(long id) {
if(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 不合法,抛出异常
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id;
}
/**
* 设置便签的通话数据。
* @param key 通话数据的属性名
* @param value 通话数据的属性值
*/
void setCallData(String key, String value) {
mCallDataValues.put(key, value);
// 标记便签为本地修改
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新便签的修改时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
* 设置便签的文本数据。
* @param key 文本数据的属性名
* @param value 文本数据的属性值
*/
void setTextData(String key, String value) {
mTextDataValues.put(key, value);
// 标记便签为本地修改
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新便签的修改时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
* 将便签数据推送到内容解析器中。
* @param context 上下文对象
* @param noteId 便签的 ID
* @return 操作成功返回 Uri否则返回 null
*/
Uri pushIntoContentResolver(Context context, long noteId) {
/**
* 安全检查
*/
if (noteId <= 0) {
// 若便签 ID 不合法,抛出异常
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 创建一个用于批量操作的 ContentProviderOperation 列表
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// ContentProviderOperation 构建器
ContentProviderOperation.Builder builder = null;
if(mTextDataValues.size() > 0) {
// 设置文本数据所属的便签 ID
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
if (mTextDataId == 0) {
// 若文本数据 ID 为 0插入新的文本数据
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mTextDataValues);
try {
// 获取插入的文本数据的 ID
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) {
// 设置通话数据所属的便签 ID
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
if (mCallDataId == 0) {
// 若通话数据 ID 为 0插入新的通话数据
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mCallDataValues);
try {
// 获取插入的通话数据的 ID
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);
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;
}
}
}