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

414 lines
19 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;
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 {
// 定义UriMatcher对象
private static final UriMatcher mMatcher;
// 定义NotesDatabaseHelper对象
private NotesDatabaseHelper mHelper;
// 定义TAG常量
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;
// 静态代码块初始化UriMatcher对象
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 添加URI匹配规则
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
// 添加URI匹配规则
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); // 添加匹配规则,匹配以"note/"开头的URI后面跟一个数字匹配结果为URI_NOTE_ITEM
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); // 添加匹配规则,匹配以"data/"开头的URI匹配结果为URI_DATA
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); // 添加匹配规则,匹配以"data/"开头的URI后面跟一个数字匹配结果为URI_DATA_ITEM
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); // 添加匹配规则,匹配以"search/"开头的URI匹配结果为URI_SEARCH
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); // 添加匹配规则匹配以SearchManager.SUGGEST_URI_PATH_QUERY开头的URI匹配结果为URI_SEARCH_SUGGEST
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); // 添加匹配规则匹配以SearchManager.SUGGEST_URI_PATH_QUERY开头的URI后面跟任意字符匹配结果为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.
*/
// 定义搜索结果的投影包括ID、文本1、文本2、图标1、意图动作和数据类型
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," // 将NoteColumns.ID作为SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," // 将NoteColumns.SNIPPET中的换行符替换为空并作为SearchManager.SUGGEST_COLUMN_TEXT_1
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," // 将NoteColumns.SNIPPET中的换行符替换为空并作为SearchManager.SUGGEST_COLUMN_TEXT_2
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," // 将R.drawable.search_result作为SearchManager.SUGGEST_COLUMN_ICON_1
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," // 将Intent.ACTION_VIEW作为SearchManager.SUGGEST_COLUMN_INTENT_ACTION
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; // 将Notes.TextNote.CONTENT_TYPE作为SearchManager.SUGGEST_COLUMN_INTENT_DATA
// 定义一个静态字符串变量,用于存储查询语句
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
// 查询Note表中的数据
+ " FROM " + TABLE.NOTE
// 查询条件NoteColumns.SNIPPET字段中包含指定字符串
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
// 查询条件NoteColumns.PARENT_ID字段不等于Notes.ID_TRASH_FOLER
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER
// 查询条件NoteColumns.TYPE字段等于Notes.TYPE_NOTE
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
@Override
public boolean onCreate() {
// 获取NotesDatabaseHelper的实例
mHelper = NotesDatabaseHelper.getInstance(getContext());
// 返回true表示数据库创建成功
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// 根据传入的uri查询数据库中的数据
Cursor c = null;
// 获取可读的数据库
SQLiteDatabase db = mHelper.getReadableDatabase();
// 获取uri中的id
String id = null;
// 根据uri匹配查询类型
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 查询note表中的数据
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);
break;
// 查询URI_NOTE_ITEM类型的URI
case URI_NOTE_ITEM:
// 获取URI的路径段获取第二个路径段作为id
id = uri.getPathSegments().get(1);
// 查询NOTE表根据id和selection条件查询返回结果集
c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
// 查询URI_DATA类型的URI
case URI_DATA:
// 查询DATA表根据selection条件查询返回结果集
c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null,
sortOrder);
break;
// 查询URI_DATA_ITEM类型的URI
case URI_DATA_ITEM:
// 获取URI的路径段获取第二个路径段作为id
id = uri.getPathSegments().get(1);
// 查询DATA表根据id和selection条件查询返回结果集
c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
// 如果URI是URI_SEARCH或URI_SEARCH_SUGGEST
case URI_SEARCH:
case URI_SEARCH_SUGGEST:
// 如果sortOrder或projection不为空
if (sortOrder != null || projection != null) {
// 抛出异常不允许指定sortOrder、selection、selectionArgs或projection
throw new IllegalArgumentException(
"do not specify sortOrder, selection, selectionArgs, or projection" + "with this query");
}
// 定义一个字符串变量,用于存储搜索字符串
String searchString = null;
// 如果匹配到的URI是URI_SEARCH_SUGGEST
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
// 如果URI的路径段大于1
if (uri.getPathSegments().size() > 1) {
// 将路径段的第二个元素赋值给searchString
searchString = uri.getPathSegments().get(1);
}
} else {
// 否则将URI的查询参数中名为"pattern"的值赋值给searchString
searchString = uri.getQueryParameter("pattern");
}
// 判断搜索字符串是否为空
if (TextUtils.isEmpty(searchString)) {
// 如果为空则返回null
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());
}
// 结束switch语句
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果c不为空则设置通知URI
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
// 返回c
return c;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// 获取可写的数据库
SQLiteDatabase db = mHelper.getWritableDatabase();
// 定义变量用于存储插入的数据ID
long dataId = 0, noteId = 0, insertedId = 0;
// 根据传入的URI匹配对应的操作
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 插入数据并返回插入的数据ID
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
case URI_DATA:
// 如果values中包含DataColumns.NOTE_ID则获取其值并赋给noteId
if (values.containsKey(DataColumns.NOTE_ID)) {
noteId = values.getAsLong(DataColumns.NOTE_ID);
} else {
// 否则,输出错误日志
Log.d(TAG, "Wrong data format without note id:" + values.toString());
}
// 将values插入到TABLE.DATA表中并获取插入的id
insertedId = dataId = db.insert(TABLE.DATA, null, values);
break;
default:
// 如果uri不匹配则抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify the note uri
// 如果noteId大于0则通知ContentResolver有数据发生变化
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// Notify the data uri
// 如果dataId大于0则通知ContentResolver数据已更改
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
// 返回插入的ID
return ContentUris.withAppendedId(uri, insertedId);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 删除数据
int count = 0;
// 获取要删除的数据的id
String id = null;
// 获取可写的数据库
SQLiteDatabase db = mHelper.getWritableDatabase();
// 标记是否删除数据
boolean deleteData = false;
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 that smaller than 0 is system folder which is not allowed to
* trash
*/
// 将id转换为long类型
long noteId = Long.valueOf(id);
// 如果noteId小于等于0则跳出循环
if (noteId <= 0) {
break;
}
// 删除指定ID的NOTE表中的数据
count = db.delete(TABLE.NOTE,
NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
break;
// 删除指定URI的DATA表中的数据
case URI_DATA:
count = db.delete(TABLE.DATA, selection, selectionArgs);
deleteData = true;
break;
case URI_DATA_ITEM:
// 获取URI路径中的ID
id = uri.getPathSegments().get(1);
// 删除指定ID的数据
count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
// 标记删除数据
deleteData = true;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果删除数据则通知ContentResolver数据已更改
if (count > 0) {
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知ContentResolver数据已更改
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
@Override
// 重写update方法用于更新数据库中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// 定义一个计数器,用于记录更新的数据条数
int count = 0;
// 定义一个字符串用于存储要更新的数据的id
String id = null;
// 获取可写的数据库
SQLiteDatabase db = mHelper.getWritableDatabase();
// 定义一个布尔值,用于判断是否更新了数据
boolean updateData = false;
// 根据uri匹配的结果执行相应的操作
switch (mMatcher.match(uri)) {
// 如果uri匹配的是URI_NOTE则执行以下操作
case URI_NOTE:
// 将note的版本号减1
increaseNoteVersion(-1, selection, selectionArgs);
// 更新数据库中的note表将values中的数据更新到满足selection和selectionArgs的记录中
count = db.update(TABLE.NOTE, values, selection, selectionArgs);
break;
// 根据URI_NOTE_ITEM的值获取路径中的第二个参数作为id
case URI_NOTE_ITEM:
id = uri.getPathSegments().get(1);
// 根据idselection和selectionArgs增加Note的版本号
increaseNoteVersion(Long.valueOf(id), selection, selectionArgs);
// 根据idvaluesselection和selectionArgs更新Note表中的数据并返回更新的行数
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
id = uri.getPathSegments().get(1);
// 更新数据表中的数据
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
// 标记更新数据
updateData = true;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果count大于0则通知ContentResolver更新数据
if (count > 0) {
// 如果updateData为true则通知ContentResolver更新Notes.CONTENT_NOTE_URI
if (updateData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知ContentResolver更新uri
getContext().getContentResolver().notifyChange(uri, null);
}
// 返回count
return count;
}
// 解析selection字符串
private String parseSelection(String selection) {
// 如果selection不为空则返回" AND (" + selection + ')',否则返回空字符串
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
// 创建一个StringBuilder对象用于拼接SQL语句
StringBuilder sql = new StringBuilder(120);
// 拼接UPDATE语句
sql.append("UPDATE ");
// 拼接表名
sql.append(TABLE.NOTE);
// 拼接SET语句
sql.append(" SET ");
// 拼接版本号字段
sql.append(NoteColumns.VERSION);
// 拼接版本号增加1的语句
sql.append("=" + NoteColumns.VERSION + "+1 ");
// 如果id大于0或者selection不为空则添加WHERE关键字
if (id > 0 || !TextUtils.isEmpty(selection)) {
sql.append(" WHERE ");
}
// 如果id大于0则添加id等于id的语句
if (id > 0) {
// 拼接SQL语句将id添加到NoteColumns.ID中
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
}
// 如果selection不为空则解析selection并添加到sql语句中
if (!TextUtils.isEmpty(selection)) {
// 根据id的值选择不同的selection字符串
String selectString = id > 0 ? parseSelection(selection) : selection;
// 遍历selectionArgs数组将每个元素替换selectString中的第一个问号
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args);
}
// 将替换后的selectString添加到sql中
sql.append(selectString);
}
mHelper.getWritableDatabase().execSQL(sql.toString());
}
// 根据Uri返回MIME类型
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}