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.

352 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.

/*
* 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.data;
// 导入需要的Android和本地类
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
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;
/**
* NotesProvider 类继承自 ContentProvider
* 负责与外部交互以进行笔记数据的增删改查操作。
*/
public class NotesProvider extends ContentProvider {
// UriMatcher用于匹配不同的URI请求
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
// 静态代码块,初始化 URI 匹配器并添加各种 URI 匹配规则
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
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' 代表换行符。为了更好地展示信息,
* 我们将搜索结果中的标题和内容进行修剪以去除换行符和空格。
*/
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," // 笔记 ID
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," // 笔记 ID 作为意图额外数据
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," // 修剪后的内容作为建议文本1
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," // 修剪后的内容作为建议文本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; // 仅匹配笔记类型
@Override
public boolean onCreate() {
// 初始化数据库助手
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true; // 创建成功
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// 查询方法处理不同的URI请求并返回结果的Cursor
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);
}
} else {
// 从查询参数获取搜索字符串
searchString = uri.getQueryParameter("pattern");
}
if (TextUtils.isEmpty(searchString)) {
return null; // 如果搜索字符串为空则返回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);
}
if (c != null) {
// 设置通知URI数据变化时通知的URI
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; // 初始化ID
switch (mMatcher.match(uri)) { // 根据URI匹配不同的插入类型
case URI_NOTE:
// 插入新的笔记
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
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()); // 记录错误日志
}
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);
}
return ContentUris.withAppendedId(uri, insertedId); // 返回新插入项的URI
}
@Override
public int delete(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 "; // 除去系统文件夹
count = db.delete(TABLE.NOTE, selection, selectionArgs);
break;
case URI_NOTE_ITEM:
// 删除单个笔记
id = uri.getPathSegments().get(1); // 从URI中获取笔记ID
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:
// 删除单个数据
id = uri.getPathSegments().get(1); // 从URI中获取数据ID
count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true; // 标记为删除数据
break;
default:
// 未知的URI抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (count > 0) {
if (deleteData) {
// 如果删除了数据通知笔记URI
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; // 用于存储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.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:
// 更新单个数据
id = uri.getPathSegments().get(1); // 从URI中获取数据ID
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
updateData = true; // 标记为更新数据
break;
default:
// 未知的URI抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (count > 0) {
if (updateData) {
// 如果更新了数据通知笔记URI
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知数据URI
getContext().getContentResolver().notifyChange(uri, null);
}
return count; // 返回更新的行数
}
// 辅助方法,用于解析选择条件
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); // 如果选择条件不为空则添加 AND
}
// 辅助方法,用于增加笔记版本
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE ");
sql.append(TABLE.NOTE);
sql.append(" SET ");
sql.append(NoteColumns.VERSION);
sql.append("=" + NoteColumns.VERSION + "+1 "); // 增加版本号
if (id > 0 || !TextUtils.isEmpty(selection)) {
sql.append(" WHERE "); // 如果有ID或选择条件添加WHERE
}
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id)); // 添加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更新版本号
}
@Override
public String getType(Uri uri) {
// 返回特定URI的MIME类型这里暂时不实现
return null;
}
}