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/NotesProvider.java

377 lines
17 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)
*
* 遵循 Apache 许可证 2.0 版(“许可证”);
* 除非遵守许可证,否则不得使用此文件。
* 你可以在以下网址获取许可证副本:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 除非适用法律要求或书面同意,
* 根据许可证分发的软件按“原样”分发,
* 不附带任何明示或暗示的保证或条件。
* 请参阅许可证,了解具体的权限和限制。
*/
package net.micode.notes.data;
import android.app.SearchManager; // 用于管理搜索功能的类
import android.content.ContentProvider; // 用于在不同的应用程序之间共享数据的抽象类
import android.content.ContentUris; // 用于操作包含 ID 的 Uri 的工具类
import android.content.ContentValues; // 用于存储一组键值对,通常用于插入或更新数据库记录
import android.content.Intent; // 用于在不同组件之间进行通信的消息对象
import android.content.UriMatcher; // 用于匹配 Uri 的类
import android.database.Cursor; // 用于遍历查询结果集的类
import android.database.sqlite.SQLiteDatabase; // 用于管理 SQLite 数据库的类
import android.net.Uri; // 用于表示统一资源标识符
import android.text.TextUtils; // 用于处理文本相关操作的工具类
import android.util.Log; // 用于记录日志信息的类
import net.micode.notes.R; // 应用程序的资源类
import net.micode.notes.data.Notes.DataColumns; // 导入数据列相关的接口
import net.micode.notes.data.Notes.NoteColumns; // 导入笔记列相关的接口
import net.micode.notes.data.NotesDatabaseHelper.TABLE; // 导入数据库表名相关的接口
// 定义一个继承自 ContentProvider 的类,用于提供笔记数据的访问
public class NotesProvider extends ContentProvider {
// 用于匹配 Uri 的 UriMatcher 实例
private static final UriMatcher mMatcher;
// 数据库帮助类的实例
private NotesDatabaseHelper mHelper;
// 用于日志记录的标签
private static final String TAG = "NotesProvider";
// 定义不同 Uri 匹配的常量
private static final int URI_NOTE = 1; // 匹配查询所有笔记的 Uri
private static final int URI_NOTE_ITEM = 2; // 匹配查询单个笔记的 Uri
private static final int URI_DATA = 3; // 匹配查询所有数据的 Uri
private static final int URI_DATA_ITEM = 4; // 匹配查询单个数据的 Uri
private static final int URI_SEARCH = 5; // 匹配搜索的 Uri
private static final int URI_SEARCH_SUGGEST = 6; // 匹配搜索建议的 Uri
// 静态代码块,用于初始化 UriMatcher
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 添加匹配查询所有笔记的 Uri
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
// 添加匹配查询单个笔记的 Uri其中 # 表示匹配一个数字(笔记的 ID
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
// 添加匹配查询所有数据的 Uri
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
// 添加匹配查询单个数据的 Uri其中 # 表示匹配一个数字(数据的 ID
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM);
// 添加匹配搜索的 Uri
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH);
// 添加匹配搜索建议的 Uri其中 SearchManager.SUGGEST_URI_PATH_QUERY 是搜索建议路径的常量
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
// 添加匹配带参数的搜索建议的 Uri
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
}
/**
* x'0A' 表示 sqlite 中的 '\n' 字符。对于搜索结果中的标题和内容,
* 我们将修剪 '\n' 和空白字符,以便显示更多信息。
*/
// 定义搜索投影的 SQL 语句,用于搜索结果的列选择
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + ","
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA;
// 定义搜索笔记内容的 SQL 查询语句
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
+ " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.SNIPPET + " LIKE?"
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
// 初始化 ContentProvider 时调用的方法
@Override
public boolean onCreate() {
// 获取数据库帮助类的实例
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
// 处理查询请求的方法
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor c = null;
// 获取可读的数据库实例
SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null;
// 根据 Uri 匹配结果进行不同的查询操作
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 查询所有笔记
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);
break;
case URI_NOTE_ITEM:
// 获取 Uri 中笔记的 ID
id = uri.getPathSegments().get(1);
// 查询单个笔记
c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
case URI_DATA:
// 查询所有数据
c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null,
sortOrder);
break;
case URI_DATA_ITEM:
// 获取 Uri 中数据的 ID
id = uri.getPathSegments().get(1);
// 查询单个数据
c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
case URI_SEARCH:
case URI_SEARCH_SUGGEST:
// 搜索和搜索建议操作不允许指定排序、投影等参数
if (sortOrder!= null || projection!= null) {
throw new IllegalArgumentException(
"do not specify sortOrder, selection, selectionArgs, or projection" + "with this query");
}
String searchString = null;
// 如果是搜索建议的 Uri获取搜索字符串
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
if (uri.getPathSegments().size() > 1) {
searchString = uri.getPathSegments().get(1);
}
} else {
// 如果是搜索的 Uri从查询参数中获取搜索字符串
searchString = uri.getQueryParameter("pattern");
}
// 如果搜索字符串为空,返回 null
if (TextUtils.isEmpty(searchString)) {
return null;
}
try {
// 格式化搜索字符串,添加通配符
searchString = String.format("%%%s%%", searchString);
// 执行搜索查询
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
new String[] { searchString });
} catch (IllegalStateException ex) {
// 记录查询异常日志
Log.e(TAG, "got exception: " + ex.toString());
}
break;
default:
// 如果 Uri 不匹配任何已知模式,抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果查询结果不为空,设置通知 Uri
if (c!= null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
// 处理插入请求的方法
@Override
public Uri insert(Uri uri, ContentValues values) {
// 获取可写的数据库实例
SQLiteDatabase db = mHelper.getWritableDatabase();
long dataId = 0, noteId = 0, insertedId = 0;
// 根据 Uri 匹配结果进行不同的插入操作
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 插入笔记
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
case URI_DATA:
// 如果 ContentValues 中包含所属笔记的 ID
if (values.containsKey(DataColumns.NOTE_ID)) {
noteId = values.getAsLong(DataColumns.NOTE_ID);
} else {
// 记录错误日志,提示数据格式错误
Log.d(TAG, "Wrong data format without note id:" + values.toString());
}
// 插入数据
insertedId = dataId = db.insert(TABLE.DATA, null, values);
break;
default:
// 如果 Uri 不匹配任何已知模式,抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果插入了笔记,通知笔记 Uri 发生变化
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// 如果插入了数据,通知数据 Uri 发生变化
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
// 返回插入数据的 Uri
return ContentUris.withAppendedId(uri, insertedId);
}
// 处理删除请求的方法
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
// 获取可写的数据库实例
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false;
// 根据 Uri 匹配结果进行不同的删除操作
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 添加条件,确保只删除 ID 大于 0 的笔记
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
// 删除笔记
count = db.delete(TABLE.NOTE, selection, selectionArgs);
break;
case URI_NOTE_ITEM:
// 获取 Uri 中笔记的 ID
id = uri.getPathSegments().get(1);
// 检查 ID 是否小于等于 0系统文件夹不允许删除
long noteId = Long.valueOf(id);
if (noteId <= 0) {
break;
}
// 删除单个笔记
count = db.delete(TABLE.NOTE,
NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
break;
case URI_DATA:
// 删除数据
count = db.delete(TABLE.DATA, selection, selectionArgs);
deleteData = true;
break;
case URI_DATA_ITEM:
// 获取 Uri 中数据的 ID
id = uri.getPathSegments().get(1);
// 删除单个数据
count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true;
break;
default:
// 如果 Uri 不匹配任何已知模式,抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果删除了数据,通知笔记 Uri 发生变化
if (count > 0) {
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知 Uri 发生变化
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
// 处理更新请求的方法
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
// 获取可写的数据库实例
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean updateData = false;
// 根据 Uri 匹配结果进行不同的更新操作
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 增加笔记的版本号
increaseNoteVersion(-1, selection, selectionArgs);
// 更新笔记
count = db.update(TABLE.NOTE, values, selection, selectionArgs);
break;
case URI_NOTE_ITEM:
// 获取 Uri 中笔记的 ID
id = uri.getPathSegments().get(1);
// 增加指定笔记的版本号
increaseNoteVersion(Long.valueOf(id), selection, selectionArgs);
// 更新单个笔记
count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
break;
case URI_DATA:
// 更新数据
count = db.update(TABLE.DATA, values, selection, selectionArgs);
updateData = true;
break;
case URI_DATA_ITEM:
// 获取 Uri 中数据的 ID
id = uri.getPathSegments().get(1);
// 更新单个数据
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
updateData = true;
break;
default:
// 如果 Uri 不匹配任何已知模式,抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果更新了数据,通知笔记 Uri 发生变化
if (count > 0) {
if (updateData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知 Uri 发生变化
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
// 解析查询条件的方法
private String parseSelection(String selection) {
// 如果查询条件不为空,添加 AND 关键字并包裹查询条件
return (!TextUtils.isEmpty(selection)? " AND (" + selection + ')' : "");
}
// 增加笔记版本号的方法
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
// 创建 SQL 语句构建器
StringBuilder sql = new StringBuilder(120);
// 添加更新表名
sql.append("UPDATE ");
sql.append(TABLE.NOTE);
// 添加更新的列和操作,将版本号加 1
sql.append(" SET ");
sql.append(NoteColumns.VERSION);
sql.append("=" + NoteColumns.VERSION + "+1 ");
// 如果有指定的 ID 或查询条件,添加 WHERE 子句
if (id > 0 ||!TextUtils.isEmpty(selection)) {
sql.append(" WHERE ");
}
// 如果有指定的 ID添加 ID 条件
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
}
// 如果有查询条件,处理查询条件中的参数
if (!TextUtils.isEmpty(selection)) {
String selectString = id > 0? parseSelection(selection) : selection;
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args);
}
sql.append(selectString);
}
// 执行 SQL 语句
mHelper.getWritableDatabase().execSQL(sql.toString());
}
// 获取 Uri 对应的 MIME 类型的方法,暂时未实现
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}