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.

361 lines
15 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 {
// 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; // 匹配搜索建议URI
// 静态初始化块配置URI匹配器
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
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); // 搜索建议URI
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); // 带查询的搜索建议URI
}
/**
* 搜索结果的投影(列)定义
* x'0A'代表SQLite中的换行符'\n'。对于搜索结果中的标题和内容,
* 我们会去除'\n'和空格以显示更多信息。
*/
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 + "," // 建议文本行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) {
Cursor c = null;
SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null;
// 根据URI匹配不同类型请求
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);
// 执行原始SQL查询
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(getContext().getContentResolver(), uri);
}
return c;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = mHelper.getWritableDatabase();
long dataId = 0, noteId = 0, insertedId = 0;
// 根据URI类型处理插入请求
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);
}
// 通知笔记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);
}
// 返回新插入项的URI
return ContentUris.withAppendedId(uri, insertedId);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false;
// 根据URI类型处理删除请求
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:
// 删除单个笔记记录
id = uri.getPathSegments().get(1);
/**
* ID小于0的是系统文件夹不允许删除
*/
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);
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) {
// 如果删除的是数据需要通知笔记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;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean updateData = false;
// 根据URI类型处理更新请求
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) {
// 如果更新的是数据需要通知笔记URI变化
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知当前URI变化
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
/**
* 解析选择条件将普通选择条件转换为AND连接的条件
* @param selection 原始选择条件
* @return 格式化后的选择条件
*/
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
/**
* 增加笔记版本号
* @param id 笔记ID如果<=0则忽略
* @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 ");
// 添加WHERE条件
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);
}
// 执行SQL
mHelper.getWritableDatabase().execSQL(sql.toString());
}
@Override
public String getType(Uri uri) {
// TODO: 根据需要实现获取MIME类型
return null;
}
}