@ -0,0 +1,271 @@
|
||||
package net.micode.notes.model;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentProviderResult;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.OperationApplicationException;
|
||||
import android.net.Uri;
|
||||
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.DataColumns;
|
||||
import net.micode.notes.data.Notes.NoteColumns;
|
||||
import net.micode.notes.data.Notes.TextNote;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Note {
|
||||
private ContentValues mNoteDiffValues; // 存储笔记的修改值
|
||||
private NoteData mNoteData; // 存储笔记的文本和通话数据
|
||||
private static final String TAG = "Note"; // 日志标签
|
||||
|
||||
/**
|
||||
* 为新笔记创建一个新的 ID
|
||||
* @param context 上下文
|
||||
* @param folderId 文件夹 ID
|
||||
* @return 新笔记的 ID
|
||||
*/
|
||||
public static synchronized long getNewNoteId(Context context, long folderId) {
|
||||
// 创建一个新的笔记并插入到数据库中
|
||||
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); // 设置父文件夹 ID
|
||||
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); // 插入笔记
|
||||
|
||||
long noteId = 0; // 初始化笔记 ID
|
||||
try {
|
||||
noteId = Long.valueOf(uri.getPathSegments().get(1)); // 从 URI 中获取笔记 ID
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Get note id error :" + e.toString()); // 记录错误
|
||||
noteId = 0; // 设置为 0 表示错误
|
||||
}
|
||||
if (noteId == -1) {
|
||||
throw new IllegalStateException("Wrong note id:" + noteId); // 抛出异常
|
||||
}
|
||||
return noteId; // 返回新笔记 ID
|
||||
}
|
||||
|
||||
// 构造函数
|
||||
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); // 将文本数据设置到 NoteData 中
|
||||
}
|
||||
|
||||
// 设置文本数据 ID
|
||||
public void setTextDataId(long id) {
|
||||
mNoteData.setTextDataId(id); // 设置文本数据 ID
|
||||
}
|
||||
|
||||
// 获取文本数据 ID
|
||||
public long getTextDataId() {
|
||||
return mNoteData.mTextDataId; // 返回文本数据 ID
|
||||
}
|
||||
|
||||
// 设置通话数据 ID
|
||||
public void setCallDataId(long id) {
|
||||
mNoteData.setCallDataId(id); // 设置通话数据 ID
|
||||
}
|
||||
|
||||
// 设置通话数据
|
||||
public void setCallData(String key, String value) {
|
||||
mNoteData.setCallData(key, value); // 将通话数据设置到 NoteData 中
|
||||
}
|
||||
|
||||
// 检查笔记是否被本地修改
|
||||
public boolean isLocalModified() {
|
||||
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); // 如果有修改则返回 true
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步笔记到内容提供者
|
||||
* @param context 上下文
|
||||
* @param noteId 笔记 ID
|
||||
* @return 同步是否成功
|
||||
*/
|
||||
public boolean syncNote(Context context, long noteId) {
|
||||
if (noteId <= 0) {
|
||||
throw new IllegalArgumentException("Wrong note id:" + noteId); // 检查笔记 ID
|
||||
}
|
||||
|
||||
if (!isLocalModified()) {
|
||||
return true; // 如果没有本地修改,直接返回成功
|
||||
}
|
||||
|
||||
// 更新笔记的本地修改和修改日期
|
||||
if (context.getContentResolver().update(
|
||||
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
|
||||
null) == 0) {
|
||||
Log.e(TAG, "Update note error, should not happen"); // 记录更新错误
|
||||
// 不返回,继续执行
|
||||
}
|
||||
mNoteDiffValues.clear(); // 清空修改值
|
||||
|
||||
// 如果有本地修改的笔记数据,推送到内容提供者
|
||||
if (mNoteData.isLocalModified()
|
||||
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
|
||||
return false; // 如果推送失败,返回 false
|
||||
}
|
||||
|
||||
return true; // 返回成功
|
||||
}
|
||||
|
||||
// 内部类,用于管理笔记的文本和通话数据
|
||||
private class NoteData {
|
||||
private long mTextDataId; // 文本数据 ID
|
||||
private ContentValues mTextDataValues; // 存储文本数据的修改值
|
||||
private long mCallDataId; // 通话数据 ID
|
||||
private ContentValues mCallDataValues; // 存储通话数据的修改值
|
||||
private static final String TAG = "NoteData"; // 日志标签
|
||||
|
||||
// 构造函数
|
||||
public NoteData() {
|
||||
mTextDataValues = new ContentValues(); // 初始化文本数据值
|
||||
mCallDataValues = new ContentValues(); // 初始化通话数据值
|
||||
mTextDataId = 0; // 初始化文本数据 ID
|
||||
mCallDataId = 0; // 初始化通话数据 ID
|
||||
}
|
||||
|
||||
// 检查文本和通话数据是否被本地修改
|
||||
boolean isLocalModified() {
|
||||
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; // 如果有修改则返回 true
|
||||
}
|
||||
|
||||
// 设置文本数据 ID
|
||||
void setTextDataId(long id) {
|
||||
if(id <= 0) {
|
||||
throw new IllegalArgumentException("Text data id should larger than 0"); // 检查 ID
|
||||
}
|
||||
mTextDataId = id; // 设置文本数据 ID
|
||||
}
|
||||
|
||||
// 设置通话数据 ID
|
||||
void setCallDataId(long id) {
|
||||
if (id <= 0) {
|
||||
throw new IllegalArgumentException("Call data id should larger than 0"); // 检查 ID
|
||||
}
|
||||
mCallDataId = id; // 设置通话数据 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()); // 更新修改日期
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据推送到内容提供者
|
||||
* @param context 上下文
|
||||
* @param noteId 笔记 ID
|
||||
* @return 推送结果的 URI
|
||||
*/
|
||||
Uri pushIntoContentResolver(Context context, long noteId) {
|
||||
// 检查安全性
|
||||
if (noteId <= 0) {
|
||||
throw new IllegalArgumentException("Wrong note id:" + noteId); // 检查笔记 ID
|
||||
}
|
||||
|
||||
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); // 操作列表
|
||||
ContentProviderOperation.Builder builder = null; // 操作构建器
|
||||
|
||||
// 如果有文本数据需要推送
|
||||
if(mTextDataValues.size() > 0) {
|
||||
mTextDataValues.put(DataColumns.NOTE_ID, noteId); // 设置笔记 ID
|
||||
if (mTextDataId == 0) {
|
||||
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); // 设置 MIME 类型
|
||||
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
|
||||
mTextDataValues); // 插入文本数据
|
||||
try {
|
||||
setTextDataId(Long.valueOf(uri.getPathSegments().get(1))); // 获取并设置文本数据 ID
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Insert new text data fail with noteId" + noteId); // 记录插入错误
|
||||
mTextDataValues.clear(); // 清空文本数据值
|
||||
return null; // 返回 null 表示失败
|
||||
}
|
||||
} else {
|
||||
// 更新已有的文本数据
|
||||
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
|
||||
Notes.CONTENT_DATA_URI, mTextDataId));
|
||||
builder.withValues(mTextDataValues); // 设置更新值
|
||||
operationList.add(builder.build()); // 添加到操作列表
|
||||
}
|
||||
mTextDataValues.clear(); // 清空文本数据值
|
||||
}
|
||||
|
||||
// 如果有通话数据需要推送
|
||||
if(mCallDataValues.size() > 0) {
|
||||
mCallDataValues.put(DataColumns.NOTE_ID, noteId); // 设置笔记 ID
|
||||
if (mCallDataId == 0) {
|
||||
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); // 设置 MIME 类型
|
||||
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
|
||||
mCallDataValues); // 插入通话数据
|
||||
try {
|
||||
setCallDataId(Long.valueOf(uri.getPathSegments().get(1))); // 获取并设置通话数据 ID
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Insert new call data fail with noteId" + noteId); // 记录插入错误
|
||||
mCallDataValues.clear(); // 清空通话数据值
|
||||
return null; // 返回 null 表示失败
|
||||
}
|
||||
} else {
|
||||
// 更新已有的通话数据
|
||||
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
|
||||
Notes.CONTENT_DATA_URI, mCallDataId));
|
||||
builder.withValues(mCallDataValues); // 设置更新值
|
||||
operationList.add(builder.build()); // 添加到操作列表
|
||||
}
|
||||
mCallDataValues.clear(); // 清空通话数据值
|
||||
}
|
||||
|
||||
// 如果有操作需要执行
|
||||
if (operationList.size() > 0) {
|
||||
try {
|
||||
// 执行批量操作
|
||||
ContentProviderResult[] results = context.getContentResolver().applyBatch(
|
||||
Notes.AUTHORITY, operationList);
|
||||
return (results == null || results.length == 0 || results[0] == null) ? null
|
||||
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId); // 返回结果 URI
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); // 记录远程异常
|
||||
return null; // 返回 null 表示失败
|
||||
} catch (OperationApplicationException e) {
|
||||
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); // 记录操作应用异常
|
||||
return null; // 返回 null 表示失败
|
||||
}
|
||||
}
|
||||
return null; // 返回 null 表示没有操作
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
总结:
|
||||
类 Note: 主要用于创建和管理笔记,包括设置笔记的值、同步笔记到内容提供者等功能。
|
||||
内部类 NoteData: 负责管理笔记的文本和通话数据,提供设置和推送数据到内容提供者的方法。
|
||||
异常处理: 代码中包含了多处异常处理,确保在操作失败时能够记录错误并返回适当的结果。
|
||||
内容提供者操作: 通过 ContentResolver 与内容提供者进行交互,插入和更新笔记数据。
|
||||
@ -0,0 +1,324 @@
|
||||
package net.micode.notes.tool;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.***;
|
||||
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 instance
|
||||
private static BackupUtils sInstance;
|
||||
|
||||
// 获取 BackupUtils 的单例实例
|
||||
public static synchronized BackupUtils getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new BackupUtils(context); // 创建实例
|
||||
}
|
||||
return sInstance; // 返回实例
|
||||
}
|
||||
|
||||
/**
|
||||
* 备份或恢复状态的常量
|
||||
*/
|
||||
public static final int STATE_SD_CARD_UNMOUONTED = 0; // SD卡未挂载
|
||||
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; // 笔记ID列索引
|
||||
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; // MIME类型列索引
|
||||
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) {
|
||||
// 查询属于该文件夹的笔记
|
||||
*** 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.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
|
||||
mContext.getString(R.string.format_datetime_mdhm),
|
||||
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
|
||||
// 查询属于该笔记的数据
|
||||
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
|
||||
exportNoteToText(noteId, ps); // 导出笔记内容
|
||||
} while (notesCursor.moveToNext());
|
||||
}
|
||||
notesCursor.close(); // 关闭游标
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出指定ID的笔记到打印流
|
||||
*/
|
||||
private void exportNoteToText(String noteId, PrintStream ps) {
|
||||
// 查询属于该笔记的数据
|
||||
*** dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI,
|
||||
DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[]{
|
||||
noteId
|
||||
}, null);
|
||||
|
||||
if (dataCursor != null) {
|
||||
if (dataCursor.moveToFirst()) {
|
||||
do {
|
||||
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); // 获取MIME类型
|
||||
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(); // 关闭游标
|
||||
}
|
||||
// 在笔记之间打印行分隔符
|
||||
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; // 返回SD卡未挂载状态
|
||||
}
|
||||
|
||||
PrintStream ps = getExportToTextPrintStream(); // 获取打印流
|
||||
if (ps == null) {
|
||||
Log.e(TAG, "get print stream error");
|
||||
return STATE_SYSTEM_ERROR; // 返回系统错误状态
|
||||
}
|
||||
// 首先导出文件夹及其笔记
|
||||
*** 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(); // 关闭游标
|
||||
}
|
||||
|
||||
// 导出根文件夹中的笔记
|
||||
*** 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))));
|
||||
// 查询属于该笔记的数据
|
||||
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); // 创建打印流
|
||||
} 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()); // 获取外部存储目录
|
||||
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) {
|
||||
e.printStackTrace(); // 打印IO异常
|
||||
}
|
||||
|
||||
return null; // 返回空
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package net.micode.notes.tool;
|
||||
|
||||
public class GTaskStringUtils {
|
||||
|
||||
// JSON字段常量定义
|
||||
public final static String GTASK_JSON_ACTION_ID = "action_id"; // 动作ID
|
||||
public final static String GTASK_JSON_ACTION_LIST = "action_list"; // 动作列表
|
||||
public final static String GTASK_JSON_ACTION_TYPE = "action_type"; // 动作类型
|
||||
public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create"; // 创建动作
|
||||
public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all"; // 获取所有动作
|
||||
public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move"; // 移动动作
|
||||
public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update"; // 更新动作
|
||||
public final static String GTASK_JSON_CREATOR_ID = "creator_id"; // 创建者ID
|
||||
public final static String GTASK_JSON_CHILD_ENTITY = "child_entity"; // 子实体
|
||||
public final static String GTASK_JSON_CLIENT_VERSION = "client_version"; // 客户端版本
|
||||
public final static String GTASK_JSON_COMPLETED = "completed"; // 是否完成
|
||||
public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id"; // 当前列表ID
|
||||
public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id"; // 默认列表ID
|
||||
public final static String GTASK_JSON_DELETED = "deleted"; // 是否已删除
|
||||
public final static String GTASK_JSON_DEST_LIST = "dest_list"; // 目标列表
|
||||
public final static String GTASK_JSON_DEST_PARENT = "dest_parent"; // 目标父级
|
||||
public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type"; // 目标父级类型
|
||||
public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta"; // 实体增量
|
||||
public final static String GTASK_JSON_ENTITY_TYPE = "entity_type"; // 实体类型
|
||||
public final static String GTASK_JSON_GET_DELETED = "get_deleted"; // 获取已删除项
|
||||
public final static String GTASK_JSON_ID = "id"; // ID
|
||||
public final static String GTASK_JSON_INDEX = "index"; // 索引
|
||||
public final static String GTASK_JSON_LAST_MODIFIED = "last_modified"; // 最后修改时间
|
||||
public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point"; // 最新同步点
|
||||
public final static String GTASK_JSON_LIST_ID = "list_id"; // 列表ID
|
||||
public final static String GTASK_JSON_LISTS = "lists"; // 列表集合
|
||||
public final static String GTASK_JSON_NAME = "name"; // 名称
|
||||
public final static String GTASK_JSON_NEW_ID = "new_id"; // 新ID
|
||||
public final static String GTASK_JSON_NOTES = "notes"; // 笔记
|
||||
public final static String GTASK_JSON_PARENT_ID = "parent_id"; // 父级ID
|
||||
public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id"; // 前一个兄弟ID
|
||||
public final static String GTASK_JSON_RESULTS = "results"; // 结果
|
||||
public final static String GTASK_JSON_SOURCE_LIST = "source_list"; // 源列表
|
||||
public final static String GTASK_JSON_TASKS = "tasks"; // 任务集合
|
||||
public final static String GTASK_JSON_TYPE = "type"; // 类型
|
||||
public final static String GTASK_JSON_TYPE_GROUP = "GROUP"; // 组类型
|
||||
public final static String GTASK_JSON_TYPE_TASK = "TASK"; // 任务类型
|
||||
public final static String GTASK_JSON_USER = "user"; // 用户
|
||||
|
||||
// 文件夹相关常量
|
||||
public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]"; // MIUI笔记文件夹前缀
|
||||
public final static String FOLDER_DEFAULT = "Default"; // 默认文件夹
|
||||
public final static String FOLDER_CALL_NOTE = "Call_Note"; // 通话笔记文件夹
|
||||
public final static String FOLDER_META = "METADATA"; // 元数据文件夹
|
||||
|
||||
// 元数据相关常量
|
||||
public final static String META_HEAD_GTASK_ID = "meta_gid"; // 元数据头 - GTASK ID
|
||||
public final static String META_HEAD_NOTE = "meta_note"; // 元数据头 - 笔记
|
||||
public final static String META_HEAD_DATA = "meta_data"; // 元数据头 - 数据
|
||||
public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE"; // 元笔记名称
|
||||
}
|
||||
@ -0,0 +1,182 @@
|
||||
package net.micode.notes.tool;
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
// 获取默认背景ID
|
||||
public static int getDefaultBgId(Context context) {
|
||||
// 检查用户是否设置了背景颜色
|
||||
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
||||
NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) {
|
||||
// 随机返回一个背景颜色ID
|
||||
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,
|
||||
};
|
||||
|
||||
// 获取2x小部件背景资源
|
||||
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
|
||||
};
|
||||
|
||||
// 获取4x小部件背景资源
|
||||
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
|
||||
};
|
||||
|
||||
// 获取文本外观资源
|
||||
public static int getTexAppearanceResource(int id) {
|
||||
/**
|
||||
* HACKME: Fix bug of store the resource id in shared preference.
|
||||
* The id may larger than the length of resources, in this case,
|
||||
* return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
|
||||
*/
|
||||
if (id >= TEXTAPPEARANCE_RESOURCES.length) {
|
||||
return BG_DEFAULT_FONT_SIZE; // 返回默认字体大小
|
||||
}
|
||||
return TEXTAPPEARANCE_RESOURCES[id]; // 返回指定ID的资源
|
||||
}
|
||||
|
||||
// 获取资源数量
|
||||
public static int getResourcesSize() {
|
||||
return TEXTAPPEARANCE_RESOURCES.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,143 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.tool.DataUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
|
||||
private long mNoteId; // 笔记ID
|
||||
private String mSnippet; // 笔记片段
|
||||
private static final int SNIPPET_PREW_MAX_LEN = 60; // 片段最大长度
|
||||
MediaPlayer mPlayer; // 媒体播放器
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE); // 请求无标题窗口
|
||||
|
||||
final Window win = getWindow();
|
||||
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); // 显示在锁屏上
|
||||
|
||||
// 如果屏幕未开启,保持屏幕常亮
|
||||
if (!isScreenOn()) {
|
||||
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
|
||||
}
|
||||
|
||||
Intent intent = getIntent(); // 获取意图
|
||||
|
||||
try {
|
||||
// 从意图中获取笔记ID
|
||||
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
|
||||
// 根据ID获取笔记片段
|
||||
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
|
||||
// 如果片段过长,截断并添加提示
|
||||
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
|
||||
SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info)
|
||||
: mSnippet;
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace(); // 打印异常
|
||||
return; // 退出
|
||||
}
|
||||
|
||||
mPlayer = new MediaPlayer(); // 初始化媒体播放器
|
||||
// 检查笔记是否可见
|
||||
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
|
||||
showActionDialog(); // 显示操作对话框
|
||||
playAlarmSound(); // 播放闹钟声音
|
||||
} else {
|
||||
finish(); // 结束活动
|
||||
}
|
||||
}
|
||||
|
||||
// 检查屏幕是否开启
|
||||
private boolean isScreenOn() {
|
||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
return pm.isScreenOn();
|
||||
}
|
||||
|
||||
// 播放闹钟声音
|
||||
private void playAlarmSound() {
|
||||
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); // 获取闹钟铃声URI
|
||||
|
||||
int silentModeStreams = Settings.System.getInt(getContentResolver(),
|
||||
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
|
||||
|
||||
// 设置音频流类型
|
||||
if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) {
|
||||
mPlayer.setAudioStreamType(silentModeStreams);
|
||||
} else {
|
||||
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
|
||||
}
|
||||
try {
|
||||
mPlayer.setDataSource(this, url); // 设置数据源
|
||||
mPlayer.prepare(); // 准备播放器
|
||||
mPlayer.setLooping(true); // 循环播放
|
||||
mPlayer.start(); // 开始播放
|
||||
} catch (IllegalArgumentException | SecurityException | IllegalStateException | IOException e) {
|
||||
e.printStackTrace(); // 打印异常
|
||||
}
|
||||
}
|
||||
|
||||
// 显示操作对话框
|
||||
private void showActionDialog() {
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
|
||||
dialog.setTitle(R.string.app_name); // 设置对话框标题
|
||||
dialog.setMessage(mSnippet); // 设置对话框消息
|
||||
dialog.setPositiveButton(R.string.notealert_ok, this); // 设置确认按钮
|
||||
if (isScreenOn()) {
|
||||
dialog.setNegativeButton(R.string.notealert_enter, this); // 设置取消按钮
|
||||
}
|
||||
dialog.show().setOnDismissListener(this); // 显示对话框并设置消失监听
|
||||
}
|
||||
|
||||
// 处理对话框按钮点击事件
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switch (which) {
|
||||
case DialogInterface.BUTTON_NEGATIVE:
|
||||
Intent intent = new Intent(this, NoteEditActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra(Intent.EXTRA_UID, mNoteId); // 传递笔记ID
|
||||
startActivity(intent); // 启动编辑活动
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理对话框消失事件
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
stopAlarmSound(); // 停止闹钟声音
|
||||
finish(); // 结束活动
|
||||
}
|
||||
|
||||
// 停止闹钟声音
|
||||
private void stopAlarmSound() {
|
||||
if (mPlayer != null) {
|
||||
mPlayer.stop(); // 停止播放
|
||||
mPlayer.release(); // 释放资源
|
||||
mPlayer = null; // 清空播放器引用
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class AlarmReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// 设置意图的目标类为 AlarmAlertActivity
|
||||
intent.setClass(context, AlarmAlertActivity.class);
|
||||
// 添加标志以启动新任务
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
// 启动 AlarmAlertActivity
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.ui.DateTimePicker;
|
||||
import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
|
||||
|
||||
private Calendar mDate = Calendar.getInstance(); // 当前日期和时间
|
||||
private boolean mIs24HourView; // 是否为24小时制
|
||||
private OnDateTimeSetListener mOnDateTimeSetListener; // 日期时间设置监听器
|
||||
private DateTimePicker mDateTimePicker; // 日期时间选择器
|
||||
|
||||
// 日期时间设置监听器接口
|
||||
public interface OnDateTimeSetListener {
|
||||
void OnDateTimeSet(AlertDialog dialog, long date); // 设置日期时间的方法
|
||||
}
|
||||
|
||||
// 构造函数
|
||||
public DateTimePickerDialog(Context context, long date) {
|
||||
super(context);
|
||||
mDateTimePicker = new DateTimePicker(context); // 初始化日期时间选择器
|
||||
setView(mDateTimePicker); // 设置对话框视图为日期时间选择器
|
||||
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
|
||||
public void onDateTimeChanged(DateTimePicker view, int year, int month,
|
||||
int dayOfMonth, int hourOfDay, int minute) {
|
||||
// 更新日期和时间
|
||||
mDate.set(Calendar.YEAR, year);
|
||||
mDate.set(Calendar.MONTH, month);
|
||||
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
|
||||
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
|
||||
mDate.set(Calendar.MINUTE, minute);
|
||||
updateTitle(mDate.getTimeInMillis()); // 更新对话框标题
|
||||
}
|
||||
});
|
||||
mDate.setTimeInMillis(date); // 设置初始日期
|
||||
mDate.set(Calendar.SECOND, 0); // 将秒数设置为0
|
||||
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); // 设置选择器的当前日期
|
||||
setButton(context.getString(R.string.datetime_dialog_ok), this); // 设置确认按钮
|
||||
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null); // 设置取消按钮
|
||||
set24HourView(DateFormat.is24HourFormat(this.getContext())); // 设置24小时制
|
||||
updateTitle(mDate.getTimeInMillis()); // 更新对话框标题
|
||||
}
|
||||
|
||||
// 设置24小时制
|
||||
public void set24HourView(boolean is24HourView) {
|
||||
mIs24HourView = is24HourView; // 更新24小时制状态
|
||||
}
|
||||
|
||||
// 设置日期时间设置监听器
|
||||
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
|
||||
mOnDateTimeSetListener = callBack; // 更新监听器
|
||||
}
|
||||
|
||||
// 更新对话框标题
|
||||
private void updateTitle(long date) {
|
||||
int flag =
|
||||
DateUtils.FORMAT_SHOW_YEAR |
|
||||
DateUtils.FORMAT_SHOW_DATE |
|
||||
DateUtils.FORMAT_SHOW_TIME; // 设置标题格式
|
||||
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_12HOUR; // 根据24小时制设置格式
|
||||
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); // 设置对话框标题
|
||||
}
|
||||
|
||||
// 确认按钮点击事件
|
||||
public void onClick(DialogInterface arg0, int arg1) {
|
||||
if (mOnDateTimeSetListener != null) {
|
||||
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); // 通知监听器设置的日期时间
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.PopupMenu.OnMenuItemClickListener;
|
||||
|
||||
import net.micode.notes.R;
|
||||
|
||||
public class DropdownMenu {
|
||||
private Button mButton; // 下拉菜单按钮
|
||||
private PopupMenu mPopupMenu; // 弹出菜单
|
||||
private Menu mMenu; // 菜单对象
|
||||
|
||||
// 构造函数
|
||||
public DropdownMenu(Context context, Button button, int menuId) {
|
||||
mButton = button; // 初始化按钮
|
||||
mButton.setBackgroundResource(R.drawable.dropdown_icon); // 设置按钮背景图标
|
||||
mPopupMenu = new PopupMenu(context, mButton); // 创建弹出菜单
|
||||
mMenu = mPopupMenu.getMenu(); // 获取菜单对象
|
||||
mPopupMenu.getMenuInflater().inflate(menuId, mMenu); // 从资源文件中加载菜单
|
||||
mButton.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mPopupMenu.show(); // 显示弹出菜单
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 设置下拉菜单项点击监听器
|
||||
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
|
||||
if (mPopupMenu != null) {
|
||||
mPopupMenu.setOnMenuItemClickListener(listener); // 设置菜单项点击监听器
|
||||
}
|
||||
}
|
||||
|
||||
// 根据ID查找菜单项
|
||||
public MenuItem findItem(int id) {
|
||||
return mMenu.findItem(id); // 返回指定ID的菜单项
|
||||
}
|
||||
|
||||
// 设置按钮标题
|
||||
public void setTitle(CharSequence title) {
|
||||
mButton.setText(title); // 更新按钮文本
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.***;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.***Adapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.data.Notes.NoteColumns;
|
||||
|
||||
public class FoldersListAdapter extends ***Adapter {
|
||||
// 定义要查询的列
|
||||
public static final String[] PROJECTION = {
|
||||
NoteColumns.ID, // 文件夹ID
|
||||
NoteColumns.SNIPPET // 文件夹名称
|
||||
};
|
||||
|
||||
// 列索引常量
|
||||
public static final int ID_COLUMN = 0; // ID列索引
|
||||
public static final int NAME_COLUMN = 1; // 名称列索引
|
||||
|
||||
// 构造函数,接收上下文和***对象
|
||||
public FoldersListAdapter(Context context, *** c) {
|
||||
super(context, c); // 调用父类构造函数
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
// 创建新视图的方法
|
||||
@Override
|
||||
public View newView(Context context, *** cursor, ViewGroup parent) {
|
||||
return new FolderListItem(context); // 返回新的文件夹列表项视图
|
||||
}
|
||||
|
||||
// 绑定数据到视图的方法
|
||||
@Override
|
||||
public void bindView(View view, Context context, *** cursor) {
|
||||
if (view instanceof FolderListItem) { // 确保视图是FolderListItem的实例
|
||||
// 获取文件夹名称,如果是根文件夹则使用特定字符串
|
||||
String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
|
||||
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
|
||||
// 将文件夹名称绑定到视图
|
||||
((FolderListItem) view).bind(folderName);
|
||||
}
|
||||
}
|
||||
|
||||
// 根据位置获取文件夹名称的方法
|
||||
public String getFolderName(Context context, int position) {
|
||||
*** cursor = (***) getItem(position); // 获取指定位置的***
|
||||
// 返回文件夹名称,如果是根文件夹则使用特定字符串
|
||||
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
|
||||
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
|
||||
}
|
||||
|
||||
// 内部类,表示文件夹列表项
|
||||
private class FolderListItem extends LinearLayout {
|
||||
private TextView mName; // 文件夹名称的TextView
|
||||
|
||||
// 构造函数,接收上下文
|
||||
public FolderListItem(Context context) {
|
||||
super(context);
|
||||
// 从布局文件中加载视图
|
||||
inflate(context, R.layout.folder_list_item, this);
|
||||
// 获取文件夹名称的TextView
|
||||
mName = (TextView) findViewById(R.id.tv_folder_name);
|
||||
}
|
||||
|
||||
// 绑定文件夹名称到TextView的方法
|
||||
public void bind(String name) {
|
||||
mName.setText(name); // 设置TextView的文本为文件夹名称
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,665 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.***;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.ActionMode;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Display;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MenuItem.OnMenuItemClickListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnCreateContextMenuListener;
|
||||
import android.view.View.OnTouchListener;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.AdapterView.OnItemLongClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.data.Notes.NoteColumns;
|
||||
import net.micode.notes.gtask.remote.GTaskSyncService;
|
||||
import net.micode.notes.model.WorkingNote;
|
||||
import net.micode.notes.tool.BackupUtils;
|
||||
import net.micode.notes.tool.DataUtils;
|
||||
import net.micode.notes.tool.ResourceParser;
|
||||
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
|
||||
import net.micode.notes.widget.NoteWidgetProvider_2x;
|
||||
import net.micode.notes.widget.NoteWidgetProvider_4x;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener {
|
||||
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
|
||||
private static final int FOLDER_LIST_QUERY_TOKEN = 1;
|
||||
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 String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction";
|
||||
|
||||
private enum ListEditState {
|
||||
NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER
|
||||
};
|
||||
|
||||
private ListEditState mState;
|
||||
private BackgroundQueryHandler mBackgroundQueryHandler;
|
||||
private NotesListAdapter mNotesListAdapter;
|
||||
private ListView mNotesListView;
|
||||
private Button mAddNewNote;
|
||||
private boolean mDispatch;
|
||||
private int mOriginY;
|
||||
private int mDispatchY;
|
||||
private TextView mTitleBar;
|
||||
private long mCurrentFolderId;
|
||||
private ContentResolver mContentResolver;
|
||||
private ModeCallback mModeCallBack;
|
||||
private static final String TAG = "NotesListActivity";
|
||||
public static final int NOTES_LISTVIEW_SCROLL_RATE = 30;
|
||||
private NoteItemData mFocusNoteDataItem;
|
||||
|
||||
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 ("
|
||||
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND "
|
||||
+ NoteColumns.NOTES_COUNT + ">0)";
|
||||
|
||||
private final static int REQUEST_CODE_OPEN_NODE = 102;
|
||||
private final static int REQUEST_CODE_NEW_NODE = 103;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.note_list);
|
||||
initResources();
|
||||
|
||||
/**
|
||||
* Insert an introduction when user first uses this application
|
||||
*/
|
||||
setAppInfoFromRawRes();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == RESULT_OK
|
||||
&& (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) {
|
||||
mNotesListAdapter.changeCursor(null); // 更新适配器的光标
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAppInfoFromRawRes() {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = getResources().openRawResource(R.raw.introduction);
|
||||
if (in != null) {
|
||||
InputStreamReader isr = new InputStreamReader(in);
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
char [] buf = new char[1024];
|
||||
int len = 0;
|
||||
while ((len = br.read(buf)) > 0) {
|
||||
sb.append(buf, 0, len); // 读取介绍内容
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Read introduction file error");
|
||||
return;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
} finally {
|
||||
if(in != null) {
|
||||
try {
|
||||
in.close(); // 关闭输入流
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建并保存介绍笔记
|
||||
WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER,
|
||||
AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE,
|
||||
ResourceParser.RED);
|
||||
note.setWorkingText(sb.toString());
|
||||
if (note.saveNote()) {
|
||||
sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); // 更新偏好设置
|
||||
} else {
|
||||
Log.e(TAG, "Save introduction note error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
startAsyncNotesListQuery(); // 启动异步查询
|
||||
}
|
||||
|
||||
private void initResources() {
|
||||
mContentResolver = this.getContentResolver();
|
||||
mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver());
|
||||
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
|
||||
mNotesListView = (ListView) findViewById(R.id.notes_list);
|
||||
mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null),
|
||||
null, false);
|
||||
mNotesListView.setOnItemClickListener(new OnListItemClickListener());
|
||||
mNotesListView.setOnItemLongClickListener(this);
|
||||
mNotesListAdapter = new NotesListAdapter(this);
|
||||
mNotesListView.setAdapter(mNotesListAdapter);
|
||||
mAddNewNote = (Button) findViewById(R.id.btn_new_note);
|
||||
mAddNewNote.setOnClickListener(this);
|
||||
mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener());
|
||||
mDispatch = false;
|
||||
mDispatchY = 0;
|
||||
mOriginY = 0;
|
||||
mTitleBar = (TextView) findViewById(R.id.tv_title_bar);
|
||||
mState = ListEditState.NOTE_LIST;
|
||||
mModeCallBack = new ModeCallback();
|
||||
}
|
||||
|
||||
private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
|
||||
private DropdownMenu mDropDownMenu;
|
||||
private ActionMode mActionMode;
|
||||
private MenuItem mMoveMenu;
|
||||
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.note_list_options, menu);
|
||||
menu.findItem(R.id.delete).setOnMenuItemClickListener(this);
|
||||
mMoveMenu = menu.findItem(R.id.move);
|
||||
// 根据条件设置移动菜单的可见性
|
||||
if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER
|
||||
|| DataUtils.getUserFolderCount(mContentResolver) == 0) {
|
||||
mMoveMenu.setVisible(false);
|
||||
} else {
|
||||
mMoveMenu.setVisible(true);
|
||||
mMoveMenu.setOnMenuItemClickListener(this);
|
||||
}
|
||||
mActionMode = mode;
|
||||
mNotesListAdapter.setChoiceMode(true);
|
||||
mNotesListView.setLongClickable(false);
|
||||
mAddNewNote.setVisibility(View.GONE); // 隐藏添加新笔记按钮
|
||||
|
||||
View customView = LayoutInflater.from(NotesListActivity.this).inflate(
|
||||
R.layout.note_list_dropdown_menu, null);
|
||||
mode.setCustomView(customView);
|
||||
mDropDownMenu = new DropdownMenu(NotesListActivity.this,
|
||||
(Button) customView.findViewById(R.id.selection_menu),
|
||||
R.menu.note_list_dropdown);
|
||||
mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected()); // 切换全选状态
|
||||
updateMenu(); // 更新菜单
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateMenu() {
|
||||
int selectedCount = mNotesListAdapter.getSelectedCount();
|
||||
// 更新下拉菜单
|
||||
String format = getResources().getString(R.string.menu_select_title, selectedCount);
|
||||
mDropDownMenu.setTitle(format);
|
||||
MenuItem item = mDropDownMenu.findItem(R.id.action_select_all);
|
||||
if (item != null) {
|
||||
if (mNotesListAdapter.isAllSelected()) {
|
||||
item.setChecked(true);
|
||||
item.setTitle(R.string.menu_deselect_all);
|
||||
} else {
|
||||
item.setChecked(false);
|
||||
item.setTitle(R.string.menu_select_all);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void showCreateOrModifyFolderDialog(final boolean create) {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
|
||||
// ActionMode的回调方法
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
mNotesListAdapter.setChoiceMode(false);
|
||||
mNotesListView.setLongClickable(true);
|
||||
mAddNewNote.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void finishActionMode() {
|
||||
mActionMode.finish();
|
||||
}
|
||||
|
||||
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
|
||||
mNotesListAdapter.setCheckedItem(position, checked);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (mNotesListAdapter.getSelectedCount() == 0) {
|
||||
Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none), Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case R.id.delete:
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
|
||||
builder.setTitle(getString(R.string.alert_title_delete));
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setMessage(getString(R.string.alert_message_delete_notes, mNotesListAdapter.getSelectedCount()));
|
||||
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
batchDelete(); // 批量删除选中的笔记
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.show();
|
||||
break;
|
||||
case R.id.move:
|
||||
startQueryDestinationFolders(); // 查询目标文件夹
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 创建或修改文件夹的对话框视图
|
||||
View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
|
||||
final EditText etName = (EditText) view.findViewById(R.id.et_foler_name);
|
||||
showSoftInput(); // 显示软键盘
|
||||
|
||||
if (!create) {
|
||||
if (mFocusNoteDataItem != null) {
|
||||
etName.setText(mFocusNoteDataItem.getSnippet()); // 设置当前文件夹名称
|
||||
builder.setTitle(getString(R.string.menu_folder_change_name));
|
||||
} else {
|
||||
Log.e(TAG, "The long click data item is null");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
etName.setText(""); // 新建文件夹时清空输入框
|
||||
builder.setTitle(this.getString(R.string.menu_create_folder));
|
||||
}
|
||||
|
||||
builder.setPositiveButton(android.R.string.ok, null);
|
||||
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
hideSoftInput(etName); // 隐藏软键盘
|
||||
}
|
||||
});
|
||||
|
||||
final Dialog dialog = builder.setView(view).show();
|
||||
final Button positive = (Button) dialog.findViewById(android.R.id.button1);
|
||||
positive.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
hideSoftInput(etName); // 隐藏软键盘
|
||||
String name = etName.getText().toString();
|
||||
if (DataUtils.checkVisibleFolderName(mContentResolver, name)) {
|
||||
Toast.makeText(NotesListActivity.this, getString(R.string.folder_exist, name), Toast.LENGTH_LONG).show();
|
||||
etName.setSelection(0, etName.length()); // 重新选择文本
|
||||
return;
|
||||
}
|
||||
if (!create) {
|
||||
if (!TextUtils.isEmpty(name)) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NoteColumns.SNIPPET, name);
|
||||
values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
|
||||
values.put(NoteColumns.LOCAL_MODIFIED, 1);
|
||||
mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID + "=?", new String[] {
|
||||
String.valueOf(mFocusNoteDataItem.getId())
|
||||
});
|
||||
}
|
||||
} else if (!TextUtils.isEmpty(name)) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NoteColumns.SNIPPET, name);
|
||||
values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
|
||||
mContentResolver.insert(Notes.CONTENT_NOTE_URI, values); // 插入新文件夹
|
||||
}
|
||||
dialog.dismiss(); // 关闭对话框
|
||||
}
|
||||
});
|
||||
}
|
||||
if (TextUtils.isEmpty(etName.getText())) {
|
||||
positive.setEnabled(false); // 如果输入框为空,禁用确认按钮
|
||||
}
|
||||
/**
|
||||
* 当名称编辑框为空时,禁用确认按钮
|
||||
*/
|
||||
etName.addTextChangedListener(new TextWatcher() {
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
// 根据输入框内容启用或禁用确认按钮
|
||||
if (TextUtils.isEmpty(etName.getText())) {
|
||||
positive.setEnabled(false);
|
||||
} else {
|
||||
positive.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterTextChanged(Editable s) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
switch (mState) {
|
||||
case SUB_FOLDER:
|
||||
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
|
||||
mState = ListEditState.NOTE_LIST;
|
||||
startAsyncNotesListQuery(); // 查询笔记列表
|
||||
mTitleBar.setVisibility(View.GONE);
|
||||
break;
|
||||
case CALL_RECORD_FOLDER:
|
||||
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
|
||||
mState = ListEditState.NOTE_LIST;
|
||||
mAddNewNote.setVisibility(View.VISIBLE);
|
||||
mTitleBar.setVisibility(View.GONE);
|
||||
startAsyncNotesListQuery(); // 查询笔记列表
|
||||
break;
|
||||
case NOTE_LIST:
|
||||
super.onBackPressed(); // 调用父类的返回处理
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateWidget(int appWidgetId, int appWidgetType) {
|
||||
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
||||
if (appWidgetType == Notes.TYPE_WIDGET_2X) {
|
||||
intent.setClass(this, NoteWidgetProvider_2x.class);
|
||||
} else if (appWidgetType == Notes.TYPE_WIDGET_4X) {
|
||||
intent.setClass(this, NoteWidgetProvider_4x.class);
|
||||
} else {
|
||||
Log.e(TAG, "Unsupported widget type");
|
||||
return;
|
||||
}
|
||||
|
||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { appWidgetId });
|
||||
sendBroadcast(intent); // 发送更新小部件的广播
|
||||
setResult(RESULT_OK, intent); // 设置结果为成功
|
||||
}
|
||||
|
||||
private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() {
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
if (mFocusNoteDataItem != null) {
|
||||
menu.setHeaderTitle(mFocusNoteDataItem.getSnippet());
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onContextMenuClosed(Menu menu) {
|
||||
if (mNotesListView != null) {
|
||||
mNotesListView.setOnCreateContextMenuListener(null); // 清除上下文菜单监听器
|
||||
}
|
||||
super.onContextMenuClosed(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
if (mFocusNoteDataItem == null) {
|
||||
Log.e(TAG, "The long click data item is null");
|
||||
return false;
|
||||
}
|
||||
switch (item.getItemId()) {
|
||||
case MENU_FOLDER_VIEW:
|
||||
openFolder(mFocusNoteDataItem); // 打开文件夹
|
||||
break;
|
||||
case MENU_FOLDER_DELETE:
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(getString(R.string.alert_title_delete));
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setMessage(getString(R.string.alert_message_delete_folder));
|
||||
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
deleteFolder(mFocusNoteDataItem.getId()); // 删除文件夹
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.show();
|
||||
break;
|
||||
case MENU_FOLDER_CHANGE_NAME:
|
||||
showCreateOrModifyFolderDialog(false); // 显示修改文件夹名称对话框
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
menu.clear(); // 清空菜单
|
||||
if (mState == ListEditState.NOTE_LIST) {
|
||||
getMenuInflater().inflate(R.menu.note_list, menu);
|
||||
// 设置同步或取消同步
|
||||
menu.findItem(R.id.menu_sync).setTitle(
|
||||
GTaskSyncService.isSyncing() ? R.string.menu_sync_cancel : R.string.menu_sync);
|
||||
} else if (mState == ListEditState.SUB_FOLDER) {
|
||||
getMenuInflater().inflate(R.menu.sub_folder, menu);
|
||||
} else if (mState == ListEditState.CALL_RECORD_FOLDER) {
|
||||
getMenuInflater().inflate(R.menu.call_record_folder, menu);
|
||||
} else {
|
||||
Log.e(TAG, "Wrong state:" + mState);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_new_folder: {
|
||||
showCreateOrModifyFolderDialog(true); // 显示创建新文件夹对话框
|
||||
break;
|
||||
}
|
||||
case R.id.menu_export_text: {
|
||||
exportNoteToText(); // 导出笔记为文本
|
||||
break;
|
||||
}
|
||||
case R.id.menu_sync: {
|
||||
if (isSyncMode()) {
|
||||
if (TextUtils.equals(item.getTitle(), getString(R.string.menu_sync))) {
|
||||
GTaskSyncService.startSync(this); // 开始同步
|
||||
} else {
|
||||
GTaskSyncService.cancelSync(this); // 取消同步
|
||||
}
|
||||
} else {
|
||||
startPreferenceActivity(); // 启动设置活动
|
||||
}
|
||||
break;
|
||||
}
|
||||
case R.id.menu_setting: {
|
||||
startPreferenceActivity(); // 启动设置活动
|
||||
break;
|
||||
}
|
||||
case R.id.menu_new_note: {
|
||||
createNewNote(); // 创建新笔记
|
||||
break;
|
||||
}
|
||||
case R.id.menu_search:
|
||||
onSearchRequested(); // 请求搜索
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSearchRequested() {
|
||||
startSearch(null, false, null /* appData */, false); // 启动搜索
|
||||
return true;
|
||||
}
|
||||
|
||||
private void exportNoteToText() {
|
||||
final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this);
|
||||
new AsyncTask<Void, Void, Integer>() {
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... unused) {
|
||||
return backup.exportToText(); // 导出笔记到文本
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
// 根据导出结果显示相应的对话框
|
||||
if (result == BackupUtils.STATE_SD_CARD_UNMOUONTED) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
|
||||
builder.setTitle(NotesListActivity.this.getString(R.string.failed_sdcard_export));
|
||||
builder.setMessage(NotesListActivity.this.getString(R.string.error_sdcard_unmounted));
|
||||
builder.setPositiveButton(android.R.string.ok, null);
|
||||
builder.show();
|
||||
} else if (result == BackupUtils.STATE_SUCCESS) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
|
||||
builder.setTitle(NotesListActivity.this.getString(R.string.success_sdcard_export));
|
||||
builder.setMessage(NotesListActivity.this.getString(
|
||||
R.string.format_exported_file_location, backup.getExportedTextFileName(), backup.getExportedTextFileDir()));
|
||||
builder.setPositiveButton(android.R.string.ok, null);
|
||||
builder.show();
|
||||
} else if (result == BackupUtils.STATE_SYSTEM_ERROR) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
|
||||
builder.setTitle(NotesListActivity.this.getString(R.string.failed_sdcard_export));
|
||||
builder.setMessage(NotesListActivity.this.getString(R.string.error_sdcard_export));
|
||||
builder.setPositiveButton(android.R.string.ok, null);
|
||||
builder.show();
|
||||
}
|
||||
}
|
||||
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private boolean isSyncMode() {
|
||||
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; // 检查是否在同步模式
|
||||
}
|
||||
|
||||
private void startPreferenceActivity() {
|
||||
Activity from = getParent() != null ? getParent() : this;
|
||||
Intent intent = new Intent(from, NotesPreferenceActivity.class);
|
||||
from.startActivityIfNeeded(intent, -1); // 启动设置活动
|
||||
}
|
||||
|
||||
private class OnListItemClickListener implements OnItemClickListener {
|
||||
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (view instanceof NotesListItem) {
|
||||
NoteItemData item = ((NotesListItem) view).getItemData();
|
||||
if (mNotesListAdapter.isInChoiceMode()) {
|
||||
if (item.getType() == Notes.TYPE_NOTE) {
|
||||
position = position - mNotesListView.getHeaderViewsCount();
|
||||
mModeCallBack.onItemCheckedStateChanged(null, position, id, !mNotesListAdapter.isSelectedItem(position));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mState) {
|
||||
case NOTE_LIST:
|
||||
if (item.getType() == Notes.TYPE_FOLDER || item.getType() == Notes.TYPE_SYSTEM) {
|
||||
openFolder(item); // 打开文件夹
|
||||
} else if (item.getType() == Notes.TYPE_NOTE) {
|
||||
openNode(item); // 打开笔记
|
||||
} else {
|
||||
Log.e(TAG, "Wrong note type in NOTE_LIST");
|
||||
}
|
||||
break;
|
||||
case SUB_FOLDER:
|
||||
case CALL_RECORD_FOLDER:
|
||||
if (item.getType() == Notes.TYPE_NOTE) {
|
||||
openNode(item); // 打开笔记
|
||||
} else {
|
||||
Log.e(TAG, "Wrong note type in SUB_FOLDER");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startQueryDestinationFolders() {
|
||||
String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?";
|
||||
selection = (mState == ListEditState.NOTE_LIST) ? selection :
|
||||
"(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")";
|
||||
|
||||
mBackgroundQueryHandler.startQuery(FOLDER_LIST_QUERY_TOKEN,
|
||||
null,
|
||||
Notes.CONTENT_NOTE_URI,
|
||||
FoldersListAdapter.PROJECTION,
|
||||
selection,
|
||||
new String[] {
|
||||
String.valueOf(Notes.TYPE_FOLDER),
|
||||
String.valueOf(Notes.ID_TRASH_FOLDER),
|
||||
String.valueOf(mCurrentFolderId)
|
||||
},
|
||||
NoteColumns.MODIFIED_DATE + " DESC"); // 按修改日期降序查询文件夹
|
||||
}
|
||||
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (view instanceof NotesListItem) {
|
||||
mFocusNoteDataItem = ((NotesListItem) view).getItemData();
|
||||
if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) {
|
||||
if (mNotesListView.startActionMode(mModeCallBack) != null) {
|
||||
mModeCallBack.onItemCheckedStateChanged(null, position, id, true); // 进入选择模式
|
||||
mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); // 触觉反馈
|
||||
} else {
|
||||
Log.e(TAG, "startActionMode fails");
|
||||
}
|
||||
} else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) {
|
||||
mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener); // 设置上下文菜单监听器
|
||||
}
|
||||
}
|
||||
return false; // 返回false以允许其他处理
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.tool.DataUtils;
|
||||
import net.micode.notes.tool.ResourceParser.NoteItemBgResources;
|
||||
|
||||
public class NotesListItem extends LinearLayout {
|
||||
private ImageView mAlert; // 警告图标
|
||||
private TextView mTitle; // 笔记标题
|
||||
private TextView mTime; // 修改时间
|
||||
private TextView mCallName; // 通话名称
|
||||
private NoteItemData mItemData; // 笔记项数据
|
||||
private CheckBox mCheckBox; // 选择框
|
||||
|
||||
public NotesListItem(Context context) {
|
||||
super(context);
|
||||
inflate(context, R.layout.note_item, this); // 加载布局
|
||||
mAlert = (ImageView) findViewById(R.id.iv_alert_icon);
|
||||
mTitle = (TextView) findViewById(R.id.tv_title);
|
||||
mTime = (TextView) findViewById(R.id.tv_time);
|
||||
mCallName = (TextView) findViewById(R.id.tv_name);
|
||||
mCheckBox = (CheckBox) findViewById(android.R.id.checkbox);
|
||||
}
|
||||
|
||||
public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) {
|
||||
if (choiceMode && data.getType() == Notes.TYPE_NOTE) {
|
||||
mCheckBox.setVisibility(View.VISIBLE); // 显示选择框
|
||||
mCheckBox.setChecked(checked); // 设置选择框状态
|
||||
} else {
|
||||
mCheckBox.setVisibility(View.GONE); // 隐藏选择框
|
||||
}
|
||||
|
||||
mItemData = data; // 绑定数据
|
||||
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
|
||||
mCallName.setVisibility(View.GONE); // 隐藏通话名称
|
||||
mAlert.setVisibility(View.VISIBLE); // 显示警告图标
|
||||
mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem);
|
||||
mTitle.setText(context.getString(R.string.call_record_folder_name)
|
||||
+ context.getString(R.string.format_folder_files_count, data.getNotesCount()));
|
||||
mAlert.setImageResource(R.drawable.call_record); // 设置警告图标
|
||||
} else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) {
|
||||
mCallName.setVisibility(View.VISIBLE); // 显示通话名称
|
||||
mCallName.setText(data.getCallName());
|
||||
mTitle.setTextAppearance(context, R.style.TextAppearanceSecondaryItem);
|
||||
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
|
||||
if (data.hasAlert()) {
|
||||
mAlert.setImageResource(R.drawable.clock); // 设置时钟图标
|
||||
mAlert.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mAlert.setVisibility(View.GONE); // 隐藏警告图标
|
||||
}
|
||||
} else {
|
||||
mCallName.setVisibility(View.GONE); // 隐藏通话名称
|
||||
mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem);
|
||||
|
||||
if (data.getType() == Notes.TYPE_FOLDER) {
|
||||
mTitle.setText(data.getSnippet()
|
||||
+ context.getString(R.string.format_folder_files_count,
|
||||
data.getNotesCount())); // 设置文件夹标题
|
||||
mAlert.setVisibility(View.GONE); // 隐藏警告图标
|
||||
} else {
|
||||
mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
|
||||
if (data.hasAlert()) {
|
||||
mAlert.setImageResource(R.drawable.clock); // 设置时钟图标
|
||||
mAlert.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mAlert.setVisibility(View.GONE); // 隐藏警告图标
|
||||
}
|
||||
}
|
||||
}
|
||||
mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); // 设置修改时间
|
||||
|
||||
setBackground(data); // 设置背景
|
||||
}
|
||||
|
||||
private void setBackground(NoteItemData data) {
|
||||
int id = data.getBgColorId(); // 获取背景颜色ID
|
||||
if (data.getType() == Notes.TYPE_NOTE) {
|
||||
if (data.isSingle() || data.isOneFollowingFolder()) {
|
||||
setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); // 设置单个笔记背景
|
||||
} else if (data.isLast()) {
|
||||
setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id)); // 设置最后一个笔记背景
|
||||
} else if (data.isFirst() || data.isMultiFollowingFolder()) {
|
||||
setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); // 设置第一个笔记背景
|
||||
} else {
|
||||
setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); // 设置普通笔记背景
|
||||
}
|
||||
} else {
|
||||
setBackgroundResource(NoteItemBgResources.getFolderBgRes()); // 设置文件夹背景
|
||||
}
|
||||
}
|
||||
|
||||
public NoteItemData getItemData() {
|
||||
return mItemData; // 获取笔记项数据
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,358 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.ActionBar;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.Preference.OnPreferenceClickListener;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceCategory;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.data.Notes.NoteColumns;
|
||||
import net.micode.notes.gtask.remote.GTaskSyncService;
|
||||
|
||||
public class NotesPreferenceActivity extends PreferenceActivity {
|
||||
public static final String PREFERENCE_NAME = "notes_preferences";
|
||||
public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name";
|
||||
public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time";
|
||||
public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear";
|
||||
|
||||
private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key";
|
||||
private static final String AUTHORITIES_FILTER_KEY = "authorities";
|
||||
|
||||
private PreferenceCategory mAccountCategory; // 账户类别
|
||||
private GTaskReceiver mReceiver; // 广播接收器
|
||||
private Account[] mOriAccounts; // 原始账户
|
||||
private boolean mHasAddedAccount; // 是否添加了账户
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true); // 使用应用图标进行导航
|
||||
|
||||
addPreferencesFromResource(R.xml.preferences); // 加载偏好设置
|
||||
mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);
|
||||
mReceiver = new GTaskReceiver(); // 初始化广播接收器
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME);
|
||||
registerReceiver(mReceiver, filter); // 注册广播接收器
|
||||
|
||||
mOriAccounts = null;
|
||||
View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null);
|
||||
getListView().addHeaderView(header, null, true); // 添加头部视图
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// 如果用户添加了新账户,则需要自动设置同步账户
|
||||
if (mHasAddedAccount) {
|
||||
Account[] accounts = getGoogleAccounts();
|
||||
if (mOriAccounts != null && accounts.length > mOriAccounts.length) {
|
||||
for (Account accountNew : accounts) {
|
||||
boolean found = false;
|
||||
for (Account accountOld : mOriAccounts) {
|
||||
if (TextUtils.equals(accountOld.name, accountNew.name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
setSyncAccount(accountNew.name); // 设置同步账户
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
refreshUI(); // 刷新UI
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (mReceiver != null) {
|
||||
unregisterReceiver(mReceiver); // 注销广播接收器
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void loadAccountPreference() {
|
||||
mAccountCategory.removeAll(); // 清空账户类别
|
||||
|
||||
Preference accountPref = new Preference(this);
|
||||
final String defaultAccount = getSyncAccountName(this);
|
||||
accountPref.setTitle(getString(R.string.preferences_account_title));
|
||||
accountPref.setSummary(getString(R.string.preferences_account_summary));
|
||||
accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (!GTaskSyncService.isSyncing()) {
|
||||
if (TextUtils.isEmpty(defaultAccount)) {
|
||||
// 第一次设置账户
|
||||
showSelectAccountAlertDialog();
|
||||
} else {
|
||||
// 如果账户已经设置,需要提示用户风险
|
||||
showChangeAccountConfirmAlertDialog();
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(NotesPreferenceActivity.this,
|
||||
R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
mAccountCategory.addPreference(accountPref); // 添加账户偏好设置
|
||||
}
|
||||
|
||||
private void loadSyncButton() {
|
||||
Button syncButton = (Button) findViewById(R.id.preference_sync_button);
|
||||
TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
|
||||
|
||||
// 设置按钮状态
|
||||
if (GTaskSyncService.isSyncing()) {
|
||||
syncButton.setText(getString(R.string.preferences_button_sync_cancel));
|
||||
syncButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
GTaskSyncService.cancelSync(NotesPreferenceActivity.this); // 取消同步
|
||||
}
|
||||
});
|
||||
} else {
|
||||
syncButton.setText(getString(R.string.preferences_button_sync_immediately));
|
||||
syncButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
GTaskSyncService.startSync(NotesPreferenceActivity.this); // 立即同步
|
||||
}
|
||||
});
|
||||
}
|
||||
syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); // 根据账户状态启用按钮
|
||||
|
||||
// 设置最后同步时间
|
||||
if (GTaskSyncService.isSyncing()) {
|
||||
lastSyncTimeView.setText(GTaskSyncService.getProgressString());
|
||||
lastSyncTimeView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
long lastSyncTime = getLastSyncTime(this);
|
||||
if (lastSyncTime != 0) {
|
||||
lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time,
|
||||
DateFormat.format(getString(R.string.preferences_last_sync_time_format),
|
||||
lastSyncTime)));
|
||||
lastSyncTimeView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
lastSyncTimeView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshUI() {
|
||||
loadAccountPreference(); // 加载账户偏好设置
|
||||
loadSyncButton(); // 加载同步按钮
|
||||
}
|
||||
|
||||
private void showSelectAccountAlertDialog() {
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
|
||||
|
||||
View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
|
||||
TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
|
||||
titleTextView.setText(getString(R.string.preferences_dialog_select_account_title));
|
||||
TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
|
||||
subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips));
|
||||
|
||||
dialogBuilder.setCustomTitle(titleView);
|
||||
dialogBuilder.setPositiveButton(null, null);
|
||||
|
||||
Account[] accounts = getGoogleAccounts();
|
||||
String defAccount = getSyncAccountName(this);
|
||||
|
||||
mOriAccounts = accounts;
|
||||
mHasAddedAccount = false;
|
||||
|
||||
if (accounts.length > 0) {
|
||||
CharSequence[] items = new CharSequence[accounts.length];
|
||||
final CharSequence[] itemMapping = items;
|
||||
int checkedItem = -1;
|
||||
int index = 0;
|
||||
for (Account account : accounts) {
|
||||
if (TextUtils.equals(account.name, defAccount)) {
|
||||
checkedItem = index; // 记录默认账户
|
||||
}
|
||||
items[index++] = account.name; // 添加账户名称
|
||||
}
|
||||
dialogBuilder.setSingleChoiceItems(items, checkedItem,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
setSyncAccount(itemMapping[which].toString()); // 设置同步账户
|
||||
dialog.dismiss();
|
||||
refreshUI(); // 刷新UI
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null);
|
||||
dialogBuilder.setView(addAccountView);
|
||||
|
||||
final AlertDialog dialog = dialogBuilder.show();
|
||||
addAccountView.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mHasAddedAccount = true;
|
||||
Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
|
||||
intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] {
|
||||
"gmail-ls"
|
||||
});
|
||||
startActivityForResult(intent, -1); // 启动添加账户设置
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showChangeAccountConfirmAlertDialog() {
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
|
||||
|
||||
View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
|
||||
TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
|
||||
titleTextView.setText(getString(R.string.preferences_dialog_change_account_title,
|
||||
getSyncAccountName(this)));
|
||||
TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
|
||||
subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg));
|
||||
dialogBuilder.setCustomTitle(titleView);
|
||||
|
||||
CharSequence[] menuItemArray = new CharSequence[] {
|
||||
getString(R.string.preferences_menu_change_account),
|
||||
getString(R.string.preferences_menu_remove_account),
|
||||
getString(R.string.preferences_menu_cancel)
|
||||
};
|
||||
dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == 0) {
|
||||
showSelectAccountAlertDialog(); // 显示选择账户对话框
|
||||
} else if (which == 1) {
|
||||
removeSyncAccount(); // 移除同步账户
|
||||
refreshUI(); // 刷新UI
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogBuilder.show();
|
||||
}
|
||||
|
||||
private Account[] getGoogleAccounts() {
|
||||
AccountManager accountManager = AccountManager.get(this);
|
||||
return accountManager.getAccountsByType("com.google"); // 获取Google账户
|
||||
}
|
||||
|
||||
private void setSyncAccount(String account) {
|
||||
if (!getSyncAccountName(this).equals(account)) {
|
||||
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = settings.edit();
|
||||
if (account != null) {
|
||||
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account); // 设置同步账户名称
|
||||
} else {
|
||||
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
|
||||
}
|
||||
editor.commit();
|
||||
|
||||
// 清除最后同步时间
|
||||
setLastSyncTime(this, 0);
|
||||
|
||||
// 清除本地GTask相关信息
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NoteColumns.GTASK_ID, "");
|
||||
values.put(NoteColumns.SYNC_ID, 0);
|
||||
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
|
||||
}
|
||||
}).start();
|
||||
|
||||
Toast.makeText(NotesPreferenceActivity.this,
|
||||
getString(R.string.preferences_toast_success_set_accout, account),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeSyncAccount() {
|
||||
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = settings.edit();
|
||||
if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) {
|
||||
editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME); // 移除同步账户名称
|
||||
}
|
||||
if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) {
|
||||
editor.remove(PREFERENCE_LAST_SYNC_TIME); // 移除最后同步时间
|
||||
}
|
||||
editor.commit();
|
||||
|
||||
// 清除本地GTask相关信息
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NoteColumns.GTASK_ID, "");
|
||||
values.put(NoteColumns.SYNC_ID, 0);
|
||||
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static String getSyncAccountName(Context context) {
|
||||
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); // 获取同步账户名称
|
||||
}
|
||||
|
||||
public static void setLastSyncTime(Context context, long time) {
|
||||
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = settings.edit();
|
||||
editor.putLong(PREFERENCE_LAST_SYNC_TIME, time); // 设置最后同步时间
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public static long getLastSyncTime(Context context) {
|
||||
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); // 获取最后同步时间
|
||||
}
|
||||
|
||||
private class GTaskReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
refreshUI(); // 刷新UI
|
||||
if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) {
|
||||
TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
|
||||
syncStatus.setText(intent
|
||||
.getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG)); // 更新同步状态
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, NotesListActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(intent); // 返回到笔记列表活动
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package net.micode.notes.widget;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.tool.ResourceParser;
|
||||
|
||||
public class NoteWidgetProvider_2x extends NoteWidgetProvider {
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
super.update(context, appWidgetManager, appWidgetIds); // 调用父类的更新方法
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.widget_2x; // 返回2x小部件的布局ID
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getBgResourceId(int bgId) {
|
||||
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId); // 获取2x小部件的背景资源ID
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getWidgetType() {
|
||||
return Notes.TYPE_WIDGET_2X; // 返回小部件类型
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package net.micode.notes.widget;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.tool.ResourceParser;
|
||||
|
||||
public class NoteWidgetProvider_4x extends NoteWidgetProvider {
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
super.update(context, appWidgetManager, appWidgetIds); // 调用父类的更新方法
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
return R.layout.widget_4x; // 返回4x小部件的布局ID
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getBgResourceId(int bgId) {
|
||||
return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId); // 获取4x小部件的背景资源ID
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getWidgetType() {
|
||||
return Notes.TYPE_WIDGET_4X; // 返回小部件类型
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,117 @@
|
||||
package net.micode.notes.widget;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.***;
|
||||
import android.util.Log;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.data.Notes.NoteColumns;
|
||||
import net.micode.notes.tool.ResourceParser;
|
||||
import net.micode.notes.ui.NoteEditActivity;
|
||||
import net.micode.notes.ui.NotesListActivity;
|
||||
|
||||
public abstract class NoteWidgetProvider extends AppWidgetProvider {
|
||||
public static final String[] PROJECTION = new String[]{
|
||||
NoteColumns.ID,
|
||||
NoteColumns.BG_COLOR_ID,
|
||||
NoteColumns.SNIPPET
|
||||
};
|
||||
|
||||
public static final int COLUMN_ID = 0;
|
||||
public static final int COLUMN_BG_COLOR_ID = 1;
|
||||
public static final int COLUMN_SNIPPET = 2;
|
||||
|
||||
private static final String TAG = "NoteWidgetProvider";
|
||||
|
||||
@Override
|
||||
public void onDeleted(Context context, int[] appWidgetIds) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
|
||||
for (int i = 0; i < appWidgetIds.length; i++) {
|
||||
context.getContentResolver().update(Notes.CONTENT_NOTE_URI,
|
||||
values,
|
||||
NoteColumns.WIDGET_ID + "=?",
|
||||
new String[]{String.valueOf(appWidgetIds[i])});
|
||||
}
|
||||
}
|
||||
|
||||
private *** getNoteWidgetInfo(Context context, int widgetId) {
|
||||
return context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
|
||||
PROJECTION,
|
||||
NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?",
|
||||
new String[]{String.valueOf(widgetId), String.valueOf(Notes.ID_TRASH_FOLER)},
|
||||
null);
|
||||
}
|
||||
|
||||
protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
update(context, appWidgetManager, appWidgetIds, false);
|
||||
}
|
||||
|
||||
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds,
|
||||
boolean privacyMode) {
|
||||
for (int i = 0; i < appWidgetIds.length; i++) {
|
||||
if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) {
|
||||
int bgId = ResourceParser.getDefaultBgId(context);
|
||||
String snippet = "";
|
||||
Intent intent = new Intent(context, NoteEditActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]);
|
||||
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType());
|
||||
|
||||
*** c = getNoteWidgetInfo(context, appWidgetIds[i]);
|
||||
if (c != null && c.moveToFirst()) {
|
||||
if (c.getCount() > 1) {
|
||||
Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]);
|
||||
c.close();
|
||||
return;
|
||||
}
|
||||
snippet = c.getString(COLUMN_SNIPPET);
|
||||
bgId = c.getInt(COLUMN_BG_COLOR_ID);
|
||||
intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID));
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
} else {
|
||||
snippet = context.getResources().getString(R.string.widget_havenot_content);
|
||||
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
|
||||
}
|
||||
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
|
||||
RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId());
|
||||
rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId));
|
||||
intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId);
|
||||
/**
|
||||
* Generate the pending intent to start host for the widget
|
||||
*/
|
||||
PendingIntent pendingIntent = null;
|
||||
if (privacyMode) {
|
||||
rv.setTextViewText(R.id.widget_text,
|
||||
context.getString(R.string.widget_under_visit_mode));
|
||||
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent(
|
||||
context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
} else {
|
||||
rv.setTextViewText(R.id.widget_text, snippet);
|
||||
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent);
|
||||
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract int getBgResourceId(int bgId); // 获取背景资源ID
|
||||
|
||||
protected abstract int getLayoutId(); // 获取布局ID
|
||||
|
||||
protected abstract int getWidgetType(); // 获取小部件类型
|
||||
}
|
||||
Loading…
Reference in new issue