|
|
@ -1,279 +0,0 @@
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* BackupUtils 工具类
|
|
|
|
|
|
|
|
* 提供了笔记备份到文本文件的功能。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
package net.micode.notes.tool;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 引入需要用到的 Android 和 Java 标准库类
|
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
|
|
|
import android.os.Environment;
|
|
|
|
|
|
|
|
import android.text.TextUtils;
|
|
|
|
|
|
|
|
import android.text.format.DateFormat;
|
|
|
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.R;
|
|
|
|
|
|
|
|
import net.micode.notes.data.Notes;
|
|
|
|
|
|
|
|
import net.micode.notes.data.Notes.DataColumns;
|
|
|
|
|
|
|
|
import net.micode.notes.data.Notes.DataConstants;
|
|
|
|
|
|
|
|
import net.micode.notes.data.Notes.NoteColumns;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
import java.io.PrintStream;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* BackupUtils 是一个工具类,用于实现笔记的备份功能。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public class BackupUtils {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 日志标志,用于记录类中的日志
|
|
|
|
|
|
|
|
private static final String TAG = "BackupUtils";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 单例模式:存储唯一实例
|
|
|
|
|
|
|
|
private static BackupUtils sInstance;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取 BackupUtils 类的单例实例。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param context 上下文对象,用于初始化内部组件。
|
|
|
|
|
|
|
|
* @return 返回 BackupUtils 实例。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static synchronized BackupUtils getInstance(Context context) {
|
|
|
|
|
|
|
|
if (sInstance == null) { // 如果实例不存在,则创建新实例
|
|
|
|
|
|
|
|
sInstance = new BackupUtils(context);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return sInstance; // 返回单例实例
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 定义备份操作的状态常量
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static final int STATE_SD_CARD_UNMOUONTED = 0; // SD卡未挂载
|
|
|
|
|
|
|
|
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; // 备份文件不存在
|
|
|
|
|
|
|
|
public static final int STATE_DATA_DESTROIED = 2; // 数据已损坏
|
|
|
|
|
|
|
|
public static final int STATE_SYSTEM_ERROR = 3; // 系统错误
|
|
|
|
|
|
|
|
public static final int STATE_SUCCESS = 4; // 备份成功
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 用于文本导出的工具类
|
|
|
|
|
|
|
|
private TextExport mTextExport;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 私有化构造函数,防止直接实例化。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param context 上下文对象,用于初始化导出工具类。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private BackupUtils(Context context) {
|
|
|
|
|
|
|
|
mTextExport = new TextExport(context); // 初始化文本导出工具
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 检查 SD 卡是否可用。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return 如果 SD 卡已挂载,则返回 true,否则返回 false。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static boolean externalStorageAvailable() {
|
|
|
|
|
|
|
|
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 导出笔记到文本文件。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return 返回导出操作的状态码。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public int exportToText() {
|
|
|
|
|
|
|
|
return mTextExport.exportToText(); // 调用 TextExport 类中的导出方法
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取导出文本的文件名。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return 返回文件名字符串。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public String getExportedTextFileName() {
|
|
|
|
|
|
|
|
return mTextExport.mFileName; // 返回文件名
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取导出文件的目录。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return 返回目录路径字符串。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public String getExportedTextFileDir() {
|
|
|
|
|
|
|
|
return mTextExport.mFileDirectory; // 返回文件目录路径
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 内部类,用于执行文本导出功能。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static class TextExport {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 定义查询笔记的列名
|
|
|
|
|
|
|
|
private static final String[] NOTE_PROJECTION = {
|
|
|
|
|
|
|
|
NoteColumns.ID, // 笔记 ID
|
|
|
|
|
|
|
|
NoteColumns.MODIFIED_DATE, // 修改时间
|
|
|
|
|
|
|
|
NoteColumns.SNIPPET, // 摘要
|
|
|
|
|
|
|
|
NoteColumns.TYPE // 类型
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 定义笔记列的索引
|
|
|
|
|
|
|
|
private static final int NOTE_COLUMN_ID = 0; // ID 列索引
|
|
|
|
|
|
|
|
private static final int NOTE_COLUMN_MODIFIED_DATE = 1; // 修改时间列索引
|
|
|
|
|
|
|
|
private static final int NOTE_COLUMN_SNIPPET = 2; // 摘要列索引
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 定义查询数据表的列
|
|
|
|
|
|
|
|
private static final String[] DATA_PROJECTION = {
|
|
|
|
|
|
|
|
DataColumns.CONTENT, // 内容
|
|
|
|
|
|
|
|
DataColumns.MIME_TYPE, // MIME 类型
|
|
|
|
|
|
|
|
DataColumns.DATA1, // 数据 1
|
|
|
|
|
|
|
|
DataColumns.DATA2, // 数据 2
|
|
|
|
|
|
|
|
DataColumns.DATA3, // 数据 3
|
|
|
|
|
|
|
|
DataColumns.DATA4, // 数据 4
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 定义数据列的索引
|
|
|
|
|
|
|
|
private static final int DATA_COLUMN_CONTENT = 0; // 内容列索引
|
|
|
|
|
|
|
|
private static final int DATA_COLUMN_MIME_TYPE = 1; // MIME 类型列索引
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 上下文对象,用于访问系统资源
|
|
|
|
|
|
|
|
private Context mContext;
|
|
|
|
|
|
|
|
private String mFileName; // 文件名
|
|
|
|
|
|
|
|
private String mFileDirectory; // 文件目录
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化文本导出格式
|
|
|
|
|
|
|
|
private final String[] TEXT_FORMAT;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public TextExport(Context context) {
|
|
|
|
|
|
|
|
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); // 导出格式
|
|
|
|
|
|
|
|
mContext = context;
|
|
|
|
|
|
|
|
mFileName = "";
|
|
|
|
|
|
|
|
mFileDirectory = "";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 根据文件夹 ID 将笔记导出为文本。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param folderId 文件夹 ID。
|
|
|
|
|
|
|
|
* @param ps 打印流,用于写入文本内容。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private void exportFolderToText(String folderId, PrintStream ps) {
|
|
|
|
|
|
|
|
Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, NOTE_PROJECTION,
|
|
|
|
|
|
|
|
NoteColumns.PARENT_ID + "=?", new String[]{folderId}, null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (notesCursor != null) {
|
|
|
|
|
|
|
|
if (notesCursor.moveToFirst()) {
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
// 输出笔记的修改时间
|
|
|
|
|
|
|
|
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
|
|
|
|
|
|
|
|
mContext.getString(R.string.format_datetime_mdhm),
|
|
|
|
|
|
|
|
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
|
|
|
|
|
|
|
|
// 导出笔记内容
|
|
|
|
|
|
|
|
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
|
|
|
|
|
|
|
|
exportNoteToText(noteId, ps);
|
|
|
|
|
|
|
|
} while (notesCursor.moveToNext());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
notesCursor.close();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 导出指定笔记 ID 的内容到文本。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param noteId 笔记 ID。
|
|
|
|
|
|
|
|
* @param ps 打印流。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private void exportNoteToText(String noteId, PrintStream ps) {
|
|
|
|
|
|
|
|
Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
|
|
|
|
|
|
|
|
DataColumns.NOTE_ID + "=?", new String[]{noteId}, null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (dataCursor != null) {
|
|
|
|
|
|
|
|
if (dataCursor.moveToFirst()) {
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
|
|
|
|
|
|
|
|
if (DataConstants.CALL_NOTE.equals(mimeType)) {
|
|
|
|
|
|
|
|
// 导出通话笔记
|
|
|
|
|
|
|
|
} else if (DataConstants.NOTE.equals(mimeType)) {
|
|
|
|
|
|
|
|
// 导出普通笔记
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (dataCursor.moveToNext());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dataCursor.close();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取指向文件的打印流,用于导出笔记内容。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return 返回指向生成的文本文件的打印流对象,如果失败则返回 null。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private PrintStream getExportToTextPrintStream() {
|
|
|
|
|
|
|
|
// 调用辅助方法,生成导出文件
|
|
|
|
|
|
|
|
File file = generateFileMountedOnSDcard(mContext, R.string.file_path, R.string.file_name_txt_format);
|
|
|
|
|
|
|
|
if (file == null) { // 如果文件生成失败
|
|
|
|
|
|
|
|
Log.e(TAG, "create file to exported failed"); // 输出错误日志
|
|
|
|
|
|
|
|
return null; // 返回 null,表示打印流创建失败
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 更新文件名和目录信息
|
|
|
|
|
|
|
|
mFileName = file.getName(); // 设置文件名
|
|
|
|
|
|
|
|
mFileDirectory = mContext.getString(R.string.file_path); // 设置文件目录
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PrintStream ps = null; // 初始化打印流为 null
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
// 创建文件输出流并包装为打印流
|
|
|
|
|
|
|
|
FileOutputStream fos = new FileOutputStream(file);
|
|
|
|
|
|
|
|
ps = new PrintStream(fos);
|
|
|
|
|
|
|
|
} catch (FileNotFoundException e) { // 捕获文件未找到异常
|
|
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
|
|
return null; // 返回 null,表示打印流创建失败
|
|
|
|
|
|
|
|
} catch (NullPointerException e) { // 捕获空指针异常
|
|
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
|
|
return null; // 返回 null
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return ps; // 返回成功创建的打印流对象
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 在 SD 卡上生成用于存储导出数据的文件。
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param context 上下文对象,用于访问应用资源。
|
|
|
|
|
|
|
|
* @param filePathResId 文件路径的资源 ID。
|
|
|
|
|
|
|
|
* @param fileNameFormatResId 文件名格式的资源 ID,用于生成包含日期的文件名。
|
|
|
|
|
|
|
|
* @return 返回生成的文件对象,如果失败则返回 null。
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
|
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder(); // 使用 StringBuilder 拼接路径和文件名
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取 SD 卡的根目录并拼接路径
|
|
|
|
|
|
|
|
sb.append(Environment.getExternalStorageDirectory());
|
|
|
|
|
|
|
|
sb.append(context.getString(filePathResId)); // 从资源中获取路径字符串
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 创建文件目录对象
|
|
|
|
|
|
|
|
File filedir = new File(sb.toString());
|
|
|
|
|
|
|
|
// 生成文件名并拼接到路径中,文件名包含日期信息
|
|
|
|
|
|
|
|
sb.append(context.getString(fileNameFormatResId,
|
|
|
|
|
|
|
|
DateFormat.format(context.getString(R.string.format_date_ymd), System.currentTimeMillis())));
|
|
|
|
|
|
|
|
File file = new File(sb.toString()); // 创建文件对象
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
if (!filedir.exists()) { // 如果目录不存在
|
|
|
|
|
|
|
|
filedir.mkdir(); // 创建目录
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!file.exists()) { // 如果文件不存在
|
|
|
|
|
|
|
|
file.createNewFile(); // 创建文件
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return file; // 返回成功生成的文件对象
|
|
|
|
|
|
|
|
} catch (SecurityException e) { // 捕获安全异常
|
|
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
|
|
} catch (IOException e) { // 捕获 I/O 异常
|
|
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return null; // 如果发生异常,返回 null
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|