Compare commits

...

2 Commits

Author SHA1 Message Date
czy 008e7ed2e5 12.31
1 year ago
czy adc88a91a4 88
1 year ago

@ -1,3 +1,6 @@
Android
```java
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
@ -5,7 +8,7 @@
* 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
* 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,
@ -13,9 +16,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 版权声明说明该代码遵循Apache License 2.0。
package net.micode.notes.tool;
// 导入所需的Android类库
import android.content.Context;
import android.database.Cursor;
import android.os.Environment;
@ -23,6 +28,7 @@ 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;
@ -35,63 +41,60 @@ 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实例
// 获取 BackupUtils 的单例实例
// 获取BackupUtils实例的方法
public static synchronized BackupUtils getInstance(Context context) {
if (sInstance == null) {
sInstance = new BackupUtils(context); // 初始化单例实例
sInstance = new BackupUtils(context);
}
return sInstance;
}
// 定义备份或恢复的状态码
/**
*
*/
// SD卡未挂载
// 定义备份状态常量
public static final int STATE_SD_CARD_UNMOUONTED = 0;
// 备份文件不存在
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;
// TextExport实例用于将数据导出到文本
// 私有构造方法,防止外部直接实例化
// 私有构造方法,确保只能通过getInstance方法获取实例
private BackupUtils(Context context) {
mTextExport = new TextExport(context); // 初始化 TextExport 实例
mTextExport = new TextExport(context);
}
// 检查外部存储是否可用
// 检查外部存储是否可用
private static boolean externalStorageAvailable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
// 导出笔记到文本文件
// 导出数据到文本的方法
public int exportToText() {
return mTextExport.exportToText(); // 调用 TextExport 类的 exportToText 方法
return mTextExport.exportToText();
}
// 获取导出文本文件名
// 获取导出文本文件的文件名
public String getExportedTextFileName() {
return mTextExport.mFileName; // 返回 TextExport 类中的文件名
return mTextExport.mFileName;
}
// 获取导出文本文件目录
// 获取导出文本文件目录
public String getExportedTextFileDir() {
return mTextExport.mFileDirectory; // 返回 TextExport 类中的文件目录
return mTextExport.mFileDirectory;
}
// TextExport内部类用于将笔记数据导出到文本
private static class TextExport {
// 定义查询笔记时的列信息
// 定义查询笔记数据的投影数组
private static final String[] NOTE_PROJECTION = {
NoteColumns.ID,
NoteColumns.MODIFIED_DATE,
@ -99,12 +102,12 @@ public class BackupUtils {
NoteColumns.TYPE
};
// 定义每列的索引
// 定义投影数组的索引常量
private static final int NOTE_COLUMN_ID = 0;
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,
@ -114,36 +117,34 @@ public class BackupUtils {
DataColumns.DATA4,
};
// 定义每列的索引
// 定义投影数组的索引常量
private static final int DATA_COLUMN_CONTENT = 0;
private static final int DATA_COLUMN_MIME_TYPE = 1;
private static final int DATA_COLUMN_CALL_DATE = 2;
private static final int DATA_COLUMN_PHONE_NUMBER = 4;
// 用于格式化导出文本的字符串数组
// 定义文本格式数组
private final String[] TEXT_FORMAT;
private Context mContext;
private String mFileName;
private String mFileDirectory;
// 构造方法,初始化字段
// TextExport构造方法
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;
mFileName = ""; // 初始化文件名为空字符串
mFileDirectory = ""; // 初始化文件目录为空字符串
mFileName = "";
mFileDirectory = "";
}
// 获取指定格式的字符串
// 获取文本格式的方法
private String getFormat(int id) {
return TEXT_FORMAT[id]; // 返回格式化字符串数组中的指定元素
return TEXT_FORMAT[id];
}
/**
* ID
*/
// 导出文件夹到文本的方法
private void exportFolderToText(String folderId, PrintStream ps) {
// 查询属于该文件夹的笔记
// 查询文件夹内笔记的数据
Cursor notesCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
@ -154,24 +155,22 @@ public class BackupUtils {
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); // 导出该笔记的数据
exportNoteToText(noteId, ps);
} while (notesCursor.moveToNext());
}
notesCursor.close(); // 关闭游标
notesCursor.close();
}
}
/**
* ID
*/
// 导出笔记到文本的方法
private void exportNoteToText(String noteId, PrintStream ps) {
// 查询属于该笔记的数据
// 查询笔记的内容
Cursor dataCursor = mContext.getContentResolver().query(
Notes.CONTENT_DATA_URI,
DATA_PROJECTION,
@ -184,7 +183,7 @@ public class BackupUtils {
do {
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
if (DataConstants.CALL_NOTE.equals(mimeType)) {
// 打印电话号码
// 处理通话记录类型的笔记
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER);
long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE);
String location = dataCursor.getString(DATA_COLUMN_CONTENT);
@ -193,16 +192,17 @@ public class BackupUtils {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
phoneNumber));
}
// 打印通话日期
// 打印通话日期
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat
.format(mContext.getString(R.string.format_datetime_mdhm),
callDate)));
// 打印通话附件位置
// 打印通话地点
if (!TextUtils.isEmpty(location)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
location));
}
} else if (DataConstants.NOTE.equals(mimeType)) {
// 处理普通笔记
String content = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(content)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
@ -211,33 +211,31 @@ public class BackupUtils {
}
} while (dataCursor.moveToNext());
}
dataCursor.close(); // 关闭游标
dataCursor.close();
}
// 在笔记之间打印一个换行符
// 打印换行符
try {
ps.write(new byte[] {
Character.LINE_SEPARATOR, Character.LETTER_NUMBER
});
} catch (IOException e) {
Log.e(TAG, e.toString()); // 记录异常信息
Log.e(TAG, e.toString());
}
}
/**
*
*/
// 导出数据为文本文件的方法
public int exportToText() {
if (!externalStorageAvailable()) {
Log.d(TAG, "Media was not mounted"); // 记录调试信息SD卡未挂载
return STATE_SD_CARD_UNMOUONTED; // 返回 SD卡未挂载 的状态码
Log.d(TAG, "Media was not mounted");
return STATE_SD_CARD_UNMOUONTED;
}
PrintStream ps = getExportToTextPrintStream(); // 获取 PrintStream 实例
PrintStream ps = getExportToTextPrintStream();
if (ps == null) {
Log.e(TAG, "get print stream error"); // 记录错误信息,获取 PrintStream 失败
return STATE_SYSTEM_ERROR; // 返回 系统错误 的状态码
Log.e(TAG, "get print stream error");
return STATE_SYSTEM_ERROR;
}
// 首先导出文件夹及其笔记
// 查询所有文件夹和笔记的数据
Cursor folderCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
@ -248,24 +246,24 @@ public class BackupUtils {
if (folderCursor != null) {
if (folderCursor.moveToFirst()) {
do {
// 打印文件夹名称
// 打印文件夹名称
String folderName = "";
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);
} else {
folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET); // 获取文件夹的摘要
folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET);
}
if (!TextUtils.isEmpty(folderName)) {
ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName));
}
String folderId = folderCursor.getString(NOTE_COLUMN_ID);
exportFolderToText(folderId, ps); // 导出该文件夹下的笔记
exportFolderToText(folderId, ps);
} while (folderCursor.moveToNext());
}
folderCursor.close(); // 关闭游标
folderCursor.close();
}
// 导出根文件夹中的笔记
// 打印笔记内容
Cursor noteCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
@ -273,85 +271,80 @@ public class BackupUtils {
+ "=0", null, null);
if (noteCursor != null) {
if (noteCursor.moveToFirst()) {
do {
// 打印笔记的最后修改日期
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// 查询属于该笔记的数据
String noteId = noteCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps); // 导出该笔记的数据
} while (noteCursor.moveToNext());
}
noteCursor.close(); // 关闭游标
if (noteCursor.moveToFirst()) {
do {
// 打印笔记的修改日期
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// 查询笔记的内容
String noteId = noteCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps);
} while (noteCursor.moveToNext());
}
ps.close(); // 关闭 PrintStream
return STATE_SUCCESS; // 返回 成功 的状态码
noteCursor.close();
}
ps.close();
/**
* PrintStream
*/
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;
}
mFileName = file.getName(); // 设置文件名
mFileDirectory = mContext.getString(R.string.file_path); // 设置文件目录
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(file); // 创建 FileOutputStream 实例
ps = new PrintStream(fos); // 创建 PrintStream 实例
} catch (FileNotFoundException e) {
e.printStackTrace(); // 打印异常堆栈信息
return null;
} catch (NullPointerException e) {
e.printStackTrace(); // 打印异常堆栈信息
return null;
}
return ps; // 返回 PrintStream 实例
}
return STATE_SUCCESS;
}
/**
*
*/
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder();
sb.append(Environment.getExternalStorageDirectory()); // 获取外部存储目录
sb.append(context.getString(filePathResId)); // 追加文件路径
File filedir = new File(sb.toString()); // 创建文件目录对象
// 如果目录不存在,则创建目录
if (!filedir.exists()) {
filedir.mkdir();
// 获取导出文本的PrintStream对象
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;
}
// 构建文件名
sb.append(context.getString(
fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd),
System.currentTimeMillis()))); // 追加格式化的日期
File file = new File(sb.toString()); // 创建文件对象
mFileName = file.getName();
mFileDirectory = mContext.getString(R.string.file_path);
PrintStream ps = null;
try {
// 如果文件不存在,则创建文件
if (!file.exists()) {
file.createNewFile();
}
return file; // 返回文件对象
} catch (SecurityException e) {
e.printStackTrace(); // 打印安全异常堆栈信息
} catch (IOException e) {
e.printStackTrace(); // 打印IO异常堆栈信息
FileOutputStream fos = new FileOutputStream(file);
ps = new PrintStream(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (NullPointerException e) {
e.printStackTrace();
return null;
}
return ps;
}
}
return null; // 返回 null表示文件创建失败
// 在SD卡上生成文件的方法
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder();
sb.append(Environment.getExternalStorageDirectory());
sb.append(context.getString(filePathResId));
File filedir = new File(sb.toString());
// 创建目录
if (!filedir.exists()) {
filedir.mkdir();
}
// 创建文件名
sb.append(context.getString(
fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd),
System.currentTimeMillis())));
File file = new File(sb.toString());
try {
// 创建文件
if (!file.exists()) {
file.createNewFile();
}
return file;
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

@ -5,7 +5,7 @@
* 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
* 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,
@ -29,24 +29,29 @@ public class Contact {
private static HashMap<String, String> sContactCache;
private static final String TAG = "Contact";
// SQL查询语句模板用于匹配电话号码
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN "
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "')"
+ " AND " + Data.RAW_CONTACT_ID + " IN "
+ "(SELECT raw_contact_id "
+ " FROM phone_lookup"
+ " WHERE min_match = '+')";
public static String getContact(Context context, String phoneNumber) {
// 初始化缓存
if(sContactCache == null) {
sContactCache = new HashMap<String, String>();
}
// 如果缓存中已存在该电话号码对应的联系人,则直接返回缓存中的联系人名
if(sContactCache.containsKey(phoneNumber)) {
return sContactCache.get(phoneNumber);
}
// 将查询语句中的"+"替换为实际的电话号码,以进行最小匹配
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
// 执行数据库查询,获取联系人名字
Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME },
@ -54,20 +59,25 @@ public class Contact {
new String[] { phoneNumber },
null);
// 如果查询成功并且游标指向第一条记录
if (cursor != null && cursor.moveToFirst()) {
try {
// 从游标中获取联系人名字,并将其放入缓存
String name = cursor.getString(0);
sContactCache.put(phoneNumber, name);
return name;
} catch (IndexOutOfBoundsException e) {
// 如果发生异常,记录错误日志
Log.e(TAG, " Cursor get string error " + e.toString());
return null;
} finally {
// 无论如何都要关闭游标
cursor.close();
}
} else {
// 如果没有找到匹配的联系人记录日志并返回null
Log.d(TAG, "No contact matched with number:" + phoneNumber);
return null;
}
}
}
}

@ -5,7 +5,7 @@
* 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
* 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,
@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 这段注释是文件的版权声明表明该文件由MiCode开源社区编写并遵循Apache License 2.0。
package net.micode.notes.gtask.data;
@ -24,59 +25,75 @@ import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
// 定义了一个名为MetaData的类它继承自Task类用于处理与Google任务相关的元数据。
public class MetaData extends Task {
// 类的标签,用于日志记录。
private final static String TAG = MetaData.class.getSimpleName();
// 用于存储与Google任务相关的全局ID。
private String mRelatedGid = null;
// 设置元数据信息的方法。
public void setMeta(String gid, JSONObject metaInfo) {
try {
// 将全局ID添加到元信息对象中。
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
} catch (JSONException e) {
// 如果在添加全局ID时发生错误记录错误日志。
Log.e(TAG, "failed to put related gid");
}
// 将元信息对象转换为字符串,并设置为笔记内容。
setNotes(metaInfo.toString());
// 设置元数据的名称。
setName(GTaskStringUtils.META_NOTE_NAME);
}
// 获取与Google任务相关的全局ID。
public String getRelatedGid() {
return mRelatedGid;
}
// 重写isWorthSaving方法判断是否有值得保存的笔记内容。
@Override
public boolean isWorthSaving() {
return getNotes() != null;
}
// 重写setContentByRemoteJSON方法从远程JSON设置内容。
@Override
public void setContentByRemoteJSON(JSONObject js) {
super.setContentByRemoteJSON(js);
if (getNotes() != null) {
try {
// 从笔记内容中解析出元信息对象。
JSONObject metaInfo = new JSONObject(getNotes().trim());
// 获取并设置与Google任务相关的全局ID。
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
} catch (JSONException e) {
// 如果解析元信息对象失败记录警告日志并设置全局ID为null。
Log.w(TAG, "failed to get related gid");
mRelatedGid = null;
}
}
}
// 重写setContentByLocalJSON方法但由于MetaData类的特殊性此方法不应该被调用。
@Override
public void setContentByLocalJSON(JSONObject js) {
// this function should not be called
// 抛出异常,表明此方法不应该被调用。
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
}
// 重写getLocalJSONFromContent方法但由于MetaData类的特殊性此方法不应该被调用。
@Override
public JSONObject getLocalJSONFromContent() {
// 抛出异常,表明此方法不应该被调用。
throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");
}
// 重写getSyncAction方法但由于MetaData类的特殊性此方法不应该被调用。
@Override
public int getSyncAction(Cursor c) {
// 抛出异常,表明此方法不应该被调用。
throw new IllegalAccessError("MetaData:getSyncAction should not be called");
}
}
}

@ -233,43 +233,58 @@ public class Note {
mTextDataValues.clear();
}
// 如果有呼叫数据需要更新
// 检查是否有呼叫数据需要更新。
if(mCallDataValues.size() > 0) {
// 如果有数据需要更新将笔记ID放入数据值中。
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
// 如果mCallDataId为0表示这是一个新的呼叫数据记录需要插入操作。
if (mCallDataId == 0) {
// 设置MIME类型为呼叫记录的类型。
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mCallDataValues);
// 插入新的呼叫数据记录到内容提供者并获取返回的URI。
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, mCallDataValues);
// 尝试从返回的URI中解析出新的呼叫数据ID。
try {
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
// 如果解析失败记录错误日志并清除数据值返回null。
Log.e(TAG, "Insert new call data fail with noteId" + noteId);
mCallDataValues.clear();
return null;
}
} else {
// 如果mCallDataId不为0表示是更新已有的呼叫数据记录。
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId));
// 设置更新的数据值。
builder.withValues(mCallDataValues);
// 将更新操作添加到操作列表中。
operationList.add(builder.build());
}
// 清除数据值,为下一次更新做准备。
mCallDataValues.clear();
}
// 检查操作列表是否有内容需要执行。
if (operationList.size() > 0) {
try {
// 应用批量操作。
ContentProviderResult[] results = context.getContentResolver().applyBatch(
Notes.AUTHORITY, operationList);
// 如果操作结果为空或者结果数组长度为0或者第一个结果为null返回null。
return (results == null || results.length == 0 || results[0] == null) ? null
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
} catch (RemoteException e) {
// 如果发生远程异常记录错误日志并返回null。
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
} catch (OperationApplicationException e) {
// 如果操作应用异常记录错误日志并返回null。
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
}
}
// 如果操作列表为空返回null。
return null;
}
}

Loading…
Cancel
Save