Merge pull request '实践任务' (#41) from dev into master

胡逸飞_branch
ppu9cqlvf 3 years ago
commit 831de3e465

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

@ -0,0 +1,3 @@
胡逸飞:用户界面原型
王俊龙用户界面的UML类图模型
王志成:界面跳转的顺序图模型

@ -0,0 +1,4 @@
谢成扬:类图
胡逸飞:状态图
王俊龙:顺序图
王志成:活动图

@ -0,0 +1 @@
<mxfile host="Electron" modified="2023-05-19T06:10:12.943Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="T0tQnj9NwKXQe3GHPA9i" version="20.3.0" type="device"><diagram id="e9VWi3nR8J8FZAH3Ml_h" name="第 1 页">7Vhrb5swFP01SNuHVhjy6se82kltt2qZFPWjCzdg1WBqTB779bsGE0JImrRrVk2KFEX4+NrY5xxf38Ryh9HyRtIkvBc+cMux/aXljizHaRMbvzWwKoBO2y2AQDK/gEgFTNhvMKAZF2TMh7QWqITgiiV10BNxDJ6qYVRKsaiHzQSvvzWhATSAiUd5E50yX4UF2nO6Ff4NWBCWbyadq6InomWw2UkaUl8sNiB3bLlDKYQqnqLlELjmruSlGHe9p3e9MAmxOmbAxfRWfB+TCYSPU9L7wdXjy+2FU8wypzwzG54CLhxk31NsztTKrF2tSkLSBYs4jbE1mIlYTUwPwTblLIjx2cMVgURgDlIx5LJvOpRIEPVCxv07uhKZXneqqPdctgahkOw3Tku5mRO7pTK2cDq1iIkeibCNqIQUYx5KMsgWdE+XtcA7mioDeIJzmqTsab2NiMqAxQOhlIhMUJNrQ7/eISw3IMP9DYgIlET6bNPbKn1gDoJ7ZdqLylZrr4SbluoZkBorB+u5K7XxwQj+BvHdhviWg1u1J0qyOMAH4wULiXdcUhChA3yRabrwKEKUgKQqk9AIWs/ChUcVE3HDSsicyiWW4hmGggv0zCgWhbcY51tQaS8OM7XXXGlCPXztXR4zalXIT8OohgSOnfH8MIbM9yHWxhCKKlq4QG8iESxWOePtAX5Qg6F92bbauPAhtknVxo8Ol2ooYtwLZblHAC22AG2zHe559SwetpSxkGb8GAd1WycyUGuHgbY05izXrtC4zKDkXQJHKBWHStFfWvDRBWmo7jZVd3cozOkT8AeRstyc7kgWsVvKHxK37l4W43lhpxSd2Efmjd6JRG/vyRoSXjKkxOSML18bCSEAhflid4eHV43uOWeIDzZL78gU4ZzILZ2GW8ZLBbGfNrRGsK8LNmw94ZWBN/sAIXP1k07RvGb69Tn9oYrKIkGKLPbBP3RZg1+r9ZqsbbBEOoYlCRxvr3m9HNxFk5nuQbuiuvadbv3ab3Xcy3Z9klRk0gMzbrOA25qq5R6cCoslPEyNqXLl1vt8v5jdhphvLRPtv67/dhz7/7UkJNuCkmZqJ61dJaF9qhu9tye5zxjoH059XfOtEjgn6tcTdfdoK+wv5XYqX8Z9uPBXZ+E/Rfi288nClznnrPw/Vr7bLM0+SnlsVv8rFZd/9eecO/4D</diagram></mxfile>

@ -0,0 +1 @@
<mxfile host="Electron" modified="2023-05-18T13:54:00.718Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="DGN9s7_pGRWWOMTsA7K7" version="20.3.0" type="device"><diagram id="WYATknTTQbvD28lRpk5o" name="第 1 页">7Vhtb9owEP41kbYPnfJC0vIRKN2ktWtVJk3aNzcxiYXji5zjbb9+Z+IQQkClW1k1qRJCvsfnw77n8dnYCUb56rNmRXYHCZeO7yYrJ7h2fD/0XPo2wLoCojCogFSLpIK8BpiIX9yCdlw6FwkvW44IIFEUbTAGpXiMLYxpDcu22xRk+1cLlvIOMImZ7KI/RIJZhV75lw3+hYs0q3/Zi/pVT85qZ7uSMmMJLHegYOwEIw2AVStfjbg0uavzUo27OdK7nZjmCk8ZMJzff/P6l4v7n18f3RsMF4+z8MJGWTA5twu+hVSoQYxiIXDtjHxnUM8f13VSyqXIJVNkDaegcGJ7PLKZFKmidkyz4pqABdcoKJ8D24FQEBpnQia3bA1zM/cSWTyrrWEGWvyisEzamNSt0UrDj1oeEzOSYJdQzUvyeagT4u1Bd2zVcrxlJVogBilZUYqn7TJypikNQ0CE3DrZTNFy+OooBd6WWNoQHHKOek0udoDft+Kwm8H3rip72UjLD2y+s11Z9awjs3JOt7EbxqlhSX+BAPyOABx/aBalxYIhp9YEtVApNQZxDHOF40SgQzT4gVel5Yh7wcpyCTo56D+cU2YVNaSR2/HumKnYFJQ9ARIFuBGGhhkfgQRS2rWCSpFCyj2oFqXkUzwqybJgMc38duNz3WuQR8uDgYDGTuVmG2ciSbgycgJkyCrtmCUUIBRueAqH9CE6R+6n0Alp4iOyvcamj3HXOAJFa2FiIyNOwlxyI87TNHd8Y3eFWAsvOk13Ue9MsgsOyG6PYyk23FUc17XX+yOCc6JK8obR74bw6wuvw3rQZT04wLBkT1w+QClQgImvK9895p8jt61eoTKuxTlJ77unkX6uUtM7UmpAxZpT8fjwsVMHqEuKeGZ63ivA64rhxJMndM+khqijhu2l48TrhvvX94gDQvnvrhZ1Re91d7fXO3SVcM9V0y+P7O+p4ObSPTBX93XB37fyi7dy9NLD/CDztd+rE3/1TvybEB/6b0x8/534NyH+snt4/1vi69eZHebHK+QqKTtcEzgw7zBkPUkwJ+qQIHsKe1Fl3gjz+5v0Z5jX57Wmv5sJT1qHJE867zXPHpG7aYrszDWXjK4b7ViH8mTDPRhVNP/kt+mua3A/IE20gpQw1zG343bfZfZCBe6zoejeknLshNpQt13nITbJbB6YKvfmlS4Y/wY=</diagram></mxfile>

@ -0,0 +1 @@
<mxfile host="Electron" modified="2023-06-16T08:19:20.637Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="gtWmVeqlHOZvrUYasmf_" version="20.3.0" type="device"><diagram id="hj5LIC55-opOv8qK0RZo" name="第 1 页">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</diagram></mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@ -0,0 +1 @@
<mxfile host="Electron" modified="2023-06-16T08:19:18.894Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="MpbqZ1p5TD8ZKWFB1bEV" version="20.3.0" type="device"><diagram id="hj5LIC55-opOv8qK0RZo" name="第 1 页">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</diagram></mxfile>

@ -0,0 +1 @@
<mxfile host="Electron" modified="2023-06-16T08:15:20.097Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="Zu1HVDr_d27NGK3yVVgX" version="20.3.0" type="device"><diagram name="页-1" id="Page-1">1VZRb5swEP41fuwEGAp5DAntpnZdtayb9jS5cAVrBjNzNEl//UwxAUqabmo6aS/IfPadz993dzahi3xzrliZfZQJCOJYyYbQJXEcz7b0twG2LXDqzVogVTxpIbsHVvwBDGjs0ponUI0WopQCeTkGY1kUEOMIY0rJ9XjZnRTjXUuWwgRYxUxM0W88waxFA8fv8ffA06zb2T4158tZt9icpMpYItcDiEaELpSU2I7yzQJEw13HS2t39sysCeyeidqESqKAhGdkFpHolAQRmXsk8kk4b0ATrIIC/8Q5daYW3YagEDYDyHg4B5kDqq1e0s1aDm1tjPaeZahgRpR0Z9PHogcmnGdCC94iNDc4Qmhf/fjh+2W4uEFRLL98sAPbnp247lSoNh9w2yVZhrn2ubQJDUvJC3yMwQuJt2wQUFyHAkqDUmEmU1kwcd2j4REICWx/xIdDDR/rPum7kswG+f5mtHnWhLYriXDJK5zHyO85bic06gorm2Gdi0t+B4IX8IQ/YeAhe+uMI6xKFjema93ENDYQRDcWZNpE7f6FYGXFbx93tTSiIK5Vxe/hM1Rt/2pQWWOz02LXl6zjKOX7zkgpe49Ss2CqFLXc10t1dxHadHEbZ/jwq068H1e+ujhx6USqhFclwzg7lOnNkblutHPB00JjtxJR5noCimTedO4GEzL+2VAs6yKBZMQiJJPO3dN6MKeQqRTw0ImekWBAcZf4CgTT6TiOZB/Fxtt1U9+9mp43FtOdvfPGPipZqxiM2bBlP/Fk0xddteeeuHoUfXfKV+TB9EqSxacSuSx0heUrELoQtIj/a9lOanRPJR+4cbr2eaBubXdPi6XHuDX3C+b8o6vpBeb+qgY33TtyzKb1ZveV/u0faW2t9C9dGv0G</diagram></mxfile>

Binary file not shown.

@ -0,0 +1 @@
<mxfile host="Electron" modified="2023-06-07T06:55:00.590Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" version="20.3.0" etag="YdsqbKZzjNToVRv-NuoM" type="device"><diagram name="页-1" id="Page-1">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</diagram></mxfile>

@ -0,0 +1 @@
<mxfile host="Electron" modified="2023-06-06T11:36:39.685Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="qZUmTnZK499RawxCXfE0" version="20.3.0" type="device"><diagram id="mVGf_721GO8iSgKUREEm" name="第 1 页">7VZdb5swFP01SNtDJz4S0j4W0q2V0qpaJnWvLjhg1fgic9Mk/fW7xiaU0GzptL5NiiLfc4+N7z3HBi9Kq+03zeryFnIuvdDPt14098Iw9n36N8DOArP43AKFFrmFgh5YihfuQDevWIucNwMiAkgU9RDMQCme4QBjWsNmSFuBHD61ZgUfAcuMyTH6IHIsLXoeznr8moui7J4cxBc2U7GO7CppSpbD5hUUXXlRqgHQjqptyqXpXdcXO+/rkex+Y5orPGUC3BS3yd2GJS/VTD38nNzs4PosmNhlnplcu4rvAPlCNHiZoXgWuPPS0LvsasBd15hmIyrJFEXJChQuXSagmElRKBpntDOuCXjmGgX19NIlEGpCs1LIfMF2sDb7b5BlT12UlKDFCy3LpFuT0hqdPcJ4wFiamQT7hGreEOe+a0pwAN2y7YC4YA06IAMpWd2Ix30ZFdOFUAkgQuVIrllUDt8elSHYi0uHgkPFUe+I4iZEvjOIOxBkJhtvensRyWLla2tNHJE5Sxf7tXvVaeCEf48JpiMTeCHV6idrql2ZAXW40LBWORUXe2EU2G4cIVEQjgxDLcNWSA1PPAUJ5Iy5AusgIeUB1JlI8hUetVBTs0yoYtFy5pMe+e76ZiCguSvZHr1S5DlXRn5AhsxqbUqpQShs+zpN6EftT/0vU29KG08pDvqYfoauMQVFtTDRys7JSBtuzHSaR35zGMfO6ZwSn2aUePJRPonf8MmBylK06lmVuxsz+CuJKxJL8l7TH0by+Vkw0j0a6x69obFkj1zeQyNQgFlfW+6B9n+Sd+hfoUquxYfKfuGfJvuH3Q6zI7cDqExzhvzT59GdQCmoTZup2bxquKRXM88N8f+l8I/dceLbY+q/2x4U9l8nbe7VJ1509Qs=</diagram></mxfile>

Binary file not shown.

@ -69,6 +69,8 @@ import java.util.HashSet;
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { //没有用特定的标签加注释。。。感觉没有什么用
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
private int mode=-1; /*首页背景切换*/
private static final int FOLDER_LIST_QUERY_TOKEN = 1;
private static final int MENU_FOLDER_DELETE = 0;
@ -132,6 +134,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
//final不能用于修饰构造方法。
super.onCreate(savedInstanceState); // 调用父类的onCreate函数
setContentView(R.layout.note_list);
getWindow().setBackgroundDrawableResource(R.drawable.grassland);
initResources();
/**
@ -796,12 +799,25 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} else {
Log.e(TAG, "Wrong state:" + mState);
}
if(mode==-1)
menu.findItem(R.id.menu_grassland).setVisible(false);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_grassland:{
mode=-1;
getWindow().setBackgroundDrawableResource(R.drawable.grassland);
break;
}
case R.id.menu_cauc:{
mode=1;
getWindow().setBackgroundDrawableResource(R.drawable.cauc);
break;
}
case R.id.menu_new_folder: {
showCreateOrModifyFolderDialog(true);
break;

@ -0,0 +1,336 @@
/*
* 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;
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;
public class BackupUtils {
private static final String TAG = "BackupUtils";
// Singleton stuff
private static BackupUtils sInstance;
public static synchronized BackupUtils getInstance(Context context) {
//ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程例如线程A
//运行到这个方法时,都要检查有没有其它线程B或者C、 D等正在用这个方法(或者该类的其他同步方法)有的话要等正在使用synchronized方法的线程B或者C 、D运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。
//它包括两种用法synchronized 方法和 synchronized 块。
if (sInstance == null) {
//如果当前备份不存在,则新声明一个
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;
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
};
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) {
// 通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note
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里面保存有这份note的日期
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);
//将文件导出到text
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);
//利用光标来扫描内容区别为callnote和note两种靠ps.printline输出
if (dataCursor != null) {
if (dataCursor.moveToFirst()) {
do {
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
if (DataConstants.CALL_NOTE.equals(mimeType)) {
// Print phone number
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();
}
try {
ps.write(new byte[] {
Character.LINE_SEPARATOR, Character.LETTER_NUMBER
});
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
public int exportToText() { //总函数调用上面的exportFolder和exportNote
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();
}
// 将根目录里的便签导出(由于不属于任何文件夹,因此无法通过文件夹导出来实现这一部分便签的导出)
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;
}
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);//将ps输出流输出到特定的文件目的就是导出到文件而不是直接输出
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (NullPointerException e) {
e.printStackTrace();
return null;
}
return ps;
}
}
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder();
sb.append(Environment.getExternalStorageDirectory()); //外部SD卡的存储路径
sb.append(context.getString(filePathResId)); //文件的存储路径
File filedir = new File(sb.toString()); //filedir应该就是用来存储路径信息
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) {
e.printStackTrace();
}
// try catch 异常处理
return null;
}
}

@ -0,0 +1,301 @@
/*
* 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";
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
//直接删除多个笔记
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
}
if (ids.size() == 0) {
Log.d(TAG, "no id is in the hashset");
return true;
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
//提供一个任务列表
for (long id : ids) {
if(id == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Don't delete system folder root");
continue;
} //如果发现是根文件夹,则不删除
ContentProviderOperation.Builder builder = ContentProviderOperation
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
//用newDelete实现删除功能
operationList.add(builder.build());
}
try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
//主机名或叫Authority用于唯一标识这个ContentProvider外部调用者可以根据这个标识来找到它。
//数据库事务,数据库事务是由一组数据库操作序列组成,事务作为一个整体被执行
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
}
return true;
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
return false;
}
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, desFolderId);
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
values.put(NoteColumns.LOCAL_MODIFIED, 1);
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); //对需要移动的便签进行数据更新然后用update实现
}
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
long folderId) {
if (ids == null) {
Log.d(TAG, "the ids is 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));
//通过withAppendedId方法为该Uri加上ID
builder.withValue(NoteColumns.PARENT_ID, folderId);
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
operationList.add(builder.build());
}//将ids里包含的每一列的数据逐次加入到operationList中等待最后的批量处理
try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); //applyBatch一次性处理一个操作列表
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
}
return true;
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
return false;
}
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);
//筛选条件源文件不为trash folder
int count = 0;
if(cursor != null) {
if(cursor.moveToFirst()) {
try {
count = cursor.getInt(0);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "get folder count failed:" + e.toString());
} finally {
cursor.close();
}
}
}
return count;
}
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), //通过withAppendedId方法为该Uri加上ID
null,
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
new String [] {String.valueOf(type)},
null); //查询条件type符合且不属于垃圾文件夹
boolean exist = false;
if (cursor != null) {
if (cursor.getCount() > 0) {
//用getcount函数判断cursor是否为空
exist = true;
}
cursor.close();
}
return exist;
}
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;
}
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;
}
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;
}
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); //查询条件父ID是传入的folderId;
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); //0对应的NoteColumns.WIDGET_ID
widget.widgetType = c.getInt(1); //1对应的NoteColumns.WIDGET_TYPE
set.add(widget);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, e.toString());
}
} while (c.moveToNext()); //查询下一条
}
c.close();
}
return set;
}
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, "Get call number fails " + e.toString());
} finally {
cursor.close();
}
}
return "";
}
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);
//通过数据库操作查询条件是callDate和phoneNumber匹配传入参数的值
if (cursor != null) {
if (cursor.moveToFirst()) {
try {
return cursor.getLong(0); //0对应的CallNote.NOTE_ID
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "Get call note id fails " + e.toString());
}
}
cursor.close();
}
return 0;
}
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);//查询条件noteId
if (cursor != null) {
String snippet = "";
if (cursor.moveToFirst()) {
snippet = cursor.getString(0);
}
cursor.close();
return snippet;
}
throw new IllegalArgumentException("Note is not found with id: " + noteId);
}
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;
}
}

@ -1,21 +1,11 @@
/*
* 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;
//定义了很多的静态字符串目的就是为了提供jsonObject中相应字符串的"key"。把这些静态的定义单独写到了一个类里面,这是非常好的编程规范
package net.micode.notes.tool;
public class GTaskStringUtils {
public final static String GTASK_JSON_ACTION_ID = "action_id";

@ -0,0 +1,175 @@
package net.micode.notes.tool;
/*使
* R.java
* R.id
* R.drawable 使
* R.layout
* R.menu
* R.String
* R.style 使
* idgetXXX
*
*
* @BG_DEFAULT_COLOR
* BG_DEFAULT_FONT_SIZE
*/
import android.content.Context;
import android.preference.PreferenceManager;
import net.micode.notes.R;
import net.micode.notes.ui.NotesPreferenceActivity;
public class ResourceParser {
public static final int YELLOW = 0;
public static final int BLUE = 1;
public static final int WHITE = 2;
public static final int GREEN = 3;
public static final int RED = 4;
public static final int BG_DEFAULT_COLOR = YELLOW;
public static final int TEXT_SMALL = 0;
public static final int TEXT_MEDIUM = 1;
public static final int TEXT_LARGE = 2;
public static final int TEXT_SUPER = 3;
public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM;
public static class NoteBgResources {
private final static int [] BG_EDIT_RESOURCES = new int [] {
R.drawable.edit_yellow,
R.drawable.edit_blue,
R.drawable.edit_white,
R.drawable.edit_green,
R.drawable.edit_red
};
private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] {
R.drawable.edit_title_yellow,
R.drawable.edit_title_blue,
R.drawable.edit_title_white,
R.drawable.edit_title_green,
R.drawable.edit_title_red
};
public static int getNoteBgResource(int id) {
return BG_EDIT_RESOURCES[id];
}
public static int getNoteTitleBgResource(int id) {
return BG_EDIT_TITLE_RESOURCES[id];
}
}
public static int getDefaultBgId(Context context) {
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) {
return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length);
} else {
return BG_DEFAULT_COLOR;
}
}
public static class NoteItemBgResources {
private final static int [] BG_FIRST_RESOURCES = new int [] {
R.drawable.list_yellow_up,
R.drawable.list_blue_up,
R.drawable.list_white_up,
R.drawable.list_green_up,
R.drawable.list_red_up
};
private final static int [] BG_NORMAL_RESOURCES = new int [] {
R.drawable.list_yellow_middle,
R.drawable.list_blue_middle,
R.drawable.list_white_middle,
R.drawable.list_green_middle,
R.drawable.list_red_middle
};
private final static int [] BG_LAST_RESOURCES = new int [] {
R.drawable.list_yellow_down,
R.drawable.list_blue_down,
R.drawable.list_white_down,
R.drawable.list_green_down,
R.drawable.list_red_down,
};
private final static int [] BG_SINGLE_RESOURCES = new int [] {
R.drawable.list_yellow_single,
R.drawable.list_blue_single,
R.drawable.list_white_single,
R.drawable.list_green_single,
R.drawable.list_red_single
};
public static int getNoteBgFirstRes(int id) {
return BG_FIRST_RESOURCES[id];
}
public static int getNoteBgLastRes(int id) {
return BG_LAST_RESOURCES[id];
}
public static int getNoteBgSingleRes(int id) {
return BG_SINGLE_RESOURCES[id];
}
public static int getNoteBgNormalRes(int id) {
return BG_NORMAL_RESOURCES[id];
}
public static int getFolderBgRes() {
return R.drawable.list_folder;
}
}
public static class WidgetBgResources {
private final static int [] BG_2X_RESOURCES = new int [] {
R.drawable.widget_2x_yellow,
R.drawable.widget_2x_blue,
R.drawable.widget_2x_white,
R.drawable.widget_2x_green,
R.drawable.widget_2x_red,
};
public static int getWidget2xBgResource(int id) {
return BG_2X_RESOURCES[id];
}
private final static int [] BG_4X_RESOURCES = new int [] {
R.drawable.widget_4x_yellow,
R.drawable.widget_4x_blue,
R.drawable.widget_4x_white,
R.drawable.widget_4x_green,
R.drawable.widget_4x_red
};
public static int getWidget4xBgResource(int id) {
return BG_4X_RESOURCES[id];
}
}
public static class TextAppearanceResources {
private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] {
R.style.TextAppearanceNormal,
R.style.TextAppearanceMedium,
R.style.TextAppearanceLarge,
R.style.TextAppearanceSuper
};
//这里有一个容错的函数防止输入的id大于资源总量若如此则自动返回默认的设置结果
public static int getTexAppearanceResource(int id) {
if (id >= TEXTAPPEARANCE_RESOURCES.length) {
return BG_DEFAULT_FONT_SIZE;
}
return TEXTAPPEARANCE_RESOURCES[id];
}
public static int getResourcesSize() {
return TEXTAPPEARANCE_RESOURCES.length;
}
}
}

@ -27,10 +27,11 @@ import net.micode.notes.tool.ResourceParser;
//2倍大小的插件
public class NoteWidgetProvider_2x extends NoteWidgetProvider {
@Override
//重写更新方法
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.update(context, appWidgetManager, appWidgetIds);
}
//重写刷新Id方法
@Override
protected int getLayoutId() {
return R.layout.widget_2x;
@ -40,7 +41,7 @@ public class NoteWidgetProvider_2x extends NoteWidgetProvider {
protected int getBgResourceId(int bgId) {
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);
}
//重写插件方法
@Override
protected int getWidgetType() {
return Notes.TYPE_WIDGET_2X;

@ -25,6 +25,7 @@ import net.micode.notes.tool.ResourceParser;
//4倍大小的插件
public class NoteWidgetProvider_4x extends NoteWidgetProvider {
//重写更新方法
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.update(context, appWidgetManager, appWidgetIds);

@ -0,0 +1,894 @@
/*
* 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.remote;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
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.NoteColumns;
import net.micode.notes.gtask.data.MetaData;
import net.micode.notes.gtask.data.Node;
import net.micode.notes.gtask.data.SqlNote;
import net.micode.notes.gtask.data.Task;
import net.micode.notes.gtask.data.TaskList;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.gtask.exception.NetworkFailureException;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
public class GTaskManager {
private static final String TAG = GTaskManager.class.getSimpleName();
public static final int STATE_SUCCESS = 0;
public static final int STATE_NETWORK_ERROR = 1;
public static final int STATE_INTERNAL_ERROR = 2;
public static final int STATE_SYNC_IN_PROGRESS = 3;
public static final int STATE_SYNC_CANCELLED = 4;
private static GTaskManager mInstance = null;
private Activity mActivity;
private Context mContext;
private ContentResolver mContentResolver;
private boolean mSyncing;
private boolean mCancelled;
private HashMap<String, TaskList> mGTaskListHashMap;
private HashMap<String, Node> mGTaskHashMap;
private HashMap<String, MetaData> mMetaHashMap;
private TaskList mMetaList;
private HashSet<Long> mLocalDeleteIdMap;
private HashMap<String, Long> mGidToNid;
private HashMap<Long, String> mNidToGid;
private GTaskManager() { //对象初始化函数
mSyncing = false; //正在同步,flase代表未执行
mCancelled = false; //全局标识flase代表可以执行
mGTaskListHashMap = new HashMap<String, TaskList>(); //<>代表Java的泛型,就是创建一个用类型作为参数的类。
mGTaskHashMap = new HashMap<String, Node>();
mMetaHashMap = new HashMap<String, MetaData>();
mMetaList = null;
mLocalDeleteIdMap = new HashSet<Long>();
mGidToNid = new HashMap<String, Long>(); //GoogleID to NodeID??
mNidToGid = new HashMap<Long, String>(); //NodeID to GoogleID???通过hashmap散列表建立映射
}
/**
* synchronized线
*
* @author TTS
* @return GtaskManger
*/
public static synchronized GTaskManager getInstance() { //可能运行在多线程环境下,使用语言级同步--synchronized
if (mInstance == null) {
mInstance = new GTaskManager();
}
return mInstance;
}
/**
* synchronized线
* @author TTS
* @param activity
*/
public synchronized void setActivityContext(Activity activity) {
// used for getting auth token
mActivity = activity;
}
/**
*
*
* @author TTS
* @param context-----
* @param asyncTask-------
* @return int
*/
public int sync(Context context, GTaskASyncTask asyncTask) { //核心函数
if (mSyncing) {
Log.d(TAG, "Sync is in progress"); //创建日志文件调试信息debug
return STATE_SYNC_IN_PROGRESS;
}
mContext = context;
mContentResolver = mContext.getContentResolver();
mSyncing = true;
mCancelled = false;
mGTaskListHashMap.clear();
mGTaskHashMap.clear();
mMetaHashMap.clear();
mLocalDeleteIdMap.clear();
mGidToNid.clear();
mNidToGid.clear();
try {
GTaskClient client = GTaskClient.getInstance(); //getInstance即为创建一个实例,client--客户机
client.resetUpdateArray(); //JSONArray类型reset即置为NULL
// login google task
if (!mCancelled) {
if (!client.login(mActivity)) {
throw new NetworkFailureException("login google task failed");
}
}
// get the task list from google
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list));
initGTaskList(); //获取Google上的JSONtasklist转为本地TaskList
// do content sync work
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing));
syncContent();
} catch (NetworkFailureException e) { //分为两种异常,此类异常为网络异常
Log.e(TAG, e.toString()); //创建日志文件调试信息error
return STATE_NETWORK_ERROR;
} catch (ActionFailureException e) { //此类异常为操作异常
Log.e(TAG, e.toString());
return STATE_INTERNAL_ERROR;
} catch (Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return STATE_INTERNAL_ERROR;
} finally {
mGTaskListHashMap.clear();
mGTaskHashMap.clear();
mMetaHashMap.clear();
mLocalDeleteIdMap.clear();
mGidToNid.clear();
mNidToGid.clear();
mSyncing = false;
}
return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS;
}
/**
*GtaskListGoogleJSONtasklistTaskList
*mMetaListmGTaskListHashMapmGTaskHashMap
*@author TTS
*@exception NetworkFailureException
*@return void
*/
private void initGTaskList() throws NetworkFailureException {
if (mCancelled)
return;
GTaskClient client = GTaskClient.getInstance(); //getInstance即为创建一个实例client应指远端客户机
try {
//Json对象是Name Value对(即子元素)的无序集合相当于一个Map对象。JsonObject类是bantouyan-json库对Json对象的抽象提供操纵Json对象的各种方法。
//其格式为{"key1":value1,"key2",value2....};key 必须是字符串。
//因为ajax请求不刷新页面但配合js可以实现局部刷新因此json常常被用来作为异步请求的返回对象使用。
JSONArray jsTaskLists = client.getTaskLists(); //原注释为get task list------lists
// init meta list first
mMetaList = null; //TaskList类型
for (int i = 0; i < jsTaskLists.length(); i++) {
JSONObject object = jsTaskLists.getJSONObject(i); //JSONObject与JSONArray一个为对象一个为数组。此处取出单个JASONObject
String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);
String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);
if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) {
mMetaList = new TaskList(); //MetaList意为元表,Tasklist类型此处为初始化
mMetaList.setContentByRemoteJSON(object); //将JSON中部分数据复制到自己定义的对象中相对应的数据name->mname...
// load meta data
JSONArray jsMetas = client.getTaskList(gid); //原注释为get action_list------list
for (int j = 0; j < jsMetas.length(); j++) {
object = (JSONObject) jsMetas.getJSONObject(j);
MetaData metaData = new MetaData(); //继承自Node
metaData.setContentByRemoteJSON(object);
if (metaData.isWorthSaving()) { //if not worth to savemetadata将不加入mMetaList
mMetaList.addChildTask(metaData);
if (metaData.getGid() != null) {
mMetaHashMap.put(metaData.getRelatedGid(), metaData);
}
}
}
}
}
// create meta list if not existed
if (mMetaList == null) {
mMetaList = new TaskList();
mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_META);
GTaskClient.getInstance().createTaskList(mMetaList);
}
// init task list
for (int i = 0; i < jsTaskLists.length(); i++) {
JSONObject object = jsTaskLists.getJSONObject(i);
String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); //通过getString函数传入本地某个标志数据的名称获取其在远端的名称。
String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);
if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)
&& !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_META)) {
TaskList tasklist = new TaskList(); //继承自Node
tasklist.setContentByRemoteJSON(object);
mGTaskListHashMap.put(gid, tasklist);
mGTaskHashMap.put(gid, tasklist); //为什么加两遍???
// load tasks
JSONArray jsTasks = client.getTaskList(gid);
for (int j = 0; j < jsTasks.length(); j++) {
object = (JSONObject) jsTasks.getJSONObject(j);
gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);
Task task = new Task();
task.setContentByRemoteJSON(object);
if (task.isWorthSaving()) {
task.setMetaInfo(mMetaHashMap.get(gid));
tasklist.addChildTask(task);
mGTaskHashMap.put(gid, task);
}
}
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("initGTaskList: handing JSONObject failed");
}
}
/**
*
* @throws NetworkFailureException
* @return
*/
private void syncContent() throws NetworkFailureException { //本地内容同步操作
int syncType;
Cursor c = null; //数据库指针
String gid; //GoogleID??
Node node; //Node包含Sync_Action的不同类型
mLocalDeleteIdMap.clear(); //HashSet<Long>类型
if (mCancelled) {
return;
}
// for local deleted note
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type<>? AND parent_id=?)", new String[] {
String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)
}, null);
if (c != null) {
while (c.moveToNext()) {
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c);
}
mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN));
}
} else {
Log.w(TAG, "failed to query trash folder");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// sync folder first
syncFolder();
// for note existing in database
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type=? AND parent_id<>?)", new String[] {
String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER)
}, NoteColumns.TYPE + " DESC");
if (c != null) {
while (c.moveToNext()) {
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); //通过hashmap建立联系
mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); //通过hashmap建立联系
syncType = node.getSyncAction(c);
} else {
if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {
// local add
syncType = Node.SYNC_ACTION_ADD_REMOTE;
} else {
// remote delete
syncType = Node.SYNC_ACTION_DEL_LOCAL;
}
}
doContentSync(syncType, node, c);
}
} else {
Log.w(TAG, "failed to query existing note in database");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// go through remaining items
Iterator<Map.Entry<String, Node>> iter = mGTaskHashMap.entrySet().iterator(); //Iterator迭代器
while (iter.hasNext()) {
Map.Entry<String, Node> entry = iter.next();
node = entry.getValue();
doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);
}
// mCancelled can be set by another thread, so we neet to check one by //thread----线程
// one
// clear local delete table
if (!mCancelled) {
if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) {
throw new ActionFailureException("failed to batch-delete local deleted notes");
}
}
// refresh local sync id
if (!mCancelled) {
GTaskClient.getInstance().commitUpdate();
refreshLocalSyncId();
}
}
/**
*
* @author TTS
* @throws NetworkFailureException
*/
private void syncFolder() throws NetworkFailureException {
Cursor c = null;
String gid;
Node node;
int syncType;
if (mCancelled) {
return;
}
// for root folder
try {
c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,
Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null);
if (c != null) {
c.moveToNext();
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER);
mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid);
// for system folder, only update remote name if necessary
if (!node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT))
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);
}
} else {
Log.w(TAG, "failed to query root folder");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// for call-note folder
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)",
new String[] {
String.valueOf(Notes.ID_CALL_RECORD_FOLDER)
}, null);
if (c != null) {
if (c.moveToNext()) {
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER);
mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid);
// for system folder, only update remote name if
// necessary
if (!node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE))
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);
}
}
} else {
Log.w(TAG, "failed to query call note folder");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// for local existing folders
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type=? AND parent_id<>?)", new String[] {
String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)
}, NoteColumns.TYPE + " DESC");
if (c != null) {
while (c.moveToNext()) {
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN));
mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid);
syncType = node.getSyncAction(c);
} else {
if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {
// local add
syncType = Node.SYNC_ACTION_ADD_REMOTE;
} else {
// remote delete
syncType = Node.SYNC_ACTION_DEL_LOCAL;
}
}
doContentSync(syncType, node, c);
}
} else {
Log.w(TAG, "failed to query existing folder");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
// for remote add folders
Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, TaskList> entry = iter.next();
gid = entry.getKey();
node = entry.getValue();
if (mGTaskHashMap.containsKey(gid)) {
mGTaskHashMap.remove(gid);
doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);
}
}
if (!mCancelled)
GTaskClient.getInstance().commitUpdate();
}
/**
* syncTypeaddLocalNodeaddRemoteNodedeleteNodeupdateLocalNodeupdateRemoteNode
* @author TTS
* @param syncType
* @param node
* @param c
* @throws NetworkFailureException
*/
private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
}
MetaData meta;
switch (syncType) {
case Node.SYNC_ACTION_ADD_LOCAL:
addLocalNode(node);
break;
case Node.SYNC_ACTION_ADD_REMOTE:
addRemoteNode(node, c);
break;
case Node.SYNC_ACTION_DEL_LOCAL:
meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN));
if (meta != null) {
GTaskClient.getInstance().deleteNode(meta);
}
mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN));
break;
case Node.SYNC_ACTION_DEL_REMOTE:
meta = mMetaHashMap.get(node.getGid());
if (meta != null) {
GTaskClient.getInstance().deleteNode(meta);
}
GTaskClient.getInstance().deleteNode(node);
break;
case Node.SYNC_ACTION_UPDATE_LOCAL:
updateLocalNode(node, c);
break;
case Node.SYNC_ACTION_UPDATE_REMOTE:
updateRemoteNode(node, c);
break;
case Node.SYNC_ACTION_UPDATE_CONFLICT:
// merging both modifications maybe a good idea
// right now just use local update simply
updateRemoteNode(node, c);
break;
case Node.SYNC_ACTION_NONE:
break;
case Node.SYNC_ACTION_ERROR:
default:
throw new ActionFailureException("unkown sync action type");
}
}
/**
* Node
* @author TTS
* @param node
* @throws NetworkFailureException
*/
private void addLocalNode(Node node) throws NetworkFailureException {
if (mCancelled) {
return;
}
SqlNote sqlNote;
if (node instanceof TaskList) {
if (node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) {
sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER);
} else if (node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) {
sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER);
} else {
sqlNote = new SqlNote(mContext);
sqlNote.setContent(node.getLocalJSONFromContent());
sqlNote.setParentId(Notes.ID_ROOT_FOLDER);
}
} else {
sqlNote = new SqlNote(mContext);
JSONObject js = node.getLocalJSONFromContent();
try {
if (js.has(GTaskStringUtils.META_HEAD_NOTE)) {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (note.has(NoteColumns.ID)) {
long id = note.getLong(NoteColumns.ID);
if (DataUtils.existInNoteDatabase(mContentResolver, id)) {
// the id is not available, have to create a new one
note.remove(NoteColumns.ID);
}
}
}
if (js.has(GTaskStringUtils.META_HEAD_DATA)) {
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (data.has(DataColumns.ID)) {
long dataId = data.getLong(DataColumns.ID);
if (DataUtils.existInDataDatabase(mContentResolver, dataId)) {
// the data id is not available, have to create
// a new one
data.remove(DataColumns.ID);
}
}
}
}
} catch (JSONException e) {
Log.w(TAG, e.toString());
e.printStackTrace();
}
sqlNote.setContent(js);
Long parentId = mGidToNid.get(((Task) node).getParent().getGid());
if (parentId == null) {
Log.e(TAG, "cannot find task's parent id locally");
throw new ActionFailureException("cannot add local node");
}
sqlNote.setParentId(parentId.longValue());
}
// create the local node
sqlNote.setGtaskId(node.getGid());
sqlNote.commit(false);
// update gid-nid mapping
mGidToNid.put(node.getGid(), sqlNote.getId());
mNidToGid.put(sqlNote.getId(), node.getGid());
// update meta
updateRemoteMeta(node.getGid(), sqlNote);
}
/**
* updatenode
* @author TTS
* @param node
* ----
* @param c
* ----Cursor
* @throws NetworkFailureException
*/
private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
}
SqlNote sqlNote;
// update the note locally
sqlNote = new SqlNote(mContext, c);
sqlNote.setContent(node.getLocalJSONFromContent());
Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid())
: new Long(Notes.ID_ROOT_FOLDER);
if (parentId == null) {
Log.e(TAG, "cannot find task's parent id locally");
throw new ActionFailureException("cannot update local node");
}
sqlNote.setParentId(parentId.longValue());
sqlNote.commit(true);
// update meta info
updateRemoteMeta(node.getGid(), sqlNote);
}
/**
* Node
* updateRemoteMeta
* @author TTS
* @param node
* ----
* @param c
* --Cursor
* @throws NetworkFailureException
*/
private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
}
SqlNote sqlNote = new SqlNote(mContext, c); //从本地mContext中获取内容
Node n;
// update remotely
if (sqlNote.isNoteType()) {
Task task = new Task();
task.setContentByLocalJSON(sqlNote.getContent());
String parentGid = mNidToGid.get(sqlNote.getParentId());
if (parentGid == null) {
Log.e(TAG, "cannot find task's parent tasklist"); //调试信息
throw new ActionFailureException("cannot add remote task");
}
mGTaskListHashMap.get(parentGid).addChildTask(task); //在本地生成的GTaskList中增加子结点
//登录远程服务器创建Task
GTaskClient.getInstance().createTask(task);
n = (Node) task;
// add meta
updateRemoteMeta(task.getGid(), sqlNote);
} else {
TaskList tasklist = null;
// we need to skip folder if it has already existed
String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX;
if (sqlNote.getId() == Notes.ID_ROOT_FOLDER)
folderName += GTaskStringUtils.FOLDER_DEFAULT;
else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER)
folderName += GTaskStringUtils.FOLDER_CALL_NOTE;
else
folderName += sqlNote.getSnippet();
//iterator迭代器通过统一的接口迭代所有的map元素
Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, TaskList> entry = iter.next();
String gid = entry.getKey();
TaskList list = entry.getValue();
if (list.getName().equals(folderName)) {
tasklist = list;
if (mGTaskHashMap.containsKey(gid)) {
mGTaskHashMap.remove(gid);
}
break;
}
}
// no match we can add now
if (tasklist == null) {
tasklist = new TaskList();
tasklist.setContentByLocalJSON(sqlNote.getContent());
GTaskClient.getInstance().createTaskList(tasklist);
mGTaskListHashMap.put(tasklist.getGid(), tasklist);
}
n = (Node) tasklist;
}
// update local note
sqlNote.setGtaskId(n.getGid());
sqlNote.commit(false);
sqlNote.resetLocalModified();
sqlNote.commit(true);
// gid-id mapping //创建id间的映射
mGidToNid.put(n.getGid(), sqlNote.getId());
mNidToGid.put(sqlNote.getId(), n.getGid());
}
/**
* Nodemeta(updateRemoteMeta)
* @author TTS
* @param node
* ----
* @param c
* --Cursor
* @throws NetworkFailureException
*/
private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
}
SqlNote sqlNote = new SqlNote(mContext, c);
// update remotely
node.setContentByLocalJSON(sqlNote.getContent());
GTaskClient.getInstance().addUpdateNode(node); //GTaskClient用途为从本地登陆远端服务器
// update meta
updateRemoteMeta(node.getGid(), sqlNote);
// move task if necessary
if (sqlNote.isNoteType()) {
Task task = (Task) node;
TaskList preParentList = task.getParent();
//preParentList为通过node获取的父节点列表
String curParentGid = mNidToGid.get(sqlNote.getParentId());
//curParentGid为通过光标在数据库中找到sqlNote的mParentId再通过mNidToGid由long类型转为String类型的Gid
if (curParentGid == null) {
Log.e(TAG, "cannot find task's parent tasklist");
throw new ActionFailureException("cannot update remote task");
}
TaskList curParentList = mGTaskListHashMap.get(curParentGid);
//通过HashMap找到对应Gid的TaskList
if (preParentList != curParentList) { //?????????????
preParentList.removeChildTask(task);
curParentList.addChildTask(task);
GTaskClient.getInstance().moveTask(task, preParentList, curParentList);
}
}
// clear local modified flag
sqlNote.resetLocalModified();
//commit到本地数据库
sqlNote.commit(true);
}
/**
* meta meta----------
* @author TTS
* @param gid
* ---GoogleIDString
* @param sqlNote
* ---使SqlNote
* @throws NetworkFailureException
*/
private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException {
if (sqlNote != null && sqlNote.isNoteType()) {
MetaData metaData = mMetaHashMap.get(gid);
if (metaData != null) {
metaData.setMeta(gid, sqlNote.getContent());
GTaskClient.getInstance().addUpdateNode(metaData);
} else {
metaData = new MetaData();
metaData.setMeta(gid, sqlNote.getContent());
mMetaList.addChildTask(metaData);
mMetaHashMap.put(gid, metaData);
GTaskClient.getInstance().createTask(metaData);
}
}
}
/**
* syncID
* @author TTS
* @return void
* @throws NetworkFailureException
*/
private void refreshLocalSyncId() throws NetworkFailureException {
if (mCancelled) {
return;
}
// get the latest gtask list //获取最近的最晚的gtask list
mGTaskHashMap.clear();
mGTaskListHashMap.clear();
mMetaHashMap.clear();
initGTaskList();
Cursor c = null;
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type<>? AND parent_id<>?)", new String[] {
String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)
}, NoteColumns.TYPE + " DESC"); //query语句五个参数NoteColumns.TYPE + " DESC"-----为按类型递减顺序返回查询结果。new String[] {String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)}------为选择参数。"(type<>? AND parent_id<>?)"-------指明返回行过滤器。SqlNote.PROJECTION_NOTE--------应返回的数据列的名字。Notes.CONTENT_NOTE_URI--------contentProvider包含所有数据集所对应的uri
if (c != null) {
while (c.moveToNext()) {
String gid = c.getString(SqlNote.GTASK_ID_COLUMN);
Node node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
ContentValues values = new ContentValues(); //在ContentValues中创建键值对。准备通过contentResolver写入数据
values.put(NoteColumns.SYNC_ID, node.getLastModified());
mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, //进行批量更改选择参数为NULL应该可以用insert替换参数分别为表名和需要更新的value对象。
c.getLong(SqlNote.ID_COLUMN)), values, null, null);
} else {
Log.e(TAG, "something is missed");
throw new ActionFailureException(
"some local items don't have gid after sync");
}
}
} else {
Log.w(TAG, "failed to query local note to refresh sync id");
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
}
/**
* ,mAccount.name
* @author TTS
* @return String
*/
public String getSyncAccount() {
return GTaskClient.getInstance().getSyncAccount().name;
}
/**
* mCancelledtrue
* @author TTS
*/
public void cancelSync() {
mCancelled = true;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save