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

314 lines
16 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.

/*
* 版权所有 (c) 2010-2011MiCode 开源社区 (www.micode.net)
* 根据 Apache 许可证 2.0 版本("许可证")授权;
* 除非符合许可证的规定,否则不得使用本文件。
* 您可以从以下网址获取许可证副本:
* http://www.apache.org/licenses/LICENSE-2.0
* 除非适用法律要求或书面同意,本软件按"原样"分发,
* 没有任何明示或暗示的保证或条件。
* 详见许可证中规定的权限和限制。
* 这是一份标准的Apache许可证2.0版本的开源声明)
*/
// 笔记内容提供者的实现类提供对笔记数据的CRUD操作
package net.micode.notes.data;
// 导入所需的Android类
import android.app.SearchManager; // 搜索相关功能
import android.content.ContentProvider; // 内容提供者基类
import android.content.ContentUris; // 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; // URI处理
import android.text.TextUtils; // 文本处理工具
import android.util.Log; // 日志工具
// 导入项目资源
import androidx.annotation.NonNull;
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; // 数据库表名
import java.util.Objects;
// 内容提供者实现类
public class NotesProvider extends ContentProvider {
private static final UriMatcher mMatcher; // URI匹配器用于匹配不同的URI请求
private NotesDatabaseHelper mHelper; // 数据库帮助类
private static final String TAG = "NotesProvider"; // 日志标签
// URI类型常量
private static final int URI_NOTE = 1; // 笔记表操作
private static final int URI_NOTE_ITEM = 2; // 单条笔记操作
private static final int URI_DATA = 3; // 数据表操作
private static final int URI_DATA_ITEM = 4; // 单条数据操作
private static final int URI_SEARCH = 5; // 搜索操作
private static final int URI_SEARCH_SUGGEST = 6; // 搜索建议
// 静态初始化块配置URI匹配规则
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH); // 创建URI匹配器
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); // 匹配笔记表URI
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); // 匹配单条笔记URI
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); // 匹配数据表URI
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); // 匹配单条数据URI
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); // 匹配搜索URI
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); // 匹配带参数的搜索建议URI
}
/**
* x'0A'代表SQLite中的换行符。对于搜索结果中的标题和内容
* 我们将删除换行符和空格以显示更多信息。
*/
// 搜索结果的投影(列)定义
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," // 笔记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 final 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; // 只查询普通笔记
// 内容提供者创建时调用
@Override
public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext()); // 获取数据库帮助类实例
return true;
}
// 查询方法
@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor c = null; // 查询结果游标
SQLiteDatabase db = mHelper.getReadableDatabase(); // 获取可读数据库
String id = null; // ID变量
switch (mMatcher.match(uri)) { // 根据URI类型处理不同查询
case URI_NOTE: // 查询笔记表
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);
break;
case URI_NOTE_ITEM: // 查询单条笔记
id = uri.getPathSegments().get(1); // 从URI中获取笔记ID
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: // 查询单条数据
id = uri.getPathSegments().get(1); // 从URI中获取数据ID
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; // 搜索关键字
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { // 处理搜索建议请求
if (uri.getPathSegments().size() > 1) {
searchString = uri.getPathSegments().get(1); // 从URI获取搜索词
}
} else { // 处理普通搜索请求
searchString = uri.getQueryParameter("pattern"); // 从查询参数获取搜索模式
}
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:
throw new IllegalArgumentException("Unknown URI " + uri); // 未知URI异常
}
if (c != null) {
c.setNotificationUri(Objects.requireNonNull(getContext()).getContentResolver(), uri); // 设置通知URI
}
return c; // 返回查询结果
}
// 插入方法
@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写数据库
long dataId = 0, noteId = 0, insertedId = 0; // ID变量
insertedId = switch (mMatcher.match(uri)) { // 根据URI类型处理不同插入
case URI_NOTE -> // 插入笔记
noteId = db.insert(TABLE.NOTE, null, values);
case URI_DATA -> {
if (values.containsKey(DataColumns.NOTE_ID)) { // 检查是否包含笔记ID
noteId = values.getAsLong(DataColumns.NOTE_ID);
} else {
Log.d(TAG, "Wrong data format without note id:" + values.toString());
}
yield dataId = db.insert(TABLE.DATA, null, values);
}
default -> throw new IllegalArgumentException("Unknown URI " + uri); // 未知URI异常
};
// 通知笔记URI变更
if (noteId > 0) {
Objects.requireNonNull(getContext()).getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// 通知数据URI变更
if (dataId > 0) {
Objects.requireNonNull(getContext()).getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
return ContentUris.withAppendedId(uri, insertedId); // 返回插入数据的URI
}
// 删除方法
@Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
int count = 0; // 删除计数
String id = null; // ID变量
SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写数据库
boolean deleteData = false; // 数据删除标志
switch (mMatcher.match(uri)) { // 根据URI类型处理不同删除
case URI_NOTE: // 删除笔记
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; // 只删除ID大于0的笔记
count = db.delete(TABLE.NOTE, selection, selectionArgs);
break;
case URI_NOTE_ITEM: // 删除单条笔记
id = uri.getPathSegments().get(1); // 从URI获取笔记ID
/*
* 小于0的ID是系统文件夹不允许删除
*/
long noteId = Long.parseLong(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: // 删除单条数据
id = uri.getPathSegments().get(1); // 从URI获取数据ID
count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true; // 标记为数据删除
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri); // 未知URI异常
}
if (count > 0) { // 如果有数据被删除
if (deleteData) { // 如果是数据删除通知笔记URI变更
Objects.requireNonNull(getContext()).getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
Objects.requireNonNull(getContext()).getContentResolver().notifyChange(uri, null); // 通知当前URI变更
}
return count; // 返回删除数量
}
// 更新方法
@Override
public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0; // 更新计数
String id = null; // ID变量
SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写数据库
boolean updateData = false; // 数据更新标志
switch (mMatcher.match(uri)) { // 根据URI类型处理不同更新
case URI_NOTE: // 更新笔记表
increaseNoteVersion(-1, selection, selectionArgs); // 增加笔记版本
count = db.update(TABLE.NOTE, values, selection, selectionArgs);
break;
case URI_NOTE_ITEM: // 更新单条笔记
id = uri.getPathSegments().get(1); // 从URI获取笔记ID
increaseNoteVersion(Long.parseLong(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: // 更新单条数据
id = uri.getPathSegments().get(1); // 从URI获取数据ID
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
updateData = true; // 标记为数据更新
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri); // 未知URI异常
}
if (count > 0) { // 如果有数据被更新
if (updateData) { // 如果是数据更新通知笔记URI变更
Objects.requireNonNull(getContext()).getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
Objects.requireNonNull(getContext()).getContentResolver().notifyChange(uri, null); // 通知当前URI变更
}
return count; // 返回更新数量
}
// 解析选择条件添加AND连接
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
// 增加笔记版本号
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
StringBuilder sql = new StringBuilder(120); // SQL语句构建器
sql.append("UPDATE ");
sql.append(TABLE.NOTE);
sql.append(" SET ");
sql.append(NoteColumns.VERSION);
sql.append("=" + NoteColumns.VERSION + "+1 "); // 版本号+1
if (id > 0 || !TextUtils.isEmpty(selection)) { // 有条件时添加WHERE
sql.append(" WHERE ");
}
if (id > 0) { // 指定ID的条件
sql.append(NoteColumns.ID + "=").append(id);
}
if (!TextUtils.isEmpty(selection)) { // 处理其他条件
String selectString = id > 0 ? parseSelection(selection) : selection;
for (String args : selectionArgs) { // 替换参数占位符
selectString = selectString.replaceFirst("\\?", args);
}
sql.append(selectString);
}
mHelper.getWritableDatabase().execSQL(sql.toString()); // 执行SQL
}
// 获取URI类型未实现
@Override
public String getType(@NonNull Uri uri) {
// TODO Auto-generated method stub
return null;
}
}