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.
git-test/src/main/java/net/micode/notes/model/Note.java

431 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;
/**
* 笔记核心数据模型类,负责笔记的创建、更新和同步操作。
* <p>
* 该类是笔记应用的核心数据模型,提供了笔记的创建、更新和同步功能,
* 支持文本笔记和通话笔记两种类型并通过ContentResolver与数据库进行交互。
* </p>
*/
public class Note {
/**
* 用于存储笔记基本属性的变更值
*/
private ContentValues mNoteDiffValues;
/**
* 用于存储笔记具体数据(文本或通话数据)
*/
private NoteData mNoteData;
/**
* 日志标签
*/
private static final String TAG = Note.class.getSimpleName();
/**
* 创建新笔记并返回其ID
* <p>
* 在数据库中创建一个新的笔记记录并返回生成的笔记ID。
* 新笔记将包含默认的创建时间、修改时间、类型等信息。
* </p>
*
* @param context 应用上下文用于获取ContentResolver
* @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();
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);
values.put(NoteColumns.PARENT_ID, folderId);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
long noteId = 0;
try {
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
}
if (noteId == -1) {
throw new IllegalStateException("Wrong note id:" + noteId);
}
return noteId;
}
/**
* 构造方法,初始化笔记数据模型
*/
public Note() {
mNoteDiffValues = new ContentValues();
mNoteData = new NoteData();
}
/**
* 设置笔记的基本属性值
* <p>
* 更新笔记的基本属性,并标记为本地修改状态,同时更新修改时间。
* </p>
*
* @param key 属性键名对应NoteColumns中的字段名
* @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());
}
/**
* 设置笔记文本数据
* <p>
* 更新笔记的文本内容数据,并标记为本地修改状态。
* </p>
*
* @param key 文本数据键名对应TextNote中的字段名
* @param value 文本数据值
*/
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);
}
/**
* 设置文本数据ID
* <p>
* 设置与当前笔记关联的文本数据记录ID。
* </p>
*
* @param id 文本数据ID
*/
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}
/**
* 获取文本数据ID
* <p>
* 获取与当前笔记关联的文本数据记录ID。
* </p>
*
* @return 文本数据ID
*/
public long getTextDataId() {
return mNoteData.mTextDataId;
}
/**
* 设置通话数据ID
* <p>
* 设置与当前笔记关联的通话数据记录ID。
* </p>
*
* @param id 通话数据ID
*/
public void setCallDataId(long id) {
mNoteData.setCallDataId(id);
}
/**
* 设置通话数据
* <p>
* 更新笔记的通话内容数据,并标记为本地修改状态。
* </p>
*
* @param key 通话数据键名对应CallNote中的字段名
* @param value 通话数据值
*/
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}
/**
* 检查笔记是否在本地被修改
* <p>
* 检查笔记的基本属性或具体数据是否在本地被修改过。
* </p>
*
* @return 如果有本地修改则返回true否则返回false
*/
public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
/**
* 执行笔记同步操作,将本地修改提交到数据库
* <p>
* 将本地对笔记的修改同步到数据库中,包括基本属性和具体数据的更新。
* 如果同步失败,会记录错误日志但仍尝试完成数据更新。
* </p>
*
* @param context 应用上下文用于获取ContentResolver
* @param noteId 笔记ID
* @return 同步成功返回true失败返回false
*/
public boolean syncNote(Context context, long noteId) {
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
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
*/
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();
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
return false;
}
return true;
}
/**
* 笔记数据内部类,负责管理笔记的文本和通话数据。
* <p>
* 该内部类封装了笔记的具体内容数据,包括文本笔记和通话笔记,
* 并提供了数据的设置和持久化方法。
* </p>
*/
private class NoteData {
/**
* 文本数据ID
*/
private long mTextDataId;
/**
* 文本数据内容
*/
private ContentValues mTextDataValues;
/**
* 通话数据ID
*/
private long mCallDataId;
/**
* 通话数据内容
*/
private ContentValues mCallDataValues;
/**
* 日志标签
*/
private static final String TAG = NoteData.class.getSimpleName();
/**
* 构造方法,初始化笔记数据
*/
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
}
/**
* 检查笔记数据是否在本地被修改
* <p>
* 检查文本数据或通话数据是否在本地被修改过。
* </p>
*
* @return 如果有本地修改则返回true否则返回false
*/
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
/**
* 设置文本数据ID
* <p>
* 设置与当前笔记关联的文本数据记录ID。
* </p>
*
* @param id 文本数据ID
*/
void setTextDataId(long id) {
if(id <= 0) {
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;
}
/**
* 设置通话数据ID
* <p>
* 设置与当前笔记关联的通话数据记录ID。
* </p>
*
* @param id 通话数据ID
*/
void setCallDataId(long id) {
if (id <= 0) {
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id;
}
/**
* 设置通话数据
* <p>
* 更新笔记的通话内容数据,并标记为本地修改状态。
* </p>
*
* @param key 通话数据键名对应CallNote中的字段名
* @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());
}
/**
* 设置文本数据
* <p>
* 更新笔记的文本内容数据,并标记为本地修改状态。
* </p>
*
* @param key 文本数据键名对应TextNote中的字段名
* @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());
}
/**
* 将笔记数据推送到ContentResolver进行持久化
* <p>
* 将本地修改的文本数据或通话数据持久化到数据库中。
* 如果数据ID为0则执行插入操作否则执行更新操作。
* </p>
*
* @param context 应用上下文用于获取ContentResolver
* @param noteId 笔记ID
* @return 成功返回笔记URI失败返回null
*/
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;
}
}
}