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.

402 lines
14 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.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;
/**
* 数据工具类
* 提供便签数据操作的实用方法,包括批量删除、移动便签、查询数据等功能
* 所有方法均为静态方法,便于在其他类中直接调用
*/
public class DataUtils {
public static final String TAG = "DataUtils";
/**
* 批量删除便签
* 使用ContentProvider的批量操作功能删除多个便签
* 跳过系统根文件夹的删除操作
*
* @param resolver ContentResolver实例
* @param ids 待删除的便签ID集合
* @return 删除是否成功
*/
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
if (ids == null) {
Log.d(TAG, "待删除的ID集合为null");
return true;
}
if (ids.size() == 0) {
Log.d(TAG, "ID集合为空无需删除");
return true;
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
for (long id : ids) {
if (id == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "尝试删除系统根文件夹,已跳过");
continue;
}
// 构建删除操作
ContentProviderOperation.Builder builder = ContentProviderOperation
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
operationList.add(builder.build());
}
try {
// 执行批量操作
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "删除便签失败ID集合: " + ids.toString());
return false;
}
return true;
} catch (RemoteException e) {
Log.e(TAG, "远程异常: " + e.toString());
} catch (OperationApplicationException e) {
Log.e(TAG, "操作应用异常: " + e.toString());
}
return false;
}
/**
* 将便签移动到指定文件夹
* 更新便签的父文件夹ID并标记为本地已修改
*
* @param resolver ContentResolver实例
* @param id 待移动的便签ID
* @param srcFolderId 源文件夹ID
* @param desFolderId 目标文件夹ID
*/
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, desFolderId); // 设置新的父文件夹ID
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); // 记录原始父文件夹ID
values.put(NoteColumns.LOCAL_MODIFIED, 1); // 标记为本地已修改
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
}
/**
* 批量将便签移动到指定文件夹
* 使用ContentProvider的批量操作功能移动多个便签
*
* @param resolver ContentResolver实例
* @param ids 待移动的便签ID集合
* @param folderId 目标文件夹ID
* @return 移动是否成功
*/
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids, long folderId) {
if (ids == null) {
Log.d(TAG, "待移动的ID集合为null");
return true;
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
for (long id : ids) {
// 构建更新操作
ContentProviderOperation.Builder builder = ContentProviderOperation
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
builder.withValue(NoteColumns.PARENT_ID, folderId); // 设置新的父文件夹ID
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); // 标记为本地已修改
operationList.add(builder.build());
}
try {
// 执行批量操作
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "移动便签失败ID集合: " + ids.toString());
return false;
}
return true;
} catch (RemoteException e) {
Log.e(TAG, "远程异常: " + e.toString());
} catch (OperationApplicationException e) {
Log.e(TAG, "操作应用异常: " + e.toString());
}
return false;
}
/**
* 获取用户创建的文件夹数量(不包括系统文件夹)
* 查询类型为文件夹且不是垃圾文件夹的记录数量
*
* @param resolver ContentResolver实例
* @return 用户文件夹数量
*/
public static int 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);
int count = 0;
if (cursor != null) {
if (cursor.moveToFirst()) {
try {
count = cursor.getInt(0);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "获取文件夹数量失败: " + e.toString());
} finally {
cursor.close();
}
}
}
return count;
}
/**
* 检查便签在数据库中是否可见
* 检查便签类型和父文件夹是否为非垃圾文件夹
*
* @param resolver ContentResolver实例
* @param noteId 便签ID
* @param type 便签类型
* @return 是否可见
*/
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, 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);
boolean exist = false;
if (cursor != null) {
if (cursor.getCount() > 0) {
exist = true;
}
cursor.close();
}
return exist;
}
/**
* 检查便签是否存在于数据库
*
* @param resolver ContentResolver实例
* @param noteId 便签ID
* @return 是否存在
*/
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) {
if (cursor.getCount() > 0) {
exist = true;
}
cursor.close();
}
return exist;
}
/**
* 检查数据是否存在于数据库
*
* @param resolver ContentResolver实例
* @param dataId 数据ID
* @return 是否存在
*/
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) {
if (cursor.getCount() > 0) {
exist = true;
}
cursor.close();
}
return exist;
}
/**
* 检查文件夹名称是否已存在(不包括垃圾文件夹)
*
* @param resolver ContentResolver实例
* @param name 文件夹名称
* @return 是否存在同名文件夹
*/
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
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;
}
/**
* 获取文件夹中便签的小部件信息
*
* @param resolver ContentResolver实例
* @param folderId 文件夹ID
* @return 小部件属性集合
*/
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
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();
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获取通话便签的电话号码
*
* @param resolver ContentResolver实例
* @param noteId 便签ID
* @return 电话号码,不存在则返回空字符串
*/
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
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, "获取电话号码失败: " + e.toString());
} finally {
cursor.close();
}
}
return "";
}
/**
* 根据电话号码和通话日期获取通话便签的ID
* 使用PHONE_NUMBERS_EQUAL函数进行电话号码匹配忽略格式
*
* @param resolver ContentResolver实例
* @param phoneNumber 电话号码
* @param callDate 通话日期
* @return 便签ID不存在则返回0
*/
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
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 {
return cursor.getLong(0);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "获取通话便签ID失败: " + e.toString());
}
}
cursor.close();
}
return 0;
}
/**
* 根据便签ID获取便签摘要
*
* @param resolver ContentResolver实例
* @param noteId 便签ID
* @return 便签摘要
* @throws IllegalArgumentException 便签不存在时抛出
*/
public static String getSnippetById(ContentResolver resolver, long noteId) {
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;
}
throw new IllegalArgumentException("未找到ID为 " + noteId + " 的便签");
}
/**
* 格式化便签摘要
* 去除前后空格,并截断第一个换行符之后的内容
*
* @param snippet 原始摘要
* @return 格式化后的摘要
*/
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;
}
}