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

547 lines
20 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.
*/
// 版权声明2010 - 2011 年MiCode 开源社区www.micode.net
// 在 Apache License 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;
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;
// 导入相关的包和类。
public class NotesProvider extends ContentProvider {
// 定义公共类 NotesProvider继承自 ContentProvider。
private static final UriMatcher mMatcher;
// 定义静态的 UriMatcher 对象 mMatcher。
private NotesDatabaseHelper mHelper;
// 定义 NotesDatabaseHelper 对象 mHelper。
private static final String TAG = "NotesProvider";
// 定义静态常量 TAG值为“NotesProvider”。
private static final int URI_NOTE = 1;
// 定义常量 URI_NOTE值为 1。
private static final int URI_NOTE_ITEM = 2;
// 定义常量 URI_NOTE_ITEM值为 2。
private static final int URI_DATA = 3;
// 定义常量 URI_DATA值为 3。
private static final int URI_DATA_ITEM = 4;
// 定义常量 URI_DATA_ITEM值为 4。
private static final int URI_SEARCH = 5;
// 定义常量 URI_SEARCH值为 5。
private static final int URI_SEARCH_SUGGEST = 6;
// 定义常量 URI_SEARCH_SUGGEST值为 6。
static {
// 静态初始化块。
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 创建一个新的 UriMatcher 对象,并设置初始匹配结果为 UriMatcher.NO_MATCH。
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
// 将 Uri “content://micode_notes/note” 与常量 URI_NOTE 关联。
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
// 将 Uri “content://micode_notes/note/[ID]” 与常量 URI_NOTE_ITEM 关联。
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
// 将 Uri “content://micode_notes/data” 与常量 URI_DATA 关联。
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM);
// 将 Uri “content://micode_notes/data/[ID]” 与常量 URI_DATA_ITEM 关联。
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH);
// 将 Uri “content://micode_notes/search” 与常量 URI_SEARCH 关联。
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
// 将 Uri “content://micode_notes/search_query”根据 SearchManager.SUGGEST_URI_PATH_QUERY与常量 URI_SEARCH_SUGGEST 关联。
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
// 将 Uri “content://micode_notes/search_query/[SEARCH_STRING]”(根据 SearchManager.SUGGEST_URI_PATH_QUERY 和通配符)与常量 URI_SEARCH_SUGGEST 关联。
}
/**
* x'0A' represents the '\n' character in sqlite. For title and content in the search result,
* we will trim '\n' and white space in order to show more information.
*/
// 注释说明以下字符串常量的用途。
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;
// 定义常量 NOTES_SEARCH_PROJECTION用于搜索结果中的投影列。
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;
// 定义常量 NOTES_SNIPPET_SEARCH_QUERY用于搜索笔记片段的查询语句。
@Override
public boolean onCreate() {
// 重写 onCreate 方法。
mHelper = NotesDatabaseHelper.getInstance(getContext());
// 获取 NotesDatabaseHelper 的实例。
return true;
// 返回 true表示创建成功。
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// 重写 query 方法,用于查询数据。
Cursor c = null;
// 定义游标对象 c并初始化为 null。
SQLiteDatabase db = mHelper.getReadableDatabase();
// 获取可读的 SQLiteDatabase 对象。
String id = null;
// 定义字符串 id初始化为 null。
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);
// 获取笔记的 ID。
c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
// 根据 ID 查询单个笔记。
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);
// 获取数据的 ID。
c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
// 根据 ID 查询单个数据。
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;
// 定义字符串 searchString初始化为 null。
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
// 如果是搜索建议的 Uri。
if (uri.getPathSegments().size() > 1) {
// 如果路径段数量大于 1。
searchString = uri.getPathSegments().get(1);
// 获取搜索字符串。
}
} else {
// 否则是普通搜索的 Uri。
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:
throw new IllegalArgumentException("Unknown URI " + uri);
// 如果 Uri 不匹配任何已知的情况,抛出异常。
}
if (c!= null) {
// 如果游标不为 null。
c.setNotificationUri(getContext().getContentResolver(), uri);
// 设置通知 Uri。
}
return c;
// 返回游标。
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// 重写 insert 方法,用于插入数据。
SQLiteDatabase db = mHelper.getWritableDatabase();
// 获取可写的 SQLiteDatabase 对象。
long dataId = 0, noteId = 0, insertedId = 0;
// 定义长整型变量 dataId、noteId 和 insertedId并初始化为 0。
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)) {
// 如果 ContentValues 中包含 NOTE_ID。
noteId = values.getAsLong(DataColumns.NOTE_ID);
// 获取笔记 ID。
} else {
// 否则。
Log.d(TAG, "Wrong data format without note id:" + values.toString());
// 记录错误日志。
}
insertedId = dataId = db.insert(TABLE.DATA, null, values);
// 插入数据。
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
// 如果 Uri 不匹配任何已知的情况,抛出异常。
}
// Notify the note uri
if (noteId > 0) {
// 如果笔记 ID 大于 0。
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
// 通知笔记 Uri 的更改。
}
// Notify the data uri
if (dataId > 0) {
// 如果数据 ID 大于 0。
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
// 通知数据 Uri 的更改。
}
return ContentUris.withAppendedId(uri, insertedId);
// 返回插入后的 Uri。
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 重写 delete 方法,用于删除数据。
int count = 0;
// 定义整型变量 count初始化为 0。
String id = null;
// 定义字符串 id初始化为 null。
SQLiteDatabase db = mHelper.getWritableDatabase();
// 获取可写的 SQLiteDatabase 对象。
boolean deleteData = false;
// 定义布尔变量 deleteData初始化为 false。
switch (mMatcher.match(uri)) {
// 根据 Uri 匹配结果进行分支处理。
case URI_NOTE:
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
count = db.delete(TABLE.NOTE, selection, selectionArgs);
// 删除笔记,添加条件 ID 大于 0。
break;
case URI_NOTE_ITEM:
id = uri.getPathSegments().get(1);
// 获取笔记的 ID。
/**
* ID that smaller than 0 is system folder which is not allowed to
* trash
*/
// 注释说明小于 0 的 ID 是系统文件夹,不允许删除。
long noteId = Long.valueOf(id);
// 将 ID 转换为长整型。
if (noteId <= 0) {
// 如果笔记 ID 小于等于 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;
// 删除数据,设置 deleteData 为 true。
break;
case URI_DATA_ITEM:
id = uri.getPathSegments().get(1);
// 获取数据的 ID。
count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true;
// 删除单个数据,设置 deleteData 为 true。
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
// 如果 Uri 不匹配任何已知的情况,抛出异常。
}
if (count > 0) {
// 如果删除的数量大于 0。
if (deleteData) {
// 如果删除的是数据。
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
// 通知笔记 Uri 的更改。
}
getContext().getContentResolver().notifyChange(uri, null);
// 通知当前 Uri 的更改。
}
return count;
// 返回删除的数量。
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// 重写 update 方法,用于更新数据。
int count = 0;
// 定义整型变量 count初始化为 0。
String id = null;
// 定义字符串 id初始化为 null。
SQLiteDatabase db = mHelper.getWritableDatabase();
// 获取可写的 SQLiteDatabase 对象。
boolean updateData = false;
// 定义布尔变量 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);
// 获取笔记的 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;
// 更新数据,设置 updateData 为 true。
break;
case URI_DATA_ITEM:
id = uri.getPathSegments().get(1);
// 获取数据的 ID。
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
updateData = true;
// 更新单个数据,设置 updateData 为 true。
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
// 如果 Uri 不匹配任何已知的情况,抛出
}
if (count > 0) {
// 如果更新操作影响的记录数大于 0。
if (updateData) {
// 如果更新了数据记录。
// 如果更新了数据记录,则通知监听器。
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
// 获取上下文环境通过内容解析器通知与笔记内容相关的监听器Notes.CONTENT_NOTE_URI数据发生了变化第二个参数为 null 表示没有额外的通知数据。
}
// 通知监听器指定的 URI 发生了变化。
getContext().getContentResolver().notifyChange(uri, null);
// 获取上下文环境,通过内容解析器通知本次更新操作对应的 URIuri的数据发生了变化第二个参数为 null 表示没有额外的通知数据。
}
return count;
// 返回更新操作所影响的记录数。
}
// 解析选择条件的方法。
private String parseSelection(String selection) {
// 定义一个私有方法,接收一个选择条件字符串参数。
return (!TextUtils.isEmpty(selection)? " AND (" + selection + ')' : "");
// 如果选择条件字符串不为空,返回在其前后加上“ AND (”和“)”的字符串;如果为空,返回空字符串。
}
// 增加笔记版本号的方法。
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
// 定义一个私有方法,接收笔记的 ID、选择条件字符串和选择条件参数数组。
StringBuilder sql = new StringBuilder(120);
// 创建一个 StringBuilder 对象,用于构建 SQL 语句,初始容量为 120。
sql.append("UPDATE ");
// 在 StringBuilder 中添加“UPDATE ”。
sql.append(TABLE.NOTE);
// 添加表名 TABLE.NOTE。
sql.append(" SET ");
// 添加“ SET ”。
sql.append(NoteColumns.VERSION);
// 添加版本号列名 NoteColumns.VERSION。
sql.append("=" + NoteColumns.VERSION + "+1 ");
// 添加版本号设置的 SQL 片段,将版本号设置为当前版本号加 1。
if (id > 0 ||!TextUtils.isEmpty(selection)) {
// 如果传入的 ID 大于 0 或者选择条件字符串不为空。
sql.append(" WHERE ");
// 在 StringBuilder 中添加“ WHERE ”。
}
if (id > 0) {
// 如果传入的 ID 大于 0。
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
// 添加笔记 ID 的条件到 StringBuilder 中。
}
if (!TextUtils.isEmpty(selection)) {
// 如果选择条件字符串不为空。
String selectString = id > 0? parseSelection(selection) : selection;
// 如果 ID 大于 0调用 parseSelection 方法处理选择条件字符串;否则直接使用选择条件字符串。
for (String args : selectionArgs) {
// 遍历选择条件参数数组。
selectString = selectString.replaceFirst("\\?", args);
// 将选择条件字符串中的第一个占位符替换为当前参数值。
}
sql.append(selectString);
// 将处理后的选择条件字符串添加到 StringBuilder 中。
}
mHelper.getWritableDatabase().execSQL(sql.toString());
// 使用数据库帮助类 mHelper 的可写数据库执行构建好的 SQL 语句。
}
// 内容提供器的 getType 方法,用于返回指定 URI 的 MIME 类型。
@Override
public String getType(Uri uri) {
// 重写内容提供器的 getType 方法,接收一个 URI 参数。
// TODO Auto-generated method stub
// 这里是一个待实现的方法注释。
return null;
// 返回 null表示当前未实现该方法。
}
}