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.
miNote2/java/net/micode/notes/data/NotesProvider.java

415 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;
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提供了对便签表和数据记录表的访问接口。
*/
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;
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;
static {
// 初始化URI匹配器
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 添加不同URI的匹配规则
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "search", URI_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);
}
/**
* 便签搜索的投影,定义了搜索结果的列
* x'0A'表示sqlite中的'\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 + ","
+ "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;
// 便签片段搜索的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;
/**
* 内容提供者创建时调用,初始化数据库帮助类
*
* @return 创建成功返回true否则返回false
*/
@Override
public boolean onCreate() {
// 获取数据库帮助类实例
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
/**
* 处理查询请求根据不同的URI匹配码执行相应的查询操作
*
* @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
id = uri.getPathSegments().get(1);
// 查询指定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
id = uri.getPathSegments().get(1);
// 查询指定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) {
// 从URI路径中获取搜索字符串
searchString = uri.getPathSegments().get(1);
}
} else {
// 从URI查询参数中获取搜索字符串
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());
}
break;
default:
// 未知URI抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (c != null) {
// 设置游标通知URI当数据变化时通知观察者
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
/**
* 处理插入请求根据不同的URI匹配码将数据插入到相应的表中
*
* @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)) {
// 获取便签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匹配码从相应的表中删除数据
*
* @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 = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
// 删除便签数据
count = db.delete(TABLE.NOTE, selection, selectionArgs);
break;
case URI_NOTE_ITEM:
// 获取便签ID
id = uri.getPathSegments().get(1);
/**
* ID小于0的是系统文件夹不允许删除
*/
long noteId = Long.valueOf(id);
if (noteId <= 0) {
break;
}
// 删除指定ID的便签
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
id = uri.getPathSegments().get(1);
// 删除指定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;
}
/**
* 处理更新请求根据不同的URI匹配码更新相应表中的数据并增加便签版本号
*
* @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
id = uri.getPathSegments().get(1);
// 增加指定ID便签的版本号
increaseNoteVersion(Long.valueOf(id), selection, selectionArgs);
// 更新指定ID的便签
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);
// 更新指定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;
}
/**
* 解析查询条件,添加额外的条件
*
* @param selection 查询条件
* @return 解析后的查询条件
*/
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
/**
* 增加便签的版本号根据ID和查询条件更新便签的版本号
*
* @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);
}
// 执行更新版本号的SQL语句
mHelper.getWritableDatabase().execSQL(sql.toString());
}
/**
* 获取URI对应的MIME类型目前未实现
*
* @param uri 请求的URI
* @return MIME类型
*/
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}