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.
MINotes/src/net/micode/notes/tool/DataUtils.java

469 lines
23 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
*
* <url id="ctvqpqeqvl70nnpdm1qg" type="url" status="parsed" title="Apache License, Version 2.0" wc="10467">http://www.apache.org/licenses/LICENSE-2.0</url>
*
* 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.
*/
// 文件头部包含了版权声明、许可证信息以及对应的 URL 链接,指明该文件遵循 Apache License 2.0 许可证。同时声明该软件是“按原样”提供的,没有明示或暗示的任何形式的保证或条件。
package net.micode.notes.tool;
// 定义当前类所在的包名,为 net.micode.notes.tool。
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.os.RemoteException;
import android.util.Log;
// 导入 Android 相关类库,以便在类中使用这些类的功能。
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
// 导入本项目中其他包里的类,便于调用这些类的属性和方法。
import java.util.ArrayList;
import java.util.HashSet;
// 导入 Java 集合框架中的类,用于在类中使用 ArrayList 和 HashSet。
public class DataUtils {
// 定义一个公共类 DataUtils作为工具类提供数据操作的方法。
public static final String TAG = "DataUtils";
// 定义一个公共静态常量 TAG用于日志输出时标识当前类名。
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
// 定义一个静态方法 batchDeleteNotes用于批量删除笔记。
// ContentResolver resolver内容解析器对象用于对内容提供者进行操作。
// HashSet<Long> ids需要删除的笔记 ID 集合。
if (ids == null) {
// 如果传入的 ids 为 null。
Log.d(TAG, "the ids is null");
// 输出日志,提示 ids 为 null。
return true;
// 直接返回 true表示删除操作成功因为没有需要删除的笔记
}
if (ids.size() == 0) {
// 如果 ids 集合的大小为 0即没有需要删除的笔记 ID。
Log.d(TAG, "no id is in the hashset");
// 输出日志,提示没有需要删除的笔记 ID。
return true;
// 直接返回 true表示删除操作成功。
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// 创建一个 ArrayList用于存储要执行的内容提供者操作。
for (long id : ids) {
// 遍历 ids 集合中的每个笔记 ID。
if(id == Notes.ID_ROOT_FOLDER) {
// 如果当前 ID 是系统根文件夹的 ID。
Log.e(TAG, "Don't delete system folder root");
// 输出错误日志,提示不能删除系统根文件夹。
continue;
// 跳过此次循环,不执行删除操作。
}
ContentProviderOperation.Builder builder = ContentProviderOperation
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
// 创建一个 ContentProviderOperation.Builder 对象,用于构建删除操作。
operationList.add(builder.build());
// 将构建好的删除操作添加到 operationList 中。
}
try {
// 尝试执行批量删除操作。
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
// 调用 resolver 的 applyBatch 方法,传入 Notes.AUTHORITY 和 operationList执行批量操作并返回操作结果数组。
if (results == null || results.length == 0 || results[0] == null) {
// 如果操作结果数组为 null或者数组长度为 0或者数组的第一个元素为 null。
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
// 输出日志,提示删除笔记失败,并打印出需要删除的笔记 IDs。
return false;
// 返回 false表示删除操作失败。
}
return true;
// 如果没有异常且删除操作成功,返回 true。
} catch (RemoteException e) {
// 如果在执行删除操作过程中发生远程异常。
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
// 输出错误日志,打印出异常信息和异常消息。
} catch (OperationApplicationException e) {
// 如果在应用操作过程中发生异常。
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
// 输出错误日志,打印出异常信息和异常消息。
}
return false;
// 如果在执行删除操作过程中发生异常,返回 false表示删除操作失败。
}
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
// 定义一个静态方法 moveNoteToFoler用于将笔记移动到文件夹。
// ContentResolver resolver内容解析器对象用于对内容提供者进行操作。
// long id要移动的笔记 ID。
// long srcFolderId笔记的源文件夹 ID。
// long desFolderId要移动到的目标文件夹 ID。
ContentValues values = new ContentValues();
// 创建一个 ContentValues 对象,用于存储笔记的修改信息。
values.put(NoteColumns.PARENT_ID, desFolderId);
// 将笔记的目标父文件夹 ID 存储到 ContentValues 中,修改笔记的 PARENT_ID 列。
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
// 将笔记的源父文件夹 ID 存储到 ContentValues 中,修改笔记的 ORIGIN_PARENT_ID 列。
values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 将笔记的本地修改标志设置为 1表示笔记已被本地修改。
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
// 调用 resolver 的 update 方法,传入笔记的内容 URI 和修改后的 ContentValues更新笔记数据。
// ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id):根据笔记 ID 构建笔记的内容 URI。
// values包含笔记修改信息的 ContentValues。
// null 和 null查询条件和查询条件参数这里不需要查询条件。
}
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids, long folderId) {
// 定义一个静态方法 batchMoveToFolder用于批量移动笔记到文件夹。
// ContentResolver resolver内容解析器对象用于对内容提供者进行操作。
// HashSet<Long> ids需要移动的笔记 ID 集合。
// long folderId目标文件夹 ID。
if (ids == null) {
// 如果传入的 ids 为 null。
Log.d(TAG, "the ids is null");
// 输出日志,提示 ids 为 null。
return true;
// 直接返回 true表示移动操作成功因为没有需要移动的笔记
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// 创建一个 ArrayList用于存储要执行的内容提供者操作。
for (long id : ids) {
// 遍历 ids 集合中的每个笔记 ID。
ContentProviderOperation.Builder builder = ContentProviderOperation
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
// 创建一个 ContentProviderOperation.Builder 对象,用于构建更新操作。
builder.withValue(NoteColumns.PARENT_ID, folderId);
// 设置更新操作中笔记的父文件夹 ID 为传入的目标文件夹 ID。
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
// 设置更新操作中笔记的本地修改标志为 1。
operationList.add(builder.build());
// 将构建好的更新操作添加到 operationList 中。
}
try {
// 尝试执行批量移动操作。
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
// 调用 resolver 的 applyBatch 方法,传入 Notes.AUTHORITY 和 operationList执行批量操作
if (results == null || results.length == 0 || results[0] == null) {
// 如果操作结果数组为 null或者数组长度为 0或者数组的第一个元素为 null。
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
// 输出日志,提示移动笔记失败,并打印出需要移动的笔记 IDs。
return false;
// 返回 false表示移动操作失败。
}
return true;
// 如果没有异常且移动操作成功,返回 true。
} catch (RemoteException e) {
// 如果在执行移动操作过程中发生远程异常。
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
// 输出错误日志,打印出异常信息和异常消息。
} catch (OperationApplicationException e) {
// 如果在应用操作过程中发生异常。
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
// 输出错误日志,打印出异常信息和异常消息。
}
return false;
// 如果在执行移动操作过程中发生异常,返回 false表示移动操作失败。
}
public static int getUserFolderCount(ContentResolver resolver) {
// 定义一个静态方法 getUserFolderCount用于获取用户文件夹的数量不包括系统文件夹
// ContentResolver resolver内容解析器对象用于对内容提供者进行操作。
Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { "COUNT(*)" },
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
null);
// 调用 resolver 的 query 方法,查询 Notes.CONTENT_NOTE_URI获取用户文件夹的数量。
// new String[] { "COUNT(*)" }:查询投影,只查询文件夹数量。
// NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?":查询条件,文件夹类型且父文件夹 ID 不等于回收站 ID。
// new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}:查询条件参数。
int count = 0;
// 初始化文件夹数量为 0。
if(cursor != null) {
// 如果查询结果游标不为 null。
if(cursor.moveToFirst()) {
// 将游标移动到第一条记录。
try {
count = cursor.getInt(0);
// 获取查询结果中的文件夹数量。
} catch (IndexOutOfBoundsException e) {
// 如果在获取文件夹数量时发生索引越界异常。
Log.e(TAG, "get folder count failed:" + e.toString());
// 输出错误日志,打印出异常信息。
} finally {
cursor.close();
// 关闭游标,释放资源。
}
}
}
return count;
// 返回用户文件夹的数量。
}
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
// 定义一个静态方法 visibleInNoteDatabase用于检查指定的笔记 ID 是否存在于笔记数据库中(不包括回收站)。
// ContentResolver resolver内容解析器对象用于对内容提供者进行操作。
// long noteId要检查的笔记 ID。
// int type笔记类型。
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null,
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
new String [] {String.valueOf(type)},
null);
// 调用 resolver 的 query 方法,查询指定笔记 ID 的笔记是否存在。
// ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId):根据笔记 ID 构建笔记的内容 URI。
// null查询投影这里不需要指定查询列。
// NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER查询条件笔记类型且父文件夹 ID 不等于回收站 ID。
// new String [] {String.valueOf(type)}:查询条件参数。
boolean exist = false;
// 初始化笔记是否存在为 false。
if (cursor != null) {
// 如果查询结果游标不为 null。
if (cursor.getCount() > 0) {
// 如果查询结果的数量大于 0说明笔记存在。
exist = true;
}
cursor.close();
// 关闭游标,释放资源。
}
return exist;
// 返回笔记是否存在。
}
// 检查指定的笔记 ID 是否存在于笔记数据库中
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
// 使用 ContentUris.withAppendedId() 方法将笔记 ID 附加到笔记内容 URI 后面,构建查询特定笔记的 URI
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null, null, null);
// 默认笔记不存在
boolean exist = false;
// 如果查询结果的游标不为空
if (cursor != null) {
// 如果游标中包含至少一条记录
if (cursor.getCount() > 0) {
// 表示笔记存在
exist = true;
}
// 关闭游标以释放资源
cursor.close();
}
// 返回笔记是否存在
return exist;
}
// 检查指定的数据 ID 是否存在于数据数据库中
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
// 使用 ContentUris.withAppendedId() 方法将数据 ID 附加到数据内容 URI 后面,构建查询特定数据的 URI
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
null, null, null, null);
// 默认数据不存在
boolean exist = false;
// 如果查询结果的游标不为空
if (cursor != null) {
// 如果游标中包含至少一条记录
if (cursor.getCount() > 0) {
// 表示数据存在
exist = true;
}
// 关闭游标以释放资源
cursor.close();
}
// 返回数据是否存在
return exist;
}
// 检查指定的文件夹名称是否已存在于可见文件夹中
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
// 查询笔记内容 URI筛选出类型为文件夹、父 ID 不等于回收站文件夹 ID、且摘要等于指定名称的笔记
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?",
new String[] { name }, null);
// 默认名称不存在
boolean exist = false;
// 如果查询结果的游标不为空
if(cursor != null) {
// 如果游标中包含至少一条记录
if(cursor.getCount() > 0) {
// 表示名称已存在
exist = true;
}
// 关闭游标以释放资源
cursor.close();
}
// 返回名称是否存在
return exist;
}
// 获取指定文件夹 ID 下的笔记小部件属性集合
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
// 查询笔记内容 URI筛选出父 ID 等于指定文件夹 ID 的笔记,获取小部件 ID 和类型
Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
NoteColumns.PARENT_ID + "=?",
new String[] { String.valueOf(folderId) },
null);
// 初始化小部件属性集合
HashSet<AppWidgetAttribute> set = null;
// 如果查询结果的游标不为空
if (c != null) {
// 如果游标可以移动到第一条记录
if (c.moveToFirst()) {
// 创建小部件属性集合
set = new HashSet<AppWidgetAttribute>();
// 遍历游标中的所有记录
do {
try {
// 创建小部件属性对象
AppWidgetAttribute widget = new AppWidgetAttribute();
// 设置小部件 ID 和类型
widget.widgetId = c.getInt(0);
widget.widgetType = c.getInt(1);
// 将小部件属性添加到集合中
set.add(widget);
} catch (IndexOutOfBoundsException e) {
// 如果索引越界,记录错误日志
Log.e(TAG, e.toString());
}
} while (c.moveToNext());
}
// 关闭游标以释放资源
c.close();
}
// 返回小部件属性集合
return set;
}
// 根据笔记 ID 获取电话号码
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
// 查询数据内容 URI筛选出笔记 ID 等于指定 ID、MIME 类型为电话号码的记录,获取电话号码
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.PHONE_NUMBER },
CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?",
new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
null);
// 如果查询结果的游标不为空且可以移动到第一条记录
if (cursor != null && cursor.moveToFirst()) {
try {
// 返回电话号码
return cursor.getString(0);
} catch (IndexOutOfBoundsException e) {
// 如果索引越界,记录错误日志
Log.e(TAG, "Get call number fails " + e.toString());
} finally {
// 关闭游标以释放资源
cursor.close();
}
}
// 如果查询失败,返回空字符串
return "";
}
// 根据电话号码和通话日期获取笔记 ID
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
// 查询数据内容 URI筛选出通话日期等于指定日期、MIME 类型为电话号码、且电话号码匹配的记录,获取笔记 ID
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.NOTE_ID },
CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL("
+ CallNote.PHONE_NUMBER + ",?)",
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
null);
// 如果查询结果的游标不为空
if (cursor != null) {
// 如果游标可以移动到第一条记录
if (cursor.moveToFirst()) {
try {
// 返回笔记 ID
return cursor.getLong(0);
} catch (IndexOutOfBoundsException e) {
// 如果索引越界,记录错误日志
Log.e(TAG, "Get call note id fails " + e.toString());
}
}
// 关闭游标以释放资源
cursor.close();
}
// 如果查询失败,返回 0
return 0;
}
// 根据笔记 ID 获取摘要信息
public static String getSnippetById(ContentResolver resolver, long noteId) {
// 查询笔记内容 URI筛选出 ID 等于指定笔记 ID 的记录,获取摘要信息
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String [] { NoteColumns.SNIPPET },
NoteColumns.ID + "=?",
new String [] { String.valueOf(noteId)},
null);
// 如果查询结果的游标不为空
if (cursor != null) {
// 初始化摘要信息为空字符串
String snippet = "";
// 如果游标可以移动到第一条记录
if (cursor.moveToFirst()) {
// 获取并设置摘要信息
snippet = cursor.getString(0);
}
// 关闭游标以释放资源
cursor.close();
// 返回摘要信息
return snippet;
}
// 如果查询失败,抛出 IllegalArgumentException 异常
throw new IllegalArgumentException("Note is not found with id: " + noteId);
}
// 格式化摘要信息,去除多余换行符
public static String getFormattedSnippet(String snippet) {
// 如果摘要信息不为空
if (snippet != null) {
// 去除首尾空白字符
snippet = snippet.trim();
// 查找第一个换行符的索引
int index = snippet.indexOf('\n');
// 如果找到换行符
if (index != -1) {
// 截取换行符之前的部分作为格式化后的摘要信息
snippet = snippet.substring(0, index);
}
}
// 返回格式化后的摘要信息
return snippet;
}
}