|
|
|
|
@ -23,11 +23,16 @@ import android.appwidget.AppWidgetManager;
|
|
|
|
|
import android.content.AsyncQueryHandler;
|
|
|
|
|
import android.content.ContentResolver;
|
|
|
|
|
import android.content.ContentValues;
|
|
|
|
|
import android.content.ContentUris;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.DialogInterface;
|
|
|
|
|
import android.content.Intent;
|
|
|
|
|
import android.content.SharedPreferences;
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.net.Uri;
|
|
|
|
|
import android.text.InputType;
|
|
|
|
|
import android.widget.EditText;
|
|
|
|
|
import android.widget.LinearLayout;
|
|
|
|
|
import android.os.AsyncTask;
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
import android.preference.PreferenceManager;
|
|
|
|
|
@ -92,6 +97,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
private static final int MENU_FOLDER_DELETE = 0; // 文件夹删除菜单项
|
|
|
|
|
private static final int MENU_FOLDER_VIEW = 1; // 文件夹查看菜单项
|
|
|
|
|
private static final int MENU_FOLDER_CHANGE_NAME = 2; // 文件夹改名菜单项
|
|
|
|
|
private static final int MENU_FOLDER_ENCRYPT = 3; // 文件夹加密菜单项
|
|
|
|
|
private static final int MENU_FOLDER_DECRYPT = 4; // 文件夹取消加密菜单项
|
|
|
|
|
|
|
|
|
|
// 首次使用引导标记的偏好设置键
|
|
|
|
|
private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction";
|
|
|
|
|
@ -138,11 +145,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
|
|
|
|
|
// 普通查询条件(非根文件夹)
|
|
|
|
|
private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?";
|
|
|
|
|
// 根文件夹查询条件(包含通话记录文件夹)
|
|
|
|
|
// 根文件夹查询条件(包含通话记录文件夹和回收站)
|
|
|
|
|
private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>"
|
|
|
|
|
+ Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" + " OR ("
|
|
|
|
|
+ Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?) OR ("
|
|
|
|
|
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND "
|
|
|
|
|
+ NoteColumns.NOTES_COUNT + ">0)";
|
|
|
|
|
+ NoteColumns.NOTES_COUNT + ">0) OR ("
|
|
|
|
|
+ NoteColumns.ID + "=" + Notes.ID_TRASH_FOLDER + ")";
|
|
|
|
|
|
|
|
|
|
// 请求码常量
|
|
|
|
|
private final static int REQUEST_CODE_OPEN_NODE = 102; // 打开笔记请求码
|
|
|
|
|
@ -156,6 +164,58 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
|
|
|
|
|
// 首次使用时插入应用介绍笔记
|
|
|
|
|
setAppInfoFromRawRes();
|
|
|
|
|
|
|
|
|
|
// 清理一周前的回收站笔记
|
|
|
|
|
cleanOldTrashNotes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 清理一周前的回收站笔记
|
|
|
|
|
*/
|
|
|
|
|
private void cleanOldTrashNotes() {
|
|
|
|
|
long oneWeekAgo = System.currentTimeMillis() - (7 * 24 * 60 * 60 * 1000);
|
|
|
|
|
String selection = NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLDER + " AND "
|
|
|
|
|
+ NoteColumns.MODIFIED_DATE + "<" + oneWeekAgo;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
int deletedCount = getContentResolver().delete(Notes.CONTENT_NOTE_URI, selection, null);
|
|
|
|
|
if (deletedCount > 0) {
|
|
|
|
|
Log.d(TAG, "Cleaned " + deletedCount + " old trash notes");
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error cleaning old trash notes", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 恢复回收站中的笔记
|
|
|
|
|
* @param itemData 要恢复的笔记数据项
|
|
|
|
|
*/
|
|
|
|
|
private void restoreNote(final NoteItemData itemData) {
|
|
|
|
|
if (itemData == null || itemData.getType() != Notes.TYPE_NOTE) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 显示确认对话框
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle("恢复笔记");
|
|
|
|
|
builder.setMessage("确定要恢复这条笔记吗?");
|
|
|
|
|
builder.setIcon(android.R.drawable.ic_dialog_info);
|
|
|
|
|
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
// 恢复笔记到根文件夹
|
|
|
|
|
HashSet<Long> ids = new HashSet<Long>();
|
|
|
|
|
ids.add(itemData.getId());
|
|
|
|
|
if (DataUtils.batchMoveToFolder(mContentResolver, ids, Notes.ID_ROOT_FOLDER)) {
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "笔记已恢复", Toast.LENGTH_SHORT).show();
|
|
|
|
|
} else {
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "恢复失败", Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
builder.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@ -279,6 +339,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
// 加载操作模式菜单
|
|
|
|
|
getMenuInflater().inflate(R.menu.note_list_options, menu);
|
|
|
|
|
menu.findItem(R.id.delete).setOnMenuItemClickListener(this);
|
|
|
|
|
menu.findItem(R.id.pin).setOnMenuItemClickListener(this);
|
|
|
|
|
mMoveMenu = menu.findItem(R.id.move);
|
|
|
|
|
// 根据条件设置移动菜单可见性
|
|
|
|
|
if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER
|
|
|
|
|
@ -392,6 +453,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
builder.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
|
builder.show();
|
|
|
|
|
break;
|
|
|
|
|
case R.id.pin:
|
|
|
|
|
// 批量置顶笔记
|
|
|
|
|
batchPinNotes();
|
|
|
|
|
break;
|
|
|
|
|
case R.id.move:
|
|
|
|
|
// 批量移动到文件夹
|
|
|
|
|
startQueryDestinationFolders();
|
|
|
|
|
@ -551,19 +616,54 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
protected HashSet<AppWidgetAttribute> doInBackground(Void... unused) {
|
|
|
|
|
// 获取选中笔记的小部件属性
|
|
|
|
|
HashSet<AppWidgetAttribute> widgets = mNotesListAdapter.getSelectedWidget();
|
|
|
|
|
if (!isSyncMode()) {
|
|
|
|
|
// 非同步模式下直接删除笔记
|
|
|
|
|
if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter
|
|
|
|
|
.getSelectedItemIds())) {
|
|
|
|
|
// 删除成功
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Delete notes error, should not happens");
|
|
|
|
|
// 无论是否同步模式,都将笔记移动到回收站
|
|
|
|
|
if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter
|
|
|
|
|
.getSelectedItemIds(), Notes.ID_TRASH_FOLDER)) {
|
|
|
|
|
Log.e(TAG, "Move notes to trash folder error, should not happens");
|
|
|
|
|
}
|
|
|
|
|
return widgets;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onPostExecute(HashSet<AppWidgetAttribute> widgets) {
|
|
|
|
|
// 更新相关小部件
|
|
|
|
|
if (widgets != null) {
|
|
|
|
|
for (AppWidgetAttribute widget : widgets) {
|
|
|
|
|
if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID
|
|
|
|
|
&& widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) {
|
|
|
|
|
updateWidget(widget.widgetId, widget.widgetType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 同步模式下将笔记移动到回收站
|
|
|
|
|
if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter
|
|
|
|
|
.getSelectedItemIds(), Notes.ID_TRASH_FOLDER)) {
|
|
|
|
|
Log.e(TAG, "Move notes to trash folder error, should not happens");
|
|
|
|
|
}
|
|
|
|
|
mModeCallBack.finishActionMode(); // 结束多选模式
|
|
|
|
|
}
|
|
|
|
|
}.execute();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 批量置顶笔记
|
|
|
|
|
*/
|
|
|
|
|
private void batchPinNotes() {
|
|
|
|
|
new AsyncTask<Void, Void, HashSet<AppWidgetAttribute>>() {
|
|
|
|
|
@Override
|
|
|
|
|
protected HashSet<AppWidgetAttribute> doInBackground(Void... unused) {
|
|
|
|
|
// 获取选中笔记的小部件属性
|
|
|
|
|
HashSet<AppWidgetAttribute> widgets = mNotesListAdapter.getSelectedWidget();
|
|
|
|
|
HashSet<Long> selectedIds = mNotesListAdapter.getSelectedItemIds();
|
|
|
|
|
|
|
|
|
|
// 批量更新笔记的alerted_date字段为一个很大的值,表示置顶
|
|
|
|
|
for (Long noteId : selectedIds) {
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
values.put(NoteColumns.ALERTED_DATE, 9999999999999L); // 很大的值,表示置顶
|
|
|
|
|
values.put(NoteColumns.LOCAL_MODIFIED, 1);
|
|
|
|
|
values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
getContentResolver().update(
|
|
|
|
|
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
|
|
|
|
|
values, null, null);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e(TAG, "Error pinning note: " + noteId, e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return widgets;
|
|
|
|
|
@ -580,6 +680,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "已置顶" + mNotesListAdapter.getSelectedCount() + "条笔记", Toast.LENGTH_SHORT).show();
|
|
|
|
|
mModeCallBack.finishActionMode(); // 结束多选模式
|
|
|
|
|
}
|
|
|
|
|
}.execute();
|
|
|
|
|
@ -616,6 +717,8 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 打开笔记进行编辑
|
|
|
|
|
@ -631,18 +734,30 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
* 打开文件夹浏览
|
|
|
|
|
*/
|
|
|
|
|
private void openFolder(NoteItemData data) {
|
|
|
|
|
// 检查文件夹是否加密
|
|
|
|
|
if (data.getType() == Notes.TYPE_FOLDER && isFolderEncrypted(data.getId())) {
|
|
|
|
|
// 加密文件夹需要输入密码才能进入
|
|
|
|
|
showFolderPasswordDialog(data.getId());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mCurrentFolderId = data.getId();
|
|
|
|
|
startAsyncNotesListQuery(); // 查询文件夹内容
|
|
|
|
|
// 根据文件夹类型设置状态
|
|
|
|
|
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
|
|
|
|
|
mState = ListEditState.CALL_RECORD_FOLDER;
|
|
|
|
|
mAddNewNote.setVisibility(View.GONE); // 通话记录文件夹不能新建笔记
|
|
|
|
|
} else if (data.getId() == Notes.ID_TRASH_FOLDER) {
|
|
|
|
|
mState = ListEditState.SUB_FOLDER;
|
|
|
|
|
mAddNewNote.setVisibility(View.GONE); // 回收站不能新建笔记
|
|
|
|
|
} else {
|
|
|
|
|
mState = ListEditState.SUB_FOLDER;
|
|
|
|
|
}
|
|
|
|
|
// 设置标题栏
|
|
|
|
|
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
|
|
|
|
|
mTitleBar.setText(R.string.call_record_folder_name);
|
|
|
|
|
} else if (data.getId() == Notes.ID_TRASH_FOLDER) {
|
|
|
|
|
mTitleBar.setText("回收站");
|
|
|
|
|
} else {
|
|
|
|
|
mTitleBar.setText(data.getSnippet());
|
|
|
|
|
}
|
|
|
|
|
@ -829,6 +944,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
menu.add(0, MENU_FOLDER_VIEW, 0, R.string.menu_folder_view);
|
|
|
|
|
menu.add(0, MENU_FOLDER_DELETE, 0, R.string.menu_folder_delete);
|
|
|
|
|
menu.add(0, MENU_FOLDER_CHANGE_NAME, 0, R.string.menu_folder_change_name);
|
|
|
|
|
// 添加加密选项
|
|
|
|
|
if (isFolderEncrypted(mFocusNoteDataItem.getId())) {
|
|
|
|
|
menu.add(0, MENU_FOLDER_DECRYPT, 0, "取消加密");
|
|
|
|
|
} else {
|
|
|
|
|
menu.add(0, MENU_FOLDER_ENCRYPT, 0, "加密文件夹");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
@ -870,6 +991,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
case MENU_FOLDER_CHANGE_NAME:
|
|
|
|
|
showCreateOrModifyFolderDialog(false); // 显示修改文件夹名对话框
|
|
|
|
|
break;
|
|
|
|
|
case MENU_FOLDER_ENCRYPT:
|
|
|
|
|
// 加密文件夹
|
|
|
|
|
showEncryptFolderDialog(mFocusNoteDataItem.getId());
|
|
|
|
|
break;
|
|
|
|
|
case MENU_FOLDER_DECRYPT:
|
|
|
|
|
// 取消加密文件夹
|
|
|
|
|
decryptFolder(mFocusNoteDataItem.getId());
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@ -1029,11 +1158,21 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SUB_FOLDER:
|
|
|
|
|
// 检查是否是回收站中的笔记
|
|
|
|
|
if (item.getType() == Notes.TYPE_NOTE && mCurrentFolderId == Notes.ID_TRASH_FOLDER) {
|
|
|
|
|
// 回收站中的笔记点击时显示恢复选项
|
|
|
|
|
restoreNote(item);
|
|
|
|
|
} else if (item.getType() == Notes.TYPE_NOTE) {
|
|
|
|
|
openNode(item); // 打开笔记
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Wrong note type in SUB_FOLDER");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CALL_RECORD_FOLDER:
|
|
|
|
|
if (item.getType() == Notes.TYPE_NOTE) {
|
|
|
|
|
openNode(item); // 打开笔记
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Wrong note type in SUB_FOLDER");
|
|
|
|
|
Log.e(TAG, "Wrong note type in CALL_RECORD_FOLDER");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
@ -1085,4 +1224,280 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 检查文件夹是否已加密
|
|
|
|
|
* @param folderId 文件夹ID
|
|
|
|
|
* @return 是否已加密
|
|
|
|
|
*/
|
|
|
|
|
private boolean isFolderEncrypted(long folderId) {
|
|
|
|
|
SharedPreferences preferences = getSharedPreferences("notes_prefs", Context.MODE_PRIVATE);
|
|
|
|
|
String password = preferences.getString("folder_" + folderId + "_password", "");
|
|
|
|
|
return !password.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 显示加密文件夹的对话框
|
|
|
|
|
* @param folderId 文件夹ID
|
|
|
|
|
*/
|
|
|
|
|
private void showEncryptFolderDialog(final long folderId) {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle("加密文件夹");
|
|
|
|
|
builder.setIcon(android.R.drawable.ic_lock_idle_lock);
|
|
|
|
|
|
|
|
|
|
// 创建密码输入框
|
|
|
|
|
final EditText passwordInput = new EditText(this);
|
|
|
|
|
passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
|
|
|
|
passwordInput.setHint("请设置密码");
|
|
|
|
|
builder.setView(passwordInput);
|
|
|
|
|
|
|
|
|
|
// 设置确定按钮
|
|
|
|
|
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
String password = passwordInput.getText().toString();
|
|
|
|
|
if (!password.isEmpty()) {
|
|
|
|
|
// 保存密码
|
|
|
|
|
SharedPreferences preferences = getSharedPreferences("notes_prefs", Context.MODE_PRIVATE);
|
|
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
|
editor.putString("folder_" + folderId + "_password", password);
|
|
|
|
|
editor.apply();
|
|
|
|
|
|
|
|
|
|
// 显示提示
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "文件夹已加密", Toast.LENGTH_SHORT).show();
|
|
|
|
|
} else {
|
|
|
|
|
// 密码为空,显示提示
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "密码不能为空", Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 设置取消按钮
|
|
|
|
|
builder.setNegativeButton("取消", null);
|
|
|
|
|
|
|
|
|
|
// 添加忘记密码按钮
|
|
|
|
|
builder.setNeutralButton("忘记密码", new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
// 显示通过密保问题重置密码的对话框
|
|
|
|
|
showResetPasswordWithSecurityQuestionsDialog(folderId);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 显示对话框
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 取消加密文件夹
|
|
|
|
|
* @param folderId 文件夹ID
|
|
|
|
|
*/
|
|
|
|
|
private void decryptFolder(final long folderId) {
|
|
|
|
|
// 显示密码输入对话框,验证身份
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle("取消加密");
|
|
|
|
|
builder.setIcon(android.R.drawable.ic_lock_idle_lock);
|
|
|
|
|
|
|
|
|
|
// 创建密码输入框
|
|
|
|
|
final EditText passwordInput = new EditText(this);
|
|
|
|
|
passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
|
|
|
|
passwordInput.setHint("请输入密码");
|
|
|
|
|
builder.setView(passwordInput);
|
|
|
|
|
|
|
|
|
|
// 设置确定按钮
|
|
|
|
|
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
String password = passwordInput.getText().toString();
|
|
|
|
|
if (checkFolderPassword(folderId, password)) {
|
|
|
|
|
// 密码正确,取消加密
|
|
|
|
|
SharedPreferences preferences = getSharedPreferences("notes_prefs", Context.MODE_PRIVATE);
|
|
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
|
editor.remove("folder_" + folderId + "_password");
|
|
|
|
|
editor.apply();
|
|
|
|
|
|
|
|
|
|
// 显示提示
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "文件夹已取消加密", Toast.LENGTH_SHORT).show();
|
|
|
|
|
} else {
|
|
|
|
|
// 密码错误,显示提示
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "密码错误", Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 设置取消按钮
|
|
|
|
|
builder.setNegativeButton("取消", null);
|
|
|
|
|
|
|
|
|
|
// 添加忘记密码按钮
|
|
|
|
|
builder.setNeutralButton("忘记密码", new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
// 显示通过密保问题重置密码的对话框
|
|
|
|
|
showResetPasswordWithSecurityQuestionsDialog(folderId);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 显示对话框
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 检查文件夹密码
|
|
|
|
|
* @param folderId 文件夹ID
|
|
|
|
|
* @param password 输入的密码
|
|
|
|
|
* @return 密码是否正确
|
|
|
|
|
*/
|
|
|
|
|
private boolean checkFolderPassword(long folderId, String password) {
|
|
|
|
|
SharedPreferences preferences = getSharedPreferences("notes_prefs", Context.MODE_PRIVATE);
|
|
|
|
|
String savedPassword = preferences.getString("folder_" + folderId + "_password", "");
|
|
|
|
|
return savedPassword.equals(password);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 进入加密文件夹
|
|
|
|
|
* @param folderId 文件夹ID
|
|
|
|
|
*/
|
|
|
|
|
private void enterEncryptedFolder(long folderId) {
|
|
|
|
|
mCurrentFolderId = folderId;
|
|
|
|
|
startAsyncNotesListQuery(); // 查询文件夹内容
|
|
|
|
|
mState = ListEditState.SUB_FOLDER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 显示文件夹密码输入对话框
|
|
|
|
|
* @param folderId 文件夹ID
|
|
|
|
|
*/
|
|
|
|
|
private void showFolderPasswordDialog(final long folderId) {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle("输入密码");
|
|
|
|
|
builder.setIcon(android.R.drawable.ic_lock_idle_lock);
|
|
|
|
|
|
|
|
|
|
// 创建密码输入框
|
|
|
|
|
final EditText passwordInput = new EditText(this);
|
|
|
|
|
passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
|
|
|
|
passwordInput.setHint("请输入文件夹密码");
|
|
|
|
|
builder.setView(passwordInput);
|
|
|
|
|
|
|
|
|
|
// 设置确定按钮
|
|
|
|
|
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
String password = passwordInput.getText().toString();
|
|
|
|
|
if (checkFolderPassword(folderId, password)) {
|
|
|
|
|
// 密码正确,进入文件夹
|
|
|
|
|
enterEncryptedFolder(folderId);
|
|
|
|
|
} else {
|
|
|
|
|
// 密码错误,显示提示
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "密码错误,请重新输入", Toast.LENGTH_SHORT).show();
|
|
|
|
|
// 重新显示密码输入对话框
|
|
|
|
|
showFolderPasswordDialog(folderId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 设置取消按钮
|
|
|
|
|
builder.setNegativeButton("取消", null);
|
|
|
|
|
|
|
|
|
|
// 显示对话框
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 通过密保问题重置文件夹密码
|
|
|
|
|
* @param folderId 文件夹ID
|
|
|
|
|
*/
|
|
|
|
|
private void showResetPasswordWithSecurityQuestionsDialog(final long folderId) {
|
|
|
|
|
// 检查是否设置了密保问题
|
|
|
|
|
if (!NotesPreferenceActivity.hasSecurityQuestionsSet(this)) {
|
|
|
|
|
Toast.makeText(this, "请先在设置中设置密保问题", Toast.LENGTH_SHORT).show();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle("忘记密码");
|
|
|
|
|
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
|
|
|
|
builder.setMessage("请回答密保问题以重置密码");
|
|
|
|
|
|
|
|
|
|
// 创建布局
|
|
|
|
|
LinearLayout layout = new LinearLayout(this);
|
|
|
|
|
layout.setOrientation(LinearLayout.VERTICAL);
|
|
|
|
|
layout.setPadding(40, 20, 40, 20);
|
|
|
|
|
|
|
|
|
|
// 创建姓名输入框
|
|
|
|
|
final EditText nameInput = new EditText(this);
|
|
|
|
|
nameInput.setHint("请输入姓名");
|
|
|
|
|
layout.addView(nameInput);
|
|
|
|
|
|
|
|
|
|
// 创建生日输入框
|
|
|
|
|
final EditText birthdayInput = new EditText(this);
|
|
|
|
|
birthdayInput.setHint("请输入生日 (YYYY-MM-DD)");
|
|
|
|
|
layout.addView(birthdayInput);
|
|
|
|
|
|
|
|
|
|
builder.setView(layout);
|
|
|
|
|
|
|
|
|
|
// 设置确定按钮
|
|
|
|
|
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
String name = nameInput.getText().toString();
|
|
|
|
|
String birthday = birthdayInput.getText().toString();
|
|
|
|
|
if (NotesPreferenceActivity.verifySecurityQuestions(NotesListActivity.this, name, birthday)) {
|
|
|
|
|
// 验证成功,显示设置新密码的对话框
|
|
|
|
|
showSetNewFolderPasswordDialog(folderId);
|
|
|
|
|
} else {
|
|
|
|
|
// 验证失败,显示提示
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "密保问题回答错误", Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 设置取消按钮
|
|
|
|
|
builder.setNegativeButton("取消", null);
|
|
|
|
|
|
|
|
|
|
// 显示对话框
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 显示设置新文件夹密码的对话框
|
|
|
|
|
* @param folderId 文件夹ID
|
|
|
|
|
*/
|
|
|
|
|
private void showSetNewFolderPasswordDialog(final long folderId) {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle("设置新密码");
|
|
|
|
|
builder.setIcon(android.R.drawable.ic_dialog_info);
|
|
|
|
|
|
|
|
|
|
// 创建密码输入框
|
|
|
|
|
final EditText passwordInput = new EditText(this);
|
|
|
|
|
passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
|
|
|
|
passwordInput.setHint("请输入新密码");
|
|
|
|
|
builder.setView(passwordInput);
|
|
|
|
|
|
|
|
|
|
// 设置确定按钮
|
|
|
|
|
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
String newPassword = passwordInput.getText().toString();
|
|
|
|
|
if (!newPassword.isEmpty()) {
|
|
|
|
|
// 保存新密码
|
|
|
|
|
SharedPreferences preferences = getSharedPreferences("notes_prefs", Context.MODE_PRIVATE);
|
|
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
|
editor.putString("folder_" + folderId + "_password", newPassword);
|
|
|
|
|
editor.apply();
|
|
|
|
|
|
|
|
|
|
// 显示提示
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "密码重置成功", Toast.LENGTH_SHORT).show();
|
|
|
|
|
} else {
|
|
|
|
|
// 密码为空,显示提示
|
|
|
|
|
Toast.makeText(NotesListActivity.this, "密码不能为空", Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 设置取消按钮
|
|
|
|
|
builder.setNegativeButton("取消", null);
|
|
|
|
|
|
|
|
|
|
// 显示对话框
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|