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_notes_reading/src/notes/model/Note.java

298 lines
12 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;
/**
* 笔记数据模型类,负责的底层数据操作的模型类,
* 封装了笔记的基础数据(文本、通话记录)和核心属性(修改时间等)
* 与ContentProvider交互实现笔记数据的创建、更新、同步等底层逻辑
* 仅处理数据存储逻辑不包含UI交互或业务判断,不包含业务逻辑
*/
public class Note {
private ContentValues mNoteDiffValues; //存储Note属性变化修改时间等
private NoteData mNoteData; //封装Note具体数据文本内容、通话记录等
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();
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;
}
//初始化Note数据容器存储属性变化和具体数据
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());
}
//设置Note的文本数据如笔记内容
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);
}
//设置文本数据的ID用于更新已有文本数据时定位记录
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}
public long getTextDataId() {
return mNoteData.mTextDataId;
}
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();
}
//同步Note数据到数据库
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();
//同步具体数据(文本/通话记录若数据有修改且同步失败返回false
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
return false;
}
return true;
}
/**内部类
* 管理笔记的具体数据(文本内容、通话记录)
* 封装文本和通话数据的存储、修改、同步逻辑与Note类协同工作
*/
private class NoteData {
private long mTextDataId;// 文本数据在数据库中的ID0表示未创建
private ContentValues mTextDataValues; // 存储文本数据的变化
private long mCallDataId; // 通话记录数据在数据库中的ID0表示未创建
private ContentValues mCallDataValues; // 存储通话数据的变化(如号码更新)
private static final String TAG = "NoteData";
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
}
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
void setTextDataId(long id) {
if(id <= 0) {
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = 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());
}
/**
* 将文本/通话数据的变化同步到数据库
* 若数据未创建ID=0则插入新记录若已创建ID>0则更新记录
* @param context 上下文
* @param noteId 所属笔记ID关联数据到具体笔记
* @return 同步成功返回笔记Uri失败返回null
*/
Uri pushIntoContentResolver(Context context, long noteId) {
/**
* Check for safety
*/
// 校验笔记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);
//文本数据未创建
if (mTextDataId == 0) {
// 插入数据到ContentProvider获取返回的Uri
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mTextDataValues);
try {
// 从Uri解析新插入的文本数据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对应的Uri
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 {
// 应用批量操作到ContentProvider
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) {
// 远程异常如ContentProvider断开连接
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; // 无批量操作需执行(如仅插入了新数据,未更新)
}
}
}