@ -35,12 +35,19 @@ import java.io.FileOutputStream;
import java.io.IOException ;
import java.io.IOException ;
import java.io.PrintStream ;
import java.io.PrintStream ;
/ * *
* 该 类 用 于 实 现 笔 记 数 据 的 备 份 功 能 , 将 笔 记 数 据 导 出 为 文 本 文 件 。
* /
public class BackupUtils {
public class BackupUtils {
private static final String TAG = "BackupUtils" ;
private static final String TAG = "BackupUtils" ;
// Singleton stuff
// 单例实例
private static BackupUtils sInstance ;
private static BackupUtils sInstance ;
/ * *
* 获 取 BackupUtils 的 单 例 实 例
* @param context 上 下 文 对 象
* @return BackupUtils 的 单 例 实 例
* /
public static synchronized BackupUtils getInstance ( Context context ) {
public static synchronized BackupUtils getInstance ( Context context ) {
if ( sInstance = = null ) {
if ( sInstance = = null ) {
sInstance = new BackupUtils ( context ) ;
sInstance = new BackupUtils ( context ) ;
@ -49,43 +56,67 @@ public class BackupUtils {
}
}
/ * *
/ * *
* Following states are signs to represents backup or restore
* 以 下 状 态 常 量 用 于 表 示 备 份 或 恢 复 操 作 的 状 态
* status
* /
* /
// Currently, the sdcard is not mounted
// 当前SD卡未挂载
public static final int STATE_SD_CARD_UNMOUONTED = 0 ;
public static final int STATE_SD_CARD_UNMOUONTED = 0 ;
// The backup file not exist
// 备份文件不存在
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1 ;
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1 ;
// The data is not well formated, may be changed by other programs
// 数据格式不正确,可能被其他程序修改
public static final int STATE_DATA_DESTROIED = 2 ;
public static final int STATE_DATA_DESTROIED = 2 ;
// Some run-time exception which causes restore or backup fails
// 运行时异常导致备份或恢复失败
public static final int STATE_SYSTEM_ERROR = 3 ;
public static final int STATE_SYSTEM_ERROR = 3 ;
// Backup or restore success
// 备份或恢复成功
public static final int STATE_SUCCESS = 4 ;
public static final int STATE_SUCCESS = 4 ;
// 文本导出工具类实例
private TextExport mTextExport ;
private TextExport mTextExport ;
/ * *
* 构 造 函 数 , 初 始 化 文 本 导 出 工 具 类
* @param context 上 下 文 对 象
* /
private BackupUtils ( Context context ) {
private BackupUtils ( Context context ) {
mTextExport = new TextExport ( context ) ;
mTextExport = new TextExport ( context ) ;
}
}
/ * *
* 检 查 外 部 存 储 是 否 可 用
* @return 如 果 外 部 存 储 已 挂 载 返 回 true , 否 则 返 回 false
* /
private static boolean externalStorageAvailable ( ) {
private static boolean externalStorageAvailable ( ) {
return Environment . MEDIA_MOUNTED . equals ( Environment . getExternalStorageState ( ) ) ;
return Environment . MEDIA_MOUNTED . equals ( Environment . getExternalStorageState ( ) ) ;
}
}
/ * *
* 导 出 笔 记 数 据 为 文 本 文 件
* @return 导 出 操 作 的 状 态 码
* /
public int exportToText ( ) {
public int exportToText ( ) {
return mTextExport . exportToText ( ) ;
return mTextExport . exportToText ( ) ;
}
}
/ * *
* 获 取 导 出 的 文 本 文 件 的 文 件 名
* @return 文 件 名
* /
public String getExportedTextFileName ( ) {
public String getExportedTextFileName ( ) {
return mTextExport . mFileName ;
return mTextExport . mFileName ;
}
}
/ * *
* 获 取 导 出 的 文 本 文 件 的 存 储 目 录
* @return 存 储 目 录
* /
public String getExportedTextFileDir ( ) {
public String getExportedTextFileDir ( ) {
return mTextExport . mFileDirectory ;
return mTextExport . mFileDirectory ;
}
}
/ * *
* 内 部 类 , 用 于 实 现 文 本 导 出 功 能
* /
private static class TextExport {
private static class TextExport {
// 查询笔记的投影列
private static final String [ ] NOTE_PROJECTION = {
private static final String [ ] NOTE_PROJECTION = {
NoteColumns . ID ,
NoteColumns . ID ,
NoteColumns . MODIFIED_DATE ,
NoteColumns . MODIFIED_DATE ,
@ -93,12 +124,16 @@ public class BackupUtils {
NoteColumns . TYPE
NoteColumns . TYPE
} ;
} ;
// 笔记ID列的索引
private static final int NOTE_COLUMN_ID = 0 ;
private static final int NOTE_COLUMN_ID = 0 ;
// 笔记修改日期列的索引
private static final int NOTE_COLUMN_MODIFIED_DATE = 1 ;
private static final int NOTE_COLUMN_MODIFIED_DATE = 1 ;
// 笔记摘要列的索引
private static final int NOTE_COLUMN_SNIPPET = 2 ;
private static final int NOTE_COLUMN_SNIPPET = 2 ;
// 查询数据的投影列
private static final String [ ] DATA_PROJECTION = {
private static final String [ ] DATA_PROJECTION = {
DataColumns . CONTENT ,
DataColumns . CONTENT ,
DataColumns . MIME_TYPE ,
DataColumns . MIME_TYPE ,
@ -108,23 +143,38 @@ public class BackupUtils {
DataColumns . DATA4 ,
DataColumns . DATA4 ,
} ;
} ;
// 数据内容列的索引
private static final int DATA_COLUMN_CONTENT = 0 ;
private static final int DATA_COLUMN_CONTENT = 0 ;
// 数据MIME类型列的索引
private static final int DATA_COLUMN_MIME_TYPE = 1 ;
private static final int DATA_COLUMN_MIME_TYPE = 1 ;
// 通话日期列的索引
private static final int DATA_COLUMN_CALL_DATE = 2 ;
private static final int DATA_COLUMN_CALL_DATE = 2 ;
// 电话号码列的索引
private static final int DATA_COLUMN_PHONE_NUMBER = 4 ;
private static final int DATA_COLUMN_PHONE_NUMBER = 4 ;
// 文本格式数组
private final String [ ] TEXT_FORMAT ;
private final String [ ] TEXT_FORMAT ;
// 文件夹名称格式的索引
private static final int FORMAT_FOLDER_NAME = 0 ;
private static final int FORMAT_FOLDER_NAME = 0 ;
// 笔记日期格式的索引
private static final int FORMAT_NOTE_DATE = 1 ;
private static final int FORMAT_NOTE_DATE = 1 ;
// 笔记内容格式的索引
private static final int FORMAT_NOTE_CONTENT = 2 ;
private static final int FORMAT_NOTE_CONTENT = 2 ;
// 上下文对象
private Context mContext ;
private Context mContext ;
// 导出的文件名
private String mFileName ;
private String mFileName ;
// 导出文件的存储目录
private String mFileDirectory ;
private String mFileDirectory ;
/ * *
* 构 造 函 数 , 初 始 化 上 下 文 、 文 本 格 式 、 文 件 名 和 存 储 目 录
* @param context 上 下 文 对 象
* /
public TextExport ( Context context ) {
public TextExport ( Context context ) {
TEXT_FORMAT = context . getResources ( ) . getStringArray ( R . array . format_for_exported_note ) ;
TEXT_FORMAT = context . getResources ( ) . getStringArray ( R . array . format_for_exported_note ) ;
mContext = context ;
mContext = context ;
@ -132,15 +182,22 @@ public class BackupUtils {
mFileDirectory = "" ;
mFileDirectory = "" ;
}
}
/ * *
* 根 据 索 引 获 取 文 本 格 式
* @param id 格 式 索 引
* @return 对 应 的 文 本 格 式 字 符 串
* /
private String getFormat ( int id ) {
private String getFormat ( int id ) {
return TEXT_FORMAT [ id ] ;
return TEXT_FORMAT [ id ] ;
}
}
/ * *
/ * *
* Export the folder identified by folder id to text
* 将 指 定 文 件 夹 下 的 笔 记 导 出 为 文 本
* @param folderId 文 件 夹 ID
* @param ps 打 印 流
* /
* /
private void exportFolderToText ( String folderId , PrintStream ps ) {
private void exportFolderToText ( String folderId , PrintStream ps ) {
// Query notes belong to this folder
// 查询该文件夹下的笔记
Cursor notesCursor = mContext . getContentResolver ( ) . query ( Notes . CONTENT_NOTE_URI ,
Cursor notesCursor = mContext . getContentResolver ( ) . query ( Notes . CONTENT_NOTE_URI ,
NOTE_PROJECTION , NoteColumns . PARENT_ID + "=?" , new String [ ] {
NOTE_PROJECTION , NoteColumns . PARENT_ID + "=?" , new String [ ] {
folderId
folderId
@ -149,11 +206,11 @@ public class BackupUtils {
if ( notesCursor ! = null ) {
if ( notesCursor ! = null ) {
if ( notesCursor . moveToFirst ( ) ) {
if ( notesCursor . moveToFirst ( ) ) {
do {
do {
// Print note's last modified date
// 打印笔记的最后修改日期
ps . println ( String . format ( getFormat ( FORMAT_NOTE_DATE ) , DateFormat . format (
ps . println ( String . format ( getFormat ( FORMAT_NOTE_DATE ) , DateFormat . format (
mContext . getString ( R . string . format_datetime_mdhm ) ,
mContext . getString ( R . string . format_datetime_mdhm ) ,
notesCursor . getLong ( NOTE_COLUMN_MODIFIED_DATE ) ) ) ) ;
notesCursor . getLong ( NOTE_COLUMN_MODIFIED_DATE ) ) ) ) ;
// Query data belong to this note
// 查询该笔记的数据
String noteId = notesCursor . getString ( NOTE_COLUMN_ID ) ;
String noteId = notesCursor . getString ( NOTE_COLUMN_ID ) ;
exportNoteToText ( noteId , ps ) ;
exportNoteToText ( noteId , ps ) ;
} while ( notesCursor . moveToNext ( ) ) ;
} while ( notesCursor . moveToNext ( ) ) ;
@ -163,9 +220,12 @@ public class BackupUtils {
}
}
/ * *
/ * *
* Export note identified by id to a print stream
* 将 指 定 笔 记 导 出 为 文 本
* @param noteId 笔 记 ID
* @param ps 打 印 流
* /
* /
private void exportNoteToText ( String noteId , PrintStream ps ) {
private void exportNoteToText ( String noteId , PrintStream ps ) {
// 查询该笔记的数据
Cursor dataCursor = mContext . getContentResolver ( ) . query ( Notes . CONTENT_DATA_URI ,
Cursor dataCursor = mContext . getContentResolver ( ) . query ( Notes . CONTENT_DATA_URI ,
DATA_PROJECTION , DataColumns . NOTE_ID + "=?" , new String [ ] {
DATA_PROJECTION , DataColumns . NOTE_ID + "=?" , new String [ ] {
noteId
noteId
@ -176,7 +236,7 @@ public class BackupUtils {
do {
do {
String mimeType = dataCursor . getString ( DATA_COLUMN_MIME_TYPE ) ;
String mimeType = dataCursor . getString ( DATA_COLUMN_MIME_TYPE ) ;
if ( DataConstants . CALL_NOTE . equals ( mimeType ) ) {
if ( DataConstants . CALL_NOTE . equals ( mimeType ) ) {
// Print phone number
// 打印电话号码
String phoneNumber = dataCursor . getString ( DATA_COLUMN_PHONE_NUMBER ) ;
String phoneNumber = dataCursor . getString ( DATA_COLUMN_PHONE_NUMBER ) ;
long callDate = dataCursor . getLong ( DATA_COLUMN_CALL_DATE ) ;
long callDate = dataCursor . getLong ( DATA_COLUMN_CALL_DATE ) ;
String location = dataCursor . getString ( DATA_COLUMN_CONTENT ) ;
String location = dataCursor . getString ( DATA_COLUMN_CONTENT ) ;
@ -185,11 +245,11 @@ public class BackupUtils {
ps . println ( String . format ( getFormat ( FORMAT_NOTE_CONTENT ) ,
ps . println ( String . format ( getFormat ( FORMAT_NOTE_CONTENT ) ,
phoneNumber ) ) ;
phoneNumber ) ) ;
}
}
// Print call date
// 打印通话日期
ps . println ( String . format ( getFormat ( FORMAT_NOTE_CONTENT ) , DateFormat
ps . println ( String . format ( getFormat ( FORMAT_NOTE_CONTENT ) , DateFormat
. format ( mContext . getString ( R . string . format_datetime_mdhm ) ,
. format ( mContext . getString ( R . string . format_datetime_mdhm ) ,
callDate ) ) ) ;
callDate ) ) ) ;
// Print call attachment location
// 打印通话附件位置
if ( ! TextUtils . isEmpty ( location ) ) {
if ( ! TextUtils . isEmpty ( location ) ) {
ps . println ( String . format ( getFormat ( FORMAT_NOTE_CONTENT ) ,
ps . println ( String . format ( getFormat ( FORMAT_NOTE_CONTENT ) ,
location ) ) ;
location ) ) ;
@ -205,7 +265,7 @@ public class BackupUtils {
}
}
dataCursor . close ( ) ;
dataCursor . close ( ) ;
}
}
// print a line separator between note
// 打印笔记之间的分隔符
try {
try {
ps . write ( new byte [ ] {
ps . write ( new byte [ ] {
Character . LINE_SEPARATOR , Character . LETTER_NUMBER
Character . LINE_SEPARATOR , Character . LETTER_NUMBER
@ -216,9 +276,11 @@ public class BackupUtils {
}
}
/ * *
/ * *
* Note will be exported as text which is user readable
* 将 笔 记 导 出 为 用 户 可 读 的 文 本 文 件
* @return 导 出 操 作 的 状 态 码
* /
* /
public int exportToText ( ) {
public int exportToText ( ) {
// 检查外部存储是否可用
if ( ! externalStorageAvailable ( ) ) {
if ( ! externalStorageAvailable ( ) ) {
Log . d ( TAG , "Media was not mounted" ) ;
Log . d ( TAG , "Media was not mounted" ) ;
return STATE_SD_CARD_UNMOUONTED ;
return STATE_SD_CARD_UNMOUONTED ;
@ -229,7 +291,7 @@ public class BackupUtils {
Log . e ( TAG , "get print stream error" ) ;
Log . e ( TAG , "get print stream error" ) ;
return STATE_SYSTEM_ERROR ;
return STATE_SYSTEM_ERROR ;
}
}
// First export folder and its notes
// 首先导出文件夹及其笔记
Cursor folderCursor = mContext . getContentResolver ( ) . query (
Cursor folderCursor = mContext . getContentResolver ( ) . query (
Notes . CONTENT_NOTE_URI ,
Notes . CONTENT_NOTE_URI ,
NOTE_PROJECTION ,
NOTE_PROJECTION ,
@ -240,7 +302,7 @@ public class BackupUtils {
if ( folderCursor ! = null ) {
if ( folderCursor ! = null ) {
if ( folderCursor . moveToFirst ( ) ) {
if ( folderCursor . moveToFirst ( ) ) {
do {
do {
// Print folder's name
// 打印文件夹名称
String folderName = "" ;
String folderName = "" ;
if ( folderCursor . getLong ( NOTE_COLUMN_ID ) = = Notes . ID_CALL_RECORD_FOLDER ) {
if ( folderCursor . getLong ( NOTE_COLUMN_ID ) = = Notes . ID_CALL_RECORD_FOLDER ) {
folderName = mContext . getString ( R . string . call_record_folder_name ) ;
folderName = mContext . getString ( R . string . call_record_folder_name ) ;
@ -257,7 +319,7 @@ public class BackupUtils {
folderCursor . close ( ) ;
folderCursor . close ( ) ;
}
}
// Export notes in root's folder
// 导出根文件夹下的笔记
Cursor noteCursor = mContext . getContentResolver ( ) . query (
Cursor noteCursor = mContext . getContentResolver ( ) . query (
Notes . CONTENT_NOTE_URI ,
Notes . CONTENT_NOTE_URI ,
NOTE_PROJECTION ,
NOTE_PROJECTION ,
@ -270,7 +332,7 @@ public class BackupUtils {
ps . println ( String . format ( getFormat ( FORMAT_NOTE_DATE ) , DateFormat . format (
ps . println ( String . format ( getFormat ( FORMAT_NOTE_DATE ) , DateFormat . format (
mContext . getString ( R . string . format_datetime_mdhm ) ,
mContext . getString ( R . string . format_datetime_mdhm ) ,
noteCursor . getLong ( NOTE_COLUMN_MODIFIED_DATE ) ) ) ) ;
noteCursor . getLong ( NOTE_COLUMN_MODIFIED_DATE ) ) ) ) ;
// Query data belong to this note
// 查询该笔记的数据
String noteId = noteCursor . getString ( NOTE_COLUMN_ID ) ;
String noteId = noteCursor . getString ( NOTE_COLUMN_ID ) ;
exportNoteToText ( noteId , ps ) ;
exportNoteToText ( noteId , ps ) ;
} while ( noteCursor . moveToNext ( ) ) ;
} while ( noteCursor . moveToNext ( ) ) ;
@ -283,7 +345,8 @@ public class BackupUtils {
}
}
/ * *
/ * *
* Get a print stream pointed to the file { @generateExportedTextFile }
* 获 取 指 向 导 出 文 本 文 件 的 打 印 流
* @return 打 印 流 对 象 , 如 果 获 取 失 败 返 回 null
* /
* /
private PrintStream getExportToTextPrintStream ( ) {
private PrintStream getExportToTextPrintStream ( ) {
File file = generateFileMountedOnSDcard ( mContext , R . string . file_path ,
File file = generateFileMountedOnSDcard ( mContext , R . string . file_path ,
@ -310,7 +373,11 @@ public class BackupUtils {
}
}
/ * *
/ * *
* Generate the text file to store imported data
* 在 SD 卡 上 生 成 用 于 存 储 导 入 数 据 的 文 本 文 件
* @param context 上 下 文 对 象
* @param filePathResId 文 件 路 径 资 源 ID
* @param fileNameFormatResId 文 件 名 格 式 资 源 ID
* @return 生 成 的 文 件 对 象 , 如 果 生 成 失 败 返 回 null
* /
* /
private static File generateFileMountedOnSDcard ( Context context , int filePathResId , int fileNameFormatResId ) {
private static File generateFileMountedOnSDcard ( Context context , int filePathResId , int fileNameFormatResId ) {
StringBuilder sb = new StringBuilder ( ) ;
StringBuilder sb = new StringBuilder ( ) ;
@ -340,5 +407,3 @@ public class BackupUtils {
return null ;
return null ;
}
}
}
}