main
chenjianan 7 months ago
parent 5c2c3cf910
commit e5f863580e

@ -14,331 +14,316 @@
* limitations under the License. * limitations under the License.
*/ */
package net.micode.notes.tool; package net.micode.notes.tool;
import android.content.Context; public class BackupUtils {
import android.database.Cursor; private static final String TAG = "BackupUtils";
import android.os.Environment; // Singleton stuff
import android.text.TextUtils; private static BackupUtils sInstance; //类里面为什么可以定义自身类的对象?
import android.text.format.DateFormat;
import android.util.Log; public static synchronized BackupUtils getInstance(Context context) {
//ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程例如线程A
import net.micode.notes.R; //运行到这个方法时,都要检查有没有其它线程B或者C、 D等正在用这个方法(或者该类的其他同步方法)有的话要等正在使用synchronized方法的线程B或者C 、D运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。
import net.micode.notes.data.Notes; //它包括两种用法synchronized 方法和 synchronized 块。
import net.micode.notes.data.Notes.DataColumns; if (sInstance == null) {
import net.micode.notes.data.Notes.DataConstants; //如果当前备份不存在,则新声明一个
import net.micode.notes.data.Notes.NoteColumns; sInstance = new BackupUtils(context);
}
import java.io.File; return sInstance;
import java.io.FileNotFoundException; }
import java.io.FileOutputStream;
import java.io.IOException; /**
import java.io.PrintStream; * Following states are signs to represents backup or restore
* status
*/
public class BackupUtils { // Currently, the sdcard is not mounted SD卡没有被装入手机
private static final String TAG = "BackupUtils"; public static final int STATE_SD_CARD_UNMOUONTED = 0;
// Singleton stuff // The backup file not exist 备份文件夹不存在
private static BackupUtils sInstance; public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
// The data is not well formated, may be changed by other programs 数据已被破坏,可能被修改
public static synchronized BackupUtils getInstance(Context context) { public static final int STATE_DATA_DESTROIED = 2;
if (sInstance == null) { // Some run-time exception which causes restore or backup fails 超时异常
sInstance = new BackupUtils(context); public static final int STATE_SYSTEM_ERROR = 3;
} // Backup or restore success 成功存储
return sInstance; public static final int STATE_SUCCESS = 4;
}
private TextExport mTextExport;
/**
* Following states are signs to represents backup or restore private BackupUtils(Context context) { //初始化函数
* status mTextExport = new TextExport(context);
*/ }
// Currently, the sdcard is not mounted
public static final int STATE_SD_CARD_UNMOUONTED = 0; private static boolean externalStorageAvailable() { //外部存储功能是否可用
// The backup file not exist return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; }
// The data is not well formated, may be changed by other programs
public static final int STATE_DATA_DESTROIED = 2; public int exportToText() {
// Some run-time exception which causes restore or backup fails return mTextExport.exportToText();
public static final int STATE_SYSTEM_ERROR = 3; }
// Backup or restore success
public static final int STATE_SUCCESS = 4; public String getExportedTextFileName() {
return mTextExport.mFileName;
private TextExport mTextExport; }
private BackupUtils(Context context) { public String getExportedTextFileDir() {
mTextExport = new TextExport(context); return mTextExport.mFileDirectory;
} }
private static boolean externalStorageAvailable() { private static class TextExport {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); private static final String[] NOTE_PROJECTION = {
} NoteColumns.ID,
NoteColumns.MODIFIED_DATE,
public int exportToText() { NoteColumns.SNIPPET,
return mTextExport.exportToText(); NoteColumns.TYPE
} };
public String getExportedTextFileName() { private static final int NOTE_COLUMN_ID = 0;
return mTextExport.mFileName;
} private static final int NOTE_COLUMN_MODIFIED_DATE = 1;
public String getExportedTextFileDir() { private static final int NOTE_COLUMN_SNIPPET = 2;
return mTextExport.mFileDirectory;
} private static final String[] DATA_PROJECTION = {
DataColumns.CONTENT,
private static class TextExport { DataColumns.MIME_TYPE,
private static final String[] NOTE_PROJECTION = { DataColumns.DATA1,
NoteColumns.ID, DataColumns.DATA2,
NoteColumns.MODIFIED_DATE, DataColumns.DATA3,
NoteColumns.SNIPPET, DataColumns.DATA4,
NoteColumns.TYPE };
};
private static final int DATA_COLUMN_CONTENT = 0;
private static final int NOTE_COLUMN_ID = 0;
private static final int DATA_COLUMN_MIME_TYPE = 1;
private static final int NOTE_COLUMN_MODIFIED_DATE = 1;
private static final int DATA_COLUMN_CALL_DATE = 2;
private static final int NOTE_COLUMN_SNIPPET = 2;
private static final int DATA_COLUMN_PHONE_NUMBER = 4;
private static final String[] DATA_PROJECTION = {
DataColumns.CONTENT, private final String [] TEXT_FORMAT;
DataColumns.MIME_TYPE, private static final int FORMAT_FOLDER_NAME = 0;
DataColumns.DATA1, private static final int FORMAT_NOTE_DATE = 1;
DataColumns.DATA2, private static final int FORMAT_NOTE_CONTENT = 2;
DataColumns.DATA3,
DataColumns.DATA4, private Context mContext;
}; private String mFileName;
private String mFileDirectory;
private static final int DATA_COLUMN_CONTENT = 0;
public TextExport(Context context) {
private static final int DATA_COLUMN_MIME_TYPE = 1; TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note);
mContext = context;
private static final int DATA_COLUMN_CALL_DATE = 2; mFileName = ""; //为什么为空?
mFileDirectory = "";
private static final int DATA_COLUMN_PHONE_NUMBER = 4; }
private final String [] TEXT_FORMAT; private String getFormat(int id) { //获取文本的组成部分
private static final int FORMAT_FOLDER_NAME = 0; return TEXT_FORMAT[id];
private static final int FORMAT_NOTE_DATE = 1; }
private static final int FORMAT_NOTE_CONTENT = 2;
/**
private Context mContext; * Export the folder identified by folder id to text
private String mFileName; */
private String mFileDirectory; private void exportFolderToText(String folderId, PrintStream ps) {
// Query notes belong to this folder 通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note
public TextExport(Context context) { Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI,
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] {
mContext = context; folderId
mFileName = ""; }, null);
mFileDirectory = "";
} if (notesCursor != null) {
if (notesCursor.moveToFirst()) {
private String getFormat(int id) { do {
return TEXT_FORMAT[id]; // Print note's last modified date ps里面保存有这份note的日期
} ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
/** notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
* Export the folder identified by folder id to text // Query data belong to this note
*/ String noteId = notesCursor.getString(NOTE_COLUMN_ID);
private void exportFolderToText(String folderId, PrintStream ps) { exportNoteToText(noteId, ps); //将文件导出到text
// Query notes belong to this folder } while (notesCursor.moveToNext());
Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, }
NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { notesCursor.close();
folderId }
}, null); }
if (notesCursor != null) { /**
if (notesCursor.moveToFirst()) { * Export note identified by id to a print stream
do { */
// Print note's last modified date private void exportNoteToText(String noteId, PrintStream ps) {
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI,
mContext.getString(R.string.format_datetime_mdhm), DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] {
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); noteId
// Query data belong to this note }, null);
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps); if (dataCursor != null) { //利用光标来扫描内容区别为callnote和note两种靠ps.printline输出
} while (notesCursor.moveToNext()); if (dataCursor.moveToFirst()) {
} do {
notesCursor.close(); String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
} if (DataConstants.CALL_NOTE.equals(mimeType)) {
} // Print phone number
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER);
/** long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE);
* Export note identified by id to a print stream String location = dataCursor.getString(DATA_COLUMN_CONTENT);
*/
private void exportNoteToText(String noteId, PrintStream ps) { if (!TextUtils.isEmpty(phoneNumber)) { //判断是否为空字符
Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { phoneNumber));
noteId }
}, null); // Print call date
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat
if (dataCursor != null) { .format(mContext.getString(R.string.format_datetime_mdhm),
if (dataCursor.moveToFirst()) { callDate)));
do { // Print call attachment location
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); if (!TextUtils.isEmpty(location)) {
if (DataConstants.CALL_NOTE.equals(mimeType)) { ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
// Print phone number location));
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER); }
long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE); } else if (DataConstants.NOTE.equals(mimeType)) {
String location = dataCursor.getString(DATA_COLUMN_CONTENT); String content = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(content)) {
if (!TextUtils.isEmpty(phoneNumber)) { ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), content));
phoneNumber)); }
} }
// Print call date } while (dataCursor.moveToNext());
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat }
.format(mContext.getString(R.string.format_datetime_mdhm), dataCursor.close();
callDate))); }
// Print call attachment location // print a line separator between note
if (!TextUtils.isEmpty(location)) { try {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), ps.write(new byte[] {
location)); Character.LINE_SEPARATOR, Character.LETTER_NUMBER
} });
} else if (DataConstants.NOTE.equals(mimeType)) { } catch (IOException e) {
String content = dataCursor.getString(DATA_COLUMN_CONTENT); Log.e(TAG, e.toString());
if (!TextUtils.isEmpty(content)) { }
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), }
content));
} /**
} * Note will be exported as text which is user readable
} while (dataCursor.moveToNext()); */
} public int exportToText() { //总函数调用上面的exportFolder和exportNote
dataCursor.close(); if (!externalStorageAvailable()) {
} Log.d(TAG, "Media was not mounted");
// print a line separator between note return STATE_SD_CARD_UNMOUONTED;
try { }
ps.write(new byte[] {
Character.LINE_SEPARATOR, Character.LETTER_NUMBER PrintStream ps = getExportToTextPrintStream();
}); if (ps == null) {
} catch (IOException e) { Log.e(TAG, "get print stream error");
Log.e(TAG, e.toString()); return STATE_SYSTEM_ERROR;
} }
} // First export folder and its notes 导出文件夹,就是导出里面包含的便签
Cursor folderCursor = mContext.getContentResolver().query(
/** Notes.CONTENT_NOTE_URI,
* Note will be exported as text which is user readable NOTE_PROJECTION,
*/ "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND "
public int exportToText() { + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
if (!externalStorageAvailable()) { + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null);
Log.d(TAG, "Media was not mounted");
return STATE_SD_CARD_UNMOUONTED; if (folderCursor != null) {
} if (folderCursor.moveToFirst()) {
do {
PrintStream ps = getExportToTextPrintStream(); // Print folder's name
if (ps == null) { String folderName = "";
Log.e(TAG, "get print stream error"); if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
return STATE_SYSTEM_ERROR; folderName = mContext.getString(R.string.call_record_folder_name);
} } else {
// First export folder and its notes folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET);
Cursor folderCursor = mContext.getContentResolver().query( }
Notes.CONTENT_NOTE_URI, if (!TextUtils.isEmpty(folderName)) {
NOTE_PROJECTION, ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName));
"(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " }
+ NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR " String folderId = folderCursor.getString(NOTE_COLUMN_ID);
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null); exportFolderToText(folderId, ps);
} while (folderCursor.moveToNext());
if (folderCursor != null) { }
if (folderCursor.moveToFirst()) { folderCursor.close();
do { }
// Print folder's name
String folderName = ""; // Export notes in root's folder 将根目录里的便签导出(由于不属于任何文件夹,因此无法通过文件夹导出来实现这一部分便签的导出)
if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) { Cursor noteCursor = mContext.getContentResolver().query(
folderName = mContext.getString(R.string.call_record_folder_name); Notes.CONTENT_NOTE_URI,
} else { NOTE_PROJECTION,
folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET); NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
} + "=0", null, null);
if (!TextUtils.isEmpty(folderName)) {
ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName)); if (noteCursor != null) {
} if (noteCursor.moveToFirst()) {
String folderId = folderCursor.getString(NOTE_COLUMN_ID); do {
exportFolderToText(folderId, ps); ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
} while (folderCursor.moveToNext()); mContext.getString(R.string.format_datetime_mdhm),
} noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
folderCursor.close(); // Query data belong to this note
} String noteId = noteCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps);
// Export notes in root's folder } while (noteCursor.moveToNext());
Cursor noteCursor = mContext.getContentResolver().query( }
Notes.CONTENT_NOTE_URI, noteCursor.close();
NOTE_PROJECTION, }
NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID ps.close();
+ "=0", null, null);
return STATE_SUCCESS;
if (noteCursor != null) { }
if (noteCursor.moveToFirst()) {
do { /**
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( * Get a print stream pointed to the file {@generateExportedTextFile}
mContext.getString(R.string.format_datetime_mdhm), */
noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); private PrintStream getExportToTextPrintStream() {
// Query data belong to this note File file = generateFileMountedOnSDcard(mContext, R.string.file_path,
String noteId = noteCursor.getString(NOTE_COLUMN_ID); R.string.file_name_txt_format);
exportNoteToText(noteId, ps); if (file == null) {
} while (noteCursor.moveToNext()); Log.e(TAG, "create file to exported failed");
} return null;
noteCursor.close(); }
} mFileName = file.getName();
ps.close(); mFileDirectory = mContext.getString(R.string.file_path);
PrintStream ps = null;
return STATE_SUCCESS; try {
} FileOutputStream fos = new FileOutputStream(file);
ps = new PrintStream(fos); //将ps输出流输出到特定的文件目的就是导出到文件而不是直接输出
/** } catch (FileNotFoundException e) {
* Get a print stream pointed to the file {@generateExportedTextFile} e.printStackTrace();
*/ return null;
private PrintStream getExportToTextPrintStream() { } catch (NullPointerException e) {
File file = generateFileMountedOnSDcard(mContext, R.string.file_path, e.printStackTrace();
R.string.file_name_txt_format); return null;
if (file == null) { }
Log.e(TAG, "create file to exported failed"); return ps;
return null; }
} }
mFileName = file.getName();
mFileDirectory = mContext.getString(R.string.file_path); /**
PrintStream ps = null; * Generate the text file to store imported data
try { */
FileOutputStream fos = new FileOutputStream(file); private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
ps = new PrintStream(fos); StringBuilder sb = new StringBuilder();
} catch (FileNotFoundException e) { sb.append(Environment.getExternalStorageDirectory()); //外部SD卡的存储路径
e.printStackTrace(); sb.append(context.getString(filePathResId)); //文件的存储路径
return null; File filedir = new File(sb.toString()); //filedir应该就是用来存储路径信息
} catch (NullPointerException e) { sb.append(context.getString(
e.printStackTrace(); fileNameFormatResId,
return null; DateFormat.format(context.getString(R.string.format_date_ymd),
} System.currentTimeMillis())));
return ps; File file = new File(sb.toString());
}
} try { //如果这些文件不存在,则新建
if (!filedir.exists()) {
/** filedir.mkdir();
* Generate the text file to store imported data }
*/ if (!file.exists()) {
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { file.createNewFile();
StringBuilder sb = new StringBuilder(); }
sb.append(Environment.getExternalStorageDirectory()); return file;
sb.append(context.getString(filePathResId)); } catch (SecurityException e) {
File filedir = new File(sb.toString()); e.printStackTrace();
sb.append(context.getString( } catch (IOException e) {
fileNameFormatResId, e.printStackTrace();
DateFormat.format(context.getString(R.string.format_date_ymd), }
System.currentTimeMillis()))); // try catch 异常处理
File file = new File(sb.toString()); return null;
}
try { }
if (!filedir.exists()) {
filedir.mkdir();
}
if (!file.exists()) {
file.createNewFile();
}
return file;
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*该类定义在 net.micode.notes.tool 包下并导入了Android和Java的一些核心类。这些导入的类提供了对内容提供者操作、日志记录、游标以及存储值的支持。 */
package net.micode.notes.tool; package net.micode.notes.tool;
/*定义了一个公共类 DataUtils并创建了一个常量 TAG 用于日志记录。 */
import android.content.ContentProviderOperation; import android.content.ContentProviderOperation;
import android.content.ContentProviderResult; import android.content.ContentProviderResult;
import android.content.ContentResolver; import android.content.ContentResolver;
@ -34,7 +34,9 @@ import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
/*ID
ID
ContentResolver true false */
public class DataUtils { public class DataUtils {
public static final String TAG = "DataUtils"; public static final String TAG = "DataUtils";
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) { public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
@ -71,7 +73,9 @@ public class DataUtils {
} }
return false; return false;
} }
/*
ID */
/*查询非系统文件夹的数量。异常处理用于确保在查询失败时释放游标资源。 */
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) { public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, desFolderId); values.put(NoteColumns.PARENT_ID, desFolderId);
@ -88,238 +92,294 @@ public class DataUtils {
* @param: [resolver, ids, folderId] * @param: [resolver, ids, folderId]
* @return: boolean * @return: boolean
*/ */
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids, long folderId) { /*检查数据库中是否存在特定类型的可见笔记。 */
if (ids == null) { /**
Log.d(TAG, "the ids is null"); * 便
return true; * @param resolver ContentResolver
} * @param ids 便ID
* @param folderId ID
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); * @return
for (long id : ids) { */
ContentProviderOperation.Builder builder = ContentProviderOperation public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids, long folderId) {
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); if (ids == null) {
builder.withValue(NoteColumns.PARENT_ID, folderId); Log.d(TAG, "the ids is null");
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); return true;
operationList.add(builder.build());
}
try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
}
return true;
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
return false;
} }
/** ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
* Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}} for (long id : ids) {
*/ ContentProviderOperation.Builder builder = ContentProviderOperation
public static int getUserFolderCount(ContentResolver resolver) { .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI, builder.withValue(NoteColumns.PARENT_ID, folderId);
new String[] { "COUNT(*)" }, builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", operationList.add(builder.build());
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
null);
int count = 0;
if(cursor != null) {
if(cursor.moveToFirst()) {
try {
count = cursor.getInt(0);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "get folder count failed:" + e.toString());
} finally {
cursor.close();
}
}
}
return count;
} }
/**
* @Method visibleInNoteDatabase
* @Date 2024/12/13 9:08
* @param resolver
* @param noteId
* @param type
* @Author lenovo
* @Return boolean
* @Description 访 noteId 便
*/
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
/**
* withAppendedId URI ID URI
* query Uri selection
* lenovo 2024/12/13 9:06
*/
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null,
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
new String [] {String.valueOf(type)},
null);
boolean exist = false; try {
if (cursor != null) { ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
if (cursor.getCount() > 0) { if (results == null || results.length == 0 || results[0] == null) {
exist = true; Log.d(TAG, "delete notes failed, ids:" + ids.toString());
} return false;
cursor.close();
} }
return exist; return true;
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} }
return false;
}
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { /**
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), *
null, null, null, null); * @param resolver ContentResolver
* @return
*/
public static int getUserFolderCount(ContentResolver resolver) {
Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { "COUNT(*)" },
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
null);
boolean exist = false; int count = 0;
if (cursor != null) { if(cursor != null) {
if (cursor.getCount() > 0) { if(cursor.moveToFirst()) {
exist = true; try {
count = cursor.getInt(0);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "get folder count failed:" + e.toString());
} finally {
cursor.close();
} }
cursor.close();
} }
return exist;
} }
return count;
}
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { /**
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), * ID便
null, null, null, null); * @param resolver ContentResolver
* @param noteId 便ID
* @param type 便
* @return
*/
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null,
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
new String [] {String.valueOf(type)},
null);
boolean exist = false; boolean exist = false;
if (cursor != null) { if (cursor != null) {
if (cursor.getCount() > 0) { if (cursor.getCount() > 0) {
exist = true; exist = true;
}
cursor.close();
} }
return exist; cursor.close();
} }
return exist;
}
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { /**
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, * ID便
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + * @param resolver ContentResolver
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + * @param noteId 便ID
" AND " + NoteColumns.SNIPPET + "=?", * @return
new String[] { name }, null); */
boolean exist = false; public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
if(cursor != null) { Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
if(cursor.getCount() > 0) { null, null, null, null);
exist = true;
} boolean exist = false;
cursor.close(); if (cursor != null) {
if (cursor.getCount() > 0) {
exist = true;
} }
return exist; cursor.close();
} }
return exist;
}
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) { /**
Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, * ID
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, * @param resolver ContentResolver
NoteColumns.PARENT_ID + "=?", * @param dataId ID
new String[] { String.valueOf(folderId) }, * @return
null); */
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
null, null, null, null);
HashSet<AppWidgetAttribute> set = null; boolean exist = false;
if (c != null) { if (cursor != null) {
if (c.moveToFirst()) { if (cursor.getCount() > 0) {
set = new HashSet<AppWidgetAttribute>(); exist = true;
do {
try {
AppWidgetAttribute widget = new AppWidgetAttribute();
widget.widgetId = c.getInt(0);
widget.widgetType = c.getInt(1);
set.add(widget);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, e.toString());
}
} while (c.moveToNext());
}
c.close();
} }
return set; cursor.close();
} }
return exist;
}
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { /**
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, *
new String [] { CallNote.PHONE_NUMBER }, * @param resolver ContentResolver
CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", * @param name
new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }, * @return
null); */
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
if (cursor != null && cursor.moveToFirst()) { Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
try { NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
return cursor.getString(0); " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
} catch (IndexOutOfBoundsException e) { " AND " + NoteColumns.SNIPPET + "=?",
Log.e(TAG, "Get call number fails " + e.toString()); new String[] { name }, null);
} finally { boolean exist = false;
cursor.close(); if(cursor != null) {
} if(cursor.getCount() > 0) {
exist = true;
} }
return ""; cursor.close();
} }
return exist;
}
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { /**
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, *
new String [] { CallNote.NOTE_ID }, * @param resolver ContentResolver
CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" * @param folderId ID
+ CallNote.PHONE_NUMBER + ",?)", * @return
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, */
null); public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
NoteColumns.PARENT_ID + "=?",
new String[] { String.valueOf(folderId) },
null);
if (cursor != null) { HashSet<AppWidgetAttribute> set = null;
if (cursor.moveToFirst()) { if (c != null) {
if (c.moveToFirst()) {
set = new HashSet<AppWidgetAttribute>();
do {
try { try {
return cursor.getLong(0); AppWidgetAttribute widget = new AppWidgetAttribute();
widget.widgetId = c.getInt(0);
widget.widgetType = c.getInt(1);
set.add(widget);
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
Log.e(TAG, "Get call note id fails " + e.toString()); Log.e(TAG, e.toString());
} }
} } while (c.moveToNext());
cursor.close();
} }
return 0; c.close();
} }
return set;
}
public static String getSnippetById(ContentResolver resolver, long noteId) { /**
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, * 便ID
new String [] { NoteColumns.SNIPPET }, * @param resolver ContentResolver
NoteColumns.ID + "=?", * @param noteId 便ID
new String [] { String.valueOf(noteId)}, * @return
null); */
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.PHONE_NUMBER },
CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?",
new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
null);
if (cursor != null) { if (cursor != null && cursor.moveToFirst()) {
String snippet = ""; try {
if (cursor.moveToFirst()) { return cursor.getString(0);
snippet = cursor.getString(0); } catch (IndexOutOfBoundsException e) {
} Log.e(TAG, "Get call number fails " + e.toString());
} finally {
cursor.close(); cursor.close();
return snippet;
} }
throw new IllegalArgumentException("Note is not found with id: " + noteId);
} }
return "";
}
/**
* 便ID
* @param resolver ContentResolver
* @param phoneNumber
* @param callDate
* @return 便ID
*/
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.NOTE_ID },
CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL("
+ CallNote.PHONE_NUMBER + ",?)",
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
null);
public static String getFormattedSnippet(String snippet) { if (cursor != null) {
if (snippet != null) { if (cursor.moveToFirst()) {
snippet = snippet.trim(); try {
int index = snippet.indexOf('\n'); return cursor.getLong(0);
if (index != -1) { } catch (IndexOutOfBoundsException e) {
snippet = snippet.substring(0, index); Log.e(TAG, "Get call note id fails " + e.toString());
} }
} }
cursor.close();
}
return 0;
}
/**
* 便ID便
* @param resolver ContentResolver
* @param noteId 便ID
* @return 便
*/
public static String getSnippetById(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String [] { NoteColumns.SNIPPET },
NoteColumns.ID + "=?",
new String [] { String.valueOf(noteId)},
null);
if (cursor != null) {
String snippet = "";
if (cursor.moveToFirst()) {
snippet = cursor.getString(0);
}
cursor.close();
return snippet; return snippet;
} }
throw new IllegalArgumentException("Note is not found with id: " + noteId);
}
public static Cursor searchInNoteDatabase(ContentResolver resolver, String query) { /**
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, * 便
new String[]{NoteColumns.ID}, * @param snippet 便
Notes.DataColumns.CONTENT + " LIKE'%" + query +"%'", * @return 便
null, */
null); public static String getFormattedSnippet(String snippet) {
return cursor; if (snippet != null) {
snippet = snippet.trim();
int index = snippet.indexOf('\n');
if (index != -1) {
snippet = snippet.substring(0, index);
}
} }
return snippet;
}
/**
* 便
* @param resolver ContentResolver
* @param query
* @return Cursor
*/
public static Cursor searchInNoteDatabase(ContentResolver resolver, String query) {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String[]{NoteColumns.ID},
Notes.DataColumns.CONTENT + " LIKE'%" + query +"%'",
null,
null);
return cursor;
} }

@ -16,6 +16,7 @@
package net.micode.notes.tool; package net.micode.notes.tool;
// 该类用于定义 Google 任务相关的 JSON 字段常量
public class GTaskStringUtils { public class GTaskStringUtils {
public final static String GTASK_JSON_ACTION_ID = "action_id"; public final static String GTASK_JSON_ACTION_ID = "action_id";

@ -22,6 +22,7 @@ import android.preference.PreferenceManager;
import net.micode.notes.R; import net.micode.notes.R;
import net.micode.notes.ui.NotesPreferenceActivity; import net.micode.notes.ui.NotesPreferenceActivity;
// 资源解析器类
public class ResourceParser { public class ResourceParser {
public static final int YELLOW = 0; public static final int YELLOW = 0;
@ -40,6 +41,7 @@ public class ResourceParser {
public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM; public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM;
// 备忘录背景资源类
public static class NoteBgResources { public static class NoteBgResources {
private final static int [] BG_EDIT_RESOURCES = new int [] { private final static int [] BG_EDIT_RESOURCES = new int [] {
R.drawable.edit_yellow, R.drawable.edit_yellow,
@ -57,15 +59,18 @@ public class ResourceParser {
R.drawable.edit_title_red R.drawable.edit_title_red
}; };
// 获取备忘录背景资源
public static int getNoteBgResource(int id) { public static int getNoteBgResource(int id) {
return BG_EDIT_RESOURCES[id]; return BG_EDIT_RESOURCES[id];
} }
// 获取备忘录标题背景资源
public static int getNoteTitleBgResource(int id) { public static int getNoteTitleBgResource(int id) {
return BG_EDIT_TITLE_RESOURCES[id]; return BG_EDIT_TITLE_RESOURCES[id];
} }
} }
// 获取默认背景ID
public static int getDefaultBgId(Context context) { public static int getDefaultBgId(Context context) {
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) {
@ -75,6 +80,7 @@ public class ResourceParser {
} }
} }
// 备忘录项目背景资源类
public static class NoteItemBgResources { public static class NoteItemBgResources {
private final static int [] BG_FIRST_RESOURCES = new int [] { private final static int [] BG_FIRST_RESOURCES = new int [] {
R.drawable.list_yellow_up, R.drawable.list_yellow_up,
@ -108,27 +114,33 @@ public class ResourceParser {
R.drawable.list_red_single R.drawable.list_red_single
}; };
// 获取备忘录第一个背景资源
public static int getNoteBgFirstRes(int id) { public static int getNoteBgFirstRes(int id) {
return BG_FIRST_RESOURCES[id]; return BG_FIRST_RESOURCES[id];
} }
// 获取备忘录最后一个背景资源
public static int getNoteBgLastRes(int id) { public static int getNoteBgLastRes(int id) {
return BG_LAST_RESOURCES[id]; return BG_LAST_RESOURCES[id];
} }
// 获取备忘录单独背景资源
public static int getNoteBgSingleRes(int id) { public static int getNoteBgSingleRes(int id) {
return BG_SINGLE_RESOURCES[id]; return BG_SINGLE_RESOURCES[id];
} }
// 获取备忘录正常背景资源
public static int getNoteBgNormalRes(int id) { public static int getNoteBgNormalRes(int id) {
return BG_NORMAL_RESOURCES[id]; return BG_NORMAL_RESOURCES[id];
} }
// 获取文件夹背景资源
public static int getFolderBgRes() { public static int getFolderBgRes() {
return R.drawable.list_folder; return R.drawable.list_folder;
} }
} }
// 小部件背景资源类
public static class WidgetBgResources { public static class WidgetBgResources {
private final static int [] BG_2X_RESOURCES = new int [] { private final static int [] BG_2X_RESOURCES = new int [] {
R.drawable.widget_2x_yellow, R.drawable.widget_2x_yellow,
@ -138,6 +150,7 @@ public class ResourceParser {
R.drawable.widget_2x_red, R.drawable.widget_2x_red,
}; };
// 获取2x小部件背景资源
public static int getWidget2xBgResource(int id) { public static int getWidget2xBgResource(int id) {
return BG_2X_RESOURCES[id]; return BG_2X_RESOURCES[id];
} }
@ -150,11 +163,13 @@ public class ResourceParser {
R.drawable.widget_4x_red R.drawable.widget_4x_red
}; };
// 获取4x小部件背景资源
public static int getWidget4xBgResource(int id) { public static int getWidget4xBgResource(int id) {
return BG_4X_RESOURCES[id]; return BG_4X_RESOURCES[id];
} }
} }
// 文本外观资源类
public static class TextAppearanceResources { public static class TextAppearanceResources {
private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] { private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] {
R.style.TextAppearanceNormal, R.style.TextAppearanceNormal,
@ -163,6 +178,7 @@ public class ResourceParser {
R.style.TextAppearanceSuper R.style.TextAppearanceSuper
}; };
// 获取文本外观资源
public static int getTexAppearanceResource(int id) { public static int getTexAppearanceResource(int id) {
/** /**
* HACKME: Fix bug of store the resource id in shared preference. * HACKME: Fix bug of store the resource id in shared preference.
@ -175,6 +191,7 @@ public class ResourceParser {
return TEXTAPPEARANCE_RESOURCES[id]; return TEXTAPPEARANCE_RESOURCES[id];
} }
// 获取资源大小
public static int getResourcesSize() { public static int getResourcesSize() {
return TEXTAPPEARANCE_RESOURCES.length; return TEXTAPPEARANCE_RESOURCES.length;
} }

@ -39,49 +39,41 @@ import net.micode.notes.tool.DataUtils;
import java.io.IOException; import java.io.IOException;
/**
* AlarmAlertActivity
*/
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
private long mNoteId; private long mNoteId; // 便签的ID
private String mSnippet; private String mSnippet; // 便签的摘要信息
private static final int SNIPPET_PREW_MAX_LEN = 60; private static final int SNIPPET_PREW_MAX_LEN = 60; // 摘要信息的最大长度
MediaPlayer mPlayer; MediaPlayer mPlayer; // 用于播放提醒音的MediaPlayer
@Override @Override
/** /**
* @Method onCreate * Activity
* @Date 2024/12/25 8:15 * @param savedInstanceState
* @param savedInstanceState */
* @Author lenovo
* @Return void
* @Description
*/
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
/**
* Bundel mapkey-value
* super , onCreate
* lenovo 2024/12/25 8:39
*/
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); requestWindowFeature(Window.FEATURE_NO_TITLE); // 不显示标题栏
final Window win = getWindow(); final Window win = getWindow();
// 在屏幕锁定时显示 win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); // 锁屏时显示
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
// 锁屏时到闹钟提示时间后,点亮屏幕 // 如果屏幕未点亮,则设置相关标志以确保屏幕点亮并显示对话框
if (!isScreenOn()) { if (!isScreenOn()) {
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON |
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
} }
Intent intent = getIntent(); Intent intent = getIntent();
try { try {
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); // 获取便签ID
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); // 获取便签摘要
// 超出长度则变为 substr + "..." // 如果摘要过长,则截取并添加省略号
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info) SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info)
: mSnippet; : mSnippet;
@ -91,85 +83,103 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
} }
mPlayer = new MediaPlayer(); mPlayer = new MediaPlayer();
// 查找数据库中有没有 mNoteId 的便签, 如果有则激发对话框 + 闹钟提示 // 如果便签存在于数据库中,则显示对话框并播放提醒
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog(); showActionDialog();
playAlarmSound(); playAlarmSound();
} else { } else {
finish(); finish(); // 如果不存在则结束Activity
} }
} }
/**
*
* @return
*/
private boolean isScreenOn() { private boolean isScreenOn() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn(); return pm.isScreenOn();
} }
/**
*
*/
private void playAlarmSound() { private void playAlarmSound() {
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); // 获取默认闹钟铃声
int silentModeStreams = Settings.System.getInt(getContentResolver(), int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); // 获取静音模式影响的流类型
if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) {
mPlayer.setAudioStreamType(silentModeStreams); mPlayer.setAudioStreamType(silentModeStreams); // 设置音频流类型
} else { } else {
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
} }
try { try {
mPlayer.setDataSource(this, url); mPlayer.setDataSource(this, url); // 设置播放数据源
mPlayer.prepare(); mPlayer.prepare(); // 准备播放
mPlayer.setLooping(true); mPlayer.setLooping(true); // 设置循环播放
mPlayer.start(); mPlayer.start(); // 开始播放
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} catch (SecurityException e) { } catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} catch (IOException e) { } catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
} }
private void showActionDialog() {// TODO: 2024/1/2 可以模仿这个写一个xxx条件下弹出来的Dialog /**
*
*/
private void showActionDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(this); AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setTitle(R.string.app_name); dialog.setTitle(R.string.app_name); // 设置对话框标题
dialog.setMessage(mSnippet); dialog.setMessage(mSnippet); // 设置对话框消息
dialog.setPositiveButton(R.string.notealert_ok, this); dialog.setPositiveButton(R.string.notealert_ok, this); // 设置确定按钮
if (isScreenOn()) { if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this); dialog.setNegativeButton(R.string.notealert_enter, this); // 设置取消按钮
} }
dialog.show().setOnDismissListener(this); dialog.show().setOnDismissListener(this); // 显示对话框并设置消失监听器
} }
/**
*
* @param dialog
* @param which
*/
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
switch (which) { switch (which) {
case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEGATIVE:
Intent intent = new Intent(this, NoteEditActivity.class); Intent intent = new Intent(this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_VIEW); intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, mNoteId); intent.putExtra(Intent.EXTRA_UID, mNoteId); // 传递便签ID
startActivity(intent); startActivity(intent); // 启动便签编辑Activity
break; break;
default: default:
break; break;
} }
} }
/**
*
* @param dialog
*/
public void onDismiss(DialogInterface dialog) { public void onDismiss(DialogInterface dialog) {
stopAlarmSound(); stopAlarmSound(); // 停止播放提醒音
finish(); finish(); // 结束Activity
} }
/**
*
*/
private void stopAlarmSound() { private void stopAlarmSound() {
if (mPlayer != null) { if (mPlayer != null) {
mPlayer.stop(); mPlayer.stop(); // 停止播放
mPlayer.release(); mPlayer.release(); // 释放资源
mPlayer = null; mPlayer = null; // 清空MediaPlayer对象
} }
} }
} }

@ -27,20 +27,32 @@ import android.database.Cursor;
import net.micode.notes.data.Notes; import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.NoteColumns;
/**
* AlarmInitReceiver
*/
public class AlarmInitReceiver extends BroadcastReceiver { public class AlarmInitReceiver extends BroadcastReceiver {
// 查询数据库时需要的列名
private static final String [] PROJECTION = new String [] { private static final String [] PROJECTION = new String [] {
NoteColumns.ID, NoteColumns.ID, // 便签ID
NoteColumns.ALERTED_DATE NoteColumns.ALERTED_DATE // 闹钟提醒时间
}; };
// 列索引,方便获取数据
private static final int COLUMN_ID = 0; private static final int COLUMN_ID = 0;
private static final int COLUMN_ALERTED_DATE = 1; private static final int COLUMN_ALERTED_DATE = 1;
/**
* 广
* @param context
* @param intent
*/
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
// 获取当前时间
long currentDate = System.currentTimeMillis(); long currentDate = System.currentTimeMillis();
// 查询所有未触发的闹钟
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI, Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION, PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE, NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
@ -48,18 +60,25 @@ public class AlarmInitReceiver extends BroadcastReceiver {
null); null);
if (c != null) { if (c != null) {
// 如果有未触发的闹钟
if (c.moveToFirst()) { if (c.moveToFirst()) {
do { do {
// 获取闹钟提醒时间和便签ID
long alertDate = c.getLong(COLUMN_ALERTED_DATE); long alertDate = c.getLong(COLUMN_ALERTED_DATE);
Intent sender = new Intent(context, AlarmReceiver.class); Intent sender = new Intent(context, AlarmReceiver.class);
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID)));
// 创建PendingIntent
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0);
AlarmManager alermManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE); // 获取AlarmManager服务
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
} while (c.moveToNext());
// 设置闹钟
alarmManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext()); // 继续查询下一个闹钟
} }
c.close(); c.close(); // 关闭游标
} }
} }
} }

@ -20,11 +20,22 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
/**
* AlarmReceiver
*/
public class AlarmReceiver extends BroadcastReceiver { public class AlarmReceiver extends BroadcastReceiver {
/**
* 广
* @param context
* @param intent
*/
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
// 设置意图的目标类为闹钟提醒界面
intent.setClass(context, AlarmAlertActivity.class); intent.setClass(context, AlarmAlertActivity.class);
// 添加标志,表示启动一个新的任务
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 启动闹钟提醒界面
context.startActivity(intent); context.startActivity(intent);
} }
} }

@ -21,20 +21,28 @@ import java.util.Calendar;
import net.micode.notes.R; import net.micode.notes.R;
import android.content.Context; import android.content.Context;
import android.text.format.DateFormat; import android.text.format.DateFormat;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.NumberPicker; import android.widget.NumberPicker;
/**
* DateTimePicker
*/
public class DateTimePicker extends FrameLayout { public class DateTimePicker extends FrameLayout {
// 默认使能状态
private static final boolean DEFAULT_ENABLE_STATE = true; private static final boolean DEFAULT_ENABLE_STATE = true;
// 12小时制和24小时制的小时数
private static final int HOURS_IN_HALF_DAY = 12; private static final int HOURS_IN_HALF_DAY = 12;
private static final int HOURS_IN_ALL_DAY = 24; private static final int HOURS_IN_ALL_DAY = 24;
// 一周的天数
private static final int DAYS_IN_ALL_WEEK = 7; private static final int DAYS_IN_ALL_WEEK = 7;
// 日期和时间选择器的最小和最大值
private static final int DATE_SPINNER_MIN_VAL = 0; private static final int DATE_SPINNER_MIN_VAL = 0;
private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1; private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1;
private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0; private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0;
@ -46,36 +54,51 @@ public class DateTimePicker extends FrameLayout {
private static final int AMPM_SPINNER_MIN_VAL = 0; private static final int AMPM_SPINNER_MIN_VAL = 0;
private static final int AMPM_SPINNER_MAX_VAL = 1; private static final int AMPM_SPINNER_MAX_VAL = 1;
// 日期选择器
private final NumberPicker mDateSpinner; private final NumberPicker mDateSpinner;
// 小时选择器
private final NumberPicker mHourSpinner; private final NumberPicker mHourSpinner;
// 分钟选择器
private final NumberPicker mMinuteSpinner; private final NumberPicker mMinuteSpinner;
// AM/PM选择器
private final NumberPicker mAmPmSpinner; private final NumberPicker mAmPmSpinner;
// 当前日期
private Calendar mDate; private Calendar mDate;
// 日期显示值
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];
// 是否为上午
private boolean mIsAm; private boolean mIsAm;
// 是否为24小时制
private boolean mIs24HourView; private boolean mIs24HourView;
// 是否使能
private boolean mIsEnabled = DEFAULT_ENABLE_STATE; private boolean mIsEnabled = DEFAULT_ENABLE_STATE;
// 初始化标志
private boolean mInitialising; private boolean mInitialising;
// 日期时间改变监听器
private OnDateTimeChangedListener mOnDateTimeChangedListener; private OnDateTimeChangedListener mOnDateTimeChangedListener;
// 日期改变监听器
private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() { private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() {
@Override @Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) { public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 更新日期
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal); mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal);
updateDateControl(); updateDateControl();
onDateTimeChanged(); onDateTimeChanged();
} }
}; };
// 小时改变监听器
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() { private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
@Override @Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) { public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 更新小时
boolean isDateChanged = false; boolean isDateChanged = false;
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
if (!mIs24HourView) { if (!mIs24HourView) {
@ -115,9 +138,11 @@ public class DateTimePicker extends FrameLayout {
} }
}; };
// 分钟改变监听器
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() { private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
@Override @Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) { public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 更新分钟
int minValue = mMinuteSpinner.getMinValue(); int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue(); int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0; int offset = 0;
@ -144,9 +169,11 @@ public class DateTimePicker extends FrameLayout {
} }
}; };
// AM/PM改变监听器
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() { private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
@Override @Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) { public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 更新AM/PM
mIsAm = !mIsAm; mIsAm = !mIsAm;
if (mIsAm) { if (mIsAm) {
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY); mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);
@ -158,19 +185,37 @@ public class DateTimePicker extends FrameLayout {
} }
}; };
/**
*
*/
public interface OnDateTimeChangedListener { public interface OnDateTimeChangedListener {
void onDateTimeChanged(DateTimePicker view, int year, int month, void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute); int dayOfMonth, int hourOfDay, int minute);
} }
/**
*
* @param context
*/
public DateTimePicker(Context context) { public DateTimePicker(Context context) {
this(context, System.currentTimeMillis()); this(context, System.currentTimeMillis());
} }
/**
*
* @param context
* @param date
*/
public DateTimePicker(Context context, long date) { public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context)); this(context, date, DateFormat.is24HourFormat(context));
} }
/**
*
* @param context
* @param date
* @param is24HourView 24
*/
public DateTimePicker(Context context, long date, boolean is24HourView) { public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context); super(context);
mDate = Calendar.getInstance(); mDate = Calendar.getInstance();
@ -191,6 +236,7 @@ public class DateTimePicker extends FrameLayout {
mMinuteSpinner.setOnLongPressUpdateInterval(100); mMinuteSpinner.setOnLongPressUpdateInterval(100);
mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener); mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener);
// AM/PM选择器的字符串数组
String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings(); String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings();
mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm); mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm);
mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL); mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL);
@ -198,22 +244,28 @@ public class DateTimePicker extends FrameLayout {
mAmPmSpinner.setDisplayedValues(stringsForAmPm); mAmPmSpinner.setDisplayedValues(stringsForAmPm);
mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener); mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener);
// update controls to initial state // 更新控件到初始状态
updateDateControl(); updateDateControl();
updateHourControl(); updateHourControl();
updateAmPmControl(); updateAmPmControl();
// 设置24小时制
set24HourView(is24HourView); set24HourView(is24HourView);
// set to current time // 设置当前日期
setCurrentDate(date); setCurrentDate(date);
// 设置使能状态
setEnabled(isEnabled()); setEnabled(isEnabled());
// set the content descriptions // 设置内容描述
mInitialising = false; mInitialising = false;
} }
/**
* 使
* @param enabled 使
*/
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
if (mIsEnabled == enabled) { if (mIsEnabled == enabled) {
@ -227,24 +279,26 @@ public class DateTimePicker extends FrameLayout {
mIsEnabled = enabled; mIsEnabled = enabled;
} }
/**
* 使
* @return 使
*/
@Override @Override
public boolean isEnabled() { public boolean isEnabled() {
return mIsEnabled; return mIsEnabled;
} }
/** /**
* Get the current date in millis *
* * @return
* @return the current date in millis
*/ */
public long getCurrentDateInTimeMillis() { public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis(); return mDate.getTimeInMillis();
} }
/** /**
* Set the current date *
* * @param date
* @param date The current date in millis
*/ */
public void setCurrentDate(long date) { public void setCurrentDate(long date) {
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
@ -254,13 +308,12 @@ public class DateTimePicker extends FrameLayout {
} }
/** /**
* Set the current date *
* * @param year
* @param year The current year * @param month
* @param month The current month * @param dayOfMonth
* @param dayOfMonth The current dayOfMonth * @param hourOfDay
* @param hourOfDay The current hourOfDay * @param minute
* @param minute The current minute
*/ */
public void setCurrentDate(int year, int month, public void setCurrentDate(int year, int month,
int dayOfMonth, int hourOfDay, int minute) { int dayOfMonth, int hourOfDay, int minute) {
@ -272,18 +325,16 @@ public class DateTimePicker extends FrameLayout {
} }
/** /**
* Get current year *
* * @return
* @return The current year
*/ */
public int getCurrentYear() { public int getCurrentYear() {
return mDate.get(Calendar.YEAR); return mDate.get(Calendar.YEAR);
} }
/** /**
* Set current year *
* * @param year
* @param year The current year
*/ */
public void setCurrentYear(int year) { public void setCurrentYear(int year) {
if (!mInitialising && year == getCurrentYear()) { if (!mInitialising && year == getCurrentYear()) {
@ -295,18 +346,16 @@ public class DateTimePicker extends FrameLayout {
} }
/** /**
* Get current month in the year *
* * @return
* @return The current month in the year
*/ */
public int getCurrentMonth() { public int getCurrentMonth() {
return mDate.get(Calendar.MONTH); return mDate.get(Calendar.MONTH);
} }
/** /**
* Set current month in the year *
* * @param month
* @param month The month in the year
*/ */
public void setCurrentMonth(int month) { public void setCurrentMonth(int month) {
if (!mInitialising && month == getCurrentMonth()) { if (!mInitialising && month == getCurrentMonth()) {
@ -318,18 +367,16 @@ public class DateTimePicker extends FrameLayout {
} }
/** /**
* Get current day of the month *
* * @return
* @return The day of the month
*/ */
public int getCurrentDay() { public int getCurrentDay() {
return mDate.get(Calendar.DAY_OF_MONTH); return mDate.get(Calendar.DAY_OF_MONTH);
} }
/** /**
* Set current day of the month *
* * @param dayOfMonth
* @param dayOfMonth The day of the month
*/ */
public void setCurrentDay(int dayOfMonth) { public void setCurrentDay(int dayOfMonth) {
if (!mInitialising && dayOfMonth == getCurrentDay()) { if (!mInitialising && dayOfMonth == getCurrentDay()) {
@ -341,15 +388,19 @@ public class DateTimePicker extends FrameLayout {
} }
/** /**
* Get current hour in 24 hour mode, in the range (0~23) * 24
* @return The current hour in 24 hour mode * @return 24
*/ */
public int getCurrentHourOfDay() { public int getCurrentHourOfDay() {
return mDate.get(Calendar.HOUR_OF_DAY); return mDate.get(Calendar.HOUR_OF_DAY);
} }
/**
* 1224
* @return
*/
private int getCurrentHour() { private int getCurrentHour() {
if (mIs24HourView){ if (mIs24HourView) {
return getCurrentHourOfDay(); return getCurrentHourOfDay();
} else { } else {
int hour = getCurrentHourOfDay(); int hour = getCurrentHourOfDay();
@ -362,9 +413,8 @@ public class DateTimePicker extends FrameLayout {
} }
/** /**
* Set current hour in 24 hour mode, in the range (0~23) * 24
* * @param hourOfDay 24
* @param hourOfDay
*/ */
public void setCurrentHour(int hourOfDay) { public void setCurrentHour(int hourOfDay) {
if (!mInitialising && hourOfDay == getCurrentHourOfDay()) { if (!mInitialising && hourOfDay == getCurrentHourOfDay()) {
@ -390,16 +440,16 @@ public class DateTimePicker extends FrameLayout {
} }
/** /**
* Get currentMinute *
* * @return
* @return The Current Minute
*/ */
public int getCurrentMinute() { public int getCurrentMinute() {
return mDate.get(Calendar.MINUTE); return mDate.get(Calendar.MINUTE);
} }
/** /**
* Set current minute *
* @param minute
*/ */
public void setCurrentMinute(int minute) { public void setCurrentMinute(int minute) {
if (!mInitialising && minute == getCurrentMinute()) { if (!mInitialising && minute == getCurrentMinute()) {
@ -411,16 +461,16 @@ public class DateTimePicker extends FrameLayout {
} }
/** /**
* @return true if this is in 24 hour view else false. * 24
* @return 24
*/ */
public boolean is24HourView () { public boolean is24HourView() {
return mIs24HourView; return mIs24HourView;
} }
/** /**
* Set whether in 24 hour or AM/PM mode. * 24
* * @param is24HourView 24
* @param is24HourView True for 24 hour mode. False for AM/PM mode.
*/ */
public void set24HourView(boolean is24HourView) { public void set24HourView(boolean is24HourView) {
if (mIs24HourView == is24HourView) { if (mIs24HourView == is24HourView) {
@ -434,6 +484,9 @@ public class DateTimePicker extends FrameLayout {
updateAmPmControl(); updateAmPmControl();
} }
/**
*
*/
private void updateDateControl() { private void updateDateControl() {
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(mDate.getTimeInMillis()); cal.setTimeInMillis(mDate.getTimeInMillis());
@ -448,6 +501,9 @@ public class DateTimePicker extends FrameLayout {
mDateSpinner.invalidate(); mDateSpinner.invalidate();
} }
/**
* AM/PM
*/
private void updateAmPmControl() { private void updateAmPmControl() {
if (mIs24HourView) { if (mIs24HourView) {
mAmPmSpinner.setVisibility(View.GONE); mAmPmSpinner.setVisibility(View.GONE);
@ -458,6 +514,9 @@ public class DateTimePicker extends FrameLayout {
} }
} }
/**
*
*/
private void updateHourControl() { private void updateHourControl() {
if (mIs24HourView) { if (mIs24HourView) {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW); mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
@ -469,13 +528,16 @@ public class DateTimePicker extends FrameLayout {
} }
/** /**
* Set the callback that indicates the 'Set' button has been pressed. *
* @param callback the callback, if null will do nothing * @param callback
*/ */
public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) { public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) {
mOnDateTimeChangedListener = callback; mOnDateTimeChangedListener = callback;
} }
/**
*
*/
private void onDateTimeChanged() { private void onDateTimeChanged() {
if (mOnDateTimeChangedListener != null) { if (mOnDateTimeChangedListener != null) {
mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(), mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(),

@ -29,62 +29,107 @@ import android.content.DialogInterface.OnClickListener;
import android.text.format.DateFormat; import android.text.format.DateFormat;
import android.text.format.DateUtils; import android.text.format.DateUtils;
/**
* DateTimePickerDialog
*/
public class DateTimePickerDialog extends AlertDialog implements OnClickListener { public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
// 当前日期
private Calendar mDate = Calendar.getInstance(); private Calendar mDate = Calendar.getInstance();
// 是否为24小时制
private boolean mIs24HourView; private boolean mIs24HourView;
// 日期时间设置监听器
private OnDateTimeSetListener mOnDateTimeSetListener; private OnDateTimeSetListener mOnDateTimeSetListener;
// 日期时间选择器
private DateTimePicker mDateTimePicker; private DateTimePicker mDateTimePicker;
/**
*
*/
public interface OnDateTimeSetListener { public interface OnDateTimeSetListener {
void OnDateTimeSet(AlertDialog dialog, long date); void OnDateTimeSet(AlertDialog dialog, long date);
} }
/**
*
* @param context
* @param date
*/
public DateTimePickerDialog(Context context, long date) { public DateTimePickerDialog(Context context, long date) {
super(context); super(context);
// 创建日期时间选择器
mDateTimePicker = new DateTimePicker(context); mDateTimePicker = new DateTimePicker(context);
// 设置对话框视图
setView(mDateTimePicker); setView(mDateTimePicker);
// 设置日期时间改变监听器
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() { mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
public void onDateTimeChanged(DateTimePicker view, int year, int month, public void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute) { int dayOfMonth, int hourOfDay, int minute) {
// 更新日期
mDate.set(Calendar.YEAR, year); mDate.set(Calendar.YEAR, year);
mDate.set(Calendar.MONTH, month); mDate.set(Calendar.MONTH, month);
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
mDate.set(Calendar.MINUTE, minute); mDate.set(Calendar.MINUTE, minute);
// 更新对话框标题
updateTitle(mDate.getTimeInMillis()); updateTitle(mDate.getTimeInMillis());
} }
}); });
// 设置当前日期
mDate.setTimeInMillis(date); mDate.setTimeInMillis(date);
mDate.set(Calendar.SECOND, 0); mDate.set(Calendar.SECOND, 0);
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
// 设置确定按钮
setButton(context.getString(R.string.datetime_dialog_ok), this); setButton(context.getString(R.string.datetime_dialog_ok), this);
// 设置取消按钮
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null); setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);
// 设置24小时制
set24HourView(DateFormat.is24HourFormat(this.getContext())); set24HourView(DateFormat.is24HourFormat(this.getContext()));
// 更新对话框标题
updateTitle(mDate.getTimeInMillis()); updateTitle(mDate.getTimeInMillis());
} }
/**
* 24
* @param is24HourView 24
*/
public void set24HourView(boolean is24HourView) { public void set24HourView(boolean is24HourView) {
mIs24HourView = is24HourView; mIs24HourView = is24HourView;
} }
/**
*
* @param callBack
*/
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
mOnDateTimeSetListener = callBack; mOnDateTimeSetListener = callBack;
} }
/**
*
* @param date
*/
private void updateTitle(long date) { private void updateTitle(long date) {
// 设置日期格式
int flag = int flag =
DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_YEAR |
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_DATE |
DateUtils.FORMAT_SHOW_TIME; DateUtils.FORMAT_SHOW_TIME;
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR; // 根据是否为24小时制设置时间格式
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_12HOUR;
// 设置对话框标题
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));
} }
/**
*
* @param arg0
* @param arg1 ID
*/
public void onClick(DialogInterface arg0, int arg1) { public void onClick(DialogInterface arg0, int arg1) {
// 如果设置了日期时间设置监听器,则通知日期时间已设置
if (mOnDateTimeSetListener != null) { if (mOnDateTimeSetListener != null) {
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
} }
} }
} }

@ -27,34 +27,66 @@ import android.widget.PopupMenu.OnMenuItemClickListener;
import net.micode.notes.R; import net.micode.notes.R;
/**
* DropdownMenu
*/
public class DropdownMenu { public class DropdownMenu {
// 下拉菜单按钮
private Button mButton; private Button mButton;
// 弹出菜单
private PopupMenu mPopupMenu; private PopupMenu mPopupMenu;
// 菜单项
private Menu mMenu; private Menu mMenu;
/**
*
* @param context
* @param button
* @param menuId ID
*/
public DropdownMenu(Context context, Button button, int menuId) { public DropdownMenu(Context context, Button button, int menuId) {
mButton = button; mButton = button;
// 设置按钮背景为下拉图标
mButton.setBackgroundResource(R.drawable.dropdown_icon); mButton.setBackgroundResource(R.drawable.dropdown_icon);
// 创建弹出菜单
mPopupMenu = new PopupMenu(context, mButton); mPopupMenu = new PopupMenu(context, mButton);
// 获取菜单项
mMenu = mPopupMenu.getMenu(); mMenu = mPopupMenu.getMenu();
// 加载菜单资源
mPopupMenu.getMenuInflater().inflate(menuId, mMenu); mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
// 设置按钮点击事件
mButton.setOnClickListener(new OnClickListener() { mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
// 显示弹出菜单
mPopupMenu.show(); mPopupMenu.show();
} }
}); });
} }
/**
*
* @param listener
*/
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) { public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
if (mPopupMenu != null) { if (mPopupMenu != null) {
// 设置弹出菜单项点击事件监听器
mPopupMenu.setOnMenuItemClickListener(listener); mPopupMenu.setOnMenuItemClickListener(listener);
} }
} }
/**
*
* @param id ID
* @return
*/
public MenuItem findItem(int id) { public MenuItem findItem(int id) {
return mMenu.findItem(id); return mMenu.findItem(id);
} }
/**
*
* @param title
*/
public void setTitle(CharSequence title) { public void setTitle(CharSequence title) {
mButton.setText(title); mButton.setText(title);
} }

@ -28,53 +28,94 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes; import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.NoteColumns;
/**
* FoldersListAdapter
*/
public class FoldersListAdapter extends CursorAdapter { public class FoldersListAdapter extends CursorAdapter {
// 查询数据库时需要的列名
public static final String [] PROJECTION = { public static final String [] PROJECTION = {
NoteColumns.ID, NoteColumns.ID, // 文件夹ID
NoteColumns.SNIPPET NoteColumns.SNIPPET // 文件夹名称
}; };
// 列索引,方便获取数据
public static final int ID_COLUMN = 0; public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1; public static final int NAME_COLUMN = 1;
/**
*
* @param context
* @param c
*/
public FoldersListAdapter(Context context, Cursor c) { public FoldersListAdapter(Context context, Cursor c) {
super(context, c); super(context, c);
// TODO Auto-generated constructor stub
} }
/**
*
* @param context
* @param cursor
* @param parent
* @return
*/
@Override @Override
public View newView(Context context, Cursor cursor, ViewGroup parent) { public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new FolderListItem(context); return new FolderListItem(context);
} }
/**
*
* @param view
* @param context
* @param cursor
*/
@Override @Override
public void bindView(View view, Context context, Cursor cursor) { public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof FolderListItem) { if (view instanceof FolderListItem) {
// 获取文件夹名称
String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
// 绑定文件夹名称
((FolderListItem) view).bind(folderName); ((FolderListItem) view).bind(folderName);
} }
} }
/**
*
* @param context
* @param position
* @return
*/
public String getFolderName(Context context, int position) { public String getFolderName(Context context, int position) {
Cursor cursor = (Cursor) getItem(position); Cursor cursor = (Cursor) getItem(position);
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
} }
/**
* FolderListItem
*/
private class FolderListItem extends LinearLayout { private class FolderListItem extends LinearLayout {
private TextView mName; private TextView mName; // 文件夹名称文本视图
/**
*
* @param context
*/
public FolderListItem(Context context) { public FolderListItem(Context context) {
super(context); super(context);
// 加载文件夹列表项布局
inflate(context, R.layout.folder_list_item, this); inflate(context, R.layout.folder_list_item, this);
// 获取文件夹名称文本视图
mName = (TextView) findViewById(R.id.tv_folder_name); mName = (TextView) findViewById(R.id.tv_folder_name);
} }
/**
*
* @param name
*/
public void bind(String name) { public void bind(String name) {
mName.setText(name); mName.setText(name); // 设置文件夹名称
} }
} }
} }

@ -57,7 +57,6 @@ import android.os.Environment;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Typeface; // 自带四种字体 import android.graphics.Typeface; // 自带四种字体
import net.micode.notes.R; import net.micode.notes.R;
import net.micode.notes.data.Notes; import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.TextNote; import net.micode.notes.data.Notes.TextNote;
@ -82,9 +81,9 @@ import java.util.Vector;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
/**
* NoteEditActivity 便
*/
public class NoteEditActivity extends Activity //NOTE: extends--单继承,但可多重继承 @zhoukexing 2023/12/17 23:29 public class NoteEditActivity extends Activity //NOTE: extends--单继承,但可多重继承 @zhoukexing 2023/12/17 23:29
implements OnClickListener, NoteSettingChangedListener, OnTextViewChangeListener { implements OnClickListener, NoteSettingChangedListener, OnTextViewChangeListener {
private Intent intent; //NOTE: implements--实现接口 @zhoukexing 2023/12/17 23:24 private Intent intent; //NOTE: implements--实现接口 @zhoukexing 2023/12/17 23:24
@ -93,11 +92,11 @@ public class NoteEditActivity extends Activity //NOTE: extends--单继承,但
* @zhoukexing 2023/12/17 23:39 * @zhoukexing 2023/12/17 23:39
*/ */
private class HeadViewHolder { private class HeadViewHolder {
public TextView tvModified; public TextView tvModified; // 显示修改时间的文本视图
public ImageView ivAlertIcon; public ImageView ivAlertIcon; // 提醒图标的图像视图
public TextView tvAlertDate; public TextView tvAlertDate; // 提醒日期的文本视图
// 顶部置顶文本 // 顶部置顶文本
public TextView tvTopText; public TextView tvTopText;
@ -105,9 +104,10 @@ public class NoteEditActivity extends Activity //NOTE: extends--单继承,但
// 顶部长度统计文本 // 顶部长度统计文本
public TextView tvTextNum; public TextView tvTextNum;
public ImageView ibSetBgColor; public ImageView ibSetBgColor; // 设置背景颜色的按钮
} }
// 背景颜色选择器按钮映射
private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>();
static { static {
sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW);
@ -117,6 +117,7 @@ public class NoteEditActivity extends Activity //NOTE: extends--单继承,但
sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE); sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE);
} }
// 背景颜色选择器选中状态映射
private static final Map<Integer, Integer> sBgSelectorSelectionMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sBgSelectorSelectionMap = new HashMap<Integer, Integer>();
static { static {
sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select); sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select);
@ -126,6 +127,7 @@ public class NoteEditActivity extends Activity //NOTE: extends--单继承,但
sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select);
} }
// 字体大小选择器按钮映射
private static final Map<Integer, Integer> sFontSizeBtnsMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sFontSizeBtnsMap = new HashMap<Integer, Integer>();
static { static {
sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE); sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE);
@ -134,6 +136,7 @@ public class NoteEditActivity extends Activity //NOTE: extends--单继承,但
sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER); sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER);
} }
// 字体大小选择器选中状态映射
private static final Map<Integer, Integer> sFontSelectorSelectionMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sFontSelectorSelectionMap = new HashMap<Integer, Integer>();
static { static {
sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select);
@ -142,47 +145,44 @@ public class NoteEditActivity extends Activity //NOTE: extends--单继承,但
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select);
} }
private static final String TAG = "NoteEditActivity"; private static final String TAG = "NoteEditActivity";
private static int mMaxRevokeTimes = 10; private static int mMaxRevokeTimes = 10; // 最大撤销次数
private HeadViewHolder mNoteHeaderHolder; private HeadViewHolder mNoteHeaderHolder; // 便签头部视图的持有者
private View mHeadViewPanel; private View mHeadViewPanel; // 头部视图面板
private View mNoteBgColorSelector; private View mNoteBgColorSelector; // 便签背景颜色选择器
private View mFontSizeSelector; private View mFontSizeSelector; // 字体大小选择器
private EditText mNoteEditor; private EditText mNoteEditor; // 便签编辑器
private View mNoteEditorPanel; private View mNoteEditorPanel; // 便签编辑器面板
private WorkingNote mWorkingNote; private WorkingNote mWorkingNote; // 正在编辑的便签
private SharedPreferences mSharedPrefs; private SharedPreferences mSharedPrefs; // 共享偏好设置
private int mFontSizeId; private int mFontSizeId; // 字体大小ID
private int mFontStyleId; private int mFontStyleId; // 字体样式ID
private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; // 字体大小偏好设置键
private static final String PREFERENCE_FONT_STYLE = "pref_font_style"; private static final String PREFERENCE_FONT_STYLE = "pref_font_style"; // 字体样式偏好设置键
private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; // 快捷方式图标标题最大长度
public static final String TAG_CHECKED = String.valueOf('\u221A'); public static final String TAG_CHECKED = String.valueOf('\u221A'); // 已选中标签
public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); // 未选中标签
private LinearLayout mEditTextList; private LinearLayout mEditTextList; // 编辑文本列表
private String mUserQuery; private String mUserQuery; // 用户查询
private Pattern mPattern; private Pattern mPattern; // 正则表达式模式
// 存储改变的数据 // 存储改变的数据
private Vector<SpannableString> mHistory = new Vector<SpannableString>(mMaxRevokeTimes); private Vector<SpannableString> mHistory = new Vector<SpannableString>(mMaxRevokeTimes);
private boolean mIsRvoke; private boolean mIsRvoke; // 是否撤销
/*--- 以上是此类中的数据区,以下是方法区 ---*/ /*--- 以上是此类中的数据区,以下是方法区 ---*/

@ -37,121 +37,161 @@ import net.micode.notes.R;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
* 便EditText
*
*/
public class NoteEditText extends EditText { public class NoteEditText extends EditText {
private static final String TAG = "NoteEditText"; private static final String TAG = "NoteEditText"; // 日志标签
private int mIndex; private int mIndex; // 当前文本框的索引
private int mSelectionStartBeforeDelete; private int mSelectionStartBeforeDelete; // 删除前的选择起始位置
private static final String SCHEME_TEL = "tel:" ; // 定义几种URL协议的前缀
private static final String SCHEME_HTTP = "http:" ; private static final String SCHEME_TEL = "tel:"; // 电话
private static final String SCHEME_EMAIL = "mailto:" ; private static final String SCHEME_HTTP = "http:"; // 网络
private static final String SCHEME_EMAIL = "mailto:"; // 邮箱
// URL协议到资源ID的映射
private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>(); private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
static { static {
sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); // 电话链接文本
sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web); sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web); // 网络链接文本
sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email); sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email); // 邮箱链接文本
} }
/** /**
* Call by the {@link NoteEditActivity} to delete or add edit text *
*
*/ */
public interface OnTextViewChangeListener { public interface OnTextViewChangeListener {
/** /**
* Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens *
* and the text is null * @param index
* @param text
*/ */
void onEditTextDelete(int index, String text); void onEditTextDelete(int index, String text);
/** /**
* Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER} *
* happen * @param index
* @param text
*/ */
void onEditTextEnter(int index, String text); void onEditTextEnter(int index, String text);
/** /**
* Hide or show item option when text change *
* @param index
* @param hasText
*/ */
void onTextChange(int index, boolean hasText); void onTextChange(int index, boolean hasText);
} }
private OnTextViewChangeListener mOnTextViewChangeListener; private OnTextViewChangeListener mOnTextViewChangeListener; // 文本框变化监听器
/**
*
* @param context
*/
public NoteEditText(Context context) { public NoteEditText(Context context) {
super(context, null); super(context, null);
mIndex = 0; mIndex = 0; // 默认索引为0
} }
/**
*
* @param index
*/
public void setIndex(int index) { public void setIndex(int index) {
mIndex = index; mIndex = index;
} }
/**
*
* @param listener
*/
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) { public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
mOnTextViewChangeListener = listener; mOnTextViewChangeListener = listener;
} }
/**
*
* @param context
* @param attrs
*/
public NoteEditText(Context context, AttributeSet attrs) { public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.editTextStyle); super(context, attrs, android.R.attr.editTextStyle);
} }
/**
*
* @param context
* @param attrs
* @param defStyle
*/
public NoteEditText(Context context, AttributeSet attrs, int defStyle) { public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
} }
/**
*
*
* @param event
* @return
*/
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) { if (event.getAction() == MotionEvent.ACTION_DOWN) {
case MotionEvent.ACTION_DOWN: int x = (int) event.getX();
int y = (int) event.getY();
int x = (int) event.getX(); x -= getTotalPaddingLeft();
int y = (int) event.getY(); y -= getTotalPaddingTop();
x -= getTotalPaddingLeft(); x += getScrollX();
y -= getTotalPaddingTop(); y += getScrollY();
x += getScrollX();
y += getScrollY(); Layout layout = getLayout();
int line = layout.getLineForVertical(y);
Layout layout = getLayout(); int off = layout.getOffsetForHorizontal(line, x);
int line = layout.getLineForVertical(y); Selection.setSelection(getText(), off); // 设置文本选择位置
int off = layout.getOffsetForHorizontal(line, x);
Selection.setSelection(getText(), off);
break;
} }
return super.onTouchEvent(event); return super.onTouchEvent(event);
} }
/**
*
*
* @param keyCode
* @param event
* @return
*/
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) { switch (keyCode) {
case KeyEvent.KEYCODE_ENTER: case KeyEvent.KEYCODE_ENTER:
if (mOnTextViewChangeListener != null) { if (mOnTextViewChangeListener != null) {
return false; return false; // 不处理回车键,交由监听器处理
} }
break; break;
case KeyEvent.KEYCODE_DEL: case KeyEvent.KEYCODE_DEL:
mSelectionStartBeforeDelete = getSelectionStart(); mSelectionStartBeforeDelete = getSelectionStart(); // 记录删除前的选择起始位置
break;
default:
break; break;
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
/** /**
* @method: onKeyUp *
* @description: deleteenter *
* 退 * @param keyCode
* @date: 2023/12/21 0:28 * @param event
* @author: zhoukexing * @return
* @param: [keyCode, event]
* @return: boolean
*/ */
@Override @Override
public boolean onKeyUp(int keyCode, KeyEvent event) { public boolean onKeyUp(int keyCode, KeyEvent event) {
switch(keyCode) { switch (keyCode) {
case KeyEvent.KEYCODE_DEL: // delete键的号为67 @zhoukexing 2023/12/21 0:31 case KeyEvent.KEYCODE_DEL: // 删除键
if (mOnTextViewChangeListener != null) { if (mOnTextViewChangeListener != null) {
if (0 == mSelectionStartBeforeDelete && mIndex != 0) { if (mSelectionStartBeforeDelete == 0 && mIndex != 0) {
// 如果删除前的选择起始位置为0且不是第一个文本框则删除当前文本框
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
return true; return true;
} }
@ -159,22 +199,27 @@ public class NoteEditText extends EditText {
Log.d(TAG, "OnTextViewChangeListener was not seted"); Log.d(TAG, "OnTextViewChangeListener was not seted");
} }
break; break;
case KeyEvent.KEYCODE_ENTER: // enter键的号为66 @zhoukexing 2023/12/21 0:31 case KeyEvent.KEYCODE_ENTER: // 回车键
if (mOnTextViewChangeListener != null) { if (mOnTextViewChangeListener != null) {
int selectionStart = getSelectionStart(); int selectionStart = getSelectionStart();
String text = getText().subSequence(selectionStart, length()).toString(); String text = getText().subSequence(selectionStart, length()).toString();
setText(getText().subSequence(0, selectionStart)); setText(getText().subSequence(0, selectionStart)); // 删除回车键后的内容
mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); // 添加新的文本框
} else { } else {
Log.d(TAG, "OnTextViewChangeListener was not seted"); Log.d(TAG, "OnTextViewChangeListener was not seted");
} }
break; break;
default:
break;
} }
return super.onKeyUp(keyCode, event); return super.onKeyUp(keyCode, event);
} }
/**
*
*
* @param focused
* @param direction
* @param previouslyFocusedRect
*/
@Override @Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (mOnTextViewChangeListener != null) { if (mOnTextViewChangeListener != null) {
@ -187,39 +232,4 @@ public class NoteEditText extends EditText {
super.onFocusChanged(focused, direction, previouslyFocusedRect); super.onFocusChanged(focused, direction, previouslyFocusedRect);
} }
@Override
protected void onCreateContextMenu(ContextMenu menu) {
if (getText() instanceof Spanned) {
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
int min = Math.min(selStart, selEnd);
int max = Math.max(selStart, selEnd);
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
if (urls.length == 1) {
int defaultResId = 0;
for(String schema: sSchemaActionResMap.keySet()) {
if(urls[0].getURL().indexOf(schema) >= 0) {
defaultResId = sSchemaActionResMap.get(schema);
break;
}
}
if (defaultResId == 0) {
defaultResId = R.string.note_link_other;
}
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
// goto a new intent
urls[0].onClick(NoteEditText.this);
return true;
}
});
}
}
super.onCreateContextMenu(menu);
}
}

@ -25,8 +25,12 @@ import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.tool.DataUtils; import net.micode.notes.tool.DataUtils;
/**
* NoteItemData 便
* 便便
*/
public class NoteItemData { public class NoteItemData {
// 定义查询便签数据库时需要的列
static final String [] PROJECTION = new String [] { static final String [] PROJECTION = new String [] {
NoteColumns.ID, NoteColumns.ID,
NoteColumns.ALERTED_DATE, NoteColumns.ALERTED_DATE,
@ -43,6 +47,7 @@ public class NoteItemData {
NoteColumns.TOP, NoteColumns.TOP,
}; };
// 定义列的索引
private static final int ID_COLUMN = 0; private static final int ID_COLUMN = 0;
private static final int ALERTED_DATE_COLUMN = 1; private static final int ALERTED_DATE_COLUMN = 1;
private static final int BG_COLOR_ID_COLUMN = 2; private static final int BG_COLOR_ID_COLUMN = 2;
@ -55,11 +60,9 @@ public class NoteItemData {
private static final int TYPE_COLUMN = 9; private static final int TYPE_COLUMN = 9;
private static final int WIDGET_ID_COLUMN = 10; private static final int WIDGET_ID_COLUMN = 10;
private static final int WIDGET_TYPE_COLUMN = 11; private static final int WIDGET_TYPE_COLUMN = 11;
private static final int TOP_STATE_COLUMN = 12; private static final int TOP_STATE_COLUMN = 12;
/** NotesDatabaseHelper.java // 便签项的数据字段
*
* @zhoukexing 2023/12/25 20:22 */
private long mId; private long mId;
private long mAlertDate; private long mAlertDate;
private int mBgColorId; private int mBgColorId;
@ -76,6 +79,7 @@ public class NoteItemData {
private String mName; private String mName;
private String mPhoneNumber; private String mPhoneNumber;
// 便签项的位置状态
private boolean mIsLastItem; private boolean mIsLastItem;
private boolean mIsFirstItem; private boolean mIsFirstItem;
private boolean mIsOnlyOneItem; private boolean mIsOnlyOneItem;
@ -83,37 +87,33 @@ public class NoteItemData {
private boolean mIsMultiNotesFollowingFolder; private boolean mIsMultiNotesFollowingFolder;
/** /**
* @method: NoteItemData * 便
* @description: * @param context
* @date: 2023/12/25 19:58 * @param cursor
* @author: zhoukexing
* @param: [context, cursor]
* @return:
*/ */
public NoteItemData(Context context, Cursor cursor) { // 把cursor理解为这样一个指针指向一个表格 @zhoukexing 2023/12/25 20:12 public NoteItemData(Context context, Cursor cursor) {
mId = cursor.getLong(ID_COLUMN); // 可以根据传入的列号获取到表格里对应列的值 @zhoukexing 2023/12/25 20:12 mId = cursor.getLong(ID_COLUMN); // 获取便签ID
mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); // 获取提醒日期
mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN); mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN); // 获取背景颜色ID
mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN); mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN); // 获取创建日期
mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0) ? true : false; mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0); // 是否有附件
mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN); mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN); // 获取修改日期
mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN); mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN); // 获取便签数量
mParentId = cursor.getLong(PARENT_ID_COLUMN); mParentId = cursor.getLong(PARENT_ID_COLUMN); // 获取父便签ID
mSnippet = cursor.getString(SNIPPET_COLUMN); mSnippet = cursor.getString(SNIPPET_COLUMN); // 获取便签摘要
mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace( mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace(
NoteEditActivity.TAG_UNCHECKED, ""); NoteEditActivity.TAG_UNCHECKED, ""); // 去除摘要中的标签
mType = cursor.getInt(TYPE_COLUMN); mType = cursor.getInt(TYPE_COLUMN); // 获取便签类型
mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); // 获取小部件ID
mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); // 获取小部件类型
mTop = cursor.getInt(TOP_STATE_COLUMN); mTop = cursor.getInt(TOP_STATE_COLUMN); // 获取置顶状态
mPhoneNumber = ""; mPhoneNumber = "";
if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { //Q: 文件夹为什么有电话记录之说?怎么是通过一个便签的父文件夹来判断便签内有无电话号码?@zkx 2023/12/25 if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { // 如果便签属于通话记录文件夹
mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); // 获取电话号码
// 根据电话号码锁定联系人名称,若不在联系人里,直接使用电话号码 @zhoukexing 2023/12/25 20:17 if (!TextUtils.isEmpty(mPhoneNumber)) { // 如果电话号码不为空
if (!TextUtils.isEmpty(mPhoneNumber)) { mName = Contact.getContact(context, mPhoneNumber); // 获取联系人名称
mName = Contact.getContact(context, mPhoneNumber); if (mName == null) { // 如果联系人名称为空,则使用电话号码
if (mName == null) {
mName = mPhoneNumber; mName = mPhoneNumber;
} }
} }
@ -122,70 +122,114 @@ public class NoteItemData {
if (mName == null) { if (mName == null) {
mName = ""; mName = "";
} }
checkPostion(cursor); checkPostion(cursor); // 检查便签项的位置状态
} }
/**
* 便
* @param cursor
*/
private void checkPostion(Cursor cursor) { private void checkPostion(Cursor cursor) {
mIsLastItem = cursor.isLast() ? true : false; mIsLastItem = cursor.isLast(); // 是否是最后一个便签项
mIsFirstItem = cursor.isFirst() ? true : false; mIsFirstItem = cursor.isFirst(); // 是否是第一个便签项
mIsOnlyOneItem = (cursor.getCount() == 1); mIsOnlyOneItem = (cursor.getCount() == 1); // 是否只有一个便签项
mIsMultiNotesFollowingFolder = false; mIsMultiNotesFollowingFolder = false;
mIsOneNoteFollowingFolder = false; mIsOneNoteFollowingFolder = false;
if (mType == Notes.TYPE_NOTE && !mIsFirstItem) { if (mType == Notes.TYPE_NOTE && !mIsFirstItem) { // 如果是便签且不是第一个便签项
int position = cursor.getPosition(); int position = cursor.getPosition();
if (cursor.moveToPrevious()) { if (cursor.moveToPrevious()) { // 移动到前一个便签项
if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER
|| cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) { || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) { // 如果前一个便签项是文件夹或系统便签
if (cursor.getCount() > (position + 1)) { if (cursor.getCount() > (position + 1)) { // 如果便签项数量大于当前便签项的位置+1
mIsMultiNotesFollowingFolder = true; mIsMultiNotesFollowingFolder = true; // 多个便签项跟随文件夹
} else { } else {
mIsOneNoteFollowingFolder = true; mIsOneNoteFollowingFolder = true; // 一个便签项跟随文件夹
} }
} }
if (!cursor.moveToNext()) { if (!cursor.moveToNext()) { // 移动回当前便签项
throw new IllegalStateException("cursor move to previous but can't move back"); throw new IllegalStateException("cursor move to previous but can't move back");
} }
} }
} }
} }
/**
* 便
* @return 便
*/
public boolean isOneFollowingFolder() { public boolean isOneFollowingFolder() {
return mIsOneNoteFollowingFolder; return mIsOneNoteFollowingFolder;
} }
/**
* 便
* @return 便
*/
public boolean isMultiFollowingFolder() { public boolean isMultiFollowingFolder() {
return mIsMultiNotesFollowingFolder; return mIsMultiNotesFollowingFolder;
} }
/**
* 便
* @return 便
*/
public boolean isLast() { public boolean isLast() {
return mIsLastItem; return mIsLastItem;
} }
/**
*
* @return
*/
public String getCallName() { public String getCallName() {
return mName; return mName;
} }
/**
* 便
* @return 便
*/
public boolean isFirst() { public boolean isFirst() {
return mIsFirstItem; return mIsFirstItem;
} }
/**
* 便
* @return 便
*/
public boolean isSingle() { public boolean isSingle() {
return mIsOnlyOneItem; return mIsOnlyOneItem;
} }
/**
* 便
* @return
*/
public int getTop(){ public int getTop(){
return mTop; return mTop;
} }
/**
* 便ID
* @return 便ID
*/
public long getId() { public long getId() {
return mId; return mId;
} }
/**
* 便
* @return
*/
public long getAlertDate() { public long getAlertDate() {
return mAlertDate; return mAlertDate;
} }
/**
* 便
* @return
*/
public long getCreatedDate() { public long getCreatedDate() {
return mCreatedDate; return mCreatedDate;
} }

Loading…
Cancel
Save