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.
C47/src/DataUtils.java

328 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.

package 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;
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;
// DataUtils类提供了一系列用于操作笔记数据的实用方法例如批量删除笔记、移动笔记到文件夹、查询各种数据相关的存在性等功能
public class DataUtils {
public static final String TAG = "DataUtils";
// 批量删除指定ID集合对应的笔记
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
// 如果传入的要删除的笔记ID集合为null记录日志并返回true表示无需进行删除操作直接认为成功
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
}
// 如果传入的要删除的笔记ID集合大小为0即没有要删除的笔记记录日志并返回true表示无需进行删除操作直接认为成功
if (ids.size() == 0) {
Log.d(TAG, "no id is in the hashset");
return true;
}
// 创建一个用于存储内容提供器操作的列表,后续会将批量删除操作添加到这个列表中
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// 遍历要删除的笔记ID集合
for (long id : ids) {
// 如果当前笔记的ID是系统根文件夹的ID通常系统根文件夹不允许删除记录错误日志并跳过本次循环不添加到删除操作列表中
if (id == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Don't delete system folder root");
continue;
}
// 创建一个用于删除指定笔记的内容提供器操作构建器指定要删除的笔记的URI通过将笔记ID附加到基础的笔记内容URI上
ContentProviderOperation.Builder builder = ContentProviderOperation
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
// 将构建好的删除操作添加到操作列表中
operationList.add(builder.build());
}
try {
// 执行批量的内容提供器操作,传入对应的权限和操作列表,获取操作结果数组
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
// 如果操作结果数组为null或者长度为0或者第一个结果为null表示操作可能没有正确执行记录日志并返回false表示删除笔记失败
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
}
// 如果操作执行成功返回true
return 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()));
}
// 如果发生异常导致操作未能成功完成返回false
return false;
}
// 将指定ID的笔记移动到目标文件夹同时记录笔记的原始文件夹ID并标记本地已修改
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
// 创建一个用于存储要更新的列和对应值的ContentValues对象
ContentValues values = new ContentValues();
// 设置笔记的新父文件夹ID即目标文件夹ID
values.put(NoteColumns.PARENT_ID, desFolderId);
// 设置笔记的原始父文件夹ID即来源文件夹ID
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
// 设置本地已修改的标记为1表示该笔记有本地修改操作
values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 通过内容解析器更新指定ID的笔记使用上面设置好的ContentValues对象来更新相应列的值后面两个参数为null表示不使用条件筛选和不传入额外的参数
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
}
// 批量将指定ID集合的笔记移动到指定文件夹
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
long folderId) {
// 如果传入的要移动的笔记ID集合为null记录日志并返回true表示无需进行移动操作直接认为成功
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
}
// 创建一个用于存储内容提供器操作的列表,后续会将批量移动操作添加到这个列表中
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// 遍历要移动的笔记ID集合
for (long id : ids) {
// 创建一个用于更新指定笔记的内容提供器操作构建器指定要更新的笔记的URI通过将笔记ID附加到基础的笔记内容URI上
ContentProviderOperation.Builder builder = ContentProviderOperation
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
// 设置笔记的新父文件夹ID即目标文件夹ID
builder.withValue(NoteColumns.PARENT_ID, folderId);
// 设置本地已修改的标记为1表示该笔记有本地修改操作
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
// 将构建好的更新操作添加到操作列表中
operationList.add(builder.build());
}
try {
// 执行批量的内容提供器操作,传入对应的权限和操作列表,获取操作结果数组
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
// 如果操作结果数组为null或者长度为0或者第一个结果为null表示操作可能没有正确执行记录日志并返回false表示移动笔记失败
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
}
// 如果操作执行成功返回true
return 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()));
}
// 如果发生异常导致操作未能成功完成返回false
return false;
}
/**
* 获取除系统文件夹({@link Notes#TYPE_SYSTEM} 标记的文件夹)之外的所有用户文件夹的数量
*/
public static int getUserFolderCount(ContentResolver resolver) {
// 通过内容解析器查询满足条件的文件夹数量查询条件是类型为文件夹且父文件夹ID不是回收站文件夹ID只查询记录数量通过 COUNT(*) 聚合函数)
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);
int count = 0;
// 如果查询结果游标不为空
if (cursor!= null) {
// 将游标移动到第一条数据(虽然这里只有一条数据,就是查询到的数量结果)
if (cursor.moveToFirst()) {
try {
// 尝试从游标中获取第一列也就是查询到的数量值并赋值给count变量
count = cursor.getInt(0);
} catch (IndexOutOfBoundsException e) {
// 如果发生越界异常(比如查询结果格式不符合预期等情况),记录详细的异常信息到日志中
Log.e(TAG, "get folder count failed:" + e.toString());
} finally {
// 无论是否发生异常,都关闭游标,释放相关资源
cursor.close();
}
}
}
return count;
}
// 判断指定ID的笔记是否在笔记数据库中可见即不在回收站且类型符合要求
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
// 通过内容解析器查询指定笔记是否存在且满足可见条件类型符合要求且父文件夹ID不是回收站文件夹ID
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);
boolean exist = false;
// 如果查询结果游标不为空
if (cursor!= null) {
// 如果游标中的记录数量大于0表示笔记存在且满足可见条件将exist设置为true
if (cursor.getCount() > 0) {
exist = true;
}
// 关闭游标,释放相关资源
cursor.close();
}
return exist;
}
// 判断指定ID的笔记是否存在于笔记数据库中简单查询是否存在该记录
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
// 通过内容解析器查询指定笔记是否存在,不添加额外的查询条件
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null, null, null);
boolean exist = false;
// 如果查询结果游标不为空
if (cursor!= null) {
// 如果游标中的记录数量大于0表示笔记存在将exist设置为true
if (cursor.getCount() > 0) {
exist = true;
}
// 关闭游标,释放相关资源
cursor.close();
}
return exist;
}
// 判断指定ID的数据记录是否存在于数据数据库中简单查询是否存在该记录
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
// 通过内容解析器查询指定数据记录是否存在,不添加额外的查询条件
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
null, null, null, null);
boolean exist = false;
// 如果查询结果游标不为空
if (cursor!= null) {
// 如果游标中的记录数量大于0表示数据记录存在将exist设置为true
if (cursor.getCount() > 0) {
exist = true;
}
// 关闭游标,释放相关资源
cursor.close();
}
return exist;
}
// 检查指定名称的文件夹是否在笔记数据库中可见(即不在回收站且类型为文件夹、名称匹配)
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
// 通过内容解析器查询满足条件的文件夹是否存在条件是类型为文件夹、父文件夹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) {
// 如果游标中的记录数量大于0表示文件夹存在且满足可见条件将exist设置为true
if (cursor.getCount() > 0) {
exist = true;
}
// 关闭游标,释放相关资源
cursor.close();
}
return exist;
}
// 获取指定文件夹下所有笔记对应的小部件相关属性集合包括小部件ID和小部件类型
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
// 通过内容解析器查询指定文件夹下所有笔记的小部件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()) {
// 创建一个用于存储小部件相关属性的HashSet集合
set = new HashSet<AppWidgetAttribute>();
do {
try {
// 创建一个AppWidgetAttribute对象用于存储单个小部件的属性
AppWidgetAttribute widget = new AppWidgetAttribute();
// 从游标中获取小部件ID并赋值给AppWidgetAttribute对象的对应属性
widget.widgetId = c.getInt(0);
// 从游标中获取小部件类型并赋值给AppWidgetAttribute对象的对应属性
widget.widgetType = c.getInt(1);
// 将小部件属性对象添加到HashSet集合中
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) {
// 通过内容解析器查询指定笔记对应的通话号码查询条件是笔记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) {
// 通过内容解析器查询满足条件的笔记ID条件是通话日期匹配、MIME类型为通话笔记的类型且电话号码匹配通过自定义函数PHONE_NUMBERS_EQUAL判断
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());
}
}
// 关闭游标,释放相关资源