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

457 lines
18 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;
/**
* 笔记内容提供者实现了ContentProvider接口
* 提供对笔记和数据的CRUD操作使用UriMatcher处理不同的URI请求
* 是应用与数据库之间的桥梁被其他模块通过ContentResolver调用
*/
public class NotesProvider extends ContentProvider {
/**
* Uri匹配器用于匹配不同的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;
/**
* 静态初始化块初始化UriMatcher
*/
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 添加URI匹配规则
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); // content://micode_notes/note
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); // content://micode_notes/note/1
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); // content://micode_notes/data
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); // content://micode_notes/data/1
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); // content://micode_notes/search
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); // 搜索建议
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); // 带参数的搜索建议
}
/**
* 搜索结果投影定义:替换换行符并修剪空白,确保搜索结果显示完整信息
*/
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;
/**
* 笔记内容搜索查询语句 - 搜索标题和内容通过JOIN连接NOTE和DATA表
*/
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT DISTINCT " + NoteColumns.ID + ","
+ NoteColumns.ALERTED_DATE + ","
+ NoteColumns.BG_COLOR_ID + ","
+ NoteColumns.CREATED_DATE + ","
+ NoteColumns.HAS_ATTACHMENT + ","
+ NoteColumns.MODIFIED_DATE + ","
+ NoteColumns.NOTES_COUNT + ","
+ NoteColumns.PARENT_ID + ","
+ NoteColumns.SNIPPET + ","
+ NoteColumns.TYPE + ","
+ NoteColumns.WIDGET_ID + ","
+ NoteColumns.WIDGET_TYPE + ","
+ NoteColumns.PINNED
+ " FROM " + TABLE.NOTE
+ " LEFT JOIN " + TABLE.DATA + " ON " + NoteColumns.ID + "=" + TABLE.DATA + "." + net.micode.notes.data.Notes.DataColumns.NOTE_ID
+ " WHERE (" + NoteColumns.SNIPPET + " LIKE ? OR " + TABLE.DATA + "." + net.micode.notes.data.Notes.DataColumns.CONTENT + " LIKE ?)"
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLDER
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
/**
* 搜索建议查询语句
*/
private static String NOTES_SEARCH_SUGGEST_QUERY = "SELECT DISTINCT " + 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
+ " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLDER
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
/**
* 初始化ContentProvider
* @return 是否初始化成功
*/
@Override
public boolean onCreate() {
// 获取数据库帮助类实例
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
/**
* 查询数据
* @param uri 查询的URI
* @param projection 要查询的列
* @param selection 查询条件
* @param selectionArgs 查询条件参数
* @param sortOrder 排序方式
* @return 查询结果游标
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor c = null;
SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null;
switch (mMatcher.match(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);
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);
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;
}
try {
searchString = String.format("%%%s%%", searchString);
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
// 搜索建议:返回搜索建议格式的结果
c = db.rawQuery(NOTES_SEARCH_SUGGEST_QUERY,
new String[] { searchString });
} else {
// 内容搜索返回完整NoteItemData.PROJECTION列的结果
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
new String[] { searchString, searchString });
}
} catch (IllegalStateException ex) {
Log.e(TAG, "got exception: " + ex.toString());
}
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
/**
* 插入数据
* @param uri 插入的URI
* @param values 要插入的数据
* @return 插入数据的URI
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = mHelper.getWritableDatabase();
long dataId = 0, noteId = 0, insertedId = 0;
switch (mMatcher.match(uri)) {
case URI_NOTE:
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
case URI_DATA:
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:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify the note uri
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// Notify the data uri
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
return ContentUris.withAppendedId(uri, insertedId);
}
/**
* 删除数据
* @param uri 删除的URI
* @param selection 删除条件
* @param selectionArgs 删除条件参数
* @return 删除的行数
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false;
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 检查是否是彻底删除selection包含回收站条件
boolean isPermanentDelete = selection != null && selection.contains(NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLDER);
if (isPermanentDelete) {
// 彻底删除回收站中的笔记
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
count = db.delete(TABLE.NOTE, selection, selectionArgs);
} else {
// 将笔记移动到回收站
ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, Notes.ID_TRASH_FOLDER);
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
count = db.update(TABLE.NOTE, values, selection, selectionArgs);
}
break;
case URI_NOTE_ITEM:
id = uri.getPathSegments().get(1);
/**
* ID that smaller than 0 is system folder which is not allowed to
* trash
*/
long noteId = Long.valueOf(id);
if (noteId <= 0) {
break;
}
// 检查是否是彻底删除
boolean isItemPermanentDelete = selection != null && selection.contains(NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLDER);
if (isItemPermanentDelete) {
// 彻底删除单个笔记
count = db.delete(TABLE.NOTE,
NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
} else {
// 将单个笔记移动到回收站
ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, Notes.ID_TRASH_FOLDER);
count = db.update(TABLE.NOTE, values,
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);
count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (count > 0) {
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
/**
* 更新数据
* @param uri 更新的URI
* @param values 要更新的数据
* @param selection 更新条件
* @param selectionArgs 更新条件参数
* @return 更新的行数
*/
@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;
switch (mMatcher.match(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);
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);
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
updateData = true;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (count > 0) {
if (updateData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
/**
* 解析查询条件
* @param selection 查询条件
* @return 解析后的查询条件
*/
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
/**
* 增加笔记版本号
* @param id 笔记ID
* @param selection 查询条件
* @param selectionArgs 查询条件参数
*/
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 ");
}
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);
}
mHelper.getWritableDatabase().execSQL(sql.toString());
}
/**
* 获取MIME类型
* @param uri URI
* @return MIME类型
*/
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}