Compare commits
9 Commits
main
...
chq_branch
Author | SHA1 | Date |
---|---|---|
|
0e5c75efb0 | 1 year ago |
|
04d48015e0 | 2 years ago |
|
cefa9bec0c | 2 years ago |
|
bbb85d6b56 | 2 years ago |
|
1d3e491966 | 2 years ago |
|
718398efa9 | 2 years ago |
|
f4ed669572 | 2 years ago |
|
5c3cc6a8c8 | 2 years ago |
|
a527ff020d | 2 years ago |
Binary file not shown.
Binary file not shown.
@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.gtask.data;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import android.database.Cursor;
|
|
||||||
|
|
||||||
public abstract class Node {
|
|
||||||
public static final int SYNC_ACTION_NONE = 0;// 本地和云端都无可更新内容(即本地和云端内容一致)
|
|
||||||
|
|
||||||
public static final int SYNC_ACTION_ADD_REMOTE = 1;// 在远程云端增加内容
|
|
||||||
|
|
||||||
public static final int SYNC_ACTION_ADD_LOCAL = 2;// 在本地增加内容
|
|
||||||
|
|
||||||
public static final int SYNC_ACTION_DEL_REMOTE = 3;// 在云端删除内容
|
|
||||||
|
|
||||||
public static final int SYNC_ACTION_DEL_LOCAL = 4;// 在本地删除内容
|
|
||||||
|
|
||||||
public static final int SYNC_ACTION_UPDATE_REMOTE = 5;// 本地上传云端
|
|
||||||
|
|
||||||
public static final int SYNC_ACTION_UPDATE_LOCAL = 6;// 云端更新本地
|
|
||||||
|
|
||||||
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;// 同步出现冲突
|
|
||||||
|
|
||||||
public static final int SYNC_ACTION_ERROR = 8;// 同步出现错误
|
|
||||||
|
|
||||||
// 定义了Node类中的私有字段
|
|
||||||
private String mGid; // 唯一标识符
|
|
||||||
|
|
||||||
private String mName; // 名称
|
|
||||||
|
|
||||||
private long mLastModified; // 最后一次修改时间
|
|
||||||
|
|
||||||
private boolean mDeleted; // 是否删除
|
|
||||||
|
|
||||||
public Node() {
|
|
||||||
mGid = null;
|
|
||||||
mName = "";
|
|
||||||
mLastModified = 0;
|
|
||||||
mDeleted = false;
|
|
||||||
}// 初始化
|
|
||||||
|
|
||||||
public abstract JSONObject getCreateAction(int actionId); // 根据给定的 actionId 返回一个 JSON 对象,表示创建操作
|
|
||||||
|
|
||||||
public abstract JSONObject getUpdateAction(int actionId); // 根据给定的 actionId 返回一个 JSON 对象,表示更新操作
|
|
||||||
|
|
||||||
public abstract void setContentByRemoteJSON(JSONObject js); // 根据远程的 JSON 对象设置内容
|
|
||||||
|
|
||||||
public abstract void setContentByLocalJSON(JSONObject js); // 根据本地的 JSON 对象设置内容
|
|
||||||
|
|
||||||
public abstract JSONObject getLocalJSONFromContent(); // 返回一个 JSON 对象,表示从当前内容中获取本地 JSON 数据
|
|
||||||
|
|
||||||
public abstract int getSyncAction(Cursor c); // 根据给定的 Cursor 返回一个 JSON 对象,表示同步操作
|
|
||||||
|
|
||||||
// 设置相关信息
|
|
||||||
public void setGid(String gid) {
|
|
||||||
this.mGid = gid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.mName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastModified(long lastModified) {
|
|
||||||
this.mLastModified = lastModified;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeleted(boolean deleted) {
|
|
||||||
this.mDeleted = deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取相关信息
|
|
||||||
public String getGid() {
|
|
||||||
return this.mGid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return this.mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLastModified() {
|
|
||||||
return this.mLastModified;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getDeleted() {
|
|
||||||
return this.mDeleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,249 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.model;
|
|
||||||
|
|
||||||
import android.content.ContentProviderOperation;//批量的更新、插入、删除数据。
|
|
||||||
import android.content.ContentProviderResult;//操作的结果
|
|
||||||
import android.content.ContentUris;//用于添加和获取Uri后面的ID
|
|
||||||
import android.content.ContentValues;//一种用来存储基本数据类型数据的存储机制
|
|
||||||
import android.content.Context;//需要用该类来弄清楚调用者的实例
|
|
||||||
import android.content.OperationApplicationException;//操作应用程序容错
|
|
||||||
import android.net.Uri;//表示待操作的数据
|
|
||||||
import android.os.RemoteException;//远程容错
|
|
||||||
import android.util.Log;//输出日志,比如说出错、警告等
|
|
||||||
|
|
||||||
public class Note {
|
|
||||||
// private ContentValues mNoteDiffValues;
|
|
||||||
ContentValues mNoteDiffValues;//
|
|
||||||
private NoteData mNoteData;
|
|
||||||
private static final String TAG = "Note";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new note id for adding a new note to databases
|
|
||||||
*/
|
|
||||||
public static synchronized long getNewNoteId(Context context, long folderId) {
|
|
||||||
// Create a new note in the database
|
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
long createdTime = System.currentTimeMillis();
|
|
||||||
values.put(NoteColumns.CREATED_DATE, createdTime);
|
|
||||||
values.put(NoteColumns.MODIFIED_DATE, createdTime);
|
|
||||||
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
|
|
||||||
values.put(NoteColumns.LOCAL_MODIFIED, 1);
|
|
||||||
values.put(NoteColumns.PARENT_ID, folderId);//将数据写入数据库表格
|
|
||||||
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
|
|
||||||
//ContentResolver()主要是实现外部应用对ContentProvider中的数据
|
|
||||||
//进行添加、删除、修改和查询操作
|
|
||||||
long noteId = 0;
|
|
||||||
try {
|
|
||||||
noteId = Long.valueOf(uri.getPathSegments().get(1));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "Get note id error :" + e.toString());
|
|
||||||
noteId = 0;
|
|
||||||
}//try-catch异常处理
|
|
||||||
if (noteId == -1) {
|
|
||||||
throw new IllegalStateException("Wrong note id:" + noteId);
|
|
||||||
}
|
|
||||||
return noteId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Note() {
|
|
||||||
mNoteDiffValues = new ContentValues();
|
|
||||||
mNoteData = new NoteData();
|
|
||||||
}//定义两个变量用来存储便签的数据,一个是存储便签属性、一个是存储便签内容
|
|
||||||
|
|
||||||
public void setNoteValue(String key, String value) {
|
|
||||||
mNoteDiffValues.put(key, value);
|
|
||||||
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
|
|
||||||
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
|
|
||||||
}//设置数据库表格的标签属性数据
|
|
||||||
|
|
||||||
public void setTextData(String key, String value) {
|
|
||||||
mNoteData.setTextData(key, value);
|
|
||||||
}//设置数据库表格的标签文本内容的数据
|
|
||||||
|
|
||||||
public void setTextDataId(long id) {
|
|
||||||
mNoteData.setTextDataId(id);
|
|
||||||
}//设置文本数据的ID
|
|
||||||
|
|
||||||
public long getTextDataId() {
|
|
||||||
return mNoteData.mTextDataId;
|
|
||||||
}//得到文本数据的ID
|
|
||||||
|
|
||||||
public void setCallDataId(long id) {
|
|
||||||
mNoteData.setCallDataId(id);
|
|
||||||
}//设置电话号码数据的ID
|
|
||||||
|
|
||||||
public void setCallData(String key, String value) {
|
|
||||||
mNoteData.setCallData(key, value);
|
|
||||||
}//得到电话号码数据的ID
|
|
||||||
|
|
||||||
public boolean isLocalModified() {
|
|
||||||
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
|
|
||||||
}//判断是否是本地修改
|
|
||||||
|
|
||||||
public boolean syncNote(Context context, long noteId) {
|
|
||||||
if (noteId <= 0) {
|
|
||||||
throw new IllegalArgumentException("Wrong note id:" + noteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isLocalModified()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and
|
|
||||||
* {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the
|
|
||||||
* note data info
|
|
||||||
*/
|
|
||||||
if (context.getContentResolver().update(
|
|
||||||
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
|
|
||||||
null) == 0) {
|
|
||||||
Log.e(TAG, "Update note error, should not happen");
|
|
||||||
// Do not return, fall through
|
|
||||||
}
|
|
||||||
mNoteDiffValues.clear();
|
|
||||||
|
|
||||||
if (mNoteData.isLocalModified()
|
|
||||||
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}//判断数据是否同步
|
|
||||||
|
|
||||||
private class NoteData {//定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据
|
|
||||||
private long mTextDataId;
|
|
||||||
|
|
||||||
private ContentValues mTextDataValues;//文本数据
|
|
||||||
|
|
||||||
private long mCallDataId;
|
|
||||||
|
|
||||||
private ContentValues mCallDataValues;//电话号码数据
|
|
||||||
|
|
||||||
private static final String TAG = "NoteData";
|
|
||||||
|
|
||||||
public NoteData() {
|
|
||||||
mTextDataValues = new ContentValues();
|
|
||||||
mCallDataValues = new ContentValues();
|
|
||||||
mTextDataId = 0;
|
|
||||||
mCallDataId = 0;
|
|
||||||
}
|
|
||||||
//下面是上述几个函数的具体实现
|
|
||||||
boolean isLocalModified() {
|
|
||||||
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTextDataId(long id) {
|
|
||||||
if(id <= 0) {
|
|
||||||
throw new IllegalArgumentException("Text data id should larger than 0");
|
|
||||||
}
|
|
||||||
mTextDataId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCallDataId(long id) {
|
|
||||||
if (id <= 0) {
|
|
||||||
throw new IllegalArgumentException("Call data id should larger than 0");
|
|
||||||
}
|
|
||||||
mCallDataId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCallData(String key, String value) {
|
|
||||||
mCallDataValues.put(key, value);
|
|
||||||
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
|
|
||||||
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTextData(String key, String value) {
|
|
||||||
mTextDataValues.put(key, value);
|
|
||||||
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
|
|
||||||
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
//下面函数的作用是将新的数据通过Uri的操作存储到数据库
|
|
||||||
Uri pushIntoContentResolver(Context context, long noteId) {
|
|
||||||
/**
|
|
||||||
* Check for safety
|
|
||||||
*/
|
|
||||||
if (noteId <= 0) {
|
|
||||||
throw new IllegalArgumentException("Wrong note id:" + noteId);
|
|
||||||
}//判断数据是否合法
|
|
||||||
|
|
||||||
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
|
|
||||||
ContentProviderOperation.Builder builder = null;//数据库的操作列表
|
|
||||||
|
|
||||||
if(mTextDataValues.size() > 0) {
|
|
||||||
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
|
|
||||||
if (mTextDataId == 0) {
|
|
||||||
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
|
|
||||||
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
|
|
||||||
mTextDataValues);
|
|
||||||
try {
|
|
||||||
setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "Insert new text data fail with noteId" + noteId);
|
|
||||||
mTextDataValues.clear();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
|
|
||||||
Notes.CONTENT_DATA_URI, mTextDataId));
|
|
||||||
builder.withValues(mTextDataValues);
|
|
||||||
operationList.add(builder.build());
|
|
||||||
}
|
|
||||||
mTextDataValues.clear();
|
|
||||||
}//把文本数据存入DataColumns
|
|
||||||
|
|
||||||
if(mCallDataValues.size() > 0) {
|
|
||||||
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
|
|
||||||
if (mCallDataId == 0) {
|
|
||||||
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
|
|
||||||
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
|
|
||||||
mCallDataValues);
|
|
||||||
try {
|
|
||||||
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "Insert new call data fail with noteId" + noteId);
|
|
||||||
mCallDataValues.clear();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
|
|
||||||
Notes.CONTENT_DATA_URI, mCallDataId));
|
|
||||||
builder.withValues(mCallDataValues);
|
|
||||||
operationList.add(builder.build());
|
|
||||||
}
|
|
||||||
mCallDataValues.clear();
|
|
||||||
}//把电话号码数据存入DataColumns
|
|
||||||
|
|
||||||
if (operationList.size() > 0) {
|
|
||||||
try {
|
|
||||||
ContentProviderResult[] results = context.getContentResolver().applyBatch(
|
|
||||||
Notes.AUTHORITY, operationList);
|
|
||||||
return (results == null || results.length == 0 || results[0] == null) ? null
|
|
||||||
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
|
||||||
return null;
|
|
||||||
} catch (OperationApplicationException e) {
|
|
||||||
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}//存储过程中的异常处理
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,370 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.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;//用于管理笔记数据和资源n
|
|
||||||
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;//在JAVA中实现操作功能的类
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
|
|
||||||
//笔记备份工具类
|
|
||||||
public class BackupUtils {
|
|
||||||
private static final String TAG = "BackupUtils";
|
|
||||||
// Singleton stuff 单例模式
|
|
||||||
private static BackupUtils sInstance;
|
|
||||||
|
|
||||||
public static synchronized BackupUtils getInstance(Context context) {
|
|
||||||
if (sInstance == null) {
|
|
||||||
sInstance = new BackupUtils(context);
|
|
||||||
}
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
// 备份和恢复功能
|
|
||||||
//定义备份或恢复数据时可能遇到的状态码。
|
|
||||||
|
|
||||||
public class BackupState {
|
|
||||||
|
|
||||||
//当前SD未挂载
|
|
||||||
|
|
||||||
public static final int STATE_SD_CARD_UNMOUNTED = 0;
|
|
||||||
|
|
||||||
//备份文件不存在
|
|
||||||
|
|
||||||
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
|
|
||||||
|
|
||||||
// 数据格式不正确,可能被其他程序更改
|
|
||||||
|
|
||||||
public static final int STATE_DATA_DESTROYED = 2;
|
|
||||||
|
|
||||||
//运行时异常导致恢复或备份失败
|
|
||||||
|
|
||||||
public static final int STATE_SYSTEM_ERROR = 3;
|
|
||||||
|
|
||||||
// 备份或恢复成功
|
|
||||||
|
|
||||||
public static final int STATE_SUCCESS = 4;
|
|
||||||
|
|
||||||
// 用于导出文件的目录
|
|
||||||
private TextExport mTextExport;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BackupUtils(Context context) {
|
|
||||||
mTextExport = new TextExport(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean externalStorageAvailable() {
|
|
||||||
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int exportToText() {
|
|
||||||
return mTextExport.exportToText();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExportedTextFileName() {
|
|
||||||
return mTextExport.mFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExportedTextFileDir() {
|
|
||||||
return mTextExport.mFileDirectory;
|
|
||||||
}
|
|
||||||
// 笔记备份类
|
|
||||||
private static class TextExport {
|
|
||||||
private static final String[] NOTE_PROJECTION = {
|
|
||||||
NoteColumns.ID,
|
|
||||||
NoteColumns.MODIFIED_DATE,
|
|
||||||
NoteColumns.SNIPPET,
|
|
||||||
NoteColumns.TYPE
|
|
||||||
};
|
|
||||||
//定义Note数据表中各列对应的索引常量。
|
|
||||||
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,
|
|
||||||
DataColumns.DATA1,
|
|
||||||
DataColumns.DATA2,
|
|
||||||
DataColumns.DATA3,
|
|
||||||
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 static final int FORMAT_FOLDER_NAME = 0;
|
|
||||||
private static final int FORMAT_NOTE_DATE = 1;
|
|
||||||
private static final int FORMAT_NOTE_CONTENT = 2;
|
|
||||||
|
|
||||||
private Context mContext;
|
|
||||||
private String mFileName;
|
|
||||||
private String mFileDirectory;
|
|
||||||
// 备份和恢复功能
|
|
||||||
public TextExport(Context context) {
|
|
||||||
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note);
|
|
||||||
mContext = context;
|
|
||||||
mFileName = "";
|
|
||||||
mFileDirectory = "";
|
|
||||||
}
|
|
||||||
//同上
|
|
||||||
private String getFormat(int id) {
|
|
||||||
return TEXT_FORMAT[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 导出笔记到文本
|
|
||||||
private void exportFolderToText(String folderId, PrintStream ps) {
|
|
||||||
// Query notes belong to this folder
|
|
||||||
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 {
|
|
||||||
// Print note's last modified date
|
|
||||||
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
|
|
||||||
mContext.getString(R.string.format_datetime_mdhm),
|
|
||||||
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
|
|
||||||
// Query data belong to this note
|
|
||||||
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
|
|
||||||
exportNoteToText(noteId, ps);
|
|
||||||
} while (notesCursor.moveToNext());
|
|
||||||
}
|
|
||||||
notesCursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 导出笔记到文本
|
|
||||||
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 {// 开始遍历笔记数据
|
|
||||||
// 获取当前行的MIME类型
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(phoneNumber)) {
|
|
||||||
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),
|
|
||||||
content));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (dataCursor.moveToNext());
|
|
||||||
}
|
|
||||||
// 关闭数据游标
|
|
||||||
dataCursor.close();
|
|
||||||
}
|
|
||||||
// print a line separator between note
|
|
||||||
|
|
||||||
try {
|
|
||||||
ps.write(new byte[] {
|
|
||||||
Character.LINE_SEPARATOR, Character.LETTER_NUMBER
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 导出笔记到文本
|
|
||||||
public int exportToText() {
|
|
||||||
if (!externalStorageAvailable()) {
|
|
||||||
Log.d(TAG, "Media was not mounted");
|
|
||||||
return STATE_SD_CARD_UNMOUONTED;
|
|
||||||
}
|
|
||||||
// 错误输出
|
|
||||||
PrintStream ps = getExportToTextPrintStream();
|
|
||||||
if (ps == null) {
|
|
||||||
Log.e(TAG, "get print stream error");
|
|
||||||
return STATE_SYSTEM_ERROR;
|
|
||||||
}
|
|
||||||
// First export folder and its notes
|
|
||||||
|
|
||||||
// 查询文件夹
|
|
||||||
Cursor folderCursor = mContext.getContentResolver().query(
|
|
||||||
Notes.CONTENT_NOTE_URI,
|
|
||||||
NOTE_PROJECTION,
|
|
||||||
"(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND "
|
|
||||||
+ NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
|
|
||||||
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null);
|
|
||||||
// 遍历文件夹
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
} while (folderCursor.moveToNext());
|
|
||||||
}
|
|
||||||
// 关闭文件夹游标
|
|
||||||
folderCursor.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Export trash folder
|
|
||||||
|
|
||||||
// Export notes in root's folder
|
|
||||||
Cursor noteCursor = mContext.getContentResolver().query(
|
|
||||||
Notes.CONTENT_NOTE_URI,
|
|
||||||
NOTE_PROJECTION,
|
|
||||||
NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
|
|
||||||
+ "=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))));
|
|
||||||
// Query data belong to this note
|
|
||||||
String noteId = noteCursor.getString(NOTE_COLUMN_ID);
|
|
||||||
exportNoteToText(noteId, ps);
|
|
||||||
} while (noteCursor.moveToNext());
|
|
||||||
}
|
|
||||||
noteCursor.close();
|
|
||||||
}
|
|
||||||
ps.close();
|
|
||||||
|
|
||||||
return STATE_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a print stream pointed to the file {@generateExportedTextFile}
|
|
||||||
*/
|
|
||||||
// 获取打印流
|
|
||||||
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);
|
|
||||||
ps = new PrintStream(fos);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return ps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the text file to store imported data
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 生成文件
|
|
||||||
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());
|
|
||||||
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) {
|
|
||||||
// 处理IO异常
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遇到异常返回null
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" packagePrefix="net.micode.notes.tool" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
@ -0,0 +1 @@
|
|||||||
|
AlarmAlertActivity.java
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/ui.iml" filepath="$PROJECT_DIR$/ui.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
Loading…
Reference in new issue