From f7158393b45d781223fc5b008a74a138ff27024d Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:29:18 +0800 Subject: [PATCH 01/42] =?UTF-8?q?=E5=B0=8F=E7=B1=B3=E4=BE=BF=E7=AD=BE?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/Contact.java | 77 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/data/Contact.java diff --git a/src/data/Contact.java b/src/data/Contact.java new file mode 100644 index 0000000..c54dd4f --- /dev/null +++ b/src/data/Contact.java @@ -0,0 +1,77 @@ + + +package net.micode.notes.data; + +import android.content.Context; + +import android.database.Cursor; +import android.provider.ContactsContract.CommonDataKinds.Phone; +import android.provider.ContactsContract.Data; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import java.util.HashMap; + +// 定义一个名为Contact的公开类,表示联系人。此类包含联系人相关的属性和方法。 +public class Contact { //联系人 + // 定义一个私有的静态的HashMap对象,用于缓存联系人信息。键为电话号码,值为联系人的名字。 + private static HashMap sContactCache; + + // 定义一个私有的常量String,作为日志的标签,方便调试。 + private static final String TAG = "Contact"; + + // 定义一个私有的静态常量字符串CALLER_ID_SELECTION,包含用于查询联系人的SQL语句。这个语句基于电话号码和MIME类型进行查询。 + // 这是一个复杂的查询,它从电话号码和MIME类型中选择联系人信息,并且它使用了子查询来获取匹配的电话号码。 + // 这个查询的具体含义和用法需要依赖它所在的上下文和相关的数据库表结构。 + private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + ++ Phone.NUMBER // Phone.NUMBER应该是Phone类中的一个属性,表示电话号码。 + + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" // 数据中的MIME类型等于电话内容项类型。这通常用于确定联系人的信息。 + + " AND " + Data.RAW_CONTACT_ID + " IN " // 数据中的原始联系人ID在...中 + + "(SELECT raw_contact_id " // 子查询选择所有的原始联系人ID + + " FROM phone_lookup" // 从phone_lookup表中 + + " WHERE min_match = '+')"; // 其中min_match等于'+'。这个min_match字段的含义需要依赖具体的数据库表结构。 + + // 定义一个公开的静态方法getContact,输入参数为Context(上下文对象)和String(电话号码),返回值为String(联系人的名字)。该方法用于获取联系人的名字。 + // 如果sContactCache中已经存在该电话号码的信息,则直接返回该信息。否则,查询数据库获取该电话号码对应的信息,并存入sContactCache中。 + // 如果查询出现异常或者没有找到相关信息,会返回null。 + // 获取联系人 + public static String getContact(Context context, String phoneNumber) { + // 如果sContactCache为空,则初始化它。 + if(sContactCache == null) { + sContactCache = new HashMap(); + } + + // 检查sContactCache中是否已经有该phoneNumber的信息。如果有,则直接返回该信息。 + if(sContactCache.containsKey(phoneNumber)) { + return sContactCache.get(phoneNumber); + } + + // 用电话号码替换CALLER_ID_SELECTION中的"+",并存入selection变量中。这个字符串是用于从数据库中查询信息的SQL语句。 + String selection = CALLER_ID_SELECTION.replace("+", + PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); + // 使用selection从数据库中查询phoneNumber的信息。查询的结果存储在Cursor对象中。 + // 查找数据库中phoneNumber的信息 + Cursor cursor = context.getContentResolver().query( + Data.CONTENT_URI, // 数据内容URI,通常用于访问联系人数据。 + new String [] { Phone.DISPLAY_NAME }, // 要获取的字段,这里是要获取联系人的名字。 + selection, // 查询的条件,这里是电话号码和MIME类型。 + new String[] { phoneNumber }, // 查询的参数,这里是电话号码。 + null); // 排序方式,这里不排序。 + + // 判断查询结果。如果Cursor不为空且移动到第一条记录,则说明找到了相关信息。 + // moveToFirst()返回第一条 + if (cursor != null && cursor.moveToFirst()) { + try { + // 获取联系人的名字并存入sContactCache中,然后返回该名字。 + // 如果获取过程中出现异常,则捕获异常并记录错误日志,然后返回null。 + // 找到相关信息 + String name = cursor.getString(0); + sContactCache.put(phoneNumber, name); + return name; + // 异常 + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, " Cursor get string error " + e.toString()); // 记录错误日志。 + return null; // 返回null。 + } finally { + cursor.close(); // 关闭Cursor对象。释放资源。无论是否 \ No newline at end of file From a4ae6226cb491053e064888ec443ea528554b42a Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:29:49 +0800 Subject: [PATCH 02/42] ADD file via upload --- src/data/Notes.java | 305 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 src/data/Notes.java diff --git a/src/data/Notes.java b/src/data/Notes.java new file mode 100644 index 0000000..86806b8 --- /dev/null +++ b/src/data/Notes.java @@ -0,0 +1,305 @@ + + +package net.micode.notes.data; + +import android.content.ContentUris; +import android.net.Uri; +// Notes 类中定义了很多常量,这些常量大多是int型和string型 +public class Notes { + public static final String AUTHORITY = "micode_notes"; + public static final String TAG = "Notes"; + + //以下三个常量对NoteColumns.TYPE的值进行设置时会用到 + public static final int TYPE_NOTE = 0; + public static final int TYPE_FOLDER = 1; + public static final int TYPE_SYSTEM = 2; + + /** + * Following IDs are system folders' identifiers + * {@link Notes#ID_ROOT_FOLDER } is default folder + * {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder + * {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records + */ + public static final int ID_ROOT_FOLDER = 0; + public static final int ID_TEMPARAY_FOLDER = -1; + public static final int ID_CALL_RECORD_FOLDER = -2; + public static final int ID_TRASH_FOLER = -3; + + public static final String INTENT_EXTRA_ALERT_DATE = + +"net.micode.notes.alert_date"; + public static final String INTENT_EXTRA_BACKGROUND_ID = + +"net.micode.notes.background_color_id"; + public static final String INTENT_EXTRA_WIDGET_ID = + +"net.micode.notes.widget_id"; + public static final String INTENT_EXTRA_WIDGET_TYPE = + +"net.micode.notes.widget_type"; + public static final String INTENT_EXTRA_FOLDER_ID = + +"net.micode.notes.folder_id"; + public static final String INTENT_EXTRA_CALL_DATE = + +"net.micode.notes.call_date"; + + public static final int TYPE_WIDGET_INVALIDE = -1; + public static final int TYPE_WIDGET_2X = 0; + public static final int TYPE_WIDGET_4X = 1; + + public static class DataConstants { + public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; + public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; + } + + /** + * Uri to query all notes and folders + */ + public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + + +AUTHORITY + "/note");//定义查询便签和文件夹的指针。 + +// public static final Uri my_URI = ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI , 10); + + /** + * Uri to query data + */ + public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + + +AUTHORITY + "/data");//定义查找数据的指针。 + + // 定义NoteColumns的常量,用于后面创建数据库的表头 + public interface NoteColumns { + /** + * The unique ID for a row + *

Type: INTEGER (long)

+ */ + public static final String ID = "_id"; + + /** + * The parent's id for note or folder + *

Type: INTEGER (long)

+ */ + public static final String PARENT_ID = "parent_id";//为什么会有parent_id + + /** + * Created data for note or folder + *

Type: INTEGER (long)

+ */ + public static final String CREATED_DATE = "created_date"; + + /** + * Latest modified date + *

Type: INTEGER (long)

+ */ + public static final String MODIFIED_DATE = "modified_date"; + + + /** + * Alert date + *

Type: INTEGER (long)

+ */ + public static final String ALERTED_DATE = "alert_date"; + + /** + * Folder's name or text content of note + *

Type: TEXT

+ */ + public static final String SNIPPET = "snippet"; + + /** + * Note's widget id + *

Type: INTEGER (long)

+ */ + public static final String WIDGET_ID = "widget_id"; + + /** + * Note's widget type + *

Type: INTEGER (long)

+ */ + public static final String WIDGET_TYPE = "widget_type"; + + /** + * Note's background color's id + *

Type: INTEGER (long)

+ */ + public static final String BG_COLOR_ID = "bg_color_id"; + + /** + * For text note, it doesn't has attachment, for multi-media + * note, it has at least one attachment + *

Type: INTEGER

+ */ + public static final String HAS_ATTACHMENT = "has_attachment"; + + /** + * Folder's count of notes + *

Type: INTEGER (long)

+ */ + public static final String NOTES_COUNT = "notes_count"; + + /** + * The file type: folder or note + *

Type: INTEGER

+ */ + public static final String TYPE = "type"; + + /** + * The last sync id + *

Type: INTEGER (long)

+ */ + public static final String SYNC_ID = "sync_id";//同步 + + /** + * Sign to indicate local modified or not + *

Type: INTEGER

+ */ + public static final String LOCAL_MODIFIED = "local_modified"; + + /** + * Original parent id before moving into temporary folder + *

Type : INTEGER

+ */ + public static final String ORIGIN_PARENT_ID = "origin_parent_id"; + + /** + * The gtask id + *

Type : TEXT

+ */ + public static final String GTASK_ID = "gtask_id"; + + /** + * The version code + *

Type : INTEGER (long)

+ */ + public static final String VERSION = "version"; + }//这些常量主要是定义便签的属性的。 + + // 定义DataColumns的常量,用于后面创建数据库的表头 + public interface DataColumns { + /** + * The unique ID for a row + *

Type: INTEGER (long)

+ */ + public static final String ID = "_id"; + + /** + * The MIME type of the item represented by this row. + *

Type: Text

+ */ + public static final String MIME_TYPE = "mime_type"; + + /** + * The reference id to note that this data belongs to + *

Type: INTEGER (long)

+ */ + public static final String NOTE_ID = "note_id"; + + /** + * Created data for note or folder + *

Type: INTEGER (long)

+ */ + public static final String CREATED_DATE = "created_date"; + + /** + * Latest modified date + *

Type: INTEGER (long)

+ */ + public static final String MODIFIED_DATE = "modified_date"; + + /** + * Data's content + *

Type: TEXT

+ */ + public static final String CONTENT = "content"; + + + /** + * Generic data column, the meaning is {@link #MIMETYPE} specific, +used for + * integer data type + *

Type: INTEGER

+ */ + public static final String DATA1 = "data1"; + + /** + * Generic data column, the meaning is {@link #MIMETYPE} specific, +used for + * integer data type + *

Type: INTEGER

+ */ + public static final String DATA2 = "data2"; + + /** + * Generic data column, the meaning is {@link #MIMETYPE} specific, +used for + * TEXT data type + *

Type: TEXT

+ */ + public static final String DATA3 = "data3"; + + /** + * Generic data column, the meaning is {@link #MIMETYPE} specific, +used for + * TEXT data type + *

Type: TEXT

+ */ + public static final String DATA4 = "data4"; + + /** + * Generic data column, the meaning is {@link #MIMETYPE} specific, +used for + * TEXT data type + *

Type: TEXT

+ */ + public static final String DATA5 = "data5"; + }//主要是定义存储便签内容数据的 + public static final class TextNote implements DataColumns { + /** + * Mode to indicate the text in check list mode or not + *

Type: Integer 1:check list mode 0: normal mode

+ */ + public static final String MODE = DATA1; + + public static final int MODE_CHECK_LIST = 1; + + public static final String CONTENT_TYPE = + +"vnd.android.cursor.dir/text_note"; + + public static final String CONTENT_ITEM_TYPE = + +"vnd.android.cursor.item/text_note"; + + public static final Uri CONTENT_URI = Uri.parse("content://" + + +AUTHORITY + "/text_note"); + }//文本内容的数据结构 + + public static final class CallNote implements DataColumns { + /** + * Call date for this record + *

Type: INTEGER (long)

+ */ + public static final String CALL_DATE = DATA1; + + /** + * Phone number for this record + *

Type: TEXT

+ */ + public static final String PHONE_NUMBER = DATA3; + + public static final String CONTENT_TYPE = + +"vnd.android.cursor.dir/call_note"; + + public static final String CONTENT_ITEM_TYPE = + +"vnd.android.cursor.item/call_note"; + + public static final Uri CONTENT_URI = Uri.parse("content://" + + +AUTHORITY + "/call_note"); + }//电话内容的数据结构 +} \ No newline at end of file From 7a4171b364c57f1aa6bc06e548f92b1725c98e57 Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:30:05 +0800 Subject: [PATCH 03/42] ADD file via upload --- src/data/NotesDatabaseHelper.java | 351 ++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 src/data/NotesDatabaseHelper.java diff --git a/src/data/NotesDatabaseHelper.java b/src/data/NotesDatabaseHelper.java new file mode 100644 index 0000000..6414b2a --- /dev/null +++ b/src/data/NotesDatabaseHelper.java @@ -0,0 +1,351 @@ + + +package net.micode.notes.data; + +import android.content.ContentValues;//就是用于保存一些数据(string boolean byte double float int long short ...)信息,这些信息可以被数据库操作时使用。 +import android.content.Context;//加载和访问资源。(android中主要是这两个功能,但是这里具体不清楚) +import android.database.sqlite.SQLiteDatabase;//主要提供了对应于添加、删除、更新、查询的操作方法: insert()、delete()、update()和query()。配合content.values +import android.database.sqlite.SQLiteOpenHelper;//用来管理数据的创建和版本更新 +import android.util.Log; + +import net.micode.notes.data.Notes.DataColumns; +import net.micode.notes.data.Notes.DataConstants; +import net.micode.notes.data.Notes.NoteColumns; +//数据库操作,用SQLOpenhelper,对一些note和文件进行数据库的操作,比如删除文件后,将文件里的note也相应删除 + +public class NotesDatabaseHelper extends SQLiteOpenHelper { + private static final String DB_NAME = "note.db"; + + private static final int DB_VERSION = 4; + + public interface TABLE { //接口,分成note和data,在后面的程序里分别使用过 + public static final String NOTE = "note"; + + public static final String DATA = "data"; + } + + private static final String TAG = "NotesDatabaseHelper"; + + private static NotesDatabaseHelper mInstance; + + private static final String CREATE_NOTE_TABLE_SQL = + "CREATE TABLE " + TABLE.NOTE + "(" + + NoteColumns.ID + " INTEGER PRIMARY KEY," + + NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + + NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + + NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + + NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + + NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + + ")";//数据库中需要存储的项目的名称,就相当于创建一个表格的表头的内容。 + + private static final String CREATE_DATA_TABLE_SQL = + "CREATE TABLE " + TABLE.DATA + "(" + + DataColumns.ID + " INTEGER PRIMARY KEY," + + DataColumns.MIME_TYPE + " TEXT NOT NULL," + + DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + + DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + + DataColumns.DATA1 + " INTEGER," + + DataColumns.DATA2 + " INTEGER," + + DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + + DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + + DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + + ")";//和上面的功能一样,主要是存储的项目不同 + + private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = + "CREATE INDEX IF NOT EXISTS note_id_index ON " + + TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";//存储便签编号的一个数据表格 + + /** + * Increase folder's note count when move note to the folder + */ + private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = + "CREATE TRIGGER increase_folder_count_on_update "+ + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + + " END";//在文件夹中移入一个Note之后需要更改的数据的表格。 + + /** + * Decrease folder's note count when move note from folder + */ + private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = + "CREATE TRIGGER decrease_folder_count_on_update " + + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + + " END";//在文件夹中移出一个Note之后需要更改的数据的表格。 + + /** + * Increase folder's note count when insert new note to the folder + */ + private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = + "CREATE TRIGGER increase_folder_count_on_insert " + + " AFTER INSERT ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + + " END";//在文件夹中插入一个Note之后需要更改的数据的表格。 + + /** + * Decrease folder's note count when delete note from the folder + */ + private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = + "CREATE TRIGGER decrease_folder_count_on_delete " + + " AFTER DELETE ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + + " AND " + NoteColumns.NOTES_COUNT + ">0;" + + " END";//在文件夹中删除一个Note之后需要更改的数据的表格。 + + /** + * Update note's content when insert data with type {@link DataConstants#NOTE} + */ + private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = + "CREATE TRIGGER update_note_content_on_insert " + + " AFTER INSERT ON " + TABLE.DATA + + " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + + " BEGIN" + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + + " END";//在文件夹中对一个Note导入新的数据之后需要更改的数据的表格。 + + /** + * Update note's content when data with {@link DataConstants#NOTE} type has changed + */ + private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = + "CREATE TRIGGER update_note_content_on_update " + + " AFTER UPDATE ON " + TABLE.DATA + + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + + " BEGIN" + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + + " END";//Note数据被修改后需要更改的数据的表格。 + + /** + * Update note's content when data with {@link DataConstants#NOTE} type has deleted + */ + private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = + "CREATE TRIGGER update_note_content_on_delete " + + " AFTER delete ON " + TABLE.DATA + + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + + " BEGIN" + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.SNIPPET + "=''" + + " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + + " END";//Note数据被删除后需要更改的数据的表格。 + + /** + * Delete datas belong to note which has been deleted + */ + private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = + "CREATE TRIGGER delete_data_on_delete " + + " AFTER DELETE ON " + TABLE.NOTE + + " BEGIN" + + " DELETE FROM " + TABLE.DATA + + " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + + " END";//删除已删除的便签的数据后需要更改的数据的表格。 + + /** + * Delete notes belong to folder which has been deleted + */ + private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = + "CREATE TRIGGER folder_delete_notes_on_delete " + + " AFTER DELETE ON " + TABLE.NOTE + + " BEGIN" + + " DELETE FROM " + TABLE.NOTE + + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + + " END";//删除已删除的文件夹的便签后需要更改的数据的表格。 + + /** + * Move notes belong to folder which has been moved to trash folder + */ + private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = + "CREATE TRIGGER folder_move_notes_on_trash " + + " AFTER UPDATE ON " + TABLE.NOTE + + " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + + " BEGIN" + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + + " END";//还原垃圾桶中便签后需要更改的数据的表格。 + + public NotesDatabaseHelper(Context context) { + super(context, DB_NAME, null, DB_VERSION); + }//构造函数,传入数据库的名称和版本 + + public void createNoteTable(SQLiteDatabase db) { + db.execSQL(CREATE_NOTE_TABLE_SQL); + reCreateNoteTableTriggers(db); + createSystemFolder(db); + Log.d(TAG, "note table has been created"); + }//创建表格(用来存储标签属性) + + private void reCreateNoteTableTriggers(SQLiteDatabase db) { + db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); + db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); + db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); + db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete"); + db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert"); + db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); + db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); + + db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); + db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); + db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER); + db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER); + db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); + db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); + db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); + }//execSQL是数据库操作的API,主要是更改行为的SQL语句。 + //在这里主要是用来重新创建上述定义的表格用的,先删除原来有的数据库的触发器再重新创建新的数据库 + + private void createSystemFolder(SQLiteDatabase db) { + ContentValues values = new ContentValues(); + + /** + * call record foler for call notes + */ + values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); + db.insert(TABLE.NOTE, null, values); + + /** + * root folder which is default folder + */ + values.clear(); + values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); + db.insert(TABLE.NOTE, null, values); + + /** + * temporary folder which is used for moving note + */ + values.clear(); + values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); + db.insert(TABLE.NOTE, null, values); + + /** + * create trash folder + */ + values.clear(); + values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); + db.insert(TABLE.NOTE, null, values); + }//创建几个系统文件夹 + + public void createDataTable(SQLiteDatabase db) { + db.execSQL(CREATE_DATA_TABLE_SQL); + reCreateDataTableTriggers(db); + db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); + Log.d(TAG, "data table has been created"); + }//创建表格(用来存储标签内容) + + private void reCreateDataTableTriggers(SQLiteDatabase db) { + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); + + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); + }//同上面的execSQL + + static synchronized NotesDatabaseHelper getInstance(Context context) { + if (mInstance == null) { + mInstance = new NotesDatabaseHelper(context); + } + return mInstance; + }//上网查是为解决同一时刻只能有一个线程执行. + //在写程序库代码时,有时有一个类需要被所有的其它类使用, + //但又要求这个类只能被实例化一次,是个服务类,定义一次,其它类使用同一个这个类的实例 + + @Override + public void onCreate(SQLiteDatabase db) { + createNoteTable(db); + createDataTable(db); + }//实现两个表格(上面创建的两个表格) + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + boolean reCreateTriggers = false; + boolean skipV2 = false; + + if (oldVersion == 1) { + upgradeToV2(db); + skipV2 = true; // this upgrade including the upgrade from v2 to v3 + oldVersion++; + } + + if (oldVersion == 2 && !skipV2) { + upgradeToV3(db); + reCreateTriggers = true; + oldVersion++; + } + + if (oldVersion == 3) { + upgradeToV4(db); + oldVersion++; + } + + if (reCreateTriggers) { + reCreateNoteTableTriggers(db); + reCreateDataTableTriggers(db); + } + + if (oldVersion != newVersion) { + throw new IllegalStateException("Upgrade notes database to version " + newVersion + + "fails"); + } + }//数据库版本的更新(数据库内容的更改) + + private void upgradeToV2(SQLiteDatabase db) { + db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); + db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); + createNoteTable(db); + createDataTable(db); + }//更新到V2版本 + + private void upgradeToV3(SQLiteDatabase db) { + // drop unused triggers + db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); + db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete"); + db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update"); + // add a column for gtask id + db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID + + " TEXT NOT NULL DEFAULT ''"); + // add a trash system folder + ContentValues values = new ContentValues(); + values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); + db.insert(TABLE.NOTE, null, values); + }//更新到V3版本 + + private void upgradeToV4(SQLiteDatabase db) { + db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + + " INTEGER NOT NULL DEFAULT 0"); + }//更新到V4版本 +} \ No newline at end of file From 3ab16b68b3c9f48c9794aa0b9e5b5aba402d1a12 Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:30:23 +0800 Subject: [PATCH 04/42] ADD file via upload --- src/data/NotesProvider.java | 321 ++++++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 src/data/NotesProvider.java diff --git a/src/data/NotesProvider.java b/src/data/NotesProvider.java new file mode 100644 index 0000000..41989fe --- /dev/null +++ b/src/data/NotesProvider.java @@ -0,0 +1,321 @@ + +package net.micode.notes.data; + +import android.app.SearchManager; +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Intent; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +import net.micode.notes.R; +import net.micode.notes.data.Notes.DataColumns; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.data.NotesDatabaseHelper.TABLE; +//为存储和获取数据提供接口。可以在不同的应用程序之间共享数据 +//ContentProvider提供的方法 +//query:查询 +//insert:插入 +//update:更新 +//delete:删除 +//getType:得到数据类型 +public class NotesProvider extends ContentProvider { + // UriMatcher用于匹配Uri + private static final UriMatcher mMatcher; + + private NotesDatabaseHelper mHelper; + + private static final String TAG = "NotesProvider"; + + private static final int URI_NOTE = 1; + private static final int URI_NOTE_ITEM = 2; + private static final int URI_DATA = 3; + private static final int URI_DATA_ITEM = 4; + + private static final int URI_SEARCH = 5; + private static final int URI_SEARCH_SUGGEST = 6; + + static { + // 创建UriMatcher时,调用UriMatcher(UriMatcher.NO_MATCH)表示不匹配任何路径的返回码 + mMatcher = new UriMatcher(UriMatcher.NO_MATCH); + // 把需要匹配Uri路径全部给注册上 + mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); + mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); + mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); + mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); + mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); + mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); + mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); + } + + /** + * x'0A' represents the '\n' character in sqlite. For title and content in the search result, + * we will trim '\n' and white space in order to show more information. + */ + // 声明 NOTES_SEARCH_PROJECTION + private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," + + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," + + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," + + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," + + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," + + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," + + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + // 声明NOTES_SNIPPET_SEARCH_QUERY + private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION + + " FROM " + TABLE.NOTE + + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" + + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + + @Override + // Context只有在onCreate()中才被初始化 + // 对mHelper进行实例化 + public boolean onCreate() { + mHelper = NotesDatabaseHelper.getInstance(getContext()); + return true; + } + + @Override + // 查询uri在数据库中对应的位置 + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + Cursor c = null; + // 获取可读数据库 + SQLiteDatabase db = mHelper.getReadableDatabase(); + String id = null; + // 匹配查找uri + switch (mMatcher.match(uri)) { + // 对于不同的匹配值,在数据库中查找相应的条目 + case URI_NOTE: + c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, + sortOrder); + break; + case URI_NOTE_ITEM: + id = uri.getPathSegments().get(1); + c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id + + parseSelection(selection), selectionArgs, null, null, sortOrder); + break; + case URI_DATA: + c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, + sortOrder); + break; + case URI_DATA_ITEM: + id = uri.getPathSegments().get(1); + c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id + + parseSelection(selection), selectionArgs, null, null, sortOrder); + break; + case URI_SEARCH: + case URI_SEARCH_SUGGEST: + if (sortOrder != null || projection != null) { + // 不合法的参数异常 + throw new IllegalArgumentException( + "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); + } + + String searchString = null; + if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { + if (uri.getPathSegments().size() > 1) { + // getPathSegments()方法得到一个String的List, + // 在uri.getPathSegments().get(1)为第2个元素 + searchString = uri.getPathSegments().get(1); + } + } else { + searchString = uri.getQueryParameter("pattern"); + } + + if (TextUtils.isEmpty(searchString)) { + return null; + } + + try { + searchString = String.format("%%%s%%", searchString); + c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, + new String[] { searchString }); + } catch (IllegalStateException ex) { + Log.e(TAG, "got exception: " + ex.toString()); + } + break; + default: + // 抛出异常 + throw new IllegalArgumentException("Unknown URI " + uri); + } + if (c != null) { + c.setNotificationUri(getContext().getContentResolver(), uri); + } + return c; + } + + @Override + // 插入一个uri + public Uri insert(Uri uri, ContentValues values) { + // 获得可写的数据库 + SQLiteDatabase db = mHelper.getWritableDatabase(); + long dataId = 0, noteId = 0, insertedId = 0; + switch (mMatcher.match(uri)) { + // 新增一个条目 + case URI_NOTE: + insertedId = noteId = db.insert(TABLE.NOTE, null, values); + break; + // 如果存在,查找NOTE_ID + case URI_DATA: + if (values.containsKey(DataColumns.NOTE_ID)) { + noteId = values.getAsLong(DataColumns.NOTE_ID); + } else { + Log.d(TAG, "Wrong data format without note id:" + values.toString()); + } + insertedId = dataId = db.insert(TABLE.DATA, null, values); + break; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + // Notify the note uri + // notifyChange获得一个ContextResolver对象并且更新里面的内容 + if (noteId > 0) { + getContext().getContentResolver().notifyChange( + ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); + } + + // Notify the data uri + if (dataId > 0) { + getContext().getContentResolver().notifyChange( + ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); + } + + // 返回插入的uri的路径 + return ContentUris.withAppendedId(uri, insertedId); + } + + @Override + // 删除一个uri + public int delete(Uri uri, String selection, String[] selectionArgs) { + //Uri代表要操作的数据,Android上可用的每种资源 -包括 图像、视频片段、音频资源等都可以用Uri来表示。 + int count = 0; + String id = null; + // 获得可写的数据库 + SQLiteDatabase db = mHelper.getWritableDatabase(); + boolean deleteData = false; + switch (mMatcher.match(uri)) { + case URI_NOTE: + selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; + count = db.delete(TABLE.NOTE, selection, selectionArgs); + break; + case URI_NOTE_ITEM: + id = uri.getPathSegments().get(1); + /** + * ID that smaller than 0 is system folder which is not allowed to + * trash + */ + long noteId = Long.valueOf(id); + if (noteId <= 0) { + break; + } + count = db.delete(TABLE.NOTE, + NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); + break; + case URI_DATA: + count = db.delete(TABLE.DATA, selection, selectionArgs); + deleteData = true; + break; + case URI_DATA_ITEM: + id = uri.getPathSegments().get(1); + count = db.delete(TABLE.DATA, + DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); + deleteData = true; + break; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + if (count > 0) { + if (deleteData) { + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); + } + getContext().getContentResolver().notifyChange(uri, null); + } + return count; + } + + @Override + // 更新一个uri + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + int count = 0; + String id = null; + SQLiteDatabase db = mHelper.getWritableDatabase(); + boolean updateData = false; + switch (mMatcher.match(uri)) { + case URI_NOTE: + increaseNoteVersion(-1, selection, selectionArgs); + count = db.update(TABLE.NOTE, values, selection, selectionArgs); + break; + case URI_NOTE_ITEM: + id = uri.getPathSegments().get(1); + increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); + count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id + + parseSelection(selection), selectionArgs); + break; + case URI_DATA: + count = db.update(TABLE.DATA, values, selection, selectionArgs); + updateData = true; + break; + case URI_DATA_ITEM: + id = uri.getPathSegments().get(1); + count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id + + parseSelection(selection), selectionArgs); + updateData = true; + break; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + + if (count > 0) { + if (updateData) { + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); + } + getContext().getContentResolver().notifyChange(uri, null); + } + return count; + } + + // 将字符串解析成规定格式 + private String parseSelection(String selection) { + return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); + } + + //增加一个noteVersion + private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { + StringBuilder sql = new StringBuilder(120); + sql.append("UPDATE "); + sql.append(TABLE.NOTE); + sql.append(" SET "); + sql.append(NoteColumns.VERSION); + sql.append("=" + NoteColumns.VERSION + "+1 "); + + if (id > 0 || !TextUtils.isEmpty(selection)) { + sql.append(" WHERE "); + } + if (id > 0) { + sql.append(NoteColumns.ID + "=" + String.valueOf(id)); + } + if (!TextUtils.isEmpty(selection)) { + String selectString = id > 0 ? parseSelection(selection) : selection; + for (String args : selectionArgs) { + selectString = selectString.replaceFirst("\\?", args); + } + sql.append(selectString); + } + + // execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句 + mHelper.getWritableDatabase().execSQL(sql.toString()); + } + + @Override + public String getType(Uri uri) { + // TODO Auto-generated method stub + return null; + } + +} \ No newline at end of file From b6e51b99dde62865bbf8b3e21229830e13ec31d7 Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:30:58 +0800 Subject: [PATCH 05/42] ADD file via upload --- src/model/Note.java | 234 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 src/model/Note.java diff --git a/src/model/Note.java b/src/model/Note.java new file mode 100644 index 0000000..c7cdeb2 --- /dev/null +++ b/src/model/Note.java @@ -0,0 +1,234 @@ + + +package net.micode.notes.model; + +import android.content.ContentProviderOperation;//批量的更新、插入、删除数据。 +import android.content.ContentProviderResult;//操作的结果 +import android.content.ContentUris;//用于添加和获取Uri后面的ID +import android.content.ContentValues;//一种用来存储基本数据类型数据的存储机制 +import android.content.Context;//需要用该类来弄清楚调用者的实例 +import android.content.OperationApplicationException;//操作应用程序容错 +import android.net.Uri;//表示待操作的数据 +import android.os.RemoteException;//远程容错 +import android.util.Log;//输出日志,比如说出错、警告等 + +public class Note { + // private ContentValues mNoteDiffValues; + ContentValues mNoteDiffValues;// + private NoteData mNoteData; + private static final String TAG = "Note"; + + /** + * Create a new note id for adding a new note to databases + */ + public static synchronized long getNewNoteId(Context context, long folderId) { + // Create a new note in the database + ContentValues values = new ContentValues(); + long createdTime = System.currentTimeMillis(); + values.put(NoteColumns.CREATED_DATE, createdTime); + values.put(NoteColumns.MODIFIED_DATE, createdTime); + values.put(NoteColumns.TYPE, Notes.TYPE_NOTE); + values.put(NoteColumns.LOCAL_MODIFIED, 1); + values.put(NoteColumns.PARENT_ID, folderId);//将数据写入数据库表格 + Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); + //ContentResolver()主要是实现外部应用对ContentProvider中的数据 + //进行添加、删除、修改和查询操作 + long noteId = 0; + try { + noteId = Long.valueOf(uri.getPathSegments().get(1)); + } catch (NumberFormatException e) { + Log.e(TAG, "Get note id error :" + e.toString()); + noteId = 0; + }//try-catch异常处理 + if (noteId == -1) { + throw new IllegalStateException("Wrong note id:" + noteId); + } + return noteId; + } + + public Note() { + mNoteDiffValues = new ContentValues(); + mNoteData = new NoteData(); + }//定义两个变量用来存储便签的数据,一个是存储便签属性、一个是存储便签内容 + + public void setNoteValue(String key, String value) { + mNoteDiffValues.put(key, value); + mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); + mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); + }//设置数据库表格的标签属性数据 + + public void setTextData(String key, String value) { + mNoteData.setTextData(key, value); + }//设置数据库表格的标签文本内容的数据 + + public void setTextDataId(long id) { + mNoteData.setTextDataId(id); + }//设置文本数据的ID + + public long getTextDataId() { + return mNoteData.mTextDataId; + }//得到文本数据的ID + + public void setCallDataId(long id) { + mNoteData.setCallDataId(id); + }//设置电话号码数据的ID + + public void setCallData(String key, String value) { + mNoteData.setCallData(key, value); + }//得到电话号码数据的ID + + public boolean isLocalModified() { + return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); + }//判断是否是本地修改 + + public boolean syncNote(Context context, long noteId) { + if (noteId <= 0) { + throw new IllegalArgumentException("Wrong note id:" + noteId); + } + + if (!isLocalModified()) { + return true; + } + + /** + * In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and + * {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the + * note data info + */ + if (context.getContentResolver().update( + ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null, + null) == 0) { + Log.e(TAG, "Update note error, should not happen"); + // Do not return, fall through + } + mNoteDiffValues.clear(); + + if (mNoteData.isLocalModified() + && (mNoteData.pushIntoContentResolver(context, noteId) == null)) { + return false; + } + + return true; + }//判断数据是否同步 + + private class NoteData {//定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据 + private long mTextDataId; + + private ContentValues mTextDataValues;//文本数据 + + private long mCallDataId; + + private ContentValues mCallDataValues;//电话号码数据 + + private static final String TAG = "NoteData"; + + public NoteData() { + mTextDataValues = new ContentValues(); + mCallDataValues = new ContentValues(); + mTextDataId = 0; + mCallDataId = 0; + } + //下面是上述几个函数的具体实现 + boolean isLocalModified() { + return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; + } + + void setTextDataId(long id) { + if(id <= 0) { + throw new IllegalArgumentException("Text data id should larger than 0"); + } + mTextDataId = id; + } + + void setCallDataId(long id) { + if (id <= 0) { + throw new IllegalArgumentException("Call data id should larger than 0"); + } + mCallDataId = id; + } + + void setCallData(String key, String value) { + mCallDataValues.put(key, value); + mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); + mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); + } + + void setTextData(String key, String value) { + mTextDataValues.put(key, value); + mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); + mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); + } + //下面函数的作用是将新的数据通过Uri的操作存储到数据库 + Uri pushIntoContentResolver(Context context, long noteId) { + /** + * Check for safety + */ + if (noteId <= 0) { + throw new IllegalArgumentException("Wrong note id:" + noteId); + }//判断数据是否合法 + + ArrayList operationList = new ArrayList(); + ContentProviderOperation.Builder builder = null;//数据库的操作列表 + + if(mTextDataValues.size() > 0) { + mTextDataValues.put(DataColumns.NOTE_ID, noteId); + if (mTextDataId == 0) { + mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); + Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, + mTextDataValues); + try { + setTextDataId(Long.valueOf(uri.getPathSegments().get(1))); + } catch (NumberFormatException e) { + Log.e(TAG, "Insert new text data fail with noteId" + noteId); + mTextDataValues.clear(); + return null; + } + } else { + builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( + Notes.CONTENT_DATA_URI, mTextDataId)); + builder.withValues(mTextDataValues); + operationList.add(builder.build()); + } + mTextDataValues.clear(); + }//把文本数据存入DataColumns + + if(mCallDataValues.size() > 0) { + mCallDataValues.put(DataColumns.NOTE_ID, noteId); + if (mCallDataId == 0) { + mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); + Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, + mCallDataValues); + try { + setCallDataId(Long.valueOf(uri.getPathSegments().get(1))); + } catch (NumberFormatException e) { + Log.e(TAG, "Insert new call data fail with noteId" + noteId); + mCallDataValues.clear(); + return null; + } + } else { + builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( + Notes.CONTENT_DATA_URI, mCallDataId)); + builder.withValues(mCallDataValues); + operationList.add(builder.build()); + } + mCallDataValues.clear(); + }//把电话号码数据存入DataColumns + + if (operationList.size() > 0) { + try { + ContentProviderResult[] results = context.getContentResolver().applyBatch( + Notes.AUTHORITY, operationList); + return (results == null || results.length == 0 || results[0] == null) ? null + : ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId); + } catch (RemoteException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + return null; + } catch (OperationApplicationException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + return null; + } + }//存储过程中的异常处理 + return null; + } + } +} \ No newline at end of file From 99b9a4f3a53015e8d06485e2538b3d88054c86bf Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:31:12 +0800 Subject: [PATCH 06/42] ADD file via upload --- src/model/WorkingNote.java | 376 +++++++++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 src/model/WorkingNote.java diff --git a/src/model/WorkingNote.java b/src/model/WorkingNote.java new file mode 100644 index 0000000..5fec389 --- /dev/null +++ b/src/model/WorkingNote.java @@ -0,0 +1,376 @@ + + +package net.micode.notes.model; + +public class WorkingNote { + // Note for the working note + private Note mNote; + // Note Id + private long mNoteId; + // Note content + private String mContent; + // Note mode + private int mMode; + + private long mAlertDate; + private long mModifiedDate; + private int mBgColorId; + private int mWidgetId; + private int mWidgetType; + private long mFolderId; + private Context mContext; + + private static final String TAG = "WorkingNote"; + + private boolean mIsDeleted; + + private NoteSettingChangedListener mNoteSettingStatusListener; + + // 声明 DATA_PROJECTION字符串数组 + public static final String[] DATA_PROJECTION = new String[] { + DataColumns.ID, + DataColumns.CONTENT, + DataColumns.MIME_TYPE, + DataColumns.DATA1, + DataColumns.DATA2, + DataColumns.DATA3, + DataColumns.DATA4, + }; + + // 声明 NOTE_PROJECTION字符串数组 + public static final String[] NOTE_PROJECTION = new String[] { + NoteColumns.PARENT_ID, + NoteColumns.ALERTED_DATE, + NoteColumns.BG_COLOR_ID, + NoteColumns.WIDGET_ID, + NoteColumns.WIDGET_TYPE, + NoteColumns.MODIFIED_DATE + }; + + private static final int DATA_ID_COLUMN = 0; + private static final int DATA_CONTENT_COLUMN = 1; + private static final int DATA_MIME_TYPE_COLUMN = 2; + private static final int DATA_MODE_COLUMN = 3; + private static final int NOTE_PARENT_ID_COLUMN = 0; + private static final int NOTE_ALERTED_DATE_COLUMN = 1; + private static final int NOTE_BG_COLOR_ID_COLUMN = 2; + private static final int NOTE_WIDGET_ID_COLUMN = 3; + private static final int NOTE_WIDGET_TYPE_COLUMN = 4; + private static final int NOTE_MODIFIED_DATE_COLUMN = 5; + + // New note construct + public WorkingNote(Context context, long folderId) { + mContext = context; + mAlertDate = 0; + mModifiedDate = System.currentTimeMillis(); + mFolderId = folderId; + mNote = new Note(); + mNoteId = 0; + mIsDeleted = false; + mMode = 0; + mWidgetType = Notes.TYPE_WIDGET_INVALIDE; + } + + // WorkingNote的构造函数 + // Existing note construct + private WorkingNote(Context context, long noteId, long folderId) { + mContext = context; + mNoteId = noteId; + mFolderId = folderId; + mIsDeleted = false; + mNote = new Note(); + loadNote(); + } + + // 加载Note + // 通过数据库调用query函数找到第一个条目 + private void loadNote() { + Cursor cursor = mContext.getContentResolver().query( + ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, + null, null); + + // 若存在,储存相应信息 + if (cursor != null) { + if (cursor.moveToFirst()) { + mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); + mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); + mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); + mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); + mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); + mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); + } + cursor.close(); + // 若不存在,报错 + } else { + Log.e(TAG, "No note with id:" + mNoteId); + throw new IllegalArgumentException("Unable to find note with id " + mNoteId); + } + loadNoteData(); + } + + // 加载NoteData + private void loadNoteData() { + Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, + DataColumns.NOTE_ID + "=?", new String[] { + String.valueOf(mNoteId) + }, null); + + if (cursor != null) { + // 查到信息不为空 + if (cursor.moveToFirst()) { // 查看第一项是否存在 + do { + String type = cursor.getString(DATA_MIME_TYPE_COLUMN); + if (DataConstants.NOTE.equals(type)) { + mContent = cursor.getString(DATA_CONTENT_COLUMN); + mMode = cursor.getInt(DATA_MODE_COLUMN); + mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN)); + } else if (DataConstants.CALL_NOTE.equals(type)) { + mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); + } else { + Log.d(TAG, "Wrong note type with type:" + type); + } + } while (cursor.moveToNext());//查阅所有项,直到为空 + } + cursor.close(); + } else { + Log.e(TAG, "No data with id:" + mNoteId); + throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); + } + } + + // 创建空的Note + // 传参:context,文件夹id,widget,背景颜色 + public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, + int widgetType, int defaultBgColorId) { + WorkingNote note = new WorkingNote(context, folderId); + // 设定相关属性 + note.setBgColorId(defaultBgColorId); + note.setWidgetId(widgetId); + note.setWidgetType(widgetType); + return note; + } + + public static WorkingNote load(Context context, long id) { + return new WorkingNote(context, id, 0); + } + + // 保存Note + public synchronized boolean saveNote() { + if (isWorthSaving()) { //是否值得保存 + if (!existInDatabase()) { // 是否存在数据库中 + if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { + Log.e(TAG, "Create new note fail with id:" + mNoteId); + return false; + } + } + + mNote.syncNote(mContext, mNoteId); + + /** + * Update widget content if there exist any widget of this note + */ + if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID + && mWidgetType != Notes.TYPE_WIDGET_INVALIDE + && mNoteSettingStatusListener != null) { + mNoteSettingStatusListener.onWidgetChanged(); + } + return true; + } else { + return false; + } + } + + // 是否在数据库中存在 + public boolean existInDatabase() { + return mNoteId > 0; + } + + // 是否值得保存 + private boolean isWorthSaving() { + // 被删除,或(不在数据库中 内容为空),或 本地已保存过 + if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) + || (existInDatabase() && !mNote.isLocalModified())) { + return false; + } else { + return true; + } + } + + + // 设置mNoteSettingStatusListener + public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { + mNoteSettingStatusListener = l; + } + + // 设置AlertDate + // 若 mAlertDate与data不同,则更改mAlertDate并设定NoteValue + public void setAlertDate(long date, boolean set) { + if (date != mAlertDate) { + mAlertDate = date; + mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate)); + } + if (mNoteSettingStatusListener != null) { + mNoteSettingStatusListener.onClockAlertChanged(date, set); + } + } + + // 设定删除标记 + public void markDeleted(boolean mark) { + // 设定标记 + mIsDeleted = mark; + if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID + && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { + mNoteSettingStatusListener.onWidgetChanged(); + // 调用mNoteSettingStatusListener的 onWidgetChanged方法 + } + } + + // 设定背景颜色 + public void setBgColorId(int id) { + if (id != mBgColorId) { //设定条件 id != mBgColorId + mBgColorId = id; + if (mNoteSettingStatusListener != null) { + mNoteSettingStatusListener.onBackgroundColorChanged(); + } + mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); + } + } + + // 设定检查列表模式 + // 参数:mode + public void setCheckListMode(int mode) { + if (mMode != mode) { //设定条件 mMode != mode + if (mNoteSettingStatusListener != null) { + mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode); + } + mMode = mode; + mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); + } + } + + + // 设定WidgetType + // 参数:type + public void setWidgetType(int type) { + if (type != mWidgetType) {//设定条件 type != mWidgetType + mWidgetType = type; + mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); + // 调用Note的setNoteValue方法更改WidgetType + } + } + + // 设定WidgetId + // 参数:id + public void setWidgetId(int id) { + if (id != mWidgetId) {//设定条件 id != mWidgetId + mWidgetId = id; + mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); + // 调用Note的setNoteValue方法更改WidgetId + } + } + + // 设定WorkingTex + // 参数:更改的text + public void setWorkingText(String text) { + if (!TextUtils.equals(mContent, text)) {//设定条件 mContent, text内容不同 + mContent = text; + mNote.setTextData(DataColumns.CONTENT, mContent); + // 调用Note的setTextData方法更改WorkingText + } + } + + // 转变mNote的CallData及CallNote信息 + // 参数:String phoneNumber, long callDate + public void convertToCallNote(String phoneNumber, long callDate) { + mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); + mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); + mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER)); + } + + // 判断是否有时钟题型 + public boolean hasClockAlert() { + return (mAlertDate > 0 ? true : false); + } + + // 获取Content + public String getContent() { + return mContent; + } + + // 获取AlertDate + public long getAlertDate() { + return mAlertDate; + } + + // 获取ModifiedDate + public long getModifiedDate() { + return mModifiedDate; + } + + // 获取背景颜色来源id + public int getBgColorResId() { + return NoteBgResources.getNoteBgResource(mBgColorId); + } + + // 获取背景颜色id + public int getBgColorId() { + return mBgColorId; + } + + // 获取标题背景颜色id + public int getTitleBgResId() { + return NoteBgResources.getNoteTitleBgResource(mBgColorId); + } + + // 获取CheckListMode + public int getCheckListMode() { + return mMode; + } + + // 获取便签id + public long getNoteId() { + return mNoteId; + } + + // 获取文件夹id + public long getFolderId() { + return mFolderId; + } + + // 获取WidgetId + public int getWidgetId() { + return mWidgetId; + } + + // 获取WidgetType + public int getWidgetType() { + return mWidgetType; + } + + // 创建接口 NoteSettingChangedListener,便签更新监视 + // 为NoteEditActivity提供接口 + // 提供函数有 + public interface NoteSettingChangedListener { + /** + * Called when the background color of current note has just changed + */ + void onBackgroundColorChanged(); + + /** + * Called when user set clock + */ + void onClockAlertChanged(long date, boolean set); + + /** + * Call when user create note from widget + */ + void onWidgetChanged(); + + /** + * Call when switch between check list mode and normal mode + * @param oldMode is previous mode before change + * @param newMode is new mode + */ + void onCheckListModeChanged(int oldMode, int newMode); + } +} \ No newline at end of file From 55eba243354127307edf2d93a665a54c403663e4 Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:31:44 +0800 Subject: [PATCH 07/42] ADD file via upload --- src/tool/BackupUtils.java | 313 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 src/tool/BackupUtils.java diff --git a/src/tool/BackupUtils.java b/src/tool/BackupUtils.java new file mode 100644 index 0000000..df769b8 --- /dev/null +++ b/src/tool/BackupUtils.java @@ -0,0 +1,313 @@ + + +package net.micode.notes.tool; + +public class BackupUtils { + private static final String TAG = "BackupUtils"; + // Singleton stuff + private static BackupUtils sInstance; //类里面为什么可以定义自身类的对象? + + public static synchronized BackupUtils getInstance(Context context) { + //ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A) + //运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。 + //它包括两种用法:synchronized 方法和 synchronized 块。 + if (sInstance == null) { + //如果当前备份不存在,则新声明一个 + sInstance = new BackupUtils(context); + } + return sInstance; + } + + /** + * Following states are signs to represents backup or restore + * status + */ + // Currently, the sdcard is not mounted SD卡没有被装入手机 + public static final int STATE_SD_CARD_UNMOUONTED = 0; + // The backup file not exist 备份文件夹不存在 + 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; + // Some run-time exception which causes restore or backup fails 超时异常 + public static final int STATE_SYSTEM_ERROR = 3; + // Backup or restore success 成功存储 + public static final int STATE_SUCCESS = 4; + + private TextExport mTextExport; + + private BackupUtils(Context context) { //初始化函数 + mTextExport = new TextExport(context); + } + + private static boolean externalStorageAvailable() { //外部存储功能是否可用 + return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); + } + + public int exportToText() { + return mTextExport.exportToText(); + } + + public String getExportedTextFileName() { + return mTextExport.mFileName; + } + + public String getExportedTextFileDir() { + return mTextExport.mFileDirectory; + } + + private static class TextExport { + private static final String[] NOTE_PROJECTION = { + NoteColumns.ID, + NoteColumns.MODIFIED_DATE, + NoteColumns.SNIPPET, + NoteColumns.TYPE + }; + + private static final int NOTE_COLUMN_ID = 0; + + private static final int NOTE_COLUMN_MODIFIED_DATE = 1; + + private static final int NOTE_COLUMN_SNIPPET = 2; + + private static final String[] DATA_PROJECTION = { + DataColumns.CONTENT, + DataColumns.MIME_TYPE, + DataColumns.DATA1, + DataColumns.DATA2, + DataColumns.DATA3, + DataColumns.DATA4, + }; + + private static final int DATA_COLUMN_CONTENT = 0; + + private static final int DATA_COLUMN_MIME_TYPE = 1; + + private static final int DATA_COLUMN_CALL_DATE = 2; + + private static final int DATA_COLUMN_PHONE_NUMBER = 4; + + private final String [] TEXT_FORMAT; + private static final int FORMAT_FOLDER_NAME = 0; + private static final int FORMAT_NOTE_DATE = 1; + private static final int FORMAT_NOTE_CONTENT = 2; + + private Context mContext; + private String mFileName; + private String mFileDirectory; + + public TextExport(Context context) { + TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); + mContext = context; + mFileName = ""; //为什么为空? + mFileDirectory = ""; + } + + private String getFormat(int id) { //获取文本的组成部分 + return TEXT_FORMAT[id]; + } + + /** + * Export the folder identified by folder id to text + */ + private void exportFolderToText(String folderId, PrintStream ps) { + // Query notes belong to this folder 通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note + Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, + NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { + folderId + }, null); + + if (notesCursor != null) { + if (notesCursor.moveToFirst()) { + do { + // 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)))); + // Query data belong to this note + String noteId = notesCursor.getString(NOTE_COLUMN_ID); + exportNoteToText(noteId, ps); //将文件导出到text + } while (notesCursor.moveToNext()); + } + notesCursor.close(); + } + } + + /** + * Export note identified by id to a print stream + */ + private void exportNoteToText(String noteId, PrintStream ps) { + Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, + DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { + noteId + }, null); + + if (dataCursor != null) { //利用光标来扫描内容,区别为callnote和note两种,靠ps.printline输出 + if (dataCursor.moveToFirst()) { + do { + String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); + if (DataConstants.CALL_NOTE.equals(mimeType)) { + // Print phone number + String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER); + long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE); + String location = dataCursor.getString(DATA_COLUMN_CONTENT); + + if (!TextUtils.isEmpty(phoneNumber)) { //判断是否为空字符 + ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), + phoneNumber)); + } + // Print call date + ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat + .format(mContext.getString(R.string.format_datetime_mdhm), + callDate))); + // Print call attachment location + if (!TextUtils.isEmpty(location)) { + ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), + location)); + } + } else if (DataConstants.NOTE.equals(mimeType)) { + String content = dataCursor.getString(DATA_COLUMN_CONTENT); + if (!TextUtils.isEmpty(content)) { + ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), + content)); + } + } + } while (dataCursor.moveToNext()); + } + dataCursor.close(); + } + // print a line separator between note + try { + ps.write(new byte[] { + Character.LINE_SEPARATOR, Character.LETTER_NUMBER + }); + } catch (IOException e) { + Log.e(TAG, e.toString()); + } + } + + /** + * Note will be exported as text which is user readable + */ + public int exportToText() { //总函数,调用上面的exportFolder和exportNote + if (!externalStorageAvailable()) { + Log.d(TAG, "Media was not mounted"); + return STATE_SD_CARD_UNMOUONTED; + } + + PrintStream ps = getExportToTextPrintStream(); + if (ps == null) { + Log.e(TAG, "get print stream error"); + return STATE_SYSTEM_ERROR; + } + // First export folder and its notes 导出文件夹,就是导出里面包含的便签 + Cursor folderCursor = mContext.getContentResolver().query( + Notes.CONTENT_NOTE_URI, + NOTE_PROJECTION, + "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " + + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR " + + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null); + + if (folderCursor != null) { + if (folderCursor.moveToFirst()) { + do { + // Print folder's name + String folderName = ""; + if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) { + folderName = mContext.getString(R.string.call_record_folder_name); + } else { + folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET); + } + if (!TextUtils.isEmpty(folderName)) { + ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName)); + } + String folderId = folderCursor.getString(NOTE_COLUMN_ID); + exportFolderToText(folderId, ps); + } while (folderCursor.moveToNext()); + } + folderCursor.close(); + } + + // Export notes in root's folder 将根目录里的便签导出(由于不属于任何文件夹,因此无法通过文件夹导出来实现这一部分便签的导出) + Cursor noteCursor = mContext.getContentResolver().query( + Notes.CONTENT_NOTE_URI, + NOTE_PROJECTION, + NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID + + "=0", null, null); + + if (noteCursor != null) { + if (noteCursor.moveToFirst()) { + do { + ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( + mContext.getString(R.string.format_datetime_mdhm), + noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); + // Query data belong to this note + String noteId = noteCursor.getString(NOTE_COLUMN_ID); + exportNoteToText(noteId, ps); + } while (noteCursor.moveToNext()); + } + noteCursor.close(); + } + ps.close(); + + return STATE_SUCCESS; + } + + /** + * Get a print stream pointed to the file {@generateExportedTextFile} + */ + private PrintStream getExportToTextPrintStream() { + File file = generateFileMountedOnSDcard(mContext, R.string.file_path, + R.string.file_name_txt_format); + if (file == null) { + Log.e(TAG, "create file to exported failed"); + return null; + } + mFileName = file.getName(); + mFileDirectory = mContext.getString(R.string.file_path); + PrintStream ps = null; + try { + FileOutputStream fos = new FileOutputStream(file); + ps = new PrintStream(fos); //将ps输出流输出到特定的文件,目的就是导出到文件,而不是直接输出 + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } catch (NullPointerException e) { + e.printStackTrace(); + return null; + } + return ps; + } + } + + /** + * Generate the text file to store imported data + */ + private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { + StringBuilder sb = new StringBuilder(); + sb.append(Environment.getExternalStorageDirectory()); //外部(SD卡)的存储路径 + sb.append(context.getString(filePathResId)); //文件的存储路径 + File filedir = new File(sb.toString()); //filedir应该就是用来存储路径信息 + sb.append(context.getString( + fileNameFormatResId, + DateFormat.format(context.getString(R.string.format_date_ymd), + System.currentTimeMillis()))); + File file = new File(sb.toString()); + + try { //如果这些文件不存在,则新建 + if (!filedir.exists()) { + filedir.mkdir(); + } + if (!file.exists()) { + file.createNewFile(); + } + return file; + } catch (SecurityException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } +// try catch 异常处理 + return null; + } +} + \ No newline at end of file From 1222b83d705d352559372b69584a07c031540347 Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:31:55 +0800 Subject: [PATCH 08/42] ADD file via upload --- src/tool/DataUtils.java | 265 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 src/tool/DataUtils.java diff --git a/src/tool/DataUtils.java b/src/tool/DataUtils.java new file mode 100644 index 0000000..8cf1827 --- /dev/null +++ b/src/tool/DataUtils.java @@ -0,0 +1,265 @@ + + +package net.micode.notes.tool; + +public class DataUtils { + public static final String TAG = "DataUtils"; + public static boolean batchDeleteNotes(ContentResolver resolver, HashSet ids) { //直接删除多个笔记 + if (ids == null) { + Log.d(TAG, "the ids is null"); + return true; + } + if (ids.size() == 0) { + Log.d(TAG, "no id is in the hashset"); + return true; + } + + ArrayList operationList = new ArrayList(); //提供一个任务列表 + for (long id : ids) { + if(id == Notes.ID_ROOT_FOLDER) { + Log.e(TAG, "Don't delete system folder root"); + continue; + } //如果发现是根文件夹,则不删除 + ContentProviderOperation.Builder builder = ContentProviderOperation + .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //用newDelete实现删除功能 + operationList.add(builder.build()); // + } + try { + ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);//主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。 + //数据库事务,数据库事务是由一组数据库操作序列组成,事务作为一个整体被执行 + if (results == null || results.length == 0 || results[0] == null) { + Log.d(TAG, "delete notes failed, ids:" + ids.toString()); + return false; + } + return true; + } catch (RemoteException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } catch (OperationApplicationException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } + return false; + } + + public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) { + ContentValues values = new ContentValues(); + values.put(NoteColumns.PARENT_ID, desFolderId); + values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); + values.put(NoteColumns.LOCAL_MODIFIED, 1); + resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); //对需要移动的便签进行数据更新,然后用update实现 + } + + public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids, + long folderId) { + if (ids == null) { + Log.d(TAG, "the ids is null"); + return true; + } + + ArrayList operationList = new ArrayList(); + for (long id : ids) { + ContentProviderOperation.Builder builder = ContentProviderOperation + .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //通过withAppendedId方法,为该Uri加上ID + builder.withValue(NoteColumns.PARENT_ID, folderId); + builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); + operationList.add(builder.build()); + }//将ids里包含的每一列的数据逐次加入到operationList中,等待最后的批量处理 + + try { + ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); //applyBatch一次性处理一个操作列表 + if (results == null || results.length == 0 || results[0] == null) { + Log.d(TAG, "delete notes failed, ids:" + ids.toString()); + return false; + } + return true; + } catch (RemoteException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } catch (OperationApplicationException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } + return false; + } + + /** + * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}} + */ + public static int getUserFolderCount(ContentResolver resolver) { + Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI, + new String[] { "COUNT(*)" }, + NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", + new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, + null); //筛选条件:源文件不为trash folder + + int count = 0; + if(cursor != null) { + if(cursor.moveToFirst()) { + try { + count = cursor.getInt(0); + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "get folder count failed:" + e.toString()); + } finally { + cursor.close(); + } + } + } + return count; + } + + public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), //通过withAppendedId方法,为该Uri加上ID + null, + NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, + new String [] {String.valueOf(type)}, + null); //查询条件:type符合,且不属于垃圾文件夹 + + boolean exist = false; + if (cursor != null) { + if (cursor.getCount() > 0) {//用getcount函数判断cursor是否为空 + exist = true; + } + cursor.close(); + } + return exist; + } + + public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), + null, null, null, null); + + boolean exist = false; + if (cursor != null) { + if (cursor.getCount() > 0) { + exist = true; + } + cursor.close(); + } + return exist; + } + + public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), + null, null, null, null); + + boolean exist = false; + if (cursor != null) { + if (cursor.getCount() > 0) { + exist = true; + } + cursor.close(); + } + return exist; + } + + public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { + Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + + " AND " + NoteColumns.SNIPPET + "=?", + new String[] { name }, null); + //通过名字查询文件是否存在 + boolean exist = false; + if(cursor != null) { + if(cursor.getCount() > 0) { + exist = true; + } + cursor.close(); + } + return exist; + } + + public static HashSet getFolderNoteWidget(ContentResolver resolver, long folderId) { + Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, + new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, + NoteColumns.PARENT_ID + "=?", + new String[] { String.valueOf(folderId) }, + null); //查询条件:父ID是传入的folderId; + + HashSet set = null; + if (c != null) { + if (c.moveToFirst()) { + set = new HashSet(); + do { + try { + AppWidgetAttribute widget = new AppWidgetAttribute(); + widget.widgetId = c.getInt(0); //0对应的NoteColumns.WIDGET_ID + widget.widgetType = c.getInt(1); //1对应的NoteColumns.WIDGET_TYPE + set.add(widget); + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, e.toString()); + } + } while (c.moveToNext()); //查询下一条 + } + c.close(); + } + return set; + } + + public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { + Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, + new String [] { CallNote.PHONE_NUMBER }, + CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", + new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }, + null); + + if (cursor != null && cursor.moveToFirst()) { + try { + return cursor.getString(0); + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "Get call number fails " + e.toString()); + } finally { + cursor.close(); + } + } + return ""; + } + + public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { + Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, + new String [] { CallNote.NOTE_ID }, + CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" + + CallNote.PHONE_NUMBER + ",?)", + new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, + null); + //通过数据库操作,查询条件是(callDate和phoneNumber匹配传入参数的值) + + if (cursor != null) { + if (cursor.moveToFirst()) { + try { + return cursor.getLong(0); //0对应的CallNote.NOTE_ID + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "Get call note id fails " + e.toString()); + } + } + cursor.close(); + } + return 0; + } + + public static String getSnippetById(ContentResolver resolver, long noteId) { + Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, + new String [] { NoteColumns.SNIPPET }, + NoteColumns.ID + "=?", + new String [] { String.valueOf(noteId)}, + null);//查询条件:noteId + + if (cursor != null) { + String snippet = ""; + if (cursor.moveToFirst()) { + snippet = cursor.getString(0); + } + cursor.close(); + return snippet; + } + throw new IllegalArgumentException("Note is not found with id: " + noteId); + } + public static String getFormattedSnippet(String snippet) { //对字符串进行格式处理,将字符串两头的空格去掉,同时将换行符去掉 + if (snippet != null) { + snippet = snippet.trim(); + int index = snippet.indexOf('\n'); + if (index != -1) { + snippet = snippet.substring(0, index); + } + } + return snippet; + } + +} \ No newline at end of file From 73ecc2dfaca11829ba920fa6443d615a843a7397 Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:32:03 +0800 Subject: [PATCH 09/42] ADD file via upload --- src/tool/GTaskStringUtils.java | 101 +++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/tool/GTaskStringUtils.java diff --git a/src/tool/GTaskStringUtils.java b/src/tool/GTaskStringUtils.java new file mode 100644 index 0000000..e741ba5 --- /dev/null +++ b/src/tool/GTaskStringUtils.java @@ -0,0 +1,101 @@ + + +//定义了很多的静态字符串,目的就是为了提供jsonObject中相应字符串的"key"。把这些静态的定义单独写到了一个类里面,这是非常好的编程规范 +package net.micode.notes.tool; + +//这个类就是定义了一堆static string,实际就是为jsonObject提供Key,把这些定义全部写到一个类里,方便查看管理,是一个非常好的编程习惯 +public class GTaskStringUtils { + + public final static String GTASK_JSON_ACTION_ID = "action_id"; + + public final static String GTASK_JSON_ACTION_LIST = "action_list"; + + public final static String GTASK_JSON_ACTION_TYPE = "action_type"; + + public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create"; + + public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all"; + + public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move"; + + public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update"; + + public final static String GTASK_JSON_CREATOR_ID = "creator_id"; + + public final static String GTASK_JSON_CHILD_ENTITY = "child_entity"; + + public final static String GTASK_JSON_CLIENT_VERSION = "client_version"; + + public final static String GTASK_JSON_COMPLETED = "completed"; + + public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id"; + + public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id"; + + public final static String GTASK_JSON_DELETED = "deleted"; + + public final static String GTASK_JSON_DEST_LIST = "dest_list"; + + public final static String GTASK_JSON_DEST_PARENT = "dest_parent"; + + public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type"; + + public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta"; + + public final static String GTASK_JSON_ENTITY_TYPE = "entity_type"; + + public final static String GTASK_JSON_GET_DELETED = "get_deleted"; + + public final static String GTASK_JSON_ID = "id"; + + public final static String GTASK_JSON_INDEX = "index"; + + public final static String GTASK_JSON_LAST_MODIFIED = "last_modified"; + + public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point"; + + public final static String GTASK_JSON_LIST_ID = "list_id"; + + public final static String GTASK_JSON_LISTS = "lists"; + + public final static String GTASK_JSON_NAME = "name"; + + public final static String GTASK_JSON_NEW_ID = "new_id"; + + public final static String GTASK_JSON_NOTES = "notes"; + + public final static String GTASK_JSON_PARENT_ID = "parent_id"; + + public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id"; + + public final static String GTASK_JSON_RESULTS = "results"; + + public final static String GTASK_JSON_SOURCE_LIST = "source_list"; + + public final static String GTASK_JSON_TASKS = "tasks"; + + public final static String GTASK_JSON_TYPE = "type"; + + public final static String GTASK_JSON_TYPE_GROUP = "GROUP"; + + public final static String GTASK_JSON_TYPE_TASK = "TASK"; + + public final static String GTASK_JSON_USER = "user"; + + public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]"; + + public final static String FOLDER_DEFAULT = "Default"; + + public final static String FOLDER_CALL_NOTE = "Call_Note"; + + public final static String FOLDER_META = "METADATA"; + + public final static String META_HEAD_GTASK_ID = "meta_gid"; + + public final static String META_HEAD_NOTE = "meta_note"; + + public final static String META_HEAD_DATA = "meta_data"; + + public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE"; + +} \ No newline at end of file From 7bf771cf834559e5420ea79178e4dbd9352d8f22 Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:32:10 +0800 Subject: [PATCH 10/42] ADD file via upload --- src/tool/ResourceParser.java | 177 +++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 src/tool/ResourceParser.java diff --git a/src/tool/ResourceParser.java b/src/tool/ResourceParser.java new file mode 100644 index 0000000..cde41fa --- /dev/null +++ b/src/tool/ResourceParser.java @@ -0,0 +1,177 @@ + + +package net.micode.notes.tool; + +/*字面意义是资源分析器,实际上就是获取资源并且在程序中使用,比如颜色图片等 + * 实现方法:主要利用R.java这个类,其中包括 + * R.id 组件资源引用 + * R.drawable 图片资源 (被使用) + * R.layout 布局资源 + * R.menu 菜单资源 + * R.String 文字资源 + * R.style 主题资源 (被使用) + * 在按顺序设置好相应的id后,就可以编写简单的getXXX函数获取需要的资源 + * + * 特殊的变量 : + * @BG_DEFAULT_COLOR 默认背景颜色(黄) + * BG_DEFAULT_FONT_SIZE 默认文本大小(中) + */ + +public class ResourceParser { + + public static final int YELLOW = 0; + public static final int BLUE = 1; + public static final int WHITE = 2; + public static final int GREEN = 3; + public static final int RED = 4; + + public static final int BG_DEFAULT_COLOR = YELLOW; + + public static final int TEXT_SMALL = 0; + public static final int TEXT_MEDIUM = 1; + public static final int TEXT_LARGE = 2; + public static final int TEXT_SUPER = 3; + + public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM; + + public static class NoteBgResources { + private final static int [] BG_EDIT_RESOURCES = new int [] { + R.drawable.edit_yellow, + R.drawable.edit_blue, + R.drawable.edit_white, + R.drawable.edit_green, + R.drawable.edit_red + }; + + private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] { + R.drawable.edit_title_yellow, + R.drawable.edit_title_blue, + R.drawable.edit_title_white, + R.drawable.edit_title_green, + R.drawable.edit_title_red + }; + + public static int getNoteBgResource(int id) { + return BG_EDIT_RESOURCES[id]; + } + + public static int getNoteTitleBgResource(int id) { + return BG_EDIT_TITLE_RESOURCES[id]; + } + } + //直接获取默认的背景颜色。看不太懂,这个PREFERENCE_SET_BG_COLOR_KEY是个final string,也就是说getBoolean肯定执行else,为什么要这么写 + public static int getDefaultBgId(Context context) { + if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( + NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { + return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length); + } else { + return BG_DEFAULT_COLOR; + } + } + + public static class NoteItemBgResources { + private final static int [] BG_FIRST_RESOURCES = new int [] { + R.drawable.list_yellow_up, + R.drawable.list_blue_up, + R.drawable.list_white_up, + R.drawable.list_green_up, + R.drawable.list_red_up + }; + + private final static int [] BG_NORMAL_RESOURCES = new int [] { + R.drawable.list_yellow_middle, + R.drawable.list_blue_middle, + R.drawable.list_white_middle, + R.drawable.list_green_middle, + R.drawable.list_red_middle + }; + + private final static int [] BG_LAST_RESOURCES = new int [] { + R.drawable.list_yellow_down, + R.drawable.list_blue_down, + R.drawable.list_white_down, + R.drawable.list_green_down, + R.drawable.list_red_down, + }; + + private final static int [] BG_SINGLE_RESOURCES = new int [] { + R.drawable.list_yellow_single, + R.drawable.list_blue_single, + R.drawable.list_white_single, + R.drawable.list_green_single, + R.drawable.list_red_single + }; + + public static int getNoteBgFirstRes(int id) { + return BG_FIRST_RESOURCES[id]; + } + + public static int getNoteBgLastRes(int id) { + return BG_LAST_RESOURCES[id]; + } + + public static int getNoteBgSingleRes(int id) { + return BG_SINGLE_RESOURCES[id]; + } + + public static int getNoteBgNormalRes(int id) { + return BG_NORMAL_RESOURCES[id]; + } + + public static int getFolderBgRes() { + return R.drawable.list_folder; + } + } + + public static class WidgetBgResources { + private final static int [] BG_2X_RESOURCES = new int [] { + R.drawable.widget_2x_yellow, + R.drawable.widget_2x_blue, + R.drawable.widget_2x_white, + R.drawable.widget_2x_green, + R.drawable.widget_2x_red, + }; + + public static int getWidget2xBgResource(int id) { + return BG_2X_RESOURCES[id]; + } + + private final static int [] BG_4X_RESOURCES = new int [] { + R.drawable.widget_4x_yellow, + R.drawable.widget_4x_blue, + R.drawable.widget_4x_white, + R.drawable.widget_4x_green, + R.drawable.widget_4x_red + }; + + public static int getWidget4xBgResource(int id) { + return BG_4X_RESOURCES[id]; + } + } + + public static class TextAppearanceResources { + private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] { + R.style.TextAppearanceNormal, + R.style.TextAppearanceMedium, + R.style.TextAppearanceLarge, + R.style.TextAppearanceSuper + }; + + //这里有一个容错的函数,防止输入的id大于资源总量,若如此,则自动返回默认的设置结果 + public static int getTexAppearanceResource(int id) { + /** + * HACKME: Fix bug of store the resource id in shared preference. + * The id may larger than the length of resources, in this case, + * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} + */ + if (id >= TEXTAPPEARANCE_RESOURCES.length) { + return BG_DEFAULT_FONT_SIZE; + } + return TEXTAPPEARANCE_RESOURCES[id]; + } + + public static int getResourcesSize() { + return TEXTAPPEARANCE_RESOURCES.length; + } + } +} \ No newline at end of file From 15758eeed483c9d375afce2fca9d75e0df8be07e Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:32:32 +0800 Subject: [PATCH 11/42] ADD file via upload --- src/widget/NoteWidgetProvider.java | 159 +++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/widget/NoteWidgetProvider.java diff --git a/src/widget/NoteWidgetProvider.java b/src/widget/NoteWidgetProvider.java new file mode 100644 index 0000000..db62ef5 --- /dev/null +++ b/src/widget/NoteWidgetProvider.java @@ -0,0 +1,159 @@ + + +package net.micode.notes.widget; +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.util.Log; +import android.widget.RemoteViews; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.tool.ResourceParser; +import net.micode.notes.ui.NoteEditActivity; +import net.micode.notes.ui.NotesListActivity; + +// 声明一个名为NoteWidgetProvider的公共抽象类,该类继承自AppWidgetProvider类 +public abstract class NoteWidgetProvider extends AppWidgetProvider { +// 定义一个字符串数组,包含三个元素,分别是NoteColumns.ID、NoteColumns.BG_COLOR_ID和NoteColumns.SNIPPET + public static final String [] PROJECTION = new String [] { + NoteColumns.ID, + NoteColumns.BG_COLOR_ID, + NoteColumns.SNIPPET + }; +// 定义三个整型常量,分别对应PROJECTION数组中的三个元素的索引 + public static final int COLUMN_ID = 0; + public static final int COLUMN_BG_COLOR_ID = 1; + public static final int COLUMN_SNIPPET = 2; +// 定义一个私有常量字符串,值为"NoteWidgetProvider" + private static final String TAG = "NoteWidgetProvider"; + +// 重写AppWidgetProvider类中的onDeleted方法,该方法在组件被删除时调用 + @Override + public void onDeleted(Context context, int[] appWidgetIds) { + // 创建一个ContentValues对象,用于存储要插入或更新的键值对 + ContentValues values = new ContentValues(); + // 在values中放入一个键值对,键为NoteColumns.WIDGET_ID,值为AppWidgetManager.INVALID_APPWIDGET_ID + values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); + // 遍历appWidgetIds数组 + for (int i = 0; i < appWidgetIds.length; i++) { + // 使用context的getContentResolver()方法获取内容解析器,并更新Notes表中对应appWidgetIds[i]的记录的WIDGET_ID为AppWidgetManager.INVALID_APPWIDGET_ID + context.getContentResolver().update(Notes.CONTENT_NOTE_URI, + values, + NoteColumns.WIDGET_ID + "=?", + new String[] { String.valueOf(appWidgetIds[i])}); + } + } + + +// 定义一个私有的获取NoteWidgetInfo的方法,输入参数为Context和widgetId,返回值为Cursor对象,用于查询数据库中的记录 + private Cursor getNoteWidgetInfo(Context context, int widgetId) { + // 调用getContentResolver()方法获取内容解析器,并查询Notes表中id等于widgetId且parentId不等于Notes.ID_TRASH_FOLER的记录,返回结果通过PROJECTION参数指定返回哪些列,查询结果通过Cursor对象返回 + return context.getContentResolver().query(Notes.CONTENT_NOTE_URI, + PROJECTION, + NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?", + new String[] { String.valueOf(widgetId), String.valueOf(Notes.ID_TRASH_FOLER) }, + null); + } + + // 定义一个受保护的update方法,输入参数为Context、AppWidgetManager和int数组,该方法用于更新小部件的状态,此版本的update方法不包含隐私模式参数,有一个重载版本包含隐私模式参数 + protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + // 调用update方法的重载版本,输入参数为Context、AppWidgetManager、int数组以及隐私模式参数false + update(context, appWidgetManager, appWidgetIds, false); + } + + + // 定义一个私有的更新方法,输入参数为Context、AppWidgetManager、int数组以及隐私模式参数,该方法用于更新小部件的状态 +private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, boolean privacyMode) { + // 遍历appWidgetIds数组 + for (int i = 0; i < appWidgetIds.length; i++) { + // 如果appWidgetIds[i]不等于AppWidgetManager.INVALID_APPWIDGET_ID,则执行以下代码块 + if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) { + // 调用ResourceParser类的getDefaultBgId方法获取默认背景颜色id,并通过context获取对应的资源id,将结果存储在bgId变量中 + int bgId = ResourceParser.getDefaultBgId(context); + // 将字符串变量snippet初始化为空字符串 + String snippet = ""; + // 创建一个新的Intent对象,目标为NoteEditActivity类 + Intent intent = new Intent(context, NoteEditActivity.class); + // 设置Intent的标志位为FLAG_ACTIVITY_SINGLE_TOP,表示当Activity已经在任务栈顶时,不创建新的Activity实例,而是通过onNewIntent()回调通知Activity + intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + // 向Intent中添加额外的数据,Widget的id和类型 + intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]); + intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType()); + // 调用getNoteWidgetInfo方法获取与appWidgetIds[i]关联的笔记信息,将结果存储在Cursor对象c中 + Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]); + // 如果c不为空且已移动到第一条记录,则执行以下代码块 + if (c != null && c.moveToFirst()) { + // 如果c中的记录数量大于1,则表示存在多个相同widget id的记录,打印错误日志并关闭c,然后返回 + if (c.getCount() > 1) { + Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]); + c.close(); + return; + } + // 从c中获取笔记的片段内容,将结果存储在snippet变量中 + snippet = c.getString(COLUMN_SNIPPET); + // 从c中获取背景颜色id,将结果存储在bgId变量中 + bgId = c.getInt(COLUMN_BG_COLOR_ID); + // 向Intent中添加额外的数据,UID和action类型为Intent.ACTION_VIEW + intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID)); + intent.setAction(Intent.ACTION_VIEW); + } else { + // 如果c为空或没有移动到第一条记录,则将snippet设置为“widget havenot content”字符串,action类型为Intent.ACTION_INSERT_OR_EDIT + snippet = context.getResources().getString(R.string.widget_havenot_content); + intent.setAction(Intent.ACTION_INSERT_OR_EDIT); + } + + if (c != null) { + // 关闭c(此时c为null或已读取完所有数据)以释放资源并避免内存泄漏 + c.close(); + } + + + // 创建一个RemoteViews对象,这个对象可以用来控制widget的内容。 +// RemoteViews允许你操作布局中的视图,并可以将其内容发送到其他设备。 +RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId()); + +// 设置widget背景图像的资源ID。getBgResourceId()是一个抽象方法,需要子类来实现,返回的是背景图像的资源ID。 +rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId)); + +// 将背景图像的ID放入intent中,以便于后面使用。 +intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId); + +// 开始生成用于启动widget主活动的PendingIntent。这部分是注释,注释内容表示该部分代码的功能。 +/** + * Generate the pending intent to start host for the widget + */ +PendingIntent pendingIntent = null; + +// 判断是否为隐私模式。如果是,执行以下代码块;如果不是,跳过并执行下面的else代码块。 +if (privacyMode) { + // 设置widget的文本内容为"widget正在访问中"。这是在隐私模式下显示的文本。 + rv.setTextViewText(R.id.widget_text, context.getString(R.string.widget_under_visit_mode)); + + // 创建一个PendingIntent,用于启动NotesListActivity。这是一个用于在稍后执行的Intent。 + pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent(context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); +} else { + // 如果不是隐私模式,设置widget的文本内容为"snippet"。这是一个具体的文本片段,可能来自于某个笔记或其他widget数据源。 + rv.setTextViewText(R.id.widget_text, snippet); + + // 创建一个PendingIntent,用于启动在隐私模式下的主Activity。这是一个用于在稍后执行的Intent。 + pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent, PendingIntent.FLAG_UPDATE_CURRENT); +} + +// 为widget的文本设置一个点击事件。当用户点击这个文本时,会执行上面创建的PendingIntent,从而启动对应的Activity。 +rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent); + +// 使用appWidgetManager来更新指定的widget的视图。这会使得之前对RemoteViews对象的修改生效。 +appWidgetManager.updateAppWidget(appWidgetIds[i], rv); + + protected abstract int getBgResourceId(int bgId); + + protected abstract int getLayoutId(); + + protected abstract int getWidgetType(); +} From ef8500e63fa17c877aeda3c018e83850acab9bf5 Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:32:39 +0800 Subject: [PATCH 12/42] ADD file via upload --- src/widget/NoteWidgetProvider_2x.java | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/widget/NoteWidgetProvider_2x.java diff --git a/src/widget/NoteWidgetProvider_2x.java b/src/widget/NoteWidgetProvider_2x.java new file mode 100644 index 0000000..070f900 --- /dev/null +++ b/src/widget/NoteWidgetProvider_2x.java @@ -0,0 +1,41 @@ + + +package net.micode.notes.widget; + +import android.appwidget.AppWidgetManager; +import android.content.Context; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.tool.ResourceParser; + + +// 定义一个名为NoteWidgetProvider_2x的公开类,该类继承自NoteWidgetProvider类。这可能是一个针对特定屏幕密度(如视网膜屏幕)的Widget提供器。 +public class NoteWidgetProvider_2x extends NoteWidgetProvider { + + // 重写NoteWidgetProvider类中的onUpdate方法。这个方法在Widget更新时被调用。 + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + // 调用父类的onUpdate方法,进行基础的更新操作。 + super.update(context, appWidgetManager, appWidgetIds); + } + + // 重写NoteWidgetProvider类中的getLayoutId方法,返回适用于2x屏幕的布局ID。 + @Override + protected int getLayoutId() { + return R.layout.widget_2x; // 返回2x屏幕的布局ID。 + } + + // 重写NoteWidgetProvider类中的getBgResourceId方法,用于获取2x屏幕的背景资源ID。 + @Override + protected int getBgResourceId(int bgId) { + // 通过ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId)方法获取2x屏幕的背景资源ID。 + return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId); + } + + // 重写NoteWidgetProvider类中的getWidgetType方法,返回Widget的类型,这里返回的是2x屏幕的Widget类型。 + @Override + protected int getWidgetType() { + return Notes.TYPE_WIDGET_2X; // 返回2x屏幕的Widget类型。 + } +} \ No newline at end of file From c63c1fbcc0673658bf68d4c883ca8f39992bddd3 Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:32:48 +0800 Subject: [PATCH 13/42] ADD file via upload --- src/widget/NoteWidgetProvider_4x.java | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/widget/NoteWidgetProvider_4x.java diff --git a/src/widget/NoteWidgetProvider_4x.java b/src/widget/NoteWidgetProvider_4x.java new file mode 100644 index 0000000..aab04a6 --- /dev/null +++ b/src/widget/NoteWidgetProvider_4x.java @@ -0,0 +1,41 @@ + + +package net.micode.notes.widget; + +import android.appwidget.AppWidgetManager; +import android.content.Context; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.tool.ResourceParser; + + +// 定义一个名为NoteWidgetProvider_4x的公开类,该类继承自NoteWidgetProvider类。这可能是一个针对特定屏幕密度(如超高分辨率屏幕)的Widget提供器。 +public class NoteWidgetProvider_4x extends NoteWidgetProvider { + + // 重写NoteWidgetProvider类中的onUpdate方法。这个方法在Widget更新时被调用。此方法调用父类的onUpdate方法,进行基础的更新操作。 + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + super.update(context, appWidgetManager, appWidgetIds); + } + + // 定义一个受保护的方法getLayoutId,返回适用于4x屏幕的布局ID。 + protected int getLayoutId() { + // 返回4x屏幕的布局ID。 + return R.layout.widget_4x; + } + + // 重写NoteWidgetProvider类中的getBgResourceId方法,用于获取4x屏幕的背景资源ID。此方法接收一个int类型的bgId作为参数。 + @Override + protected int getBgResourceId(int bgId) { + // 通过ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId)方法获取4x屏幕的背景资源ID,并返回。 + return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId); + } + + // 重写NoteWidgetProvider类中的getWidgetType方法,返回Widget的类型,这里返回的是4x屏幕的Widget类型。 + @Override + protected int getWidgetType() { + // 返回4x屏幕的Widget类型。 + return Notes.TYPE_WIDGET_4X; + } +} \ No newline at end of file From 7a5fc4a1ca1eceed0971bf6a498a3ee371d13241 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:38:07 +0800 Subject: [PATCH 14/42] ADD file via upload --- src/ui/AlarmAlertActivity.java | 208 +++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 src/ui/AlarmAlertActivity.java diff --git a/src/ui/AlarmAlertActivity.java b/src/ui/AlarmAlertActivity.java new file mode 100644 index 0000000..9589ed0 --- /dev/null +++ b/src/ui/AlarmAlertActivity.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.DialogInterface.OnDismissListener; +import android.content.Intent; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.PowerManager; +import android.provider.Settings; +import android.view.Window; +import android.view.WindowManager; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.tool.DataUtils; + +import java.io.IOException; + +public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { + private long mNoteId; //文本在数据库存储中的ID号 + private String mSnippet; //闹钟提示时出现的文本片段 + private static final int SNIPPET_PREW_MAX_LEN = 60; + MediaPlayer mPlayer; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //Bundle类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的 + //onsaveInstanceState方法是用来保存Activity的状态的 + //能从onCreate的参数savedInsanceState中获得状态数据 + requestWindowFeature(Window.FEATURE_NO_TITLE); + //界面显示——无标题 + + final Window win = getWindow(); + win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); + + if (!isScreenOn()) { + win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + //保持窗体点亮 + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + //将窗体点亮 + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON + //允许窗体点亮时锁屏 + | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); + }//在手机锁屏后如果到了闹钟提示时间,点亮屏幕 + + Intent intent = getIntent(); + + try { + mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); + mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); + //根据ID从数据库中获取标签的内容; + //getContentResolver()是实现数据共享,实例存储。 + mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, + SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info) + : mSnippet; + //判断标签片段是否达到符合长度 + } catch (IllegalArgumentException e) { + e.printStackTrace(); + return; + } + /* + try + { + // 代码区 + } + catch(Exception e) + { + // 异常处理 + } + 代码区如果有错误,就会返回所写异常的处理。*/ + mPlayer = new MediaPlayer(); + if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { + showActionDialog(); + //弹出对话框 + playAlarmSound(); + //闹钟提示音激发 + } else { + finish(); + //完成闹钟动作 + } + } + + private boolean isScreenOn() { + //判断屏幕是否锁屏,调用系统函数判断,最后返回值是布尔类型 + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + return pm.isScreenOn(); + } + + private void playAlarmSound() { + //闹钟提示音激发 + Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); + //调用系统的铃声管理URI,得到闹钟提示音 + int silentModeStreams = Settings.System.getInt(getContentResolver(), + Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); + + if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { + mPlayer.setAudioStreamType(silentModeStreams); + } else { + mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); + } + try { + mPlayer.setDataSource(this, url); + //方法:setDataSource(Context context, Uri uri) + //解释:无返回值,设置多媒体数据来源【根据 Uri】 + mPlayer.prepare(); + //准备同步 + mPlayer.setLooping(true); + //设置是否循环播放 + mPlayer.start(); + //开始播放 + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + //e.printStackTrace()函数功能是抛出异常, 还将显示出更深的调用信息 + //System.out.println(e),这个方法打印出异常,并且输出在哪里出现的异常 + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private void showActionDialog() { + AlertDialog.Builder dialog = new AlertDialog.Builder(this); + //AlertDialog的构造方法全部是Protected的 + //所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。 + //要创建一个AlertDialog,就要用到AlertDialog.Builder中的create()方法 + //如这里的dialog就是新建了一个AlertDialog + dialog.setTitle(R.string.app_name); + //为对话框设置标题 + dialog.setMessage(mSnippet); + //为对话框设置内容 + dialog.setPositiveButton(R.string.notealert_ok, this); + //给对话框添加"Yes"按钮 + if (isScreenOn()) { + dialog.setNegativeButton(R.string.notealert_enter, this); + }//对话框添加"No"按钮 + dialog.show().setOnDismissListener(this); + } + + public void onClick(DialogInterface dialog, int which) { + switch (which) { + //用which来选择click后下一步的操作 + case DialogInterface.BUTTON_NEGATIVE: + //这是取消操作 + Intent intent = new Intent(this, NoteEditActivity.class); + //实现两个类间的数据传输 + intent.setAction(Intent.ACTION_VIEW); + //设置动作属性 + intent.putExtra(Intent.EXTRA_UID, mNoteId); + //实现key-value对 + //EXTRA_UID为key;mNoteId为键 + startActivity(intent); + //开始动作 + break; + default: + //这是确定操作 + break; + } + } + + public void onDismiss(DialogInterface dialog) { + //忽略 + stopAlarmSound(); + //停止闹钟声音 + finish(); + //完成该动作 + } + + private void stopAlarmSound() { + if (mPlayer != null) { + mPlayer.stop(); + //停止播放 + mPlayer.release(); + //释放MediaPlayer对象 + mPlayer = null; + } + } +} From d87a62c187d92fd436c73c8528a34dc9cdf0d1c1 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:38:25 +0800 Subject: [PATCH 15/42] ADD file via upload --- src/ui/AlarmInitReceiver.java | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/ui/AlarmInitReceiver.java diff --git a/src/ui/AlarmInitReceiver.java b/src/ui/AlarmInitReceiver.java new file mode 100644 index 0000000..724373f --- /dev/null +++ b/src/ui/AlarmInitReceiver.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; + +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; + + +public class AlarmInitReceiver extends BroadcastReceiver { + + private static final String [] PROJECTION = new String [] { + NoteColumns.ID, + NoteColumns.ALERTED_DATE + }; + //对数据库的操作,调用标签ID和闹钟时间 + private static final int COLUMN_ID = 0; + private static final int COLUMN_ALERTED_DATE = 1; + + @Override + public void onReceive(Context context, Intent intent) { + long currentDate = System.currentTimeMillis(); + //System.currentTimeMillis()产生一个当前的毫秒 + //这个毫秒其实就是自1970年1月1日0时起的毫秒数 + Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI, + PROJECTION, + NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE, + new String[] { String.valueOf(currentDate) }, + //将long变量currentDate转化为字符串 + null); + //Cursor在这里的作用是通过查找数据库中的标签内容,找到和当前系统时间相等的标签 + + if (c != null) { + if (c.moveToFirst()) { + do { + long alertDate = c.getLong(COLUMN_ALERTED_DATE); + Intent sender = new Intent(context, AlarmReceiver.class); + sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); + AlarmManager alermManager = (AlarmManager) context + .getSystemService(Context.ALARM_SERVICE); + alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); + } while (c.moveToNext()); + } + c.close(); + } + //然而通过网上查找资料发现,对于闹钟机制的启动,通常需要上面的几个步骤 + //如新建Intent、PendingIntent以及AlarmManager等 + //这里就是根据数据库里的闹钟时间创建一个闹钟机制 + } +} \ No newline at end of file From af3b774cc44685139f6f1b33079e8ec845399722 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:38:34 +0800 Subject: [PATCH 16/42] ADD file via upload --- src/ui/AlarmReceiver.java | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/ui/AlarmReceiver.java diff --git a/src/ui/AlarmReceiver.java b/src/ui/AlarmReceiver.java new file mode 100644 index 0000000..a446178 --- /dev/null +++ b/src/ui/AlarmReceiver.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class AlarmReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + intent.setClass(context, AlarmAlertActivity.class); + //启动AlarmAlertActivity + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + //activity要存在于activity的栈中,而非activity的途径启动activity时必然不存在一个activity的栈 + //所以要新起一个栈装入启动的activity + context.startActivity(intent); + } +} +//这是实现alarm这个功能最接近用户层的包,基于上面的两个包, +//作用还需要深究但是对于setClass和addFlags的 + \ No newline at end of file From 29f5f469c5e0ff584b8a996df092ba72a8150387 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:38:41 +0800 Subject: [PATCH 17/42] ADD file via upload --- src/ui/DateTimePicker.java | 507 +++++++++++++++++++++++++++++++++++++ 1 file changed, 507 insertions(+) create mode 100644 src/ui/DateTimePicker.java diff --git a/src/ui/DateTimePicker.java b/src/ui/DateTimePicker.java new file mode 100644 index 0000000..9f809e9 --- /dev/null +++ b/src/ui/DateTimePicker.java @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import java.text.DateFormatSymbols; +import java.util.Calendar; + +import net.micode.notes.R; + + +import android.content.Context; +import android.text.format.DateFormat; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.NumberPicker; + +public class DateTimePicker extends FrameLayout { + //FrameLayout是布局模板之一 + //所有的子元素全部在屏幕的右上方 + private static final boolean DEFAULT_ENABLE_STATE = true; + + private static final int HOURS_IN_HALF_DAY = 12; + private static final int HOURS_IN_ALL_DAY = 24; + private static final int DAYS_IN_ALL_WEEK = 7; + 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 HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0; + private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23; + private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1; + private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12; + private static final int MINUT_SPINNER_MIN_VAL = 0; + private static final int MINUT_SPINNER_MAX_VAL = 59; + private static final int AMPM_SPINNER_MIN_VAL = 0; + private static final int AMPM_SPINNER_MAX_VAL = 1; + //初始化控件 + private final NumberPicker mDateSpinner; + private final NumberPicker mHourSpinner; + private final NumberPicker mMinuteSpinner; + private final NumberPicker mAmPmSpinner; + //NumberPicker是数字选择器 + //这里定义的四个变量全部是在设置闹钟时需要选择的变量(如日期、时、分、上午或者下午) + private Calendar mDate; + //定义了Calendar类型的变量mDate,用于操作时间 + private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; + + private boolean mIsAm; + + private boolean mIs24HourView; + + private boolean mIsEnabled = DEFAULT_ENABLE_STATE; + + private boolean mInitialising; + + private OnDateTimeChangedListener mOnDateTimeChangedListener; + + private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() { + @Override + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal); + updateDateControl(); + onDateTimeChanged(); + } + };//OnValueChangeListener,这是时间改变监听器,这里主要是对日期的监听 + //将现在日期的值传递给mDate;updateDateControl是同步操作 + + private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() { + //这里是对 小时(Hour) 的监听 + @Override + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + boolean isDateChanged = false; + Calendar cal = Calendar.getInstance(); + //声明一个Calendar的变量cal,便于后续的操作 + if (!mIs24HourView) { + if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) { + cal.setTimeInMillis(mDate.getTimeInMillis()); + cal.add(Calendar.DAY_OF_YEAR, 1); + isDateChanged = true; + //这里是对于12小时制时,晚上11点和12点交替时对日期的更改 + } else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) { + cal.setTimeInMillis(mDate.getTimeInMillis()); + cal.add(Calendar.DAY_OF_YEAR, -1); + isDateChanged = true; + } + //这里是对于12小时制时,凌晨11点和12点交替时对日期的更改 + if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY || + oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) { + mIsAm = !mIsAm; + updateAmPmControl(); + }//这里是对于12小时制时,中午11点和12点交替时对AM和PM的更改 + } else { + if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) { + cal.setTimeInMillis(mDate.getTimeInMillis()); + cal.add(Calendar.DAY_OF_YEAR, 1); + isDateChanged = true; + //这里是对于24小时制时,晚上11点和12点交替时对日期的更改 + } else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) { + cal.setTimeInMillis(mDate.getTimeInMillis()); + cal.add(Calendar.DAY_OF_YEAR, -1); + isDateChanged = true; + } + } //这里是对于12小时制时,凌晨11点和12点交替时对日期的更改 + int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY); + //通过数字选择器对newHour的赋值 + mDate.set(Calendar.HOUR_OF_DAY, newHour); + //通过set函数将新的Hour值传给mDate + onDateTimeChanged(); + if (isDateChanged) { + setCurrentYear(cal.get(Calendar.YEAR)); + setCurrentMonth(cal.get(Calendar.MONTH)); + setCurrentDay(cal.get(Calendar.DAY_OF_MONTH)); + } + } + }; + + private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() { + @Override + //这里是对 分钟(Minute)改变的监听 + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + int minValue = mMinuteSpinner.getMinValue(); + int maxValue = mMinuteSpinner.getMaxValue(); + int offset = 0; + //设置offset,作为小时改变的一个记录数据 + if (oldVal == maxValue && newVal == minValue) { + offset += 1; + } else if (oldVal == minValue && newVal == maxValue) { + offset -= 1; + } + //如果原值为59,新值为0,则offset加1 + //如果原值为0,新值为59,则offset减1 + if (offset != 0) { + mDate.add(Calendar.HOUR_OF_DAY, offset); + mHourSpinner.setValue(getCurrentHour()); + updateDateControl(); + int newHour = getCurrentHourOfDay(); + if (newHour >= HOURS_IN_HALF_DAY) { + mIsAm = false; + updateAmPmControl(); + } else { + mIsAm = true; + updateAmPmControl(); + } + } + mDate.set(Calendar.MINUTE, newVal); + onDateTimeChanged(); + } + }; + + private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() { + //对AM和PM的监听 + @Override + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + mIsAm = !mIsAm; + if (mIsAm) { + mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY); + } else { + mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY); + } + updateAmPmControl(); + onDateTimeChanged(); + } + }; + + public interface OnDateTimeChangedListener { + void onDateTimeChanged(DateTimePicker view, int year, int month, + int dayOfMonth, int hourOfDay, int minute); + } + + public DateTimePicker(Context context) { + this(context, System.currentTimeMillis()); + }//通过对数据库的访问,获取当前的系统时间 + + public DateTimePicker(Context context, long date) { + this(context, date, DateFormat.is24HourFormat(context)); + }//上面函数的得到的是一个天文数字(1970至今的秒数),需要DateFormat将其变得有意义 + + public DateTimePicker(Context context, long date, boolean is24HourView) { + super(context); + //获取系统时间 + mDate = Calendar.getInstance(); + mInitialising = true; + mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY; + inflate(context, R.layout.datetime_picker, this); + //如果当前Activity里用到别的layout,比如对话框layout + //还要设置这个layout上的其他组件的内容,就必须用inflate()方法先将对话框的layout找出来 + //然后再用findViewById()找到它上面的其它组件 + mDateSpinner = (NumberPicker) findViewById(R.id.date); + mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL); + mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL); + mDateSpinner.setOnValueChangedListener(mOnDateChangedListener); + + mHourSpinner = (NumberPicker) findViewById(R.id.hour); + mHourSpinner.setOnValueChangedListener(mOnHourChangedListener); + mMinuteSpinner = (NumberPicker) findViewById(R.id.minute); + mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL); + mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL); + mMinuteSpinner.setOnLongPressUpdateInterval(100); + mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener); + + String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings(); + mAmPmSpinner = (NumberPicker) findViewById(R.id.amPm); + mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL); + mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL); + mAmPmSpinner.setDisplayedValues(stringsForAmPm); + mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener); + + // update controls to initial state + updateDateControl(); + updateHourControl(); + updateAmPmControl(); + + set24HourView(is24HourView); + + // set to current time + setCurrentDate(date); + + setEnabled(isEnabled()); + + // set the content descriptions + mInitialising = false; + } + + @Override + public void setEnabled(boolean enabled) { + if (mIsEnabled == enabled) { + return; + } + super.setEnabled(enabled); + mDateSpinner.setEnabled(enabled); + mMinuteSpinner.setEnabled(enabled); + mHourSpinner.setEnabled(enabled); + mAmPmSpinner.setEnabled(enabled); + mIsEnabled = enabled; + } + //存在疑问!!!!!!!!!!!!!setEnabled的作用 + //下面的代码通过原程序的注释已经比较清晰,另外可以通过函数名来判断 + //下面的各函数主要是对上面代码引用到的各函数功能的实现 + @Override + public boolean isEnabled() { + return mIsEnabled; + } + + /** + * Get the current date in millis + * + * @return the current date in millis + */ + public long getCurrentDateInTimeMillis() { + return mDate.getTimeInMillis(); + }//实现函数——得到当前的秒数 + + /** + * Set the current date + * + * @param date The current date in millis + */ + public void setCurrentDate(long date) { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(date); + setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), + cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)); + }//实现函数功能——设置当前的时间,参数是date + + /** + * Set the current date + * + * @param year The current year + * @param month The current month + * @param dayOfMonth The current dayOfMonth + * @param hourOfDay The current hourOfDay + * @param minute The current minute + */ + public void setCurrentDate(int year, int month, + int dayOfMonth, int hourOfDay, int minute) { + setCurrentYear(year); + setCurrentMonth(month); + setCurrentDay(dayOfMonth); + setCurrentHour(hourOfDay); + setCurrentMinute(minute); + }//实现函数功能——设置当前的时间,参数是各详细的变量 + + /** + * Get current year + * + * @return The current year + */ + //下面是得到year、month、day等值 + public int getCurrentYear() { + return mDate.get(Calendar.YEAR); + } + + /** + * Set current year + * + * @param year The current year + */ + public void setCurrentYear(int year) { + if (!mInitialising && year == getCurrentYear()) { + return; + } + mDate.set(Calendar.YEAR, year); + updateDateControl(); + onDateTimeChanged(); + } + + /** + * Get current month in the year + * + * @return The current month in the year + */ + public int getCurrentMonth() { + return mDate.get(Calendar.MONTH); + } + + /** + * Set current month in the year + * + * @param month The month in the year + */ + public void setCurrentMonth(int month) { + if (!mInitialising && month == getCurrentMonth()) { + return; + } + mDate.set(Calendar.MONTH, month); + updateDateControl(); + onDateTimeChanged(); + } + + /** + * Get current day of the month + * + * @return The day of the month + */ + public int getCurrentDay() { + return mDate.get(Calendar.DAY_OF_MONTH); + } + + /** + * Set current day of the month + * + * @param dayOfMonth The day of the month + */ + public void setCurrentDay(int dayOfMonth) { + if (!mInitialising && dayOfMonth == getCurrentDay()) { + return; + } + mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); + updateDateControl(); + onDateTimeChanged(); + } + + /** + * Get current hour in 24 hour mode, in the range (0~23) + * @return The current hour in 24 hour mode + */ + public int getCurrentHourOfDay() { + return mDate.get(Calendar.HOUR_OF_DAY); + } + + private int getCurrentHour() { + if (mIs24HourView){ + return getCurrentHourOfDay(); + } else { + int hour = getCurrentHourOfDay(); + if (hour > HOURS_IN_HALF_DAY) { + return hour - HOURS_IN_HALF_DAY; + } else { + return hour == 0 ? HOURS_IN_HALF_DAY : hour; + } + } + } + + /** + * Set current hour in 24 hour mode, in the range (0~23) + * + * @param hourOfDay + */ + public void setCurrentHour(int hourOfDay) { + if (!mInitialising && hourOfDay == getCurrentHourOfDay()) { + return; + } + mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); + if (!mIs24HourView) { + if (hourOfDay >= HOURS_IN_HALF_DAY) { + mIsAm = false; + if (hourOfDay > HOURS_IN_HALF_DAY) { + hourOfDay -= HOURS_IN_HALF_DAY; + } + } else { + mIsAm = true; + if (hourOfDay == 0) { + hourOfDay = HOURS_IN_HALF_DAY; + } + } + updateAmPmControl(); + } + mHourSpinner.setValue(hourOfDay); + onDateTimeChanged(); + } + + /** + * Get currentMinute + * + * @return The Current Minute + */ + public int getCurrentMinute() { + return mDate.get(Calendar.MINUTE); + } + + /** + * Set current minute + */ + public void setCurrentMinute(int minute) { + if (!mInitialising && minute == getCurrentMinute()) { + return; + } + mMinuteSpinner.setValue(minute); + mDate.set(Calendar.MINUTE, minute); + onDateTimeChanged(); + } + + /** + * @return true if this is in 24 hour view else false. + */ + public boolean is24HourView () { + return mIs24HourView; + } + + /** + * Set whether in 24 hour or AM/PM mode. + * + * @param is24HourView True for 24 hour mode. False for AM/PM mode. + */ + public void set24HourView(boolean is24HourView) { + if (mIs24HourView == is24HourView) { + return; + } + mIs24HourView = is24HourView; + mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE); + int hour = getCurrentHourOfDay(); + updateHourControl(); + setCurrentHour(hour); + updateAmPmControl(); + } + + private void updateDateControl() { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(mDate.getTimeInMillis()); + cal.add(Calendar.DAY_OF_YEAR, -DAYS_IN_ALL_WEEK / 2 - 1); + mDateSpinner.setDisplayedValues(null); + for (int i = 0; i < DAYS_IN_ALL_WEEK; ++i) { + cal.add(Calendar.DAY_OF_YEAR, 1); + mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal); + } + mDateSpinner.setDisplayedValues(mDateDisplayValues); + mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); + mDateSpinner.invalidate(); + }// 对于星期几的算法 + + private void updateAmPmControl() { + if (mIs24HourView) { + mAmPmSpinner.setVisibility(View.GONE); + } else { + int index = mIsAm ? Calendar.AM : Calendar.PM; + mAmPmSpinner.setValue(index); + mAmPmSpinner.setVisibility(View.VISIBLE); + }// 对于上下午操作的算法 + } + + private void updateHourControl() { + if (mIs24HourView) { + mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW); + mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW); + } else { + mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW); + mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW); + }// 对与小时的算法 + } + + /** + * Set the callback that indicates the 'Set' button has been pressed. + * @param callback the callback, if null will do nothing + */ + public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) { + mOnDateTimeChangedListener = callback; + } + + private void onDateTimeChanged() { + if (mOnDateTimeChangedListener != null) { + mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(), + getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute()); + } + } +} From 545dc33b49a190b6b5a2fda9f22247d60b0ffedf Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:38:49 +0800 Subject: [PATCH 18/42] ADD file via upload --- src/ui/DateTimePickerDialog.java | 103 +++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/ui/DateTimePickerDialog.java diff --git a/src/ui/DateTimePickerDialog.java b/src/ui/DateTimePickerDialog.java new file mode 100644 index 0000000..41f09e8 --- /dev/null +++ b/src/ui/DateTimePickerDialog.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import java.util.Calendar; + +import net.micode.notes.R; +import net.micode.notes.ui.DateTimePicker; +import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.text.format.DateFormat; +import android.text.format.DateUtils; + +public class DateTimePickerDialog extends AlertDialog implements OnClickListener { + + private Calendar mDate = Calendar.getInstance(); + //创建一个Calendar类型的变量 mDate,方便时间的操作 + private boolean mIs24HourView; + private OnDateTimeSetListener mOnDateTimeSetListener; + //声明一个时间日期滚动选择控件 mOnDateTimeSetListener + private DateTimePicker mDateTimePicker; + //DateTimePicker控件,控件一般用于让用户可以从日期列表中选择单个值。 + //运行时,单击控件边上的下拉箭头,会显示为两个部分:一个下拉列表,一个用于选择日期的 + + public interface OnDateTimeSetListener { + void OnDateTimeSet(AlertDialog dialog, long date); + } + + public DateTimePickerDialog(Context context, long date) { + //对该界面对话框的实例化 + super(context); + //对数据库的操作 + mDateTimePicker = new DateTimePicker(context); + setView(mDateTimePicker); + //添加一个子视图 + mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() { + public void onDateTimeChanged(DateTimePicker view, int year, int month, + int dayOfMonth, int hourOfDay, int minute) { + mDate.set(Calendar.YEAR, year); + mDate.set(Calendar.MONTH, month); + mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); + mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); + mDate.set(Calendar.MINUTE, minute); + //将视图中的各选项设置为系统当前时间 + updateTitle(mDate.getTimeInMillis()); + } + }); + mDate.setTimeInMillis(date); + //得到系统时间 + mDate.set(Calendar.SECOND, 0); + //将秒数设置为0 + mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); + setButton(context.getString(R.string.datetime_dialog_ok), this); + setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null); + //设置按钮 + set24HourView(DateFormat.is24HourFormat(this.getContext())); + //时间标准化打印 + updateTitle(mDate.getTimeInMillis()); + } + + public void set24HourView(boolean is24HourView) { + mIs24HourView = is24HourView; + } + + public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { + mOnDateTimeSetListener = callBack; + }//将时间日期滚动选择控件实例化 + + private void updateTitle(long date) { + int flag = + DateUtils.FORMAT_SHOW_YEAR | + DateUtils.FORMAT_SHOW_DATE | + DateUtils.FORMAT_SHOW_TIME; + flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR; + setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); + }//android开发中常见日期管理工具类(API)——DateUtils:按照上下午显示时间 + + public void onClick(DialogInterface arg0, int arg1) { + if (mOnDateTimeSetListener != null) { + mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); + } + }//第一个参数arg0是接收到点击事件的对话框 + //第二个参数arg1是该对话框上的按钮 + +} \ No newline at end of file From 7d0776aac167a7a99d43d23d1cf8a8c90b613a3b Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:38:57 +0800 Subject: [PATCH 19/42] ADD file via upload --- src/ui/DropdownMenu.java | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/ui/DropdownMenu.java diff --git a/src/ui/DropdownMenu.java b/src/ui/DropdownMenu.java new file mode 100644 index 0000000..591e128 --- /dev/null +++ b/src/ui/DropdownMenu.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.content.Context; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.PopupMenu; +import android.widget.PopupMenu.OnMenuItemClickListener; + +import net.micode.notes.R; + +public class DropdownMenu { + private Button mButton; + private PopupMenu mPopupMenu; + //声明一个下拉菜单 + private Menu mMenu; + + public DropdownMenu(Context context, Button button, int menuId) { + mButton = button; + mButton.setBackgroundResource(R.drawable.dropdown_icon); + //设置这个view的背景 + mPopupMenu = new PopupMenu(context, mButton); + mMenu = mPopupMenu.getMenu(); + mPopupMenu.getMenuInflater().inflate(menuId, mMenu); + //MenuInflater是用来实例化Menu目录下的Menu布局文件 + //根据ID来确认menu的内容选项 + mButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + mPopupMenu.show(); + } + }); + } + + public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) { + if (mPopupMenu != null) { + mPopupMenu.setOnMenuItemClickListener(listener); + }//设置菜单的监听 + } + + public MenuItem findItem(int id) { + return mMenu.findItem(id); + }//对于菜单选项的初始化,根据索引搜索菜单需要的选项 + + public void setTitle(CharSequence title) { + mButton.setText(title); + }//布局文件,设置标题 +} \ No newline at end of file From 221b97abeb00c530ea775ba80b2a762aa426a430 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:39:04 +0800 Subject: [PATCH 20/42] ADD file via upload --- src/ui/FoldersListAdapter.java | 87 ++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/ui/FoldersListAdapter.java diff --git a/src/ui/FoldersListAdapter.java b/src/ui/FoldersListAdapter.java new file mode 100644 index 0000000..d04b4cf --- /dev/null +++ b/src/ui/FoldersListAdapter.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.content.Context; +import android.database.Cursor; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; + + +public class FoldersListAdapter extends CursorAdapter { + //CursorAdapter是Cursor和ListView的接口 + //FoldersListAdapter继承了CursorAdapter的类 + //主要作用是便签数据库和用户的交互 + //这里就是用folder(文件夹)的形式展现给用户 + public static final String [] PROJECTION = { + NoteColumns.ID, + NoteColumns.SNIPPET + };//调用数据库中便签的ID和片段 + + public static final int ID_COLUMN = 0; + public static final int NAME_COLUMN = 1; + + public FoldersListAdapter(Context context, Cursor c) { + super(context, c); + // TODO Auto-generated constructor stub + }//数据库操作 + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + //ViewGroup是容器 + return new FolderListItem(context); + }//创建一个文件夹,对于各文件夹中子标签的初始化 + + @Override + public void bindView(View view, Context context, Cursor cursor) { + if (view instanceof FolderListItem) { + String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context + .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); + ((FolderListItem) view).bind(folderName); + } + }//将各个布局文件绑定起来 + + public String getFolderName(Context context, int position) { + Cursor cursor = (Cursor) getItem(position); + return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context + .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); + }//根据数据库中标签的ID得到标签的各项内容 + + private class FolderListItem extends LinearLayout { + private TextView mName; + + public FolderListItem(Context context) { + super(context); + //操作数据库 + inflate(context, R.layout.folder_list_item, this); + //根据布局文件的名字等信息将其找出来 + mName = (TextView) findViewById(R.id.tv_folder_name); + } + + public void bind(String name) { + mName.setText(name); + } + } + +} \ No newline at end of file From e6b369e50156a16ef9a0c7e892a21c6eb903846b Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:39:12 +0800 Subject: [PATCH 21/42] ADD file via upload --- src/ui/NoteEditActivity.java | 1083 ++++++++++++++++++++++++++++++++++ 1 file changed, 1083 insertions(+) create mode 100644 src/ui/NoteEditActivity.java diff --git a/src/ui/NoteEditActivity.java b/src/ui/NoteEditActivity.java new file mode 100644 index 0000000..bb1da27 --- /dev/null +++ b/src/ui/NoteEditActivity.java @@ -0,0 +1,1083 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.app.Activity; +import android.app.AlarmManager; +import android.app.AlertDialog; +import android.app.PendingIntent; +import android.app.SearchManager; +import android.appwidget.AppWidgetManager; +import android.content.ContentUris; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Paint; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.format.DateUtils; +import android.text.style.BackgroundColorSpan; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.WindowManager; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.TextNote; +import net.micode.notes.model.WorkingNote; +import net.micode.notes.model.WorkingNote.NoteSettingChangedListener; +import net.micode.notes.tool.DataUtils; +import net.micode.notes.tool.ResourceParser; +import net.micode.notes.tool.ResourceParser.TextAppearanceResources; +import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener; +import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener; +import net.micode.notes.widget.NoteWidgetProvider_2x; +import net.micode.notes.widget.NoteWidgetProvider_4x; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class NoteEditActivity extends Activity implements OnClickListener, + NoteSettingChangedListener, OnTextViewChangeListener { + //该类主要是针对标签的编辑 + //继承了系统内部许多和监听有关的类 + private class HeadViewHolder { + public TextView tvModified; + + public ImageView ivAlertIcon; + + public TextView tvAlertDate; + + public ImageView ibSetBgColor; + } + //使用Map实现数据存储 + private static final Map sBgSelectorBtnsMap = new HashMap(); + static { + sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); + sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED); + sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE); + sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN); + sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE); + //put函数是将指定值和指定键相连 + } + + private static final Map sBgSelectorSelectionMap = new HashMap(); + static { + sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select); + sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select); + sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select); + sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select); + sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); + //put函数是将指定值和指定键相连 + } + + private static final Map sFontSizeBtnsMap = new HashMap(); + static { + sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE); + sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL); + sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM); + sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER); + //put函数是将指定值和指定键相连 + } + + private static final Map sFontSelectorSelectionMap = new HashMap(); + static { + sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select); + sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select); + sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select); + sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); + //put函数是将指定值和指定键相连 + } + + private static final String TAG = "NoteEditActivity"; + + private HeadViewHolder mNoteHeaderHolder; + + private View mHeadViewPanel; + //私有化一个界面操作mHeadViewPanel,对表头的操作 + private View mNoteBgColorSelector; + //私有化一个界面操作mNoteBgColorSelector,对背景颜色的操作 + private View mFontSizeSelector; + //私有化一个界面操作mFontSizeSelector,对标签字体的操作 + private EditText mNoteEditor; + //声明编辑控件,对文本操作 + private View mNoteEditorPanel; + //私有化一个界面操作mNoteEditorPanel,文本编辑的控制板 + //private WorkingNote mWorkingNote; + public WorkingNote mWorkingNote; + //对模板WorkingNote的初始化 + private SharedPreferences mSharedPrefs; + //私有化SharedPreferences的数据存储方式 + //它的本质是基于XML文件存储key-value键值对数据 + private int mFontSizeId; + //用于操作字体的大小 + private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; + + private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; + + public static final String TAG_CHECKED = String.valueOf('\u221A'); + public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); + + private LinearLayout mEditTextList; + //线性布局 + private String mUserQuery; + private Pattern mPattern; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.setContentView(R.layout.note_edit); + //对数据库的访问操作 + if (savedInstanceState == null && !initActivityState(getIntent())) { + finish(); + return; + } + initResources(); + } + + /** + * Current activity may be killed when the memory is low. Once it is killed, for another time + * user load this activity, we should restore the former state + */ + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID)); + if (!initActivityState(intent)) { + finish(); + return; + } + Log.d(TAG, "Restoring from killed activity"); + }//为防止内存不足时程序的终止,在这里有一个保存现场的函数 + } + + private boolean initActivityState(Intent intent) { + /** + * If the user specified the {@link Intent#ACTION_VIEW} but not provided with id, + * then jump to the NotesListActivity + */ + mWorkingNote = null; + if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { + long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); + mUserQuery = ""; + //如果用户实例化标签时,系统并未给出标签ID + /** + * Starting from the searched result + */ + //根据键值查找ID + if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) { + noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); + mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); + } + //如果ID在数据库中未找到 + if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { + Intent jump = new Intent(this, NotesListActivity.class); + startActivity(jump); + //程序将跳转到上面声明的intent——jump + showToast(R.string.error_note_not_exist); + finish(); + return false; + } + //ID在数据库中找到 + else { + mWorkingNote = WorkingNote.load(this, noteId); + if (mWorkingNote == null) { + Log.e(TAG, "load note failed with note id" + noteId); + //打印出红色的错误信息 + finish(); + return false; + } + } + //setSoftInputMode——软键盘输入模式 + getWindow().setSoftInputMode( + WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN + | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { + // intent.getAction() + // 大多用于broadcast发送广播时给机制(intent)设置一个action,就是一个字符串 + // 用户可以通过receive(接受)intent,通过 getAction得到的字符串,来决定做什么 + long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); + int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID); + int widgetType = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, + Notes.TYPE_WIDGET_INVALIDE); + int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, + ResourceParser.getDefaultBgId(this)); + // intent.getInt(Long、String)Extra是对各变量的语法分析 + // Parse call-record note + String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); + long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0); + if (callDate != 0 && phoneNumber != null) { + if (TextUtils.isEmpty(phoneNumber)) { + Log.w(TAG, "The call record number is null"); + } + long noteId = 0; + if ((noteId = DataUtils.getNoteIdByPhoneNumberAndCallDate(getContentResolver(), + phoneNumber, callDate)) > 0) { + mWorkingNote = WorkingNote.load(this, noteId); + if (mWorkingNote == null) { + Log.e(TAG, "load call note failed with note id" + noteId); + finish(); + return false; + } + //将电话号码与手机的号码簿相关 + } else { + mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, + widgetType, bgResId); + mWorkingNote.convertToCallNote(phoneNumber, callDate); + // + } + } else { + mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType, + bgResId); + }//创建一个新的WorkingNote + + getWindow().setSoftInputMode( + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE + | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + } else { + Log.e(TAG, "Intent not specified action, should not support"); + finish(); + return false; + } + mWorkingNote.setOnSettingStatusChangedListener(this); + return true; + } + + @Override + protected void onResume() { + super.onResume(); + initNoteScreen(); + } + + private void initNoteScreen() { + //对界面的初始化操作 + mNoteEditor.setTextAppearance(this, TextAppearanceResources + .getTexAppearanceResource(mFontSizeId)); + //设置外观 + if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { + switchToListMode(mWorkingNote.getContent()); + } else { + mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); + mNoteEditor.setSelection(mNoteEditor.getText().length()); + } + for (Integer id : sBgSelectorSelectionMap.keySet()) { + findViewById(sBgSelectorSelectionMap.get(id)).setVisibility(View.GONE); + } + mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); + mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); + + mNoteHeaderHolder.tvModified.setText(DateUtils.formatDateTime(this, + mWorkingNote.getModifiedDate(), DateUtils.FORMAT_SHOW_DATE + | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME + | DateUtils.FORMAT_SHOW_YEAR)); + + /** + * TODO: Add the menu for setting alert. Currently disable it because the DateTimePicker + * is not ready + */ + showAlertHeader(); + } + //设置闹钟的显示 + private void showAlertHeader() { + if (mWorkingNote.hasClockAlert()) { + long time = System.currentTimeMillis(); + if (time > mWorkingNote.getAlertDate()) { + mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired); + } + //如果系统时间大于了闹钟设置的时间,那么闹钟失效 + else { + mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( + mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); + } + mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE); + mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); + //显示闹钟开启的图标 + } else { + mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE); + mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE); + }; + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + initActivityState(intent); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + /** + * For new note without note id, we should firstly save it to + * generate a id. If the editing note is not worth saving, there + * is no id which is equivalent to create new note + */ + if (!mWorkingNote.existInDatabase()) { + saveNote(); + } + //在创建一个新的标签时,先在数据库中匹配 + //如果不存在,那么先在数据库中存储 + outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); + Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); + } + + @Override + //MotionEvent是对屏幕触控的传递机制 + public boolean dispatchTouchEvent(MotionEvent ev) { + if (mNoteBgColorSelector.getVisibility() == View.VISIBLE + && !inRangeOfView(mNoteBgColorSelector, ev)) { + mNoteBgColorSelector.setVisibility(View.GONE); + return true; + }//颜色选择器在屏幕上可见 + + if (mFontSizeSelector.getVisibility() == View.VISIBLE + && !inRangeOfView(mFontSizeSelector, ev)) { + mFontSizeSelector.setVisibility(View.GONE); + return true; + }//字体大小选择器在屏幕上可见 + return super.dispatchTouchEvent(ev); + } + //对屏幕触控的坐标进行操作 + private boolean inRangeOfView(View view, MotionEvent ev) { + int []location = new int[2]; + view.getLocationOnScreen(location); + int x = location[0]; + int y = location[1]; + if (ev.getX() < x + || ev.getX() > (x + view.getWidth()) + || ev.getY() < y + || ev.getY() > (y + view.getHeight())) + //如果触控的位置超出了给定的范围,返回false + { + return false; + } + return true; + } + + private void initResources() { + mHeadViewPanel = findViewById(R.id.note_title); + mNoteHeaderHolder = new HeadViewHolder(); + mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date); + mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon); + mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date); + mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color); + mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this); + mNoteEditor = (EditText) findViewById(R.id.note_edit_view); + mNoteEditorPanel = findViewById(R.id.sv_note_edit); + mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector); + for (int id : sBgSelectorBtnsMap.keySet()) { + ImageView iv = (ImageView) findViewById(id); + iv.setOnClickListener(this); + }//对标签各项属性内容的初始化 + + mFontSizeSelector = findViewById(R.id.font_size_selector); + for (int id : sFontSizeBtnsMap.keySet()) { + View view = findViewById(id); + view.setOnClickListener(this); + };//对字体大小的选择 + mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE); + /** + * HACKME: Fix bug of store the resource id in shared preference. + * The id may larger than the length of resources, in this case, + * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} + */ + if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) { + mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; + } + mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); + } + + @Override + protected void onPause() { + super.onPause(); + if(saveNote()) { + Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length()); + } + clearSettingState(); + } + //和桌面小工具的同步 + private void updateWidget() { + Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); + if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { + intent.setClass(this, NoteWidgetProvider_2x.class); + } else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) { + intent.setClass(this, NoteWidgetProvider_4x.class); + } else { + Log.e(TAG, "Unspported widget type"); + return; + } + + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { + mWorkingNote.getWidgetId() + }); + + sendBroadcast(intent); + setResult(RESULT_OK, intent); + } + + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.btn_set_bg_color) { + mNoteBgColorSelector.setVisibility(View.VISIBLE); + findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( + - View.VISIBLE); + } else if (sBgSelectorBtnsMap.containsKey(id)) { + findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( + View.GONE); + mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); + mNoteBgColorSelector.setVisibility(View.GONE); + } else if (sFontSizeBtnsMap.containsKey(id)) { + findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); + mFontSizeId = sFontSizeBtnsMap.get(id); + mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit(); + findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); + if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { + getWorkingText(); + switchToListMode(mWorkingNote.getContent()); + } else { + mNoteEditor.setTextAppearance(this, + TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); + } + mFontSizeSelector.setVisibility(View.GONE); + } + }//************************存在问题 + + @Override + public void onBackPressed() { + if(clearSettingState()) { + return; + } + + saveNote(); + super.onBackPressed(); + } + + private boolean clearSettingState() { + if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) { + mNoteBgColorSelector.setVisibility(View.GONE); + return true; + } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { + mFontSizeSelector.setVisibility(View.GONE); + return true; + } + return false; + } + + public void onBackgroundColorChanged() { + findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( + View.VISIBLE); + mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); + mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); + } + + @Override + //对选择菜单的准备 + public boolean onPrepareOptionsMenu(Menu menu) { + if (isFinishing()) { + return true; + } + clearSettingState(); + menu.clear(); + if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) { + getMenuInflater().inflate(R.menu.call_note_edit, menu); + // MenuInflater是用来实例化Menu目录下的Menu布局文件的 + } else { + getMenuInflater().inflate(R.menu.note_edit, menu); + } + if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { + menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_normal_mode); + } else { + menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode); + } + if (mWorkingNote.hasClockAlert()) { + menu.findItem(R.id.menu_alert).setVisible(false); + } else { + menu.findItem(R.id.menu_delete_remind).setVisible(false); + } + return true; + } + + @Override + /* + * 函数功能:动态改变菜单选项内容 + * 函数实现:如下注释 + */ + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + //根据菜单的id来编剧相关项目 + case R.id.menu_new_note: + //创建一个新的便签 + createNewNote(); + break; + case R.id.menu_delete: + //删除便签 + AlertDialog.Builder builder = new AlertDialog.Builder(this); + //创建关于删除操作的对话框 + builder.setTitle(getString(R.string.alert_title_delete)); + // 设置标签的标题为alert_title_delete + builder.setIcon(android.R.drawable.ic_dialog_alert); + //设置对话框图标 + builder.setMessage(getString(R.string.alert_message_delete_note)); + //设置对话框内容 + builder.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + //建立按键监听器 + public void onClick(DialogInterface dialog, int which) { + //点击所触发事件 + deleteCurrentNote(); + // 删除单签便签 + finish(); + } + }); + //添加“YES”按钮 + builder.setNegativeButton(android.R.string.cancel, null); + //添加“NO”的按钮 + builder.show(); + //显示对话框 + break; + case R.id.menu_font_size: + //字体大小的编辑 + mFontSizeSelector.setVisibility(View.VISIBLE); + // 将字体选择器置为可见 + findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); + // 通过id找到相应的大小 + break; + case R.id.menu_list_mode: + //选择列表模式 + mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ? + TextNote.MODE_CHECK_LIST : 0); + break; + case R.id.menu_share: + //菜单共享 + getWorkingText(); + sendTo(this, mWorkingNote.getContent()); + // 用sendto函数将运行文本发送到遍历的本文内 + break; + case R.id.menu_send_to_desktop: + //发送到桌面 + sendToDesktop(); + break; + case R.id.menu_alert: + //创建提醒器 + setReminder(); + break; + case R.id.menu_delete_remind: + //删除日期提醒 + mWorkingNote.setAlertDate(0, false); + break; + default: + break; + } + return true; + } + + /* + * 函数功能:建立事件提醒器 + * 函数实现:如下注释 + */ + private void setReminder() { + DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis()); + // 建立修改时间日期的对话框 + d.setOnDateTimeSetListener(new OnDateTimeSetListener() { + public void OnDateTimeSet(AlertDialog dialog, long date) { + mWorkingNote.setAlertDate(date , true); + //选择提醒的日期 + } + }); + //建立时间日期的监听器 + d.show(); + //显示对话框 + } + + /** + * Share note to apps that support {@link Intent#ACTION_SEND} action + * and {@text/plain} type + */ + /* + * 函数功能:共享便签 + * 函数实现:如下注释 + */ + private void sendTo(Context context, String info) { + Intent intent = new Intent(Intent.ACTION_SEND); + //建立intent链接选项 + intent.putExtra(Intent.EXTRA_TEXT, info); + //将需要传递的便签信息放入text文件中 + intent.setType("text/plain"); + //编辑连接器的类型 + context.startActivity(intent); + //在acti中进行链接 + } + + /* + * 函数功能:创建一个新的便签 + * 函数实现:如下注释 + */ + private void createNewNote() { + // Firstly, save current editing notes + //保存当前便签 + saveNote(); + + // For safety, start a new NoteEditActivity + finish(); + Intent intent = new Intent(this, NoteEditActivity.class); + //设置链接器 + intent.setAction(Intent.ACTION_INSERT_OR_EDIT); + //该活动定义为创建或编辑 + intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); + //将运行便签的id添加到INTENT_EXTRA_FOLDER_ID标记中 + startActivity(intent); + //开始activity并链接 + } + + /* + * 函数功能:删除当前便签 + * 函数实现:如下注释 + */ + private void deleteCurrentNote() { + if (mWorkingNote.existInDatabase()) { + //假如当前运行的便签内存有数据 + HashSet ids = new HashSet(); + long id = mWorkingNote.getNoteId(); + if (id != Notes.ID_ROOT_FOLDER) { + ids.add(id); + //如果不是头文件夹建立一个hash表把便签id存起来 + } else { + Log.d(TAG, "Wrong note id, should not happen"); + //否则报错 + } + if (!isSyncMode()) { + //在非同步模式情况下 + //删除操作 + if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) { + Log.e(TAG, "Delete Note error"); + } + } else { + //同步模式 + //移动至垃圾文件夹的操作 + if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) { + Log.e(TAG, "Move notes to trash folder error, should not happens"); + } + } + } + mWorkingNote.markDeleted(true); + //将这些标签的删除标记置为true + } + + /* + * 函数功能:判断是否为同步模式 + * 函数实现:直接看NotesPreferenceActivity中同步名称是否为空 + */ + private boolean isSyncMode() { + return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; + } + + /* + * 函数功能:设置提醒时间 + * 函数实现:如下注释 + */ + public void onClockAlertChanged(long date, boolean set) { + /** + * User could set clock to an unsaved note, so before setting the + * alert clock, we should save the note first + */ + if (!mWorkingNote.existInDatabase()) { + //首先保存已有的便签 + saveNote(); + } + if (mWorkingNote.getNoteId() > 0) { + Intent intent = new Intent(this, AlarmReceiver.class); + intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId())); + //若有有运行的便签就是建立一个链接器将标签id都存在uri中 + PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); + AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); + //设置提醒管理器 + showAlertHeader(); + if(!set) { + alarmManager.cancel(pendingIntent); + } else { + alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); + } + //如果用户设置了时间,就通过提醒管理器设置一个监听事项 + } else { + /** + * There is the condition that user has input nothing (the note is + * not worthy saving), we have no note id, remind the user that he + * should input something + */ + //没有运行的便签就报错 + Log.e(TAG, "Clock alert setting error"); + showToast(R.string.error_note_empty_for_clock); + } + } + + /* + * 函数功能:Widget发生改变的所触发的事件 + */ + public void onWidgetChanged() { + updateWidget();//更新Widget + } + + /* + * 函数功能: 删除编辑文本框所触发的事件 + * 函数实现:如下注释 + */ + public void onEditTextDelete(int index, String text) { + int childCount = mEditTextList.getChildCount(); + if (childCount == 1) { + return; + } + //没有编辑框的话直接返回 + for (int i = index + 1; i < childCount; i++) { + ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) + .setIndex(i - 1); + //通过id把编辑框存在便签编辑框中 + } + + mEditTextList.removeViewAt(index); + //删除特定位置的视图 + NoteEditText edit = null; + if(index == 0) { + edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( + R.id.et_edit_text); + } else { + edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById( + R.id.et_edit_text); + } + //通过id把编辑框存在空的NoteEditText中 + int length = edit.length(); + edit.append(text); + edit.requestFocus();//请求优先完成该此 编辑 + edit.setSelection(length);//定位到length位置处的条目 + } + + /* + * 函数功能:进入编辑文本框所触发的事件 + * 函数实现:如下注释 + */ + public void onEditTextEnter(int index, String text) { + /** + * Should not happen, check for debug + */ + if(index > mEditTextList.getChildCount()) { + Log.e(TAG, "Index out of mEditTextList boundrary, should not happen"); + //越界把偶偶 + } + + View view = getListItem(text, index); + mEditTextList.addView(view, index); + //建立一个新的视图并添加到编辑文本框内 + NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); + edit.requestFocus();//请求优先操作 + edit.setSelection(0);//定位到起始位置 + for (int i = index + 1; i < mEditTextList.getChildCount(); i++) { + ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) + .setIndex(i); + //遍历子文本框并设置对应对下标 + } + } + + /* + * 函数功能:切换至列表模式 + * 函数实现:如下注释 + */ + private void switchToListMode(String text) { + mEditTextList.removeAllViews(); + String[] items = text.split("\n"); + int index = 0; + //清空所有视图,初始化下标 + for (String item : items) { + if(!TextUtils.isEmpty(item)) { + mEditTextList.addView(getListItem(item, index)); + index++; + //遍历所有文本单元并添加到文本框中 + } + } + mEditTextList.addView(getListItem("", index)); + mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus(); + //优先请求此操作 + + mNoteEditor.setVisibility(View.GONE); + //便签编辑器不可见 + mEditTextList.setVisibility(View.VISIBLE); + //将文本编辑框置为可见 + } + + /* + * 函数功能:获取高亮效果的反馈情况 + * 函数实现:如下注释 + */ + private Spannable getHighlightQueryResult(String fullText, String userQuery) { + SpannableString spannable = new SpannableString(fullText == null ? "" : fullText); + //新建一个效果选项 + if (!TextUtils.isEmpty(userQuery)) { + mPattern = Pattern.compile(userQuery); + //将用户的询问进行解析 + Matcher m = mPattern.matcher(fullText); + //建立一个状态机检查Pattern并进行匹配 + int start = 0; + while (m.find(start)) { + spannable.setSpan( + new BackgroundColorSpan(this.getResources().getColor( + R.color.user_query_highlight)), m.start(), m.end(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + //设置背景颜色 + start = m.end(); + //跟新起始位置 + } + } + return spannable; + } + + /* + * 函数功能:获取列表项 + * 函数实现:如下注释 + */ + private View getListItem(String item, int index) { + View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); + //创建一个视图 + final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); + edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); + //创建一个文本编辑框并设置可见性 + CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); + cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); + } else { + edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); + } + } + }); + //建立一个打钩框并设置监听器 + + if (item.startsWith(TAG_CHECKED)) { + //选择勾选 + cb.setChecked(true); + edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); + item = item.substring(TAG_CHECKED.length(), item.length()).trim(); + } else if (item.startsWith(TAG_UNCHECKED)) { + //选择不勾选 + cb.setChecked(false); + edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); + item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); + } + + edit.setOnTextViewChangeListener(this); + edit.setIndex(index); + edit.setText(getHighlightQueryResult(item, mUserQuery)); + //运行编辑框的监听器对该行为作出反应,并设置下标及文本内容 + return view; + } + + /* + * 函数功能:便签内容发生改变所 触发的事件 + * 函数实现:如下注释 + */ + public void onTextChange(int index, boolean hasText) { + if (index >= mEditTextList.getChildCount()) { + Log.e(TAG, "Wrong index, should not happen"); + return; + //越界报错 + } + if(hasText) { + mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE); + } else { + mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE); + } + //如果内容不为空则将其子编辑框可见性置为可见,否则不可见 + } + + /* + * 函数功能:检查模式和列表模式的切换 + * 函数实现:如下注释 + */ + public void onCheckListModeChanged(int oldMode, int newMode) { + if (newMode == TextNote.MODE_CHECK_LIST) { + switchToListMode(mNoteEditor.getText().toString()); + //检查模式切换到列表模式 + } else { + if (!getWorkingText()) { + mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", + "")); + } + //若是获取到文本就改变其检查标记 + mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); + mEditTextList.setVisibility(View.GONE); + mNoteEditor.setVisibility(View.VISIBLE); + //修改文本编辑器的内容和可见性 + } + } + + /* + * 函数功能:设置勾选选项表并返回是否勾选的标记 + * 函数实现:如下注释 + */ + private boolean getWorkingText() { + boolean hasChecked = false; + //初始化check标记 + if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { + // 若模式为CHECK_LIST + StringBuilder sb = new StringBuilder(); + //创建可变字符串 + for (int i = 0; i < mEditTextList.getChildCount(); i++) { + View view = mEditTextList.getChildAt(i); + //遍历所有子编辑框的视图 + NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); + if (!TextUtils.isEmpty(edit.getText())) { + //若文本不为空 + if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { + //该选项框已打钩 + sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); + hasChecked = true; + //扩展字符串为已打钩并把标记置true + } else { + sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n"); + //扩展字符串添加未打钩 + } + } + } + mWorkingNote.setWorkingText(sb.toString()); + //利用编辑好的字符串设置运行便签的内容 + } else { + mWorkingNote.setWorkingText(mNoteEditor.getText().toString()); + // 若不是该模式直接用编辑器中的内容设置运行中标签的内容 + } + return hasChecked; + } + + /* + * 函数功能:保存便签 + * 函数实现:如下注释 + */ + private boolean saveNote() { + getWorkingText(); + boolean saved = mWorkingNote.saveNote(); + //运行 getWorkingText()之后保存 + if (saved) { + /** + * There are two modes from List view to edit view, open one note, + * create/edit a node. Opening node requires to the original + * position in the list when back from edit view, while creating a + * new node requires to the top of the list. This code + * {@link #RESULT_OK} is used to identify the create/edit state + */ + //如英文注释所说链接RESULT_OK是为了识别保存的2种情况,一是创建后保存,二是修改后保存 + setResult(RESULT_OK); + } + return saved; + } + + /* + * 函数功能:将便签发送至桌面 + * 函数实现:如下注释 + */ + private void sendToDesktop() { + /** + * Before send message to home, we should make sure that current + * editing note is exists in databases. So, for new note, firstly + * save it + */ + if (!mWorkingNote.existInDatabase()) { + saveNote(); + //若不存在数据也就是新的标签就保存起来先 + } + + if (mWorkingNote.getNoteId() > 0) { + //若是有内容 + Intent sender = new Intent(); + Intent shortcutIntent = new Intent(this, NoteEditActivity.class); + //建立发送到桌面的连接器 + shortcutIntent.setAction(Intent.ACTION_VIEW); + //链接为一个视图 + shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId()); + sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); + sender.putExtra(Intent.EXTRA_SHORTCUT_NAME, + makeShortcutIconTitle(mWorkingNote.getContent())); + sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, + Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app)); + sender.putExtra("duplicate", true); + //将便签的相关信息都添加到要发送的文件里 + sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); + //设置sneder的行为是发送 + showToast(R.string.info_note_enter_desktop); + sendBroadcast(sender); + //显示到桌面 + } else { + /** + * There is the condition that user has input nothing (the note is + * not worthy saving), we have no note id, remind the user that he + * should input something + */ + Log.e(TAG, "Send to desktop error"); + showToast(R.string.error_note_empty_for_send_to_desktop); + //空便签直接报错 + } + } + + /* + * 函数功能:编辑小图标的标题 + * 函数实现:如下注释 + */ + private String makeShortcutIconTitle(String content) { + content = content.replace(TAG_CHECKED, ""); + content = content.replace(TAG_UNCHECKED, ""); + return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, + SHORTCUT_ICON_TITLE_MAX_LEN) : content; + //直接设置为content中的内容并返回,有勾选和未勾选2种 + } + + /* + * 函数功能:显示提示的视图 + * 函数实现:根据下标显示对应的提示 + */ + private void showToast(int resId) { + showToast(resId, Toast.LENGTH_SHORT); + } + + /* + * 函数功能:持续显示提示的视图 + * 函数实现:根据下标和持续的时间(duration)编辑提示视图并显示 + */ + private void showToast(int resId, int duration) { + Toast.makeText(this, resId, duration).show(); + } +} \ No newline at end of file From f3040c385c87c4f86c8783864e20b70a8f3d65b3 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:39:21 +0800 Subject: [PATCH 22/42] ADD file via upload --- src/ui/NoteEditText.java | 286 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 src/ui/NoteEditText.java diff --git a/src/ui/NoteEditText.java b/src/ui/NoteEditText.java new file mode 100644 index 0000000..1fc3051 --- /dev/null +++ b/src/ui/NoteEditText.java @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.content.Context; +import android.graphics.Rect; +import android.text.Layout; +import android.text.Selection; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.URLSpan; +import android.util.AttributeSet; +import android.util.Log; +import android.view.ContextMenu; +import android.view.KeyEvent; +import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; +import android.view.MotionEvent; +import android.widget.EditText; + +import net.micode.notes.R; + +import java.util.HashMap; +import java.util.Map; + +//继承edittext,设置便签设置文本框 +public class NoteEditText extends EditText { + private static final String TAG = "NoteEditText"; + private int mIndex; + private int mSelectionStartBeforeDelete; + + private static final String SCHEME_TEL = "tel:" ; + private static final String SCHEME_HTTP = "http:" ; + private static final String SCHEME_EMAIL = "mailto:" ; + + ///建立一个字符和整数的hash表,用于链接电话,网站,还有邮箱 + private static final Map sSchemaActionResMap = new HashMap(); + static { + sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); + sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web); + sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email); + } + + /** + * Call by the {@link NoteEditActivity} to delete or add edit text + */ + //在NoteEditActivity中删除或添加文本的操作,可以看做是一个文本是否被变的标记,英文注释已说明的很清楚 + public interface OnTextViewChangeListener { + /** + * Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens + * and the text is null + */ + //处理删除按键时的操作 + void onEditTextDelete(int index, String text); + + /** + * Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER} + * happen + */ + //处理进入按键时的操作 + void onEditTextEnter(int index, String text); + + /** + * Hide or show item option when text change + */ + void onTextChange(int index, boolean hasText); + } + + private OnTextViewChangeListener mOnTextViewChangeListener; + + //根据context设置文本 + public NoteEditText(Context context) { + super(context, null);//用super引用父类变量 + mIndex = 0; + } + + //设置当前光标 + public void setIndex(int index) { + mIndex = index; + } + + //初始化文本修改标记 + public void setOnTextViewChangeListener(OnTextViewChangeListener listener) { + mOnTextViewChangeListener = listener; + } + + //AttributeSet 百度了一下是自定义空控件属性,用于维护便签动态变化的属性 + //初始化便签 + public NoteEditText(Context context, AttributeSet attrs) { + super(context, attrs, android.R.attr.editTextStyle); + } + + // 根据defstyle自动初始化 + public NoteEditText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + // TODO Auto-generated construct or stub + } + + @Override + //view里的函数,处理手机屏幕的所有事件 + /*参数event为手机屏幕触摸事件封装类的对象,其中封装了该事件的所有信息, + 例如触摸的位置、触摸的类型以及触摸的时间等。该对象会在用户触摸手机屏幕时被创建。*/ + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + //重写了需要处理屏幕被按下的事件 + case MotionEvent.ACTION_DOWN: + //跟新当前坐标值 + int x = (int) event.getX(); + int y = (int) event.getY(); + x -= getTotalPaddingLeft(); + y -= getTotalPaddingTop(); + x += getScrollX(); + y += getScrollY(); + + //用布局控件layout根据x,y的新值设置新的位置 + Layout layout = getLayout(); + int line = layout.getLineForVertical(y); + int off = layout.getOffsetForHorizontal(line, x); + + //更新光标新的位置 + Selection.setSelection(getText(), off); + break; + } + + return super.onTouchEvent(event); + } + + @Override + /* + * 函数功能:处理用户按下一个键盘按键时会触发 的事件 + * 实现过程:如下注释 + */ + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + //根据按键的 Unicode 编码值来处理 + case KeyEvent.KEYCODE_ENTER: + //“进入”按键 + if (mOnTextViewChangeListener != null) { + return false; + } + break; + case KeyEvent.KEYCODE_DEL: + //“删除”按键 + mSelectionStartBeforeDelete = getSelectionStart(); + break; + default: + break; + } + //继续执行父类的其他点击事件 + return super.onKeyDown(keyCode, event); + } + + @Override + /* + * 函数功能:处理用户松开一个键盘按键时会触发 的事件 + * 实现方式:如下注释 + */ + public boolean onKeyUp(int keyCode, KeyEvent event) { + switch(keyCode) { + //根据按键的 Unicode 编码值来处理,有删除和进入2种操作 + case KeyEvent.KEYCODE_DEL: + if (mOnTextViewChangeListener != null) { + //若是被修改过 + if (0 == mSelectionStartBeforeDelete && mIndex != 0) { + //若之前有被修改并且文档不为空 + mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString()); + //利用上文OnTextViewChangeListener对KEYCODE_DEL按键情况的删除函数进行删除 + return true; + } + } else { + Log.d(TAG, "OnTextViewChangeListener was not seted"); + //其他情况报错,文档的改动监听器并没有建立 + } + break; + case KeyEvent.KEYCODE_ENTER: + //同上也是分为监听器是否建立2种情况 + if (mOnTextViewChangeListener != null) { + int selectionStart = getSelectionStart(); + //获取当前位置 + String text = getText().subSequence(selectionStart, length()).toString(); + //获取当前文本 + setText(getText().subSequence(0, selectionStart)); + //根据获取的文本设置当前文本 + mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); + //当{@link KeyEvent#KEYCODE_ENTER}添加新文本 + } else { + Log.d(TAG, "OnTextViewChangeListener was not seted"); + //其他情况报错,文档的改动监听器并没有建立 + } + break; + default: + break; + } + //继续执行父类的其他按键弹起的事件 + return super.onKeyUp(keyCode, event); + } + + @Override + /* + * 函数功能:当焦点发生变化时,会自动调用该方法来处理焦点改变的事件 + * 实现方式:如下注释 + * 参数:focused表示触发该事件的View是否获得了焦点,当该控件获得焦点时,Focused等于true,否则等于false。 + direction表示焦点移动的方向,用数值表示 + Rect:表示在触发事件的View的坐标系中,前一个获得焦点的矩形区域,即表示焦点是从哪里来的。如果不可用则为null + */ + protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { + if (mOnTextViewChangeListener != null) { + //若监听器已经建立 + if (!focused && TextUtils.isEmpty(getText())) { + //获取到焦点并且文本不为空 + mOnTextViewChangeListener.onTextChange(mIndex, false); + //mOnTextViewChangeListener子函数,置false隐藏事件选项 + } else { + mOnTextViewChangeListener.onTextChange(mIndex, true); + //mOnTextViewChangeListener子函数,置true显示事件选项 + } + } + //继续执行父类的其他焦点变化的事件 + 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); + //设置url的信息的范围值 + if (urls.length == 1) { + int defaultResId = 0; + for(String schema: sSchemaActionResMap.keySet()) { + //获取计划表中所有的key值 + if(urls[0].getURL().indexOf(schema) >= 0) { + //若url可以添加则在添加后将defaultResId置为key所映射的值 + defaultResId = sSchemaActionResMap.get(schema); + break; + } + } + + if (defaultResId == 0) { + //defaultResId == 0则说明url并没有添加任何东西,所以置为连接其他SchemaActionResMap的值 + 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); + } +} \ No newline at end of file From dfe167c879ca21e22ef4191f4fc1753835365393 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:39:32 +0800 Subject: [PATCH 23/42] ADD file via upload --- src/ui/NoteItemData.java | 230 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 src/ui/NoteItemData.java diff --git a/src/ui/NoteItemData.java b/src/ui/NoteItemData.java new file mode 100644 index 0000000..f079c0d --- /dev/null +++ b/src/ui/NoteItemData.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.content.Context; +import android.database.Cursor; +import android.text.TextUtils; + +import net.micode.notes.data.Contact; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.tool.DataUtils; + + +public class NoteItemData { + static final String [] PROJECTION = new String [] { + NoteColumns.ID, + NoteColumns.ALERTED_DATE, + NoteColumns.BG_COLOR_ID, + NoteColumns.CREATED_DATE, + NoteColumns.HAS_ATTACHMENT, + NoteColumns.MODIFIED_DATE, + NoteColumns.NOTES_COUNT, + NoteColumns.PARENT_ID, + NoteColumns.SNIPPET, + NoteColumns.TYPE, + NoteColumns.WIDGET_ID, + NoteColumns.WIDGET_TYPE, + }; + //常量标记和数据就不一一标记了,意义翻译基本就知道 + private static final int ID_COLUMN = 0; + private static final int ALERTED_DATE_COLUMN = 1; + private static final int BG_COLOR_ID_COLUMN = 2; + private static final int CREATED_DATE_COLUMN = 3; + private static final int HAS_ATTACHMENT_COLUMN = 4; + private static final int MODIFIED_DATE_COLUMN = 5; + private static final int NOTES_COUNT_COLUMN = 6; + private static final int PARENT_ID_COLUMN = 7; + private static final int SNIPPET_COLUMN = 8; + private static final int TYPE_COLUMN = 9; + private static final int WIDGET_ID_COLUMN = 10; + private static final int WIDGET_TYPE_COLUMN = 11; + + private long mId; + private long mAlertDate; + private int mBgColorId; + private long mCreatedDate; + private boolean mHasAttachment; + private long mModifiedDate; + private int mNotesCount; + private long mParentId; + private String mSnippet; + private int mType; + private int mWidgetId; + private int mWidgetType; + private String mName; + private String mPhoneNumber; + + private boolean mIsLastItem; + private boolean mIsFirstItem; + private boolean mIsOnlyOneItem; + private boolean mIsOneNoteFollowingFolder; + private boolean mIsMultiNotesFollowingFolder; + //初始化NoteItemData,主要利用光标cursor获取的东西 + public NoteItemData(Context context, Cursor cursor) { + //getxxx为转换格式 + mId = cursor.getLong(ID_COLUMN); + mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); + mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN); + mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN); + mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0) ? true : false; + mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN); + mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN); + mParentId = cursor.getLong(PARENT_ID_COLUMN); + mSnippet = cursor.getString(SNIPPET_COLUMN); + mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace( + NoteEditActivity.TAG_UNCHECKED, ""); + mType = cursor.getInt(TYPE_COLUMN); + mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); + mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); + + //初始化电话号码的信息 + mPhoneNumber = ""; + if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { + mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); + if (!TextUtils.isEmpty(mPhoneNumber)) {//mphonenumber里有符合字符串,则用contart功能连接 + mName = Contact.getContact(context, mPhoneNumber); + if (mName == null) { + mName = mPhoneNumber; + } + } + } + + if (mName == null) { + mName = ""; + } + checkPostion(cursor); + } + ///根据鼠标的位置设置标记,和位置 + private void checkPostion(Cursor cursor) { + //初始化几个标记,cursor具体功能笔记中已提到,不一一叙述 + mIsLastItem = cursor.isLast() ? true : false; + mIsFirstItem = cursor.isFirst() ? true : false; + mIsOnlyOneItem = (cursor.getCount() == 1); + //初始化“多重子文件”“单一子文件”2个标记 + mIsMultiNotesFollowingFolder = false; + mIsOneNoteFollowingFolder = false; + + //主要是设置上诉2标记 + if (mType == Notes.TYPE_NOTE && !mIsFirstItem) {//若是note格式并且不是第一个元素 + int position = cursor.getPosition(); + if (cursor.moveToPrevious()) {//获取光标位置后看上一行 + if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER + || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) {//若光标满足系统或note格式 + if (cursor.getCount() > (position + 1)) { + mIsMultiNotesFollowingFolder = true;//若是数据行数大于但前位置+1则设置成正确 + } else { + mIsOneNoteFollowingFolder = true;//否则单一文件夹标记为true + } + } + if (!cursor.moveToNext()) {//若不能再往下走则报错 + throw new IllegalStateException("cursor move to previous but can't move back"); + } + } + } + } +///以下都是获取标记没什么好说的,不过倒数第二个需要说明下,很具体看下面 + public boolean isOneFollowingFolder() { + return mIsOneNoteFollowingFolder; + } + + public boolean isMultiFollowingFolder() { + return mIsMultiNotesFollowingFolder; + } + + public boolean isLast() { + return mIsLastItem; + } + + public String getCallName() { + return mName; + } + + public boolean isFirst() { + return mIsFirstItem; + } + + public boolean isSingle() { + return mIsOnlyOneItem; + } + + public long getId() { + return mId; + } + + public long getAlertDate() { + return mAlertDate; + } + + public long getCreatedDate() { + return mCreatedDate; + } + + public boolean hasAttachment() { + return mHasAttachment; + } + + public long getModifiedDate() { + return mModifiedDate; + } + + public int getBgColorId() { + return mBgColorId; + } + + public long getParentId() { + return mParentId; + } + + public int getNotesCount() { + return mNotesCount; + } + + public long getFolderId () { + return mParentId; + } + + public int getType() { + return mType; + } + + public int getWidgetType() { + return mWidgetType; + } + + public int getWidgetId() { + return mWidgetId; + } + + public String getSnippet() { + return mSnippet; + } + + public boolean hasAlert() { + return (mAlertDate > 0); + } + + //若数据父id为保存至文件夹模式的id且满足电话号码单元不为空,则isCallRecord为true + public boolean isCallRecord() { + return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber)); + } + + public static int getNoteType(Cursor cursor) { + return cursor.getInt(TYPE_COLUMN); + } +} \ No newline at end of file From 1878ded172bd4d6749c9a6b9e59303077438c466 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:39:49 +0800 Subject: [PATCH 24/42] ADD file via upload --- src/ui/NotesListActivity.java | 1018 +++++++++++++++++++++++++++++++++ 1 file changed, 1018 insertions(+) create mode 100644 src/ui/NotesListActivity.java diff --git a/src/ui/NotesListActivity.java b/src/ui/NotesListActivity.java new file mode 100644 index 0000000..31d18e7 --- /dev/null +++ b/src/ui/NotesListActivity.java @@ -0,0 +1,1018 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.appwidget.AppWidgetManager; +import android.content.AsyncQueryHandler; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.os.AsyncTask; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.Log; +import android.view.ActionMode; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.Display; +import android.view.HapticFeedbackConstants; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnCreateContextMenuListener; +import android.view.View.OnTouchListener; +import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView.OnItemLongClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.PopupMenu; +import android.widget.TextView; +import android.widget.Toast; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.gtask.remote.GTaskSyncService; +import net.micode.notes.model.WorkingNote; +import net.micode.notes.tool.BackupUtils; +import net.micode.notes.tool.DataUtils; +import net.micode.notes.tool.ResourceParser; +import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; +import net.micode.notes.widget.NoteWidgetProvider_2x; +import net.micode.notes.widget.NoteWidgetProvider_4x; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashSet; +//主界面,一进入就是这个界面 +/** + * @author k + * + */ +public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { //没有用特定的标签加注释。。。感觉没有什么用 + private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; + + private static final int FOLDER_LIST_QUERY_TOKEN = 1; + + private static final int MENU_FOLDER_DELETE = 0; + + private static final int MENU_FOLDER_VIEW = 1; + + private static final int MENU_FOLDER_CHANGE_NAME = 2; + + private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; //单行超过80个字符 + + private enum ListEditState { + NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER + }; + + private ListEditState mState; + + private BackgroundQueryHandler mBackgroundQueryHandler; + + private NotesListAdapter mNotesListAdapter; + + private ListView mNotesListView; + + private Button mAddNewNote; + + private boolean mDispatch; + + private int mOriginY; + + private int mDispatchY; + + private TextView mTitleBar; + + private long mCurrentFolderId; + + private ContentResolver mContentResolver; + + private ModeCallback mModeCallBack; + + private static final String TAG = "NotesListActivity"; + + public static final int NOTES_LISTVIEW_SCROLL_RATE = 30; + + private NoteItemData mFocusNoteDataItem; + + private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?"; + + private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>" + + Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" + " OR (" + + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " + + NoteColumns.NOTES_COUNT + ">0)"; + + private final static int REQUEST_CODE_OPEN_NODE = 102; + private final static int REQUEST_CODE_NEW_NODE = 103; + + @Override + // 创建类 + protected void onCreate(final Bundle savedInstanceState) { //需要是final类型 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。 + // final类不能被继承,没有子类,final类中的方法默认是final的。 + //final方法不能被子类的方法覆盖,但可以被继承。 + //final成员变量表示常量,只能被赋值一次,赋值后值不再改变。 + //final不能用于修饰构造方法。 + super.onCreate(savedInstanceState); // 调用父类的onCreate函数 + setContentView(R.layout.note_list); + initResources(); + + /** + * Insert an introduction when user firstly use this application + */ + setAppInfoFromRawRes(); + } + + @Override + // 返回一些子模块完成的数据交给主Activity处理 + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // 结果值 和 要求值 符合要求 + if (resultCode == RESULT_OK + && (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) { + mNotesListAdapter.changeCursor(null); + } else { + super.onActivityResult(requestCode, resultCode, data); + // 调用 Activity 的onActivityResult() + } + } + + private void setAppInfoFromRawRes() { + // Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。 + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) { + StringBuilder sb = new StringBuilder(); + InputStream in = null; + try { + // 把资源文件放到应用程序的/raw/raw下,那么就可以在应用中使用getResources获取资源后, + // 以openRawResource方法(不带后缀的资源文件名)打开这个文件。 + in = getResources().openRawResource(R.raw.introduction); + if (in != null) { + InputStreamReader isr = new InputStreamReader(in); + BufferedReader br = new BufferedReader(isr); + char [] buf = new char[1024]; // 自行定义的数值,使用者不知道有什么意义 + int len = 0; + while ((len = br.read(buf)) > 0) { + sb.append(buf, 0, len); + } + } else { + Log.e(TAG, "Read introduction file error"); + return; + } + } catch (IOException e) { + e.printStackTrace(); + return; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + // 创建空的WorkingNote + WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER, + AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE, + ResourceParser.RED); + note.setWorkingText(sb.toString()); + if (note.saveNote()) { + // 更新保存note的信息 + sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); + } else { + Log.e(TAG, "Save introduction note error"); + return; + } + } + } + + @Override + protected void onStart() { + super.onStart(); + startAsyncNotesListQuery(); + } + + // 初始化资源 + private void initResources() { + mContentResolver = this.getContentResolver(); // 获取应用程序的数据,得到类似数据表的东西 + mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); + mCurrentFolderId = Notes.ID_ROOT_FOLDER; + + // findViewById 是安卓编程的定位函数,主要是引用.R文件里的引用名 + mNotesListView = (ListView) findViewById(R.id.notes_list); // 绑定XML中的ListView,作为Item的容器 + mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null), + null, false); + mNotesListView.setOnItemClickListener(new OnListItemClickListener()); + mNotesListView.setOnItemLongClickListener(this); + mNotesListAdapter = new NotesListAdapter(this); + mNotesListView.setAdapter(mNotesListAdapter); + mAddNewNote = (Button) findViewById(R.id.btn_new_note);// 在activity中要获取该按钮 + mAddNewNote.setOnClickListener(this); + mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener()); + mDispatch = false; + mDispatchY = 0; + mOriginY = 0; + mTitleBar = (TextView) findViewById(R.id.tv_title_bar); + mState = ListEditState.NOTE_LIST; + mModeCallBack = new ModeCallback(); + } + + // 继承自ListView.MultiChoiceModeListener 和 OnMenuItemClickListener + private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { + private DropdownMenu mDropDownMenu; + private ActionMode mActionMode; + private MenuItem mMoveMenu; + + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + getMenuInflater().inflate(R.menu.note_list_options, menu); + menu.findItem(R.id.delete).setOnMenuItemClickListener(this); + mMoveMenu = menu.findItem(R.id.move); + if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER + || DataUtils.getUserFolderCount(mContentResolver) == 0) { + mMoveMenu.setVisible(false); + } else { + mMoveMenu.setVisible(true); + mMoveMenu.setOnMenuItemClickListener(this); + } + mActionMode = mode; + mNotesListAdapter.setChoiceMode(true); + mNotesListView.setLongClickable(false); + mAddNewNote.setVisibility(View.GONE); + + View customView = LayoutInflater.from(NotesListActivity.this).inflate( + R.layout.note_list_dropdown_menu, null); + mode.setCustomView(customView); + mDropDownMenu = new DropdownMenu(NotesListActivity.this, + (Button) customView.findViewById(R.id.selection_menu), + R.menu.note_list_dropdown); + mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){ + public boolean onMenuItemClick(final MenuItem item) { + mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected()); + updateMenu(); + return true; + } + + }); + return true; + } + + // 更新菜单 + private void updateMenu() { + int selectedCount = mNotesListAdapter.getSelectedCount(); + // Update dropdown menu + String format = getResources().getString(R.string.menu_select_title, selectedCount); + mDropDownMenu.setTitle(format); // 更改标题 + MenuItem item = mDropDownMenu.findItem(R.id.action_select_all); + if (item != null) { + if (mNotesListAdapter.isAllSelected()) { + item.setChecked(true); + item.setTitle(R.string.menu_deselect_all); + } else { + item.setChecked(false); + item.setTitle(R.string.menu_select_all); + } + } + } + + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + // TODO Auto-generated method stub + return false; + } + + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + // TODO Auto-generated method stub + return false; + } + + public void onDestroyActionMode(ActionMode mode) { + mNotesListAdapter.setChoiceMode(false); + mNotesListView.setLongClickable(true); + mAddNewNote.setVisibility(View.VISIBLE); + } + + public void finishActionMode() { + mActionMode.finish(); + } + + public void onItemCheckedStateChanged(ActionMode mode, int position, long id, + boolean checked) { + mNotesListAdapter.setCheckedItem(position, checked); + updateMenu(); + } + + public boolean onMenuItemClick(MenuItem item) { + if (mNotesListAdapter.getSelectedCount() == 0) { + Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none), + Toast.LENGTH_SHORT).show(); + return true; + } + + switch (item.getItemId()) { + case R.id.delete: + AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + builder.setTitle(getString(R.string.alert_title_delete)); + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setMessage(getString(R.string.alert_message_delete_notes, + mNotesListAdapter.getSelectedCount())); + builder.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + batchDelete(); + } + }); + builder.setNegativeButton(android.R.string.cancel, null); + builder.show(); + break; + case R.id.move: + startQueryDestinationFolders(); + break; + default: + return false; + } + return true; + } + } + + private class NewNoteOnTouchListener implements OnTouchListener { + + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: { + Display display = getWindowManager().getDefaultDisplay(); + int screenHeight = display.getHeight(); + int newNoteViewHeight = mAddNewNote.getHeight(); + int start = screenHeight - newNoteViewHeight; + int eventY = start + (int) event.getY(); + /** + * Minus TitleBar's height + */ + if (mState == ListEditState.SUB_FOLDER) { + eventY -= mTitleBar.getHeight(); + start -= mTitleBar.getHeight(); + } + /** + * HACKME:When click the transparent part of "New Note" button, dispatch + * the event to the list view behind this button. The transparent part of + * "New Note" button could be expressed by formula y=-0.12x+94锛圲nit:pixel锛� + * and the line top of the button. The coordinate based on left of the "New + * Note" button. The 94 represents maximum height of the transparent part. + * Notice that, if the background of the button changes, the formula should + * also change. This is very bad, just for the UI designer's strong requirement. + */ + if (event.getY() < (event.getX() * (-0.12) + 94)) { + View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1 + - mNotesListView.getFooterViewsCount()); + if (view != null && view.getBottom() > start + && (view.getTop() < (start + 94))) { + mOriginY = (int) event.getY(); + mDispatchY = eventY; + event.setLocation(event.getX(), mDispatchY); + mDispatch = true; + return mNotesListView.dispatchTouchEvent(event); + } + } + break; + } + case MotionEvent.ACTION_MOVE: { + if (mDispatch) { + mDispatchY += (int) event.getY() - mOriginY; + event.setLocation(event.getX(), mDispatchY); + return mNotesListView.dispatchTouchEvent(event); + } + break; + } + default: { + if (mDispatch) { + event.setLocation(event.getX(), mDispatchY); + mDispatch = false; + return mNotesListView.dispatchTouchEvent(event); + } + break; + } + } + return false; + } + + }; + + private void startAsyncNotesListQuery() { + String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION + : NORMAL_SELECTION; + mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null, + Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[] { + String.valueOf(mCurrentFolderId) + }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); + } + + private final class BackgroundQueryHandler extends AsyncQueryHandler { + public BackgroundQueryHandler(ContentResolver contentResolver) { + super(contentResolver); + } + + @Override + protected void onQueryComplete(int token, Object cookie, Cursor cursor) { + switch (token) { + case FOLDER_NOTE_LIST_QUERY_TOKEN: + mNotesListAdapter.changeCursor(cursor); + break; + case FOLDER_LIST_QUERY_TOKEN: + if (cursor != null && cursor.getCount() > 0) { + showFolderListMenu(cursor); + } else { + Log.e(TAG, "Query folder failed"); + } + break; + default: + return; + } + } + } + + private void showFolderListMenu(Cursor cursor) { + AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + builder.setTitle(R.string.menu_title_select_folder); + final FoldersListAdapter adapter = new FoldersListAdapter(this, cursor); + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int which) { + DataUtils.batchMoveToFolder(mContentResolver, + mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which)); + Toast.makeText( + NotesListActivity.this, + getString(R.string.format_move_notes_to_folder, + mNotesListAdapter.getSelectedCount(), + adapter.getFolderName(NotesListActivity.this, which)), + Toast.LENGTH_SHORT).show(); + mModeCallBack.finishActionMode(); + } + }); + builder.show(); + } + + private void createNewNote() { + Intent intent = new Intent(this, NoteEditActivity.class); + intent.setAction(Intent.ACTION_INSERT_OR_EDIT); + intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId); + this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE); + } + + private void batchDelete() { + new AsyncTask>() { + protected HashSet doInBackground(Void... unused) { + HashSet widgets = mNotesListAdapter.getSelectedWidget(); + if (!isSyncMode()) { + // if not synced, delete notes directly + if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter + .getSelectedItemIds())) { + } else { + Log.e(TAG, "Delete notes error, should not happens"); + } + } else { + // in sync mode, we'll move the deleted note into the trash + // folder + if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter + .getSelectedItemIds(), Notes.ID_TRASH_FOLER)) { + Log.e(TAG, "Move notes to trash folder error, should not happens"); + } + } + return widgets; + } + + @Override + protected void onPostExecute(HashSet widgets) { + if (widgets != null) { + for (AppWidgetAttribute widget : widgets) { + if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID + && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) { + updateWidget(widget.widgetId, widget.widgetType); + } + } + } + mModeCallBack.finishActionMode(); + } + }.execute(); + } + + private void deleteFolder(long folderId) { + if (folderId == Notes.ID_ROOT_FOLDER) { + Log.e(TAG, "Wrong folder id, should not happen " + folderId); + return; + } + + HashSet ids = new HashSet(); + ids.add(folderId); + HashSet widgets = DataUtils.getFolderNoteWidget(mContentResolver, + folderId); + if (!isSyncMode()) { + // if not synced, delete folder directly + DataUtils.batchDeleteNotes(mContentResolver, ids); + } else { + // in sync mode, we'll move the deleted folder into the trash folder + DataUtils.batchMoveToFolder(mContentResolver, ids, Notes.ID_TRASH_FOLER); + } + if (widgets != null) { + for (AppWidgetAttribute widget : widgets) { + if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID + && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) { + updateWidget(widget.widgetId, widget.widgetType); + } + } + } + } + + private void openNode(NoteItemData data) { + Intent intent = new Intent(this, NoteEditActivity.class); + intent.setAction(Intent.ACTION_VIEW); + intent.putExtra(Intent.EXTRA_UID, data.getId()); + this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE); + } + + private void openFolder(NoteItemData data) { + mCurrentFolderId = data.getId(); + startAsyncNotesListQuery(); + if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { + mState = ListEditState.CALL_RECORD_FOLDER; + mAddNewNote.setVisibility(View.GONE); + } else { + mState = ListEditState.SUB_FOLDER; + } + if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { + mTitleBar.setText(R.string.call_record_folder_name); + } else { + mTitleBar.setText(data.getSnippet()); + } + mTitleBar.setVisibility(View.VISIBLE); + } + + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_new_note: + createNewNote(); + break; + default: + break; + } + } + + private void showSoftInput() { + InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + if (inputMethodManager != null) { + inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + } + + private void hideSoftInput(View view) { + InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + + private void showCreateOrModifyFolderDialog(final boolean create) { + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null); + final EditText etName = (EditText) view.findViewById(R.id.et_foler_name); + showSoftInput(); + if (!create) { + if (mFocusNoteDataItem != null) { + etName.setText(mFocusNoteDataItem.getSnippet()); + builder.setTitle(getString(R.string.menu_folder_change_name)); + } else { + Log.e(TAG, "The long click data item is null"); + return; + } + } else { + etName.setText(""); + builder.setTitle(this.getString(R.string.menu_create_folder)); + } + + builder.setPositiveButton(android.R.string.ok, null); + builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + hideSoftInput(etName); + } + }); + + final Dialog dialog = builder.setView(view).show(); + final Button positive = (Button)dialog.findViewById(android.R.id.button1); + positive.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + hideSoftInput(etName); + String name = etName.getText().toString(); + if (DataUtils.checkVisibleFolderName(mContentResolver, name)) { + Toast.makeText(NotesListActivity.this, getString(R.string.folder_exist, name), + Toast.LENGTH_LONG).show(); + etName.setSelection(0, etName.length()); + return; + } + if (!create) { + if (!TextUtils.isEmpty(name)) { + ContentValues values = new ContentValues(); + values.put(NoteColumns.SNIPPET, name); + values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); + values.put(NoteColumns.LOCAL_MODIFIED, 1); + mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID + + "=?", new String[] { + String.valueOf(mFocusNoteDataItem.getId()) + }); + } + } else if (!TextUtils.isEmpty(name)) { + ContentValues values = new ContentValues(); + values.put(NoteColumns.SNIPPET, name); + values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); + mContentResolver.insert(Notes.CONTENT_NOTE_URI, values); + } + dialog.dismiss(); + } + }); + + if (TextUtils.isEmpty(etName.getText())) { + positive.setEnabled(false); + } + /** + * When the name edit text is null, disable the positive button + */ + etName.addTextChangedListener(new TextWatcher() { + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // TODO Auto-generated method stub + + } + + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (TextUtils.isEmpty(etName.getText())) { + positive.setEnabled(false); + } else { + positive.setEnabled(true); + } + } + + public void afterTextChanged(Editable s) { + // TODO Auto-generated method stub + + } + }); + } + + /* (non-Javadoc) + * @see android.app.Activity#onBackPressed() + * 按返回键时根据情况更改类中的数据 + */ + @Override + public void onBackPressed() { switch (mState) { + case SUB_FOLDER: + mCurrentFolderId = Notes.ID_ROOT_FOLDER; + mState = ListEditState.NOTE_LIST; + startAsyncNotesListQuery(); + mTitleBar.setVisibility(View.GONE); + break; + case CALL_RECORD_FOLDER: + mCurrentFolderId = Notes.ID_ROOT_FOLDER; + mState = ListEditState.NOTE_LIST; + mAddNewNote.setVisibility(View.VISIBLE); + mTitleBar.setVisibility(View.GONE); + startAsyncNotesListQuery(); + break; + case NOTE_LIST: + super.onBackPressed(); + break; + default: + break; + } + } + + /** + * @param appWidgetId + * @param appWidgetType + * 根据不同类型的widget更新插件,通过intent传送数据 + */ + private void updateWidget(int appWidgetId, int appWidgetType) { + Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); + if (appWidgetType == Notes.TYPE_WIDGET_2X) { + intent.setClass(this, NoteWidgetProvider_2x.class); + } else if (appWidgetType == Notes.TYPE_WIDGET_4X) { + intent.setClass(this, NoteWidgetProvider_4x.class); + } else { + Log.e(TAG, "Unspported widget type"); + return; + } + + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { + appWidgetId + }); + + sendBroadcast(intent); + setResult(RESULT_OK, intent); + } + + /** + * 声明监听器,建立菜单,包括名称,视图,删除操作,更改名称操作; + */ + private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() { + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + if (mFocusNoteDataItem != null) { + menu.setHeaderTitle(mFocusNoteDataItem.getSnippet()); + menu.add(0, MENU_FOLDER_VIEW, 0, R.string.menu_folder_view); + menu.add(0, MENU_FOLDER_DELETE, 0, R.string.menu_folder_delete); + menu.add(0, MENU_FOLDER_CHANGE_NAME, 0, R.string.menu_folder_change_name); + } + } + }; + + @Override + public void onContextMenuClosed(Menu menu) { + if (mNotesListView != null) { + mNotesListView.setOnCreateContextMenuListener(null); + } + super.onContextMenuClosed(menu); + } + + /* (non-Javadoc) + * @see android.app.Activity#onContextItemSelected(android.view.MenuItem) + * 针对menu中不同的选择进行不同的处理,里面详细注释 + */ + @Override + public boolean onContextItemSelected(MenuItem item) { + if (mFocusNoteDataItem == null) { + Log.e(TAG, "The long click data item is null"); + return false; + } + switch (item.getItemId()) { + case MENU_FOLDER_VIEW: + openFolder(mFocusNoteDataItem);//打开对应文件 + break; + case MENU_FOLDER_DELETE: + AlertDialog.Builder builder = new AlertDialog.Builder(this);//设置确认是否删除的对话框 + builder.setTitle(getString(R.string.alert_title_delete)); + builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setMessage(getString(R.string.alert_message_delete_folder)); + builder.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + deleteFolder(mFocusNoteDataItem.getId()); + } + }); + builder.setNegativeButton(android.R.string.cancel, null); + builder.show();//显示对话框 + break; + case MENU_FOLDER_CHANGE_NAME: + showCreateOrModifyFolderDialog(false); + break; + default: + break; + } + + return true; + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + menu.clear(); + if (mState == ListEditState.NOTE_LIST) { + getMenuInflater().inflate(R.menu.note_list, menu); + // set sync or sync_cancel + menu.findItem(R.id.menu_sync).setTitle( + GTaskSyncService.isSyncing() ? R.string.menu_sync_cancel : R.string.menu_sync); + } else if (mState == ListEditState.SUB_FOLDER) { + getMenuInflater().inflate(R.menu.sub_folder, menu); + } else if (mState == ListEditState.CALL_RECORD_FOLDER) { + getMenuInflater().inflate(R.menu.call_record_folder, menu); + } else { + Log.e(TAG, "Wrong state:" + mState); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_new_folder: { + showCreateOrModifyFolderDialog(true); + break; + } + case R.id.menu_export_text: { + exportNoteToText(); + break; + } + case R.id.menu_sync: { + if (isSyncMode()) { + if (TextUtils.equals(item.getTitle(), getString(R.string.menu_sync))) { + GTaskSyncService.startSync(this); + } else { + GTaskSyncService.cancelSync(this); + } + } else { + startPreferenceActivity(); + } + break; + } + case R.id.menu_setting: { + startPreferenceActivity(); + break; + } + case R.id.menu_new_note: { + createNewNote(); + break; + } + case R.id.menu_search: + onSearchRequested(); + break; + default: + break; + } + return true; + } + + /* (non-Javadoc) + * @see android.app.Activity#onSearchRequested() + * 直接调用startSearch函数 + */ + @Override + public boolean onSearchRequested() { + startSearch(null, false, null /* appData */, false); + return true; + } + + /** + * 函数功能:实现将便签导出到文本功能 + */ + private void exportNoteToText() { + final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this); + new AsyncTask() { + + @Override + protected Integer doInBackground(Void... unused) { + return backup.exportToText(); + } + + @Override + protected void onPostExecute(Integer result) { + if (result == BackupUtils.STATE_SD_CARD_UNMOUONTED) { + AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + builder.setTitle(NotesListActivity.this + .getString(R.string.failed_sdcard_export)); + builder.setMessage(NotesListActivity.this + .getString(R.string.error_sdcard_unmounted)); + builder.setPositiveButton(android.R.string.ok, null); + builder.show(); + } else if (result == BackupUtils.STATE_SUCCESS) { + AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + builder.setTitle(NotesListActivity.this + .getString(R.string.success_sdcard_export)); + builder.setMessage(NotesListActivity.this.getString( + R.string.format_exported_file_location, backup + .getExportedTextFileName(), backup.getExportedTextFileDir())); + builder.setPositiveButton(android.R.string.ok, null); + builder.show(); + } else if (result == BackupUtils.STATE_SYSTEM_ERROR) { + AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + builder.setTitle(NotesListActivity.this + .getString(R.string.failed_sdcard_export)); + builder.setMessage(NotesListActivity.this + .getString(R.string.error_sdcard_export)); + builder.setPositiveButton(android.R.string.ok, null); + builder.show(); + } + } + + }.execute(); + } + + /** + * @return + * 功能:判断是否正在同步 + */ + private boolean isSyncMode() { + return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; + } + + /** + * 功能:跳转到PreferenceActivity界面 + */ + private void startPreferenceActivity() { + Activity from = getParent() != null ? getParent() : this; + Intent intent = new Intent(from, NotesPreferenceActivity.class); + from.startActivityIfNeeded(intent, -1); + } + + /** + * @author k + * 函数功能:实现对便签列表项的点击事件(短按) + */ + private class OnListItemClickListener implements OnItemClickListener { + + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (view instanceof NotesListItem) { + NoteItemData item = ((NotesListItem) view).getItemData(); + if (mNotesListAdapter.isInChoiceMode()) { + if (item.getType() == Notes.TYPE_NOTE) { + position = position - mNotesListView.getHeaderViewsCount(); + mModeCallBack.onItemCheckedStateChanged(null, position, id, + !mNotesListAdapter.isSelectedItem(position)); + } + return; + } + + switch (mState) { + case NOTE_LIST: + if (item.getType() == Notes.TYPE_FOLDER + || item.getType() == Notes.TYPE_SYSTEM) { + openFolder(item); + } else if (item.getType() == Notes.TYPE_NOTE) { + openNode(item); + } else { + Log.e(TAG, "Wrong note type in NOTE_LIST"); + } + break; + case SUB_FOLDER: + case CALL_RECORD_FOLDER: + if (item.getType() == Notes.TYPE_NOTE) { + openNode(item); + } else { + Log.e(TAG, "Wrong note type in SUB_FOLDER"); + } + break; + default: + break; + } + } + } + + } + + /** + * 查询目标文件 + */ + private void startQueryDestinationFolders() { + String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?"; + selection = (mState == ListEditState.NOTE_LIST) ? selection: + "(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")"; + + mBackgroundQueryHandler.startQuery(FOLDER_LIST_QUERY_TOKEN, + null, + Notes.CONTENT_NOTE_URI, + FoldersListAdapter.PROJECTION, + selection, + new String[] { + String.valueOf(Notes.TYPE_FOLDER), + String.valueOf(Notes.ID_TRASH_FOLER), + String.valueOf(mCurrentFolderId) + }, + NoteColumns.MODIFIED_DATE + " DESC"); + } + + /* (non-Javadoc) + * @see android.widget.AdapterView.OnItemLongClickListener#onItemLongClick(android.widget.AdapterView, android.view.View, int, long) + * 长按某一项时进行的操作 + * 如果长按的是便签,则通过ActionMode菜单实现;如果长按的是文件夹,则通过ContextMenu菜单实现; + * 具体ActionMOde菜单和ContextMenu菜单的详细见精度笔记 + */ + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + if (view instanceof NotesListItem) { + mFocusNoteDataItem = ((NotesListItem) view).getItemData(); + if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) { + if (mNotesListView.startActionMode(mModeCallBack) != null) { + mModeCallBack.onItemCheckedStateChanged(null, position, id, true); + mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + } else { + Log.e(TAG, "startActionMode fails"); + } + } else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) { + mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener); + } + } + return false; + } +} \ No newline at end of file From bb05993e954b488a24145446dff1ecd085344c1a Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:39:59 +0800 Subject: [PATCH 25/42] ADD file via upload --- src/ui/NotesListAdapter.java | 273 +++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 src/ui/NotesListAdapter.java diff --git a/src/ui/NotesListAdapter.java b/src/ui/NotesListAdapter.java new file mode 100644 index 0000000..0df6d72 --- /dev/null +++ b/src/ui/NotesListAdapter.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.content.Context; +import android.database.Cursor; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; + + +import net.micode.notes.data.Notes; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + + +/* + * 功能:直译为便签表连接器,继承了CursorAdapter,它为cursor和ListView提供了连接的桥梁。 + * 所以NotesListAdapter实现的是鼠标和编辑便签链接的桥梁 + */ +public class NotesListAdapter extends CursorAdapter { + private static final String TAG = "NotesListAdapter"; + private Context mContext; + private HashMap mSelectedIndex; + private int mNotesCount; //便签数 + private boolean mChoiceMode; //选择模式标记 + + /* + * 桌面widget的属性,包括编号和类型 + */ + public static class AppWidgetAttribute { + public int widgetId; + public int widgetType; + }; + + /* + * 函数功能:初始化便签链接器 + * 函数实现:根据传进来的内容设置相关变量 + */ + public NotesListAdapter(Context context) { + super(context, null); //父类对象置空 + mSelectedIndex = new HashMap(); //新建选项下标的hash表 + mContext = context; + mNotesCount = 0; + } + + @Override + /* + * 函数功能:新建一个视图来存储光标所指向的数据 + * 函数实现:使用兄弟类NotesListItem新建一个项目选项 + */ + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return new NotesListItem(context); + } + + /* + * 函数功能:将已经存在的视图和鼠标指向的数据进行捆绑 + * 函数实现:如下注释 + */ + @Override + public void bindView(View view, Context context, Cursor cursor) { + if (view instanceof NotesListItem) { + //若view是NotesListItem的一个实例 + NoteItemData itemData = new NoteItemData(context, cursor); + ((NotesListItem) view).bind(context, itemData, mChoiceMode, + isSelectedItem(cursor.getPosition())); + //则新建一个项目选项并且用bind跟将view和鼠标,内容,便签数据捆绑在一起 + } + } + + /* + * 函数功能:设置勾选框 + * 函数实现:如下注释 + */ + public void setCheckedItem(final int position, final boolean checked) { + mSelectedIndex.put(position, checked); + //根据定位和是否勾选设置下标 + notifyDataSetChanged(); + //在修改后刷新activity + } + + /* + * 函数功能:判断单选按钮是否勾选 + */ + public boolean isInChoiceMode() { + return mChoiceMode; + } + + /* + * 函数功能:设置单项选项框 + * 函数实现:重置下标并且根据参数mode设置选项 + */ + public void setChoiceMode(boolean mode) { + mSelectedIndex.clear(); + mChoiceMode = mode; + } + + /* + * 函数功能:选择全部选项 + * 函数实现:如下注释 + */ + public void selectAll(boolean checked) { + Cursor cursor = getCursor(); + //获取光标位置 + for (int i = 0; i < getCount(); i++) { + if (cursor.moveToPosition(i)) { + if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) { + setCheckedItem(i, checked); + } + } + } + //遍历所有光标可用的位置在判断为便签类型之后勾选单项框 + } + + /* + * 函数功能:建立选择项的下标列表 + * 函数实现:如下注释 + */ + public HashSet getSelectedItemIds() { + HashSet itemSet = new HashSet(); + //建立hash表 + for (Integer position : mSelectedIndex.keySet()) { + //遍历所有的关键 + if (mSelectedIndex.get(position) == true) { + //若光标位置可用 + Long id = getItemId(position); + if (id == Notes.ID_ROOT_FOLDER) { + //原文件不需要添加 + Log.d(TAG, "Wrong item id, should not happen"); + } else { + itemSet.add(id); + } + //则将id该下标假如选项集合中 + + } + } + + return itemSet; + } + + /* + * 函数功能:建立桌面Widget的选项表 + * 函数实现:如下注释 + */ + public HashSet getSelectedWidget() { + HashSet itemSet = new HashSet(); + for (Integer position : mSelectedIndex.keySet()) { + if (mSelectedIndex.get(position) == true) { + Cursor c = (Cursor) getItem(position); + //以上4句和getSelectedItemIds一样,不再重复 + if (c != null) { + //光标位置可用的话就建立新的Widget属性并编辑下标和类型,最后添加到选项集中 + AppWidgetAttribute widget = new AppWidgetAttribute(); + NoteItemData item = new NoteItemData(mContext, c); + widget.widgetId = item.getWidgetId(); + widget.widgetType = item.getWidgetType(); + itemSet.add(widget); + /** + * Don't close cursor here, only the adapter could close it + */ + } else { + Log.e(TAG, "Invalid cursor"); + return null; + } + } + } + return itemSet; + } + + /* + * 函数功能:获取选项个数 + * 函数实现:如下注释 + */ + public int getSelectedCount() { + Collection values = mSelectedIndex.values(); + //首先获取选项下标的值 + if (null == values) { + return 0; + } + Iterator iter = values.iterator(); + //初始化叠加器 + int count = 0; + while (iter.hasNext()) { + if (true == iter.next()) { + //若value值为真计数+1 + count++; + } + } + return count; + } + + /* + * 函数功能:判断是否全部选中 + * 函数实现:如下注释 + */ + public boolean isAllSelected() { + int checkedCount = getSelectedCount(); + return (checkedCount != 0 && checkedCount == mNotesCount); + //获取选项数看是否等于便签的个数 + } + + /* + * 函数功能:判断是否为选项表 + * 函数实现:通过传递的下标来确定 + */ + public boolean isSelectedItem(final int position) { + if (null == mSelectedIndex.get(position)) { + return false; + } + return mSelectedIndex.get(position); + } + + @Override + /* + * 函数功能:在activity内容发生局部变动的时候回调该函数计算便签的数量 + * 函数实现:如下注释 + */ + protected void onContentChanged() { + super.onContentChanged(); + //执行基类函数 + calcNotesCount(); + } + + @Override + /* + * 函数功能:在activity光标发生局部变动的时候回调该函数计算便签的数量 + */ + public void changeCursor(Cursor cursor) { + super.changeCursor(cursor); + //执行基类函数 + calcNotesCount(); + } + + /* + * 函数功能:计算便签数量 + * + */ + private void calcNotesCount() { + mNotesCount = 0; + for (int i = 0; i < getCount(); i++) { + //获取总数同时遍历 + Cursor c = (Cursor) getItem(i); + if (c != null) { + if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) { + mNotesCount++; + //若该位置不为空并且文本类型为便签就+1 + } + } else { + Log.e(TAG, "Invalid cursor"); + return; + } + //否则报错 + } + } +} \ No newline at end of file From 4154aaa559e965cd35324eed12d16571c5599638 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:40:08 +0800 Subject: [PATCH 26/42] ADD file via upload --- src/ui/NotesListItem.java | 132 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 src/ui/NotesListItem.java diff --git a/src/ui/NotesListItem.java b/src/ui/NotesListItem.java new file mode 100644 index 0000000..a6788f0 --- /dev/null +++ b/src/ui/NotesListItem.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.ui; + +import android.content.Context; +import android.text.format.DateUtils; +import android.view.View; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.tool.DataUtils; +import net.micode.notes.tool.ResourceParser.NoteItemBgResources; + + +//创建便签列表项目选项 +public class NotesListItem extends LinearLayout { + private ImageView mAlert;//闹钟图片 + private TextView mTitle; //标题 + private TextView mTime; //时间 + private TextView mCallName; // + private NoteItemData mItemData; //标签数据 + private CheckBox mCheckBox; //打钩框 + + /*初始化基本信息*/ + public NotesListItem(Context context) { + super(context); //super()它的主要作用是调整调用父类构造函数的顺序 + inflate(context, R.layout.note_item, this);//Inflate可用于将一个xml中定义的布局控件找出来,这里的xml是r。layout + //findViewById用于从contentView中查找指定ID的View,转换出来的形式根据需要而定; + mAlert = (ImageView) findViewById(R.id.iv_alert_icon); + mTitle = (TextView) findViewById(R.id.tv_title); + mTime = (TextView) findViewById(R.id.tv_time); + mCallName = (TextView) findViewById(R.id.tv_name); + mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); + } + ///根据data的属性对各个控件的属性的控制,主要是可见性Visibility,内容setText,格式setTextAppearance + public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) { + if (choiceMode && data.getType() == Notes.TYPE_NOTE) { + mCheckBox.setVisibility(View.VISIBLE); ///设置可见行为可见 + mCheckBox.setChecked(checked); ///格子打钩 + } else { + mCheckBox.setVisibility(View.GONE); + } + + mItemData = data; + ///设置控件属性,一共三种情况,由data的id和父id是否与保存到文件夹的id一致来决定 + if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { + mCallName.setVisibility(View.GONE); + mAlert.setVisibility(View.VISIBLE); + //设置该textview的style + mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); + //settext为设置内容 + mTitle.setText(context.getString(R.string.call_record_folder_name) + + context.getString(R.string.format_folder_files_count, data.getNotesCount())); + mAlert.setImageResource(R.drawable.call_record); + } else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) { + mCallName.setVisibility(View.VISIBLE); + mCallName.setText(data.getCallName()); + mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem); + mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + ///关于闹钟的设置 + if (data.hasAlert()) { + mAlert.setImageResource(R.drawable.clock);//图片来源的设置 + mAlert.setVisibility(View.VISIBLE); + } else { + mAlert.setVisibility(View.GONE); + } + } else { + mCallName.setVisibility(View.GONE); + mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); + ///设置title格式 + if (data.getType() == Notes.TYPE_FOLDER) { + mTitle.setText(data.getSnippet() + + context.getString(R.string.format_folder_files_count, + data.getNotesCount())); + mAlert.setVisibility(View.GONE); + } else { + mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); + if (data.hasAlert()) { + mAlert.setImageResource(R.drawable.clock);///设置图片来源 + mAlert.setVisibility(View.VISIBLE); + } else { + mAlert.setVisibility(View.GONE); + } + } + } + ///设置内容,获取相关时间,从data里编辑的日期中获取 + mTime. setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); + + setBackground(data); + } + //根据data的文件属性来设置背景 + private void setBackground(NoteItemData data) { + int id = data.getBgColorId(); + //,若是note型文件,则4种情况,对于4种不同情况的背景来源 + if (data.getType() == Notes.TYPE_NOTE) { + //单个数据并且只有一个子文件夹 + if (data.isSingle() || data.isOneFollowingFolder()) { + setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); + } else if (data.isLast()) {//是最后一个数据 + setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id)); + } else if (data.isFirst() || data.isMultiFollowingFolder()) {//是一个数据并有多个子文件夹 + setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); + } else { + setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); + } + } else { + //若不是note直接调用文件夹的背景来源 + setBackgroundResource(NoteItemBgResources.getFolderBgRes()); + } + } + public NoteItemData getItemData() { + return mItemData; + } +} \ No newline at end of file From 0632c4265d1ba91e1b5b58f492955c90ca2988c4 Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:40:37 +0800 Subject: [PATCH 27/42] ADD file via upload --- src/ui/NotesPreferenceActivity.java | 515 ++++++++++++++++++++++++++++ 1 file changed, 515 insertions(+) create mode 100644 src/ui/NotesPreferenceActivity.java diff --git a/src/ui/NotesPreferenceActivity.java b/src/ui/NotesPreferenceActivity.java new file mode 100644 index 0000000..b4e2648 --- /dev/null +++ b/src/ui/NotesPreferenceActivity.java @@ -0,0 +1,515 @@ + +package net.micode.notes.ui; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.ActionBar; +import android.app.AlertDialog; +import android.content.BroadcastReceiver; +import android.content.ContentValues; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.Preference.OnPreferenceClickListener; +import android.preference.PreferenceActivity; +import android.preference.PreferenceCategory; +import android.text.TextUtils; +import android.text.format.DateFormat; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.gtask.remote.GTaskSyncService; + +/* + *该类功能:NotesPreferenceActivity,在小米便签中主要实现的是对背景颜色和字体大小的数据储存。 + * 继承了PreferenceActivity主要功能为对系统信息和配置进行自动保存的Activity + */ +public class NotesPreferenceActivity extends PreferenceActivity { + public static final String PREFERENCE_NAME = "notes_preferences"; + //优先名 + public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name"; + //同步账号 + public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time"; + //同步时间 + public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear"; + + private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key"; + //同步密码 + private static final String AUTHORITIES_FILTER_KEY = "authorities"; + //本地密码 + private PreferenceCategory mAccountCategory; + //账户分组 + private GTaskReceiver mReceiver; + //同步任务接收器 + private Account[] mOriAccounts; + //账户 + private boolean mHasAddedAccount; + //账户的hash标记 + + @Override + /* + *函数功能:创建一个activity,在函数里要完成所有的正常静态设置 + *参数:Bundle icicle:存放了 activity 当前的状态 + *函数实现:如下注释 + */ + protected void onCreate(Bundle icicle) { + //先执行父类的创建函数 + super.onCreate(icicle); + + /* using the app icon for navigation */ + getActionBar().setDisplayHomeAsUpEnabled(true); + //给左上角图标的左边加上一个返回的图标 + + addPreferencesFromResource(R.xml.preferences); + //添加xml来源并显示 xml + mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY); + //根据同步账户关键码来初始化分组 + mReceiver = new GTaskReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME); + registerReceiver(mReceiver, filter); + //初始化同步组件 + + mOriAccounts = null; + View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null); + //获取listvivew,ListView的作用:用于列出所有选择 + getListView().addHeaderView(header, null, true); + //在listview组件上方添加其他组件 + } + + @Override + /* + * 函数功能:activity交互功能的实现,用于接受用户的输入 + * 函数实现:如下注释 + */ + protected void onResume() { + //先执行父类 的交互实现 + super.onResume(); + + // need to set sync account automatically if user has added a new + // account + if (mHasAddedAccount) { + //若用户新加了账户则自动设置同步账户 + Account[] accounts = getGoogleAccounts(); + //获取google同步账户 + if (mOriAccounts != null && accounts.length > mOriAccounts.length) { + //若原账户不为空且当前账户有增加 + for (Account accountNew : accounts) { + boolean found = false; + for (Account accountOld : mOriAccounts) { + if (TextUtils.equals(accountOld.name, accountNew.name)) { + //更新账户 + found = true; + break; + } + } + if (!found) { + setSyncAccount(accountNew.name); + //若是没有找到旧的账户,那么同步账号中就只添加新账户 + break; + } + } + } + } + + refreshUI(); + //刷新标签界面 + } + + @Override + /* + * 函数功能:销毁一个activity + * 函数实现:如下注释 + */ + protected void onDestroy() { + if (mReceiver != null) { + unregisterReceiver(mReceiver); + //注销接收器 + } + super.onDestroy(); + //执行父类的销毁动作 + } + + /* + * 函数功能:重新设置账户信息 + * 函数实现:如下注释 + */ + private void loadAccountPreference() { + mAccountCategory.removeAll(); + //销毁所有的分组 + Preference accountPref = new Preference(this); + //建立首选项 + final String defaultAccount = getSyncAccountName(this); + accountPref.setTitle(getString(R.string.preferences_account_title)); + accountPref.setSummary(getString(R.string.preferences_account_summary)); + //设置首选项的大标题和小标题 + accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + //建立监听器 + if (!GTaskSyncService.isSyncing()) { + if (TextUtils.isEmpty(defaultAccount)) { + // the first time to set account + //若是第一次建立账户显示选择账户提示对话框 + showSelectAccountAlertDialog(); + } else { + // if the account has already been set, we need to promp + // user about the risk + //若是已经建立则显示修改对话框并进行修改操作 + showChangeAccountConfirmAlertDialog(); + } + } else { + //若在没有同步的情况下,则在toast中显示不能修改 + Toast.makeText(NotesPreferenceActivity.this, + R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT) + .show(); + } + return true; + } + }); + + //根据新建首选项编辑新的账户分组 + mAccountCategory.addPreference(accountPref); + } + + /* + *函数功能:设置按键的状态和最后同步的时间 + *函数实现:如下注释 + */ + private void loadSyncButton() { + Button syncButton = (Button) findViewById(R.id.preference_sync_button); + TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview); + //获取同步按钮控件和最终同步时间的的窗口 + // set button state + //设置按钮的状态 + if (GTaskSyncService.isSyncing()) { + //若是在同步状态下 + syncButton.setText(getString(R.string.preferences_button_sync_cancel)); + syncButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + GTaskSyncService.cancelSync(NotesPreferenceActivity.this); + } + }); + //设置按钮显示的文本为“取消同步”以及监听器 + } else { + syncButton.setText(getString(R.string.preferences_button_sync_immediately)); + syncButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + GTaskSyncService.startSync(NotesPreferenceActivity.this); + } + }); + //若是不同步则设置按钮显示的文本为“立即同步”以及对应监听器 + } + syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this))); + //设置按键可用还是不可用 + + // set last sync time + // 设置最终同步时间 + if (GTaskSyncService.isSyncing()) { + //若是在同步的情况下 + lastSyncTimeView.setText(GTaskSyncService.getProgressString()); + lastSyncTimeView.setVisibility(View.VISIBLE); + // 根据当前同步服务器设置时间显示框的文本以及可见性 + } else { + //若是非同步情况 + long lastSyncTime = getLastSyncTime(this); + if (lastSyncTime != 0) { + lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time, + DateFormat.format(getString(R.string.preferences_last_sync_time_format), + lastSyncTime))); + lastSyncTimeView.setVisibility(View.VISIBLE); + //则根据最后同步时间的信息来编辑时间显示框的文本内容和可见性 + } else { + //若时间为空直接设置为不可见状态 + lastSyncTimeView.setVisibility(View.GONE); + } + } + } + /* + *函数功能:刷新标签界面 + *函数实现:调用上文设置账号和设置按键两个函数来实现 + */ + private void refreshUI() { + loadAccountPreference(); + loadSyncButton(); + } + + /* + * 函数功能:显示账户选择的对话框并进行账户的设置 + * 函数实现:如下注释 + */ + private void showSelectAccountAlertDialog() { + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); + //创建一个新的对话框 + + View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); + TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); + titleTextView.setText(getString(R.string.preferences_dialog_select_account_title)); + TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); + subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips)); + //设置标题以及子标题的内容 + dialogBuilder.setCustomTitle(titleView); + dialogBuilder.setPositiveButton(null, null); + //设置对话框的自定义标题,建立一个YES的按钮 + Account[] accounts = getGoogleAccounts(); + String defAccount = getSyncAccountName(this); + //获取同步账户信息 + mOriAccounts = accounts; + mHasAddedAccount = false; + + if (accounts.length > 0) { + //若账户不为空 + CharSequence[] items = new CharSequence[accounts.length]; + final CharSequence[] itemMapping = items; + int checkedItem = -1; + int index = 0; + for (Account account : accounts) { + if (TextUtils.equals(account.name, defAccount)) { + checkedItem = index; + //在账户列表中查询到所需账户 + } + items[index++] = account.name; + } + dialogBuilder.setSingleChoiceItems(items, checkedItem, + //在对话框建立一个单选的复选框 + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + setSyncAccount(itemMapping[which].toString()); + dialog.dismiss(); + //取消对话框 + refreshUI(); + } + //设置点击后执行的事件,包括检录新同步账户和刷新标签界面 + }); + //建立对话框网络版的监听器 + } + + View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null); + dialogBuilder.setView(addAccountView); + //给新加账户对话框设置自定义样式 + + final AlertDialog dialog = dialogBuilder.show(); + //显示对话框 + addAccountView.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + mHasAddedAccount = true; + //将新加账户的hash置true + Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS"); + //建立网络建立组件 + intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] { + "gmail-ls" + }); + startActivityForResult(intent, -1); + //跳回上一个选项 + dialog.dismiss(); + } + }); + //建立新加账户对话框的监听器 + } + + /* + * 函数功能:显示账户选择对话框和相关账户操作 + * 函数实现:如下注释 + */ + private void showChangeAccountConfirmAlertDialog() { + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); + //创建一个新的对话框 + View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null); + TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title); + titleTextView.setText(getString(R.string.preferences_dialog_change_account_title, + getSyncAccountName(this))); + TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle); + subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg)); + //根据同步修改的账户信息设置标题以及子标题的内容 + dialogBuilder.setCustomTitle(titleView); + //设置对话框的自定义标题 + CharSequence[] menuItemArray = new CharSequence[] { + getString(R.string.preferences_menu_change_account), + getString(R.string.preferences_menu_remove_account), + getString(R.string.preferences_menu_cancel) + }; + //定义一些标记字符串 + dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() { + //设置对话框要显示的一个list,用于显示几个命令时,即change,remove,cancel + public void onClick(DialogInterface dialog, int which) { + //按键功能,由which来决定 + if (which == 0) { + //进入账户选择对话框 + showSelectAccountAlertDialog(); + } else if (which == 1) { + //删除账户并且跟新便签界面 + removeSyncAccount(); + refreshUI(); + } + } + }); + dialogBuilder.show(); + //显示对话框 + } + + /* + *函数功能:获取谷歌账户 + *函数实现:通过账户管理器直接获取 + */ + private Account[] getGoogleAccounts() { + AccountManager accountManager = AccountManager.get(this); + return accountManager.getAccountsByType("com.google"); + } + + /* + * 函数功能:设置同步账户 + * 函数实现:如下注释: + */ + private void setSyncAccount(String account) { + if (!getSyncAccountName(this).equals(account)) { + //假如该账号不在同步账号列表中 + SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + //编辑共享的首选项 + if (account != null) { + editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account); + } else { + editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); + } + //将该账号加入到首选项中 + + editor.commit(); + //提交修改的数据 + + + setLastSyncTime(this, 0); + //将最后同步时间清零 + + // clean up local gtask related info + new Thread(new Runnable() { + public void run() { + ContentValues values = new ContentValues(); + values.put(NoteColumns.GTASK_ID, ""); + values.put(NoteColumns.SYNC_ID, 0); + getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); + } + }).start(); + //重置当地同步任务的信息 + + Toast.makeText(NotesPreferenceActivity.this, + getString(R.string.preferences_toast_success_set_accout, account), + Toast.LENGTH_SHORT).show(); + //将toast的文本信息置为“设置账户成功”并显示出来 + } + } + /* + * 函数功能:删除同步账户 + * 函数实现:如下注释: + */ + private void removeSyncAccount() { + SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + //设置共享首选项 + + if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) { + editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME); + //假如当前首选项中有账户就删除 + } + if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) { + editor.remove(PREFERENCE_LAST_SYNC_TIME); + //删除当前首选项中有账户时间 + } + editor.commit(); + //提交更新后的数据 + + // clean up local gtask related info + new Thread(new Runnable() { + public void run() { + ContentValues values = new ContentValues(); + values.put(NoteColumns.GTASK_ID, ""); + values.put(NoteColumns.SYNC_ID, 0); + getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null); + } + }).start(); + //重置当地同步任务的信息 + } + + /* + * 函数功能:获取同步账户名称 + * 函数实现:通过共享的首选项里的信息直接获取 + */ + public static String getSyncAccountName(Context context) { + SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, + Context.MODE_PRIVATE); + return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, ""); + } + + /* + * 函数功能:设置最终同步的时间 + * 函数实现:如下注释 + */ + public static void setLastSyncTime(Context context, long time) { + SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, + Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + // 从共享首选项中找到相关账户并获取其编辑器 + editor.putLong(PREFERENCE_LAST_SYNC_TIME, time); + editor.commit(); + //编辑最终同步时间并提交更新 + } + /* + * 函数功能:获取最终同步时间 + * 函数实现:通过共享的首选项里的信息直接获取 + */ + public static long getLastSyncTime(Context context) { + SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, + Context.MODE_PRIVATE); + return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0); + } + + /* + * 函数功能:接受同步信息 + * 函数实现:继承BroadcastReceiver + */ + private class GTaskReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + refreshUI(); + if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) { + //获取随广播而来的Intent中的同步服务的数据 + TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview); + syncStatus.setText(intent + .getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG)); + //通过获取的数据在设置系统的状态 + } + + } + } + + /* + * 函数功能:处理菜单的选项 + * 函数实现:如下注释 + * 参数:MenuItem菜单选项 + */ + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + //根据选项的id选择,这里只有一个主页 + case android.R.id.home: + Intent intent = new Intent(this, NotesListActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + return true; + //在主页情况下在创建连接组件intent,发出清空的信号并开始一个相应的activity + default: + return false; + } + } +} + \ No newline at end of file From c6c2cf524dce49b9724af8600c7964bd583c047d Mon Sep 17 00:00:00 2001 From: p5xa2nr94 <2819669699@qq.com> Date: Mon, 11 Dec 2023 20:41:39 +0800 Subject: [PATCH 28/42] =?UTF-8?q?=E5=B0=8F=E7=B1=B3=E4=BE=BF=E7=AD=BE?= =?UTF-8?q?=E6=B3=9B=E8=AF=BB=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ..._2023317148_小米便签泛读报告.docx | Bin 0 -> 100798 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/姜洪泽_2023317148_小米便签泛读报告.docx diff --git a/doc/姜洪泽_2023317148_小米便签泛读报告.docx b/doc/姜洪泽_2023317148_小米便签泛读报告.docx new file mode 100644 index 0000000000000000000000000000000000000000..d3382cb71c6efdd8126b3b8ebee04bd16b9b882f GIT binary patch literal 100798 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�p&lW`O1Q#nZU~-X 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 Qp4-Y4t5TX9Wm4)eP8X2KX{oL@H%fOf#aQ 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 literal 0 HcmV?d00001 From f017eabf1a5a515deb4a1a846823553743521000 Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:43:53 +0800 Subject: [PATCH 29/42] =?UTF-8?q?=E5=B0=8F=E7=B1=B3=E4=BE=BF=E7=AD=BEgtask?= =?UTF-8?q?=E5=8C=85=E6=B3=9B=E8=AF=BB=E6=8A=A5=E5=91=8A.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...磊_2023317156_小米便签泛读报告.docx | Bin 0 -> 63768 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/梁圣磊_2023317156_小米便签泛读报告.docx diff --git a/doc/梁圣磊_2023317156_小米便签泛读报告.docx b/doc/梁圣磊_2023317156_小米便签泛读报告.docx new file mode 100644 index 0000000000000000000000000000000000000000..d3c321714abe3fe003c430b6d8b3b2c8a5dd7ca1 GIT binary patch literal 63768 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 L3d|+7UqL(os3n*t literal 0 HcmV?d00001 From 54c7d53b0812b3bb6b68e91a4678a50dd2098bc0 Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:44:53 +0800 Subject: [PATCH 30/42] ADD file via upload --- src/gtask/data/MetaData.java | 105 +++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/gtask/data/MetaData.java diff --git a/src/gtask/data/MetaData.java b/src/gtask/data/MetaData.java new file mode 100644 index 0000000..568372c --- /dev/null +++ b/src/gtask/data/MetaData.java @@ -0,0 +1,105 @@ + +package net.micode.notes.gtask.data; + +public class MetaData extends Task { + /* + * 功能描述:得到类的简写名称存入字符串TAG中 + * 实现过程:调用getSimpleName ()函数 + */ + private final static String TAG = MetaData.class.getSimpleName(); + private String mRelatedGid = null; + /* + * 功能描述:设置数据,即生成元数据库 + * 实现过程:调用JSONObject库函数put (),Task类中的setNotes ()和setName ()函数 + * 参数注解: + */ + public void setMeta(String gid, JSONObject metaInfo) + { + //对函数块进行注释 + try { + metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); + /* + * 将这对键值放入metaInfo这个jsonobject对象中 + */ + } catch (JSONException e) { + Log.e(TAG, "failed to put related gid"); + /* + * 输出错误信息 + */ + } + setNotes(metaInfo.toString()); + setName(GTaskStringUtils.META_NOTE_NAME); + } + /* + * 功能描述:获取相关联的Gid + */ + public String getRelatedGid() { + return mRelatedGid; + } + /* + * 功能描述:判断当前数据是否为空,若为空则返回真即值得保存 + * Made By CuiCan + */ + @Override + public boolean isWorthSaving() { + return getNotes() != null; + } + /* + * 功能描述:使用远程json数据对象设置元数据内容 + * 实现过程:调用父类Task中的setContentByRemoteJSON ()函数,并 + * 参数注解: + */ + @Override + public void setContentByRemoteJSON(JSONObject js) { + super.setContentByRemoteJSON(js); + if (getNotes() != null) { + try { + JSONObject metaInfo = new JSONObject(getNotes().trim()); + mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); + } catch (JSONException e) { + Log.w(TAG, "failed to get related gid"); + /* + * 输出警告信息 + */ + mRelatedGid = null; + } + } + } + /* + * 功能描述:使用本地json数据对象设置元数据内容,一般不会用到,若用到,则抛出异常 + * Made By CuiCan + */ + @Override + public void setContentByLocalJSON(JSONObject js) { + // this function should not be called + throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); + /* + * 传递非法参数异常 + */ + } + /* + * 功能描述:从元数据内容中获取本地json对象,一般不会用到,若用到,则抛出异常 + * Made By CuiCan + */ + @Override + public JSONObject getLocalJSONFromContent() { + throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); + /* + * 传递非法参数异常 + * Made By Cui Can + */ + } + /* + * 功能描述:获取同步动作状态,一般不会用到,若用到,则抛出异常 + * Made By CuiCan + */ + @Override + public int getSyncAction(Cursor c) { + throw new IllegalAccessError("MetaData:getSyncAction should not be called"); + /* + * 传递非法参数异常 + * Made By Cui Can + */ + } + +} \ No newline at end of file From 074d98bb3b2b36b7d245d393969934c6050a3dd1 Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:45:12 +0800 Subject: [PATCH 31/42] ADD file via upload --- src/gtask/data/Node.java | 91 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/gtask/data/Node.java diff --git a/src/gtask/data/Node.java b/src/gtask/data/Node.java new file mode 100644 index 0000000..2275f99 --- /dev/null +++ b/src/gtask/data/Node.java @@ -0,0 +1,91 @@ + +package net.micode.notes.gtask.data; + +import android.database.Cursor; + +import org.json.JSONObject; + +/** + * 应该是同步操作的基础数据类型,定义了相关指示同步操作的常量 + * 关键字:abstract + */ +public abstract class Node { + //定义了各种用于表征同步状态的常量 + public static final int SYNC_ACTION_NONE = 0;// 本地和云端都无可更新内容(即本地和云端内容一致) + + public static final int SYNC_ACTION_ADD_REMOTE = 1;// 需要在远程云端增加内容 + + public static final int SYNC_ACTION_ADD_LOCAL = 2;// 需要在本地增加内容 + + public static final int SYNC_ACTION_DEL_REMOTE = 3;// 需要在远程云端删除内容 + + public static final int SYNC_ACTION_DEL_LOCAL = 4;// 需要在本地删除内容 + + public static final int SYNC_ACTION_UPDATE_REMOTE = 5;// 需要将本地内容更新到远程云端 + + public static final int SYNC_ACTION_UPDATE_LOCAL = 6;// 需要将远程云端内容更新到本地 + + public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;// 同步出现冲突 + + public static final int SYNC_ACTION_ERROR = 8;// 同步出现错误 + + private String mGid; + + private String mName; + + private long mLastModified;//记录最后一次修改时间 + + private boolean mDeleted;//表征是否被删除 + + public Node() { + mGid = null; + mName = ""; + mLastModified = 0; + mDeleted = false; + } + + public abstract JSONObject getCreateAction(int actionId); + + public abstract JSONObject getUpdateAction(int actionId); + + public abstract void setContentByRemoteJSON(JSONObject js); + + public abstract void setContentByLocalJSON(JSONObject js); + + public abstract JSONObject getLocalJSONFromContent(); + + public abstract int getSyncAction(Cursor c); + + public void setGid(String gid) { + this.mGid = gid; + } + + public void setName(String name) { + this.mName = name; + } + + public void setLastModified(long lastModified) { + this.mLastModified = lastModified; + } + + public void setDeleted(boolean deleted) { + this.mDeleted = deleted; + } + + public String getGid() { + return this.mGid; + } + + public String getName() { + return this.mName; + } + + public long getLastModified() { + return this.mLastModified; + } + + public boolean getDeleted() { + return this.mDeleted; + } + +} \ No newline at end of file From 77431713593f92d0f9b89028db3f3243460ec87f Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:45:19 +0800 Subject: [PATCH 32/42] ADD file via upload --- src/gtask/data/SqlData.java | 226 ++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 src/gtask/data/SqlData.java diff --git a/src/gtask/data/SqlData.java b/src/gtask/data/SqlData.java new file mode 100644 index 0000000..1a1a492 --- /dev/null +++ b/src/gtask/data/SqlData.java @@ -0,0 +1,226 @@ + + +/* + * Description:用于支持小米便签最底层的数据库相关操作,和sqlnote的关系上是子集关系,即data是note的子集(节点)。 + * SqlData其实就是也就是所谓数据中的数据 + */ + +package net.micode.notes.gtask.data; +/* + * 功能描述: + * 实现过程: + * 参数注解: + * Made By CuiCan + */ + +public class SqlData { + /* + * 功能描述:得到类的简写名称存入字符串TAG中 + * 实现过程:调用getSimpleName ()函数 + * Made By CuiCan + */ + private static final String TAG = SqlData.class.getSimpleName(); + + private static final int INVALID_ID = -99999;//为mDataId置初始值-99999 + + + /** + * 来自Notes类中定义的DataColumn中的一些常量 + */ + + // 集合了interface DataColumns中所有SF常量 + public static final String[] PROJECTION_DATA = new String[] { + DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, + DataColumns.DATA3 + }; + + /** + * 以下五个变量作为sql表中5列的编号 + */ + public static final int DATA_ID_COLUMN = 0; + + public static final int DATA_MIME_TYPE_COLUMN = 1; + + public static final int DATA_CONTENT_COLUMN = 2; + + public static final int DATA_CONTENT_DATA_1_COLUMN = 3; + + public static final int DATA_CONTENT_DATA_3_COLUMN = 4; + + private ContentResolver mContentResolver; + //判断是否直接用Content生成,是为true,否则为false + private boolean mIsCreate; + + private long mDataId; + + private String mDataMimeType; + + private String mDataContent; + + private long mDataContentData1; + + private String mDataContentData3; + + private ContentValues mDiffDataValues; + + /* + * 功能描述:构造函数,用于初始化数据 + * 参数注解:mContentResolver用于获取ContentProvider提供的数据 + * 参数注解: mIsCreate表征当前数据是用哪种方式创建(两种构造函数的参数不同) + * 参数注解: + * Made By CuiCan + */ + public SqlData(Context context) { + mContentResolver = context.getContentResolver(); + mIsCreate = true; + mDataId = INVALID_ID;//mDataId置初始值-99999 + mDataMimeType = DataConstants.NOTE; + mDataContent = ""; + mDataContentData1 = 0; + mDataContentData3 = ""; + mDiffDataValues = new ContentValues(); + } + + + /* + * 功能描述:构造函数,初始化数据 + * 参数注解:mContentResolver用于获取ContentProvider提供的数据 + * 参数注解: mIsCreate表征当前数据是用哪种方式创建(两种构造函数的参数不同) + * 参数注解: + * Made By CuiCan + */ + public SqlData(Context context, Cursor c) { + mContentResolver = context.getContentResolver(); + mIsCreate = false; + loadFromCursor(c); + mDiffDataValues = new ContentValues(); + } + + /* + * 功能描述:从光标处加载数据 + * 从当前的光标处将五列的数据加载到该类的对象 + * Made By CuiCan + */ + private void loadFromCursor(Cursor c) { + mDataId = c.getLong(DATA_ID_COLUMN); + mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); + mDataContent = c.getString(DATA_CONTENT_COLUMN); + mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); + mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); + } + + + /* + * 功能描述:设置用于共享的数据,并提供异常抛出与处理机制 + * 参数注解: + * Made By CuiCan + */ + public void setContent(JSONObject js) throws JSONException { + //如果传入的JSONObject对象中有DataColumns.ID这一项,则设置,否则设为INVALID_ID + long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; + if (mIsCreate || mDataId != dataId) { + mDiffDataValues.put(DataColumns.ID, dataId); + } + mDataId = dataId; + + String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE) + : DataConstants.NOTE; + if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { + mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType); + } + mDataMimeType = dataMimeType; + + String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; + if (mIsCreate || !mDataContent.equals(dataContent)) { + mDiffDataValues.put(DataColumns.CONTENT, dataContent); + } + mDataContent = dataContent; + + long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; + if (mIsCreate || mDataContentData1 != dataContentData1) { + mDiffDataValues.put(DataColumns.DATA1, dataContentData1); + } + mDataContentData1 = dataContentData1; + + String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; + if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { + mDiffDataValues.put(DataColumns.DATA3, dataContentData3); + } + mDataContentData3 = dataContentData3; + } + + + /* + * 功能描述:获取共享的数据内容,并提供异常抛出与处理机制 + * 参数注解: + * Made By CuiCan + */ + public JSONObject getContent() throws JSONException { + if (mIsCreate) { + Log.e(TAG, "it seems that we haven't created this in database yet"); + return null; + } + //创建JSONObject对象。并将相关数据放入其中,并返回。 + JSONObject js = new JSONObject(); + js.put(DataColumns.ID, mDataId); + js.put(DataColumns.MIME_TYPE, mDataMimeType); + js.put(DataColumns.CONTENT, mDataContent); + js.put(DataColumns.DATA1, mDataContentData1); + js.put(DataColumns.DATA3, mDataContentData3); + return js; + } + + /* + * 功能描述:commit函数用于把当前造作所做的修改保存到数据库 + * 参数注解: + * Made By CuiCan + */ + public void commit(long noteId, boolean validateVersion, long version) { + + if (mIsCreate) { + if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { + mDiffDataValues.remove(DataColumns.ID); + } + + mDiffDataValues.put(DataColumns.NOTE_ID, noteId); + Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); + try { + mDataId = Long.valueOf(uri.getPathSegments().get(1)); + } catch (NumberFormatException e) { + Log.e(TAG, "Get note id error :" + e.toString()); + throw new ActionFailureException("create note failed"); + } + } else { + if (mDiffDataValues.size() > 0) { + int result = 0; + if (!validateVersion) { + result = mContentResolver.update(ContentUris.withAppendedId( + Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); + } else { + result = mContentResolver.update(ContentUris.withAppendedId( + Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, + " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE + + " WHERE " + NoteColumns.VERSION + "=?)", new String[] { + String.valueOf(noteId), String.valueOf(version) + }); + } + if (result == 0) { + Log.w(TAG, "there is no update. maybe user updates note when syncing"); + } + } + } + + mDiffDataValues.clear(); + mIsCreate = false; + } + + /* + * 功能描述:获取当前id + * 实现过程: + * 参数注解: + * Made By CuiCan + */ + public long getId() { + return mDataId; + } +} \ No newline at end of file From 8ef1a0b17f9cd0d771e1d27345d9dd3e9bd530c3 Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:45:30 +0800 Subject: [PATCH 33/42] ADD file via upload --- src/gtask/data/SqlNote.java | 578 ++++++++++++++++++++++++++++++++++++ 1 file changed, 578 insertions(+) create mode 100644 src/gtask/data/SqlNote.java diff --git a/src/gtask/data/SqlNote.java b/src/gtask/data/SqlNote.java new file mode 100644 index 0000000..de1685a --- /dev/null +++ b/src/gtask/data/SqlNote.java @@ -0,0 +1,578 @@ + +/* + * Description:用于支持小米便签最底层的数据库相关操作,和sqldata的关系上是父集关系,即note是data的子父集。 + * 和SqlData相比,SqlNote算是真正意义上的数据了。 + */ + +package net.micode.notes.gtask.data; +/* + * 功能描述: + * 实现过程: + * 参数注解: + * Made By CuiCan + */ + +public class SqlNote { + /* + * 功能描述:得到类的简写名称存入字符串TAG中 + * 实现过程:调用getSimpleName ()函数 + * Made By CuiCan + */ + private static final String TAG = SqlNote.class.getSimpleName(); + + private static final int INVALID_ID = -99999; + // 集合了interface NoteColumns中所有SF常量(17个) + public static final String[] PROJECTION_NOTE = new String[] { + NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID, + NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE, + NoteColumns.NOTES_COUNT, NoteColumns.PARENT_ID, NoteColumns.SNIPPET, NoteColumns.TYPE, + NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.SYNC_ID, + NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID, + NoteColumns.VERSION + }; + + //以下设置17个列的编号 + public static final int ID_COLUMN = 0; + + public static final int ALERTED_DATE_COLUMN = 1; + + public static final int BG_COLOR_ID_COLUMN = 2; + + public static final int CREATED_DATE_COLUMN = 3; + + public static final int HAS_ATTACHMENT_COLUMN = 4; + + public static final int MODIFIED_DATE_COLUMN = 5; + + public static final int NOTES_COUNT_COLUMN = 6; + + public static final int PARENT_ID_COLUMN = 7; + + public static final int SNIPPET_COLUMN = 8; + + public static final int TYPE_COLUMN = 9; + + public static final int WIDGET_ID_COLUMN = 10; + + public static final int WIDGET_TYPE_COLUMN = 11; + + public static final int SYNC_ID_COLUMN = 12; + + public static final int LOCAL_MODIFIED_COLUMN = 13; + + public static final int ORIGIN_PARENT_ID_COLUMN = 14; + + public static final int GTASK_ID_COLUMN = 15; + + public static final int VERSION_COLUMN = 16; + + //一下定义了17个内部的变量,其中12个可以由content中获得,5个需要初始化为0或者new + private Context mContext; + + private ContentResolver mContentResolver; + + private boolean mIsCreate; + + private long mId; + + private long mAlertDate; + + private int mBgColorId; + + private long mCreatedDate; + + private int mHasAttachment; + + private long mModifiedDate; + + private long mParentId; + + private String mSnippet; + + private int mType; + + private int mWidgetId; + + private int mWidgetType; + + private long mOriginParent; + + private long mVersion; + + private ContentValues mDiffNoteValues; + + private ArrayList mDataList; + + /* + * 功能描述:构造函数 + * 参数注解: mIsCreate用于标示构造方式 + * 参数注解: + * Made By CuiCan + */ + //构造函数只有context,对所有的变量进行初始化 + public SqlNote(Context context) { + mContext = context; + mContentResolver = context.getContentResolver(); + mIsCreate = true; + mId = INVALID_ID; + mAlertDate = 0; + mBgColorId = ResourceParser.getDefaultBgId(context); + mCreatedDate = System.currentTimeMillis();//调用系统函数获得创建时间 + mHasAttachment = 0; + mModifiedDate = System.currentTimeMillis();//最后一次修改时间初始化为创建时间 + mParentId = 0; + mSnippet = ""; + mType = Notes.TYPE_NOTE; + mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; + mWidgetType = Notes.TYPE_WIDGET_INVALIDE; + mOriginParent = 0; + mVersion = 0; + mDiffNoteValues = new ContentValues(); + mDataList = new ArrayList(); + } + + + /* + * 功能描述:构造函数 + * 参数注解: mIsCreate用于标示构造方式 + * 参数注解: + * Made By CuiCan + */ + //构造函数有context和一个数据库的cursor,多数变量通过cursor指向的一条记录直接进行初始化 + public SqlNote(Context context, Cursor c) { + mContext = context; + mContentResolver = context.getContentResolver(); + mIsCreate = false; + loadFromCursor(c); + mDataList = new ArrayList(); + // + if (mType == Notes.TYPE_NOTE) + loadDataContent(); + mDiffNoteValues = new ContentValues(); + } + + + /* + * 功能描述:构造函数 + * 参数注解: mIsCreate用于标示构造方式 + * 参数注解: + * Made By CuiCan + */ + public SqlNote(Context context, long id) { + mContext = context; + mContentResolver = context.getContentResolver(); + mIsCreate = false; + loadFromCursor(id); + mDataList = new ArrayList(); + if (mType == Notes.TYPE_NOTE) + loadDataContent(); + mDiffNoteValues = new ContentValues(); + + } + + /* + * 功能描述:通过id从光标处加载数据 + * Made By CuiCan + */ + private void loadFromCursor(long id) { + Cursor c = null; + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", + new String[] { + String.valueOf(id) + }, null);//通过id获得对应的ContentResolver中的cursor + if (c != null) { + c.moveToNext(); + loadFromCursor(c);//然后加载数据进行初始化,这样函数 + //SqlNote(Context context, long id)与SqlNote(Context context, long id)的实现方式基本相同 + } else { + Log.w(TAG, "loadFromCursor: cursor = null"); + } + } finally { + if (c != null) + c.close(); + } + } + + /* + * 功能描述:通过游标从光标处加载数据 + * Made By CuiCan + */ + private void loadFromCursor(Cursor c) { + //直接从一条记录中的获得以下变量的初始值 + mId = c.getLong(ID_COLUMN); + mAlertDate = c.getLong(ALERTED_DATE_COLUMN); + mBgColorId = c.getInt(BG_COLOR_ID_COLUMN); + mCreatedDate = c.getLong(CREATED_DATE_COLUMN); + mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN); + mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN); + mParentId = c.getLong(PARENT_ID_COLUMN); + mSnippet = c.getString(SNIPPET_COLUMN); + mType = c.getInt(TYPE_COLUMN); + mWidgetId = c.getInt(WIDGET_ID_COLUMN); + mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); + mVersion = c.getLong(VERSION_COLUMN); + } + + /* + * 功能描述:通过content机制获取共享数据并加载到数据库当前游标处 + * 参数注解: + * Made By CuiCan + */ + private void loadDataContent() { + Cursor c = null; + mDataList.clear(); + try { + c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, + "(note_id=?)", new String[] { + String.valueOf(mId) + }, null); + if (c != null) { + if (c.getCount() == 0) { + Log.w(TAG, "it seems that the note has not data"); + return; + } + while (c.moveToNext()) { + SqlData data = new SqlData(mContext, c); + mDataList.add(data); + } + } else { + Log.w(TAG, "loadDataContent: cursor = null"); + } + } finally { + if (c != null) + c.close(); + } + } + + /* + * 功能描述:设置通过content机制用于共享的数据信息 + * 参数注解: + * Made By CuiCan + */ + public boolean setContent(JSONObject js) { + try { + JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { + Log.w(TAG, "cannot set system folder"); + } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { + // for folder we can only update the snnipet and type + String snippet = note.has(NoteColumns.SNIPPET) ? note + .getString(NoteColumns.SNIPPET) : ""; + if (mIsCreate || !mSnippet.equals(snippet)) { + mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); + } + mSnippet = snippet; + + int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) + : Notes.TYPE_NOTE; + if (mIsCreate || mType != type) { + mDiffNoteValues.put(NoteColumns.TYPE, type); + } + mType = type; + } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { + JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID; + if (mIsCreate || mId != id) { + mDiffNoteValues.put(NoteColumns.ID, id); + } + mId = id; + + long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note + .getLong(NoteColumns.ALERTED_DATE) : 0; + if (mIsCreate || mAlertDate != alertDate) { + mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate); + } + mAlertDate = alertDate; + + int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note + .getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext); + if (mIsCreate || mBgColorId != bgColorId) { + mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId); + } + mBgColorId = bgColorId; + long createDate = note.has(NoteColumns.CREATED_DATE) ? note + .getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis(); + if (mIsCreate || mCreatedDate != createDate) { + mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate); + } + mCreatedDate = createDate; + + int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note + .getInt(NoteColumns.HAS_ATTACHMENT) : 0; + if (mIsCreate || mHasAttachment != hasAttachment) { + mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment); + } + mHasAttachment = hasAttachment; + + long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note + .getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis(); + if (mIsCreate || mModifiedDate != modifiedDate) { + mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate); + } + mModifiedDate = modifiedDate; + + long parentId = note.has(NoteColumns.PARENT_ID) ? note + .getLong(NoteColumns.PARENT_ID) : 0; + if (mIsCreate || mParentId != parentId) { + mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId); + } + mParentId = parentId; + + String snippet = note.has(NoteColumns.SNIPPET) ? note + .getString(NoteColumns.SNIPPET) : ""; + if (mIsCreate || !mSnippet.equals(snippet)) { + mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); + } + mSnippet = snippet; + + int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) + : Notes.TYPE_NOTE; + if (mIsCreate || mType != type) { + mDiffNoteValues.put(NoteColumns.TYPE, type); + } + mType = type; + + int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID) + : AppWidgetManager.INVALID_APPWIDGET_ID; + if (mIsCreate || mWidgetId != widgetId) { + mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId); + } + mWidgetId = widgetId; + + int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note + .getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE; + if (mIsCreate || mWidgetType != widgetType) { + mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType); + } + mWidgetType = widgetType; + + long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note + .getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; + if (mIsCreate || mOriginParent != originParent) { + mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent); + } + mOriginParent = originParent; + + for (int i = 0; i < dataArray.length(); i++) { + JSONObject data = dataArray.getJSONObject(i); + SqlData sqlData = null; + if (data.has(DataColumns.ID)) { + long dataId = data.getLong(DataColumns.ID); + for (SqlData temp : mDataList) { + if (dataId == temp.getId()) { + sqlData = temp; + } + } + } + + if (sqlData == null) { + sqlData = new SqlData(mContext); + mDataList.add(sqlData); + } + + sqlData.setContent(data); + } + } + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + return false; + } + return true; + } + + /* + * 功能描述:获取content机制提供的数据并加载到note中 + * 参数注解: + * Made By CuiCan + */ + public JSONObject getContent() { + try { + JSONObject js = new JSONObject(); + + if (mIsCreate) { + Log.e(TAG, "it seems that we haven't created this in database yet"); + return null; + } + + JSONObject note = new JSONObject(); + if (mType == Notes.TYPE_NOTE) {//类型为note时 + note.put(NoteColumns.ID, mId); + note.put(NoteColumns.ALERTED_DATE, mAlertDate); + note.put(NoteColumns.BG_COLOR_ID, mBgColorId); + note.put(NoteColumns.CREATED_DATE, mCreatedDate); + note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment); + note.put(NoteColumns.MODIFIED_DATE, mModifiedDate); + note.put(NoteColumns.PARENT_ID, mParentId); + note.put(NoteColumns.SNIPPET, mSnippet); + note.put(NoteColumns.TYPE, mType); + note.put(NoteColumns.WIDGET_ID, mWidgetId); + note.put(NoteColumns.WIDGET_TYPE, mWidgetType); + note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent); + js.put(GTaskStringUtils.META_HEAD_NOTE, note); + + JSONArray dataArray = new JSONArray(); + for (SqlData sqlData : mDataList) { + JSONObject data = sqlData.getContent(); + if (data != null) { + dataArray.put(data); + } + } + js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); + } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {//类型为文件夹或者 + note.put(NoteColumns.ID, mId); + note.put(NoteColumns.TYPE, mType); + note.put(NoteColumns.SNIPPET, mSnippet); + js.put(GTaskStringUtils.META_HEAD_NOTE, note); + } + + return js; + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + } + return null; + } + + /* + * 功能描述:给当前id设置父id + * 参数注解: + * Made By CuiCan + */ + public void setParentId(long id) { + mParentId = id; + mDiffNoteValues.put(NoteColumns.PARENT_ID, id); + } + + /* + * 功能描述:给当前id设置Gtaskid + * 参数注解: + * Made By CuiCan + */ + public void setGtaskId(String gid) { + mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); + } + + /* + * 功能描述:给当前id设置同步id + * 参数注解: + * Made By CuiCan + */ + public void setSyncId(long syncId) { + mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); + } + + /* + * 功能描述:初始化本地修改,即撤销所有当前修改 + * 参数注解: + * Made By CuiCan + */ + public void resetLocalModified() { + mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); + } + + /* + * 功能描述:获得当前id + * 参数注解: + * Made By CuiCan + */ + public long getId() { + return mId; + } + + /* + * 功能描述:获得当前id的父id + * 参数注解: + * Made By CuiCan + */ + public long getParentId() { + return mParentId; + } + + /* + * 功能描述:获取小片段即用于显示的部分便签内容 + * 参数注解: + * Made By CuiCan + */ + public String getSnippet() { + return mSnippet; + } + + /* + * 功能描述:判断是否为便签类型 + * 参数注解: + * Made By CuiCan + */ + public boolean isNoteType() { + return mType == Notes.TYPE_NOTE; + } + + /* + * 功能描述:commit函数用于把当前造作所做的修改保存到数据库 + * 参数注解: + * Made By CuiCan + */ + public void commit(boolean validateVersion) { + if (mIsCreate) { + if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { + mDiffNoteValues.remove(NoteColumns.ID); + } + + Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues); + try { + mId = Long.valueOf(uri.getPathSegments().get(1)); + } catch (NumberFormatException e) { + Log.e(TAG, "Get note id error :" + e.toString()); + throw new ActionFailureException("create note failed"); + } + if (mId == 0) { + throw new IllegalStateException("Create thread id failed"); + } + + if (mType == Notes.TYPE_NOTE) { + for (SqlData sqlData : mDataList) {//直接使用sqldata中的实现 + sqlData.commit(mId, false, -1); + } + } + } else { + if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) { + Log.e(TAG, "No such note"); + throw new IllegalStateException("Try to update note with invalid id"); + } + if (mDiffNoteValues.size() > 0) { + mVersion ++; + int result = 0; + if (!validateVersion) {//构造字符串 + result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" + + NoteColumns.ID + "=?)", new String[] { + String.valueOf(mId) + }); + } else { + result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" + + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", + new String[] { + String.valueOf(mId), String.valueOf(mVersion) + }); + } + if (result == 0) { + Log.w(TAG, "there is no update. maybe user updates note when syncing"); + } + } + + if (mType == Notes.TYPE_NOTE) { + for (SqlData sqlData : mDataList) { + sqlData.commit(mId, validateVersion, mVersion); + } + } + } + + // refresh local info + loadFromCursor(mId); + if (mType == Notes.TYPE_NOTE) + loadDataContent(); + + mDiffNoteValues.clear(); + mIsCreate = false; + } +} \ No newline at end of file From 0ee303e81df74e1146494f8b1948be4938d7240a Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:45:37 +0800 Subject: [PATCH 34/42] ADD file via upload --- src/gtask/data/Task.java | 325 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 src/gtask/data/Task.java diff --git a/src/gtask/data/Task.java b/src/gtask/data/Task.java new file mode 100644 index 0000000..b9730ae --- /dev/null +++ b/src/gtask/data/Task.java @@ -0,0 +1,325 @@ + + +package net.micode.notes.gtask.data; + +public class Task extends Node { + private static final String TAG = Task.class.getSimpleName(); + + private boolean mCompleted;//是否完成 + + private String mNotes; + + private JSONObject mMetaInfo;//将在实例中存储数据的类型 + + private Task mPriorSibling;//对应的优先兄弟Task的指针(待完善) + + private TaskList mParent;//所在的任务列表的指针 + + public Task() { + super(); + mCompleted = false; + mNotes = null; + mPriorSibling = null;//TaskList中当前Task前面的Task的指针 + mParent = null;//当前Task所在的TaskList + mMetaInfo = null; + } + + public JSONObject getCreateAction(int actionId) { + JSONObject js = new JSONObject(); + + try { + // action_type + js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); + + // action_id + js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); + + // index + js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this)); + + // entity_delta + JSONObject entity = new JSONObject(); + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); + entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); + entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, + GTaskStringUtils.GTASK_JSON_TYPE_TASK); + if (getNotes() != null) { + entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); + } + js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); + + // parent_id + if (mParent!= null) { + js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid()); + } + + // dest_parent_type + js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE, + GTaskStringUtils.GTASK_JSON_TYPE_GROUP); + + // list_id + if (mParent!= null) { + js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid()); + } + + // prior_sibling_id + if (mPriorSibling != null) { + js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid()); + } + + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("fail to generate task-create jsonobject"); + } + + return js; + } + + public JSONObject getUpdateAction(int actionId) { + JSONObject js = new JSONObject(); + + try { + // action_type + js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); + + // action_id + js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); + + // id + js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); + + // entity_delta + JSONObject entity = new JSONObject(); + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); + if (getNotes() != null) { + entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); + } + entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); + js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); + + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("fail to generate task-update jsonobject"); + } + + return js; + } + + public void setContentByRemoteJSON(JSONObject js) { + if (js != null) { + try { + // id + if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { + setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); + } + + // last_modified + if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { + setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); + } + + // name + if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { + setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); + } + + // notes + if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) { + setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); + } + + // deleted + if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) { + setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); + } + + // completed + if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) { + setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED)); + } + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("fail to get task content from jsonobject"); + } + } + } + + public void setContentByLocalJSON(JSONObject js) { // metadata ʵʩ + if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) + || !js.has(GTaskStringUtils.META_HEAD_DATA)) { + Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); + } + + try { + JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + + if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) { + Log.e(TAG, "invalid type"); + return; + } + + for (int i = 0; i < dataArray.length(); i++) { + JSONObject data = dataArray.getJSONObject(i); + if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { + setName(data.getString(DataColumns.CONTENT)); + break; + } + } + + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + } + } + + public JSONObject getLocalJSONFromContent() { + String name = getName(); + try { + if (mMetaInfo == null) { + // new task created from web + if (name == null) { + Log.w(TAG, "the note seems to be an empty one"); + return null; + } + + JSONObject js = new JSONObject(); + JSONObject note = new JSONObject(); + JSONArray dataArray = new JSONArray(); + JSONObject data = new JSONObject(); + data.put(DataColumns.CONTENT, name); + dataArray.put(data); + js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); + note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); + js.put(GTaskStringUtils.META_HEAD_NOTE, note); + return js; + } else { + // synced task + JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + + for (int i = 0; i < dataArray.length(); i++) { + JSONObject data = dataArray.getJSONObject(i); + if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { + data.put(DataColumns.CONTENT, getName()); + break; + } + } + + note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); + return mMetaInfo; + } + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + return null; + } + } + + public void setMetaInfo(MetaData metaData) { + if (metaData != null && metaData.getNotes() != null) { + try { + mMetaInfo = new JSONObject(metaData.getNotes()); + } catch (JSONException e) { + Log.w(TAG, e.toString()); + mMetaInfo = null; + } + } + } + + public int getSyncAction(Cursor c) { + try { + JSONObject noteInfo = null; + if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) { + noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + } + + if (noteInfo == null) { + Log.w(TAG, "it seems that note meta has been deleted"); + return SYNC_ACTION_UPDATE_REMOTE; + } + + if (!noteInfo.has(NoteColumns.ID)) { + Log.w(TAG, "remote note id seems to be deleted"); + return SYNC_ACTION_UPDATE_LOCAL; + } + + // validate the note id now + if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) { + Log.w(TAG, "note id doesn't match"); + return SYNC_ACTION_UPDATE_LOCAL; + } + + if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { + // there is no local update + if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { + // no update both side + return SYNC_ACTION_NONE; + } else { + // apply remote to local + return SYNC_ACTION_UPDATE_LOCAL; + } + } else { + // validate gtask id + if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { + Log.e(TAG, "gtask id doesn't match"); + return SYNC_ACTION_ERROR; + } + if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { + // local modification only + return SYNC_ACTION_UPDATE_REMOTE; + } else { + return SYNC_ACTION_UPDATE_CONFLICT; + } + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + } + + return SYNC_ACTION_ERROR; + } + + public boolean isWorthSaving() { + return mMetaInfo != null || (getName() != null && getName().trim().length() > 0) + || (getNotes() != null && getNotes().trim().length() > 0); + } + + public void setCompleted(boolean completed) { + this.mCompleted = completed; + } + + public void setNotes(String notes) { + this.mNotes = notes; + } + + public void setPriorSibling(Task priorSibling) { + this.mPriorSibling = priorSibling; + } + + public void setParent(TaskList parent) { + this.mParent = parent; + } + + public boolean getCompleted() { + return this.mCompleted; + } + + public String getNotes() { + return this.mNotes; + } + + public Task getPriorSibling() { + return this.mPriorSibling; + } + + public TaskList getParent() { + return this.mParent; + } + +} \ No newline at end of file From 09c49b1895098824b41492c53a2b0149c8d7be75 Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:45:47 +0800 Subject: [PATCH 35/42] ADD file via upload --- src/gtask/data/TaskList.java | 370 +++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 src/gtask/data/TaskList.java diff --git a/src/gtask/data/TaskList.java b/src/gtask/data/TaskList.java new file mode 100644 index 0000000..15a6bbc --- /dev/null +++ b/src/gtask/data/TaskList.java @@ -0,0 +1,370 @@ +package net.micode.notes.gtask.data; + +public class TaskList extends Node { + private static final String TAG = TaskList.class.getSimpleName();//tag标记 + + private int mIndex;//当前TaskList的指针 + + private ArrayList mChildren;//类中主要的保存数据的单元,用来实现一个以Task为元素的ArrayList + + public TaskList() { + super(); + mChildren = new ArrayList(); + mIndex = 1; + } + + /* (non-Javadoc) + * @see net.micode.notes.gtask.data.Node#getCreateAction(int) + * 生成并返回一个包含了一定数据的JSONObject实体 + */ + public JSONObject getCreateAction(int actionId) { + JSONObject js = new JSONObject(); + + try { + // action_type + js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); + + // action_id + js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); + + // index + js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); + + // entity_delta + JSONObject entity = new JSONObject();//entity实体 + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); + entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); + entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, + GTaskStringUtils.GTASK_JSON_TYPE_GROUP); + js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); + + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("fail to generate tasklist-create jsonobject"); + } + + return js; + } + + /* (non-Javadoc) + * @see net.micode.notes.gtask.data.Node#getUpdateAction(int) + * 生成并返回一个包含了一定数据的JSONObject实体 + */ + public JSONObject getUpdateAction(int actionId) { + JSONObject js = new JSONObject(); + + try { + // action_type + js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); + + // action_id + js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); + + // id + js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); + + // entity_delta + JSONObject entity = new JSONObject(); + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); + entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); + js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); + + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("fail to generate tasklist-update jsonobject"); + } + + return js; + } + + public void setContentByRemoteJSON(JSONObject js) { + if (js != null) { + try { + // id + if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { + setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); + } + + // last_modified + if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { + setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); + } + + // name + if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { + setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); + } + + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("fail to get tasklist content from jsonobject"); + } + } + } + + public void setContentByLocalJSON(JSONObject js) { + if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { + Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); + } + + try { + JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + + if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { + String name = folder.getString(NoteColumns.SNIPPET); + setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name); + } else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { + if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) + setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT); + else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) + setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + + GTaskStringUtils.FOLDER_CALL_NOTE); + else + Log.e(TAG, "invalid system folder"); + } else { + Log.e(TAG, "error type"); + } + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + } + } + + public JSONObject getLocalJSONFromContent() { + try { + JSONObject js = new JSONObject(); + JSONObject folder = new JSONObject(); + + String folderName = getName(); + if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)) + folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(), + folderName.length()); + folder.put(NoteColumns.SNIPPET, folderName); + if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT) + || folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE)) + folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); + else + folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); + + js.put(GTaskStringUtils.META_HEAD_NOTE, folder); + + return js; + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + return null; + } + } + + public int getSyncAction(Cursor c) { + try { + if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { + // there is no local update + if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { + // no update both side + return SYNC_ACTION_NONE; + } else { + // apply remote to local + return SYNC_ACTION_UPDATE_LOCAL; + } + } else { + // validate gtask id + if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { + Log.e(TAG, "gtask id doesn't match"); + return SYNC_ACTION_ERROR; + } + if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { + // local modification only + return SYNC_ACTION_UPDATE_REMOTE; + } else { + // for folder conflicts, just apply local modification + return SYNC_ACTION_UPDATE_REMOTE; + } + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + } + + return SYNC_ACTION_ERROR; + } + + /** + * @return + * 功能:获得TaskList的大小,即mChildren的大小 + */ + public int getChildTaskCount() { + return mChildren.size(); + } + + /** + * @param task + * @return 返回值为是否成功添加任务。 + * 功能:在当前任务表末尾添加新的任务。 + */ + public boolean addChildTask(Task task) { + boolean ret = false; + if (task != null && !mChildren.contains(task)) { + ret = mChildren.add(task); + if (ret) { + // need to set prior sibling and parent + task.setPriorSibling(mChildren.isEmpty() ? null : mChildren + .get(mChildren.size() - 1)); + task.setParent(this); + //注意:每一次ArrayList的变化都要紧跟相关Task中PriorSibling的更改 + //,接下来几个函数都有相关操作 + } + } + return ret; + } + + /** + * @param task + * @param index + * @return + * 功能:在当前任务表的指定位置添加新的任务。 + */ + public boolean addChildTask(Task task, int index) { + if (index < 0 || index > mChildren.size()) { + Log.e(TAG, "add child task: invalid index"); + return false; + } + + int pos = mChildren.indexOf(task); + if (task != null && pos == -1) { + mChildren.add(index, task); + + // update the task list + Task preTask = null; + Task afterTask = null; + if (index != 0) + preTask = mChildren.get(index - 1); + if (index != mChildren.size() - 1) + afterTask = mChildren.get(index + 1); + + task.setPriorSibling(preTask); + if (afterTask != null) + afterTask.setPriorSibling(task); + } + + return true; + } + + /** + * @param task + * @return 返回删除是否成功 + * 功能:删除TaskList中的一个Task + */ + public boolean removeChildTask(Task task) { + boolean ret = false; + int index = mChildren.indexOf(task); + if (index != -1) { + ret = mChildren.remove(task); + + if (ret) { + // reset prior sibling and parent + task.setPriorSibling(null); + task.setParent(null); + + // update the task list + if (index != mChildren.size()) { + mChildren.get(index).setPriorSibling( + index == 0 ? null : mChildren.get(index - 1)); + } + } + } + return ret; + } + + /** + * @param task + * @param index + * @return + * 功能:将当前TaskList中含有的某个Task移到index位置 + */ + public boolean moveChildTask(Task task, int index) { + + if (index < 0 || index >= mChildren.size()) { + Log.e(TAG, "move child task: invalid index"); + return false; + } + + int pos = mChildren.indexOf(task); + if (pos == -1) { + Log.e(TAG, "move child task: the task should in the list"); + return false; + } + + if (pos == index) + return true; + return (removeChildTask(task) && addChildTask(task, index)); + //利用已实现好的功能完成当下功能; + } + + /** + * @param gid + * @return返回寻找结果 + * 功能:按gid寻找Task + */ + public Task findChildTaskByGid(String gid) { + for (int i = 0; i < mChildren.size(); i++) { + Task t = mChildren.get(i); + if (t.getGid().equals(gid)) { + return t; + } + } + return null; + } + + /** + * @param task + * @return + * 功能:返回指定Task的index + */ + public int getChildTaskIndex(Task task) { + return mChildren.indexOf(task); + } + + /** + * @param index + * @return + * 功能:返回指定index的Task + */ + public Task getChildTaskByIndex(int index) { + if (index < 0 || index >= mChildren.size()) { + Log.e(TAG, "getTaskByIndex: invalid index"); + return null; + } + return mChildren.get(index); + } + + /** + * @param gid + * @return + * 功能:返回指定gid的Task + */ + public Task getChilTaskByGid(String gid) { + for (Task task : mChildren) {//一种常见的ArrayList的遍历方法(四种,见精读笔记) + if (task.getGid().equals(gid)) + return task; + } + return null; + } + + public ArrayList getChildTaskList() { + return this.mChildren; + } + + public void setIndex(int index) { + this.mIndex = index; + } + + public int getIndex() { + return this.mIndex; + } +} \ No newline at end of file From 4ccff28b02dc34ac71a886573605cefa77f70d8f Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:46:09 +0800 Subject: [PATCH 36/42] ADD file via upload --- .../exception/ActionFailureException.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/gtask/exception/ActionFailureException.java diff --git a/src/gtask/exception/ActionFailureException.java b/src/gtask/exception/ActionFailureException.java new file mode 100644 index 0000000..72c4cda --- /dev/null +++ b/src/gtask/exception/ActionFailureException.java @@ -0,0 +1,34 @@ + + +/* + * Description:支持小米便签运行过程中的运行异常处理。 + */ + +package net.micode.notes.gtask.exception; + +public class ActionFailureException extends RuntimeException { + private static final long serialVersionUID = 4425249765923293627L; + /* + * serialVersionUID相当于java类的身份证。主要用于版本控制。 + * serialVersionUID作用是序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。 + * Made By Cuican + */ + + public ActionFailureException() { + super(); + } + /* + * 在JAVA类中使用super来引用父类的成分,用this来引用当前对象. + * 如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象。 + * 怎么去引用里面的父类对象呢?使用super来引用 + * 也就是说,此处super()以及super (paramString)可认为是Exception ()和Exception (paramString) + * Made By Cuican + */ + public ActionFailureException(String paramString) { + super(paramString); + } + + public ActionFailureException(String paramString, Throwable paramThrowable) { + super(paramString, paramThrowable); + } +} \ No newline at end of file From d714194626cbcfee25cc6c0893df5cad5a10efb6 Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:46:22 +0800 Subject: [PATCH 37/42] ADD file via upload --- .../exception/NetworkFailureException.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/gtask/exception/NetworkFailureException.java diff --git a/src/gtask/exception/NetworkFailureException.java b/src/gtask/exception/NetworkFailureException.java new file mode 100644 index 0000000..e12b670 --- /dev/null +++ b/src/gtask/exception/NetworkFailureException.java @@ -0,0 +1,34 @@ + +/* + * Description:支持小米便签运行过程中的网络异常处理。 + */ + +package net.micode.notes.gtask.exception; + +public class NetworkFailureException extends Exception { + private static final long serialVersionUID = 2107610287180234136L; + /* + * serialVersionUID相当于java类的身份证。主要用于版本控制。 + * serialVersionUID作用是序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。 + * Made By Cuican + */ + + public NetworkFailureException() { + super(); + } + + /* + * 在JAVA类中使用super来引用父类的成分,用this来引用当前对象. + * 如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象。 + * 怎么去引用里面的父类对象呢?使用super来引用 + * 也就是说,此处super()以及super (paramString)可认为是Exception ()和Exception (paramString) + * Made By Cuican + */ + public NetworkFailureException(String paramString) { + super(paramString); + } + + public NetworkFailureException(String paramString, Throwable paramThrowable) { + super(paramString, paramThrowable); + } +} \ No newline at end of file From b6694349ff0c10dcf00ca773d80a51abb0419778 Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:46:49 +0800 Subject: [PATCH 38/42] ADD file via upload --- src/gtask/remote/GTaskASyncTask.java | 117 +++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/gtask/remote/GTaskASyncTask.java diff --git a/src/gtask/remote/GTaskASyncTask.java b/src/gtask/remote/GTaskASyncTask.java new file mode 100644 index 0000000..b1febfc --- /dev/null +++ b/src/gtask/remote/GTaskASyncTask.java @@ -0,0 +1,117 @@ + +package net.micode.notes.gtask.remote; + + +/*异步操作类,实现GTask的异步操作过程 + * 主要方法: + * private void showNotification(int tickerId, String content) 向用户提示当前同步的状态,是一个用于交互的方法 + * protected Integer doInBackground(Void... unused) 此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间 + * protected void onProgressUpdate(String... progress) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。 + * protected void onPostExecute(Integer result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI + */ + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; + +import net.micode.notes.R; +import net.micode.notes.ui.NotesListActivity; +import net.micode.notes.ui.NotesPreferenceActivity; + + +public class GTaskASyncTask extends AsyncTask { + + + private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; + + public interface OnCompleteListener { + void onComplete(); + } + + private Context mContext; + + private NotificationManager mNotifiManager; + + private GTaskManager mTaskManager; + + private OnCompleteListener mOnCompleteListener; + + public GTaskASyncTask(Context context, OnCompleteListener listener) { + mContext = context; + mOnCompleteListener = listener; + mNotifiManager = (NotificationManager) mContext + .getSystemService(Context.NOTIFICATION_SERVICE); + mTaskManager = GTaskManager.getInstance(); + } + + public void cancelSync() { + mTaskManager.cancelSync(); + } + + public void publishProgess(String message) { // 发布进度单位,系统将会调用onProgressUpdate()方法更新这些值 + publishProgress(new String[] { + message + }); + } + + private void showNotification(int tickerId, String content) { + Notification notification = new Notification(R.drawable.notification, mContext + .getString(tickerId), System.currentTimeMillis()); + notification.defaults = Notification.DEFAULT_LIGHTS; // 调用系统自带灯光 + notification.flags = Notification.FLAG_AUTO_CANCEL; // 点击清除按钮或点击通知后会自动消失 + PendingIntent pendingIntent; //一个描述了想要启动一个Activity、Broadcast或是Service的意图 + if (tickerId != R.string.ticker_success) { + pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, + NotesPreferenceActivity.class), 0); //如果同步不成功,那么从系统取得一个用于启动一个NotesPreferenceActivity的PendingIntent对象 + + } else { + pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, + NotesListActivity.class), 0); //如果同步成功,那么从系统取得一个用于启动一个NotesListActivity的PendingIntent对象 + } + notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, + pendingIntent); + mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);//通过NotificationManager对象的notify()方法来执行一个notification的消息 + } + + @Override + protected Integer doInBackground(Void... unused) { + publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity + .getSyncAccountName(mContext))); //利用getString,将把 NotesPreferenceActivity.getSyncAccountName(mContext))的字符串内容传进sync_progress_login中 + return mTaskManager.sync(mContext, this); //进行后台同步具体操作 + } + + @Override + protected void onProgressUpdate(String... progress) { + showNotification(R.string.ticker_syncing, progress[0]); + if (mContext instanceof GTaskSyncService) { //instanceof 判断mContext是否是GTaskSyncService的实例 + ((GTaskSyncService) mContext).sendBroadcast(progress[0]); + } + } + + @Override + protected void onPostExecute(Integer result) { //用于在执行完后台任务后更新UI,显示结果 + if (result == GTaskManager.STATE_SUCCESS) { + showNotification(R.string.ticker_success, mContext.getString( + R.string.success_sync_account, mTaskManager.getSyncAccount())); + NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); //设置最新同步的时间 + } else if (result == GTaskManager.STATE_NETWORK_ERROR) { + showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network)); + } else if (result == GTaskManager.STATE_INTERNAL_ERROR) { + showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); + } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { + showNotification(R.string.ticker_cancel, mContext + .getString(R.string.error_sync_cancelled)); + } //几种不同情况下的结果显示 + if (mOnCompleteListener != null) { + new Thread(new Runnable() { //这里好像是方法内的一个线程,但是并不太懂什么意思 + + public void run() { //完成后的操作,使用onComplete()将所有值都重新初始化,相当于完成一次操作 + mOnCompleteListener.onComplete(); + } + }).start(); + } + } +} From 1fb02b454ab4d05be9652c97d2be32a4bb84a0c1 Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:47:05 +0800 Subject: [PATCH 39/42] ADD file via upload --- src/gtask/remote/GTaskClient.java | 614 ++++++++++++++++++++++++++++++ 1 file changed, 614 insertions(+) create mode 100644 src/gtask/remote/GTaskClient.java diff --git a/src/gtask/remote/GTaskClient.java b/src/gtask/remote/GTaskClient.java new file mode 100644 index 0000000..13869a7 --- /dev/null +++ b/src/gtask/remote/GTaskClient.java @@ -0,0 +1,614 @@ + + +package net.micode.notes.gtask.remote; + +/* + * 主要功能:实现GTASK的登录操作,进行GTASK任务的创建,创建任务列表,从网络上获取任务和任务列表的内容 + * 主要使用类或技术:accountManager JSONObject HttpParams authToken Gid + */ +public class GTaskClient { + private static final String TAG = GTaskClient.class.getSimpleName(); + + private static final String GTASK_URL = "https://mail.google.com/tasks/"; //这个是指定的URL + + private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; + + private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; + + private static GTaskClient mInstance = null; + + private DefaultHttpClient mHttpClient; + + private String mGetUrl; + + private String mPostUrl; + + private long mClientVersion; + + private boolean mLoggedin; + + private long mLastLoginTime; + + private int mActionId; + + private Account mAccount; + + private JSONArray mUpdateArray; + + private GTaskClient() { + mHttpClient = null; + mGetUrl = GTASK_GET_URL; + mPostUrl = GTASK_POST_URL; + mClientVersion = -1; + mLoggedin = false; + mLastLoginTime = 0; + mActionId = 1; + mAccount = null; + mUpdateArray = null; + } + + /*用来获取的实例化对象 + * 使用 getInstance() + * 返回mInstance这个实例化对象 + */ + public static synchronized GTaskClient getInstance() { + if (mInstance == null) { + mInstance = new GTaskClient(); + } + return mInstance; + } + + /*用来实现登录操作的函数,传入的参数是一个Activity + * 设置登录操作限制时间,如果超时则需要重新登录 + * 有两种登录方式,使用用户自己的URL登录或者使用谷歌官方的URL登录 + * 返回true或者false,即最后是否登陆成功 + */ + public boolean login(Activity activity) { + // we suppose that the cookie would expire after 5 minutes + // then we need to re-login + //判断距离最后一次登录操作是否超过5分钟 + final long interval = 1000 * 60 * 5; + if (mLastLoginTime + interval < System.currentTimeMillis()) { + mLoggedin = false; + } + + // need to re-login after account switch 重新登录操作 + if (mLoggedin + && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity + .getSyncAccountName(activity))) { + mLoggedin = false; + } + + //如果没超过时间,则不需要重新登录 + if (mLoggedin) { + Log.d(TAG, "already logged in"); + return true; + } + + mLastLoginTime = System.currentTimeMillis();//更新最后登录时间,改为系统当前的时间 + String authToken = loginGoogleAccount(activity, false);//判断是否登录到谷歌账户 + if (authToken == null) { + Log.e(TAG, "login google account failed"); + return false; + } + + // login with custom domain if necessary + //尝试使用用户自己的域名登录 + if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() //将用户账号名改为统一格式(小写)后判断是否为一个谷歌账号地址 + .endsWith("googlemail.com"))) { + StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); + int index = mAccount.name.indexOf('@') + 1; + String suffix = mAccount.name.substring(index); + url.append(suffix + "/"); + mGetUrl = url.toString() + "ig"; //设置用户对应的getUrl + mPostUrl = url.toString() + "r/ig"; //设置用户对应的postUrl + + if (tryToLoginGtask(activity, authToken)) { + mLoggedin = true; + } + } + + // try to login with google official url + //如果用户账户无法登录,则使用谷歌官方的URI进行登录 + if (!mLoggedin) { + mGetUrl = GTASK_GET_URL; + mPostUrl = GTASK_POST_URL; + if (!tryToLoginGtask(activity, authToken)) { + return false; + } + } + + mLoggedin = true; + return true; + } + + /*具体实现登录谷歌账户的方法 + * 使用令牌机制 + * 使用AccountManager来管理注册账号 + * 返回值是账号的令牌 + */ + private String loginGoogleAccount(Activity activity, boolean invalidateToken) { + String authToken; //令牌,是登录操作保证安全性的一个方法 + AccountManager accountManager = AccountManager.get(activity);//AccountManager这个类给用户提供了集中注册账号的接口 + Account[] accounts = accountManager.getAccountsByType("com.google");//获取全部以com.google结尾的account + + if (accounts.length == 0) { + Log.e(TAG, "there is no available google account"); + return null; + } + + String accountName = NotesPreferenceActivity.getSyncAccountName(activity); + Account account = null; + //遍历获得的accounts信息,寻找已经记录过的账户信息 + for (Account a : accounts) { + if (a.name.equals(accountName)) { + account = a; + break; + } + } + if (account != null) { + mAccount = account; + } else { + Log.e(TAG, "unable to get an account with the same name in the settings"); + return null; + } + + // get the token now + //获取选中账号的令牌 + AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, + "goanna_mobile", null, activity, null, null); + try { + Bundle authTokenBundle = accountManagerFuture.getResult(); + authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); + //如果是invalidateToken,那么需要调用invalidateAuthToken(String, String)方法废除这个无效token + if (invalidateToken) { + accountManager.invalidateAuthToken("com.google", authToken); + loginGoogleAccount(activity, false); + } + } catch (Exception e) { + Log.e(TAG, "get auth token failed"); + authToken = null; + } + + return authToken; + } + + //尝试登陆Gtask,这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法 + private boolean tryToLoginGtask(Activity activity, String authToken) { + if (!loginGtask(authToken)) { + // maybe the auth token is out of authTokedate, now let's invalidate the + // token and try again + //删除过一个无效的authToken,申请一个新的后再次尝试登陆 + authToken = loginGoogleAccount(activity, true); + if (authToken == null) { + Log.e(TAG, "login google account failed"); + return false; + } + + if (!loginGtask(authToken)) { + Log.e(TAG, "login gtask failed"); + return false; + } + } + return true; + } + + //实现登录GTask的具体操作 + private boolean loginGtask(String authToken) { + int timeoutConnection = 10000; + int timeoutSocket = 15000; //socket是一种通信连接实现数据的交换的端口 + HttpParams httpParameters = new BasicHttpParams(); //实例化一个新的HTTP参数类 + HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);//设置连接超时时间 + HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);//设置设置端口超时时间 + mHttpClient = new DefaultHttpClient(httpParameters); + BasicCookieStore localBasicCookieStore = new BasicCookieStore(); //设置本地cookie + mHttpClient.setCookieStore(localBasicCookieStore); + HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); + + // login gtask + try { + String loginUrl = mGetUrl + "?auth=" + authToken; //设置登录的url + HttpGet httpGet = new HttpGet(loginUrl); //通过登录的uri实例化网页上资源的查找 + HttpResponse response = null; + response = mHttpClient.execute(httpGet); + + // get the cookie now + //获取CookieStore里存放的cookie,看如果存有“GTL(不知道什么意思)”,则说明有验证成功的有效的cookie + List cookies = mHttpClient.getCookieStore().getCookies(); + boolean hasAuthCookie = false; + for (Cookie cookie : cookies) { + if (cookie.getName().contains("GTL")) { + hasAuthCookie = true; + } + } + if (!hasAuthCookie) { + Log.w(TAG, "it seems that there is no auth cookie"); + } + + // get the client version + //获取client的内容,具体操作是在返回的Content中截取从_setup(开始到)}中间的字符串内容,也就是gtask_url的内容 + String resString = getResponseContent(response.getEntity()); + String jsBegin = "_setup("; + String jsEnd = ")}"; + int begin = resString.indexOf(jsBegin); + int end = resString.lastIndexOf(jsEnd); + String jsString = null; + if (begin != -1 && end != -1 && begin < end) { + jsString = resString.substring(begin + jsBegin.length(), end); + } + JSONObject js = new JSONObject(jsString); + mClientVersion = js.getLong("v"); + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + return false; + } catch (Exception e) { + // simply catch all exceptions + Log.e(TAG, "httpget gtask_url failed"); + return false; + } + + return true; + } + + private int getActionId() { + return mActionId++; + } + + /*实例化创建一个用于向网络传输数据的对象 + * 使用HttpPost类 + * 返回一个httpPost实例化对象,但里面还没有内容 + */ + private HttpPost createHttpPost() { + HttpPost httpPost = new HttpPost(mPostUrl); + httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); + httpPost.setHeader("AT", "1"); + return httpPost; + } + + /*通过URL获取响应后返回的数据,也就是网络上的数据和资源 + * 使用getContentEncoding()获取网络上的资源和数据 + * 返回值就是获取到的资源 + */ + private String getResponseContent(HttpEntity entity) throws IOException { + String contentEncoding = null; + if (entity.getContentEncoding() != null) {//通过URL得到HttpEntity对象,如果不为空则使用getContent()方法创建一个流将数据从网络都过来 + contentEncoding = entity.getContentEncoding().getValue(); + Log.d(TAG, "encoding: " + contentEncoding); + } + + InputStream input = entity.getContent(); + if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {//GZIP是使用DEFLATE进行压缩数据的另一个压缩库 + input = new GZIPInputStream(entity.getContent()); + } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {//DEFLATE是一个无专利的压缩算法,它可以实现无损数据压缩 + Inflater inflater = new Inflater(true); + input = new InflaterInputStream(entity.getContent(), inflater); + } + + try { + InputStreamReader isr = new InputStreamReader(input); + BufferedReader br = new BufferedReader(isr);//是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了时候,再读入内存,是为了提供读的效率而设计的 + StringBuilder sb = new StringBuilder(); + + while (true) { + String buff = br.readLine(); + if (buff == null) { + return sb.toString(); + } + sb = sb.append(buff); + } + } finally { + input.close(); + } + } + + /*通过JSON发送请求 + * 请求的具体内容在json的实例化对象js中然后传入 + * 利用UrlEncodedFormEntity entity和httpPost.setEntity(entity)方法把js中的内容放置到httpPost中 + * 执行请求后使用getResponseContent方法得到返回的数据和资源 + * 将资源再次放入json后返回 + */ + private JSONObject postRequest(JSONObject js) throws NetworkFailureException { + if (!mLoggedin) {//未登录 + Log.e(TAG, "please login first"); + throw new ActionFailureException("not logged in"); + } + + //实例化一个httpPost的对象用来向服务器传输数据,在这里就是发送请求,而请求的内容在js里 + HttpPost httpPost = createHttpPost(); + try { + LinkedList list = new LinkedList(); + list.add(new BasicNameValuePair("r", js.toString())); + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); //UrlEncodedFormEntity()的形式比较单一,是普通的键值对 + httpPost.setEntity(entity); + + // execute the post + //执行这个请求 + HttpResponse response = mHttpClient.execute(httpPost); + String jsString = getResponseContent(response.getEntity()); + return new JSONObject(jsString); + + } catch (ClientProtocolException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new NetworkFailureException("postRequest failed"); + } catch (IOException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new NetworkFailureException("postRequest failed"); + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("unable to convert response content to jsonobject"); + } catch (Exception e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("error occurs when posting request"); + } + } + + /*创建单个任务 + * 传入参数是一个.gtask.data.Task包里Task类的对象 + * 利用json获取Task里的内容,并且创建相应的jsPost + * 利用postRequest得到任务的返回信息 + * 使用task.setGid设置task的new_ID + */ + public void createTask(Task task) throws NetworkFailureException { + commitUpdate(); + try { + JSONObject jsPost = new JSONObject(); + JSONArray actionList = new JSONArray(); + + // action_list + actionList.put(task.getCreateAction(getActionId())); + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + + // client_version + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + + // post + JSONObject jsResponse = postRequest(jsPost); + JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( + GTaskStringUtils.GTASK_JSON_RESULTS).get(0); + task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); + + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("create task: handing jsonobject failed"); + } + } + + /* + * 创建一个任务列表,与createTask几乎一样,区别就是最后设置的是tasklist的gid + */ + public void createTaskList(TaskList tasklist) throws NetworkFailureException { + commitUpdate(); + try { + JSONObject jsPost = new JSONObject(); + JSONArray actionList = new JSONArray(); + + // action_list + actionList.put(tasklist.getCreateAction(getActionId())); + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + + // client version + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + + // post + JSONObject jsResponse = postRequest(jsPost); + JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( + GTaskStringUtils.GTASK_JSON_RESULTS).get(0); + tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); + + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("create tasklist: handing jsonobject failed"); + } + } + + /* + * 同步更新操作 + * 使用JSONObject进行数据存储,使用jsPost.put,Put的信息包括UpdateArray和ClientVersion + * 使用postRequest发送这个jspost,进行处理 + */ + public void commitUpdate() throws NetworkFailureException { + if (mUpdateArray != null) { + try { + JSONObject jsPost = new JSONObject(); + + // action_list + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); + + // client_version + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + + postRequest(jsPost); + mUpdateArray = null; + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("commit update: handing jsonobject failed"); + } + } + } + + /* + * 添加更新的事项 + * 调用commitUpdate()实现 + */ + public void addUpdateNode(Node node) throws NetworkFailureException { + if (node != null) { + // too many update items may result in an error + // set max to 10 items + if (mUpdateArray != null && mUpdateArray.length() > 10) { + commitUpdate(); + } + + if (mUpdateArray == null) + mUpdateArray = new JSONArray(); + mUpdateArray.put(node.getUpdateAction(getActionId())); + } + } + + /* + * 移动task,比如讲task移动到不同的task列表中去 + * 通过getGid获取task所属列表的gid + * 通过JSONObject.put(String name, Object value)函数设置移动后的task的相关属性值,从而达到移动的目的 + * 最后还是通过postRequest进行更新后的发送 + */ + public void moveTask(Task task, TaskList preParent, TaskList curParent) + throws NetworkFailureException { + commitUpdate(); + try { + JSONObject jsPost = new JSONObject(); + JSONArray actionList = new JSONArray(); + JSONObject action = new JSONObject(); + + // action_list + action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); + action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); + action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); + if (preParent == curParent && task.getPriorSibling() != null) { + // put prioring_sibing_id only if moving within the tasklist and + // it is not the first one + //设置优先级ID,只有当移动是发生在文件中 + action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); + } + action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); //设置移动前所属列表 + action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); //设置当前所属列表 + if (preParent != curParent) { + // put the dest_list only if moving between tasklists + action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); + } + actionList.put(action); + //最后将ACTION_LIST加入到jsPost中 + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + + // client_version + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + + postRequest(jsPost); + + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("move task: handing jsonobject failed"); + } + } + + /* + * 删除操作节点 + * 还是利用JSON + * 删除过后使用postRequest发送删除后的结果 + */ + public void deleteNode(Node node) throws NetworkFailureException { + commitUpdate(); + try { + JSONObject jsPost = new JSONObject(); + JSONArray actionList = new JSONArray(); + + // action_list + node.setDeleted(true); + actionList.put(node.getUpdateAction(getActionId())); //这里会获取到删除操作的ID,加入到actionLiast中 + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + + // client_version + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + + postRequest(jsPost); + mUpdateArray = null; + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("delete node: handing jsonobject failed"); + } + } + + /* + * 获取任务列表 + * 首先通过GetURI使用getResponseContent从网上获取数据 + * 然后筛选出"_setup("到)}的部分,并且从中获取GTASK_JSON_LISTS的内容返回 + */ + public JSONArray getTaskLists() throws NetworkFailureException { + if (!mLoggedin) { + Log.e(TAG, "please login first"); + throw new ActionFailureException("not logged in"); + } + + try { + HttpGet httpGet = new HttpGet(mGetUrl); + HttpResponse response = null; + response = mHttpClient.execute(httpGet); + + // get the task list + //筛选工作,把筛选出的字符串放入jsString + String resString = getResponseContent(response.getEntity()); + String jsBegin = "_setup("; + String jsEnd = ")}"; + int begin = resString.indexOf(jsBegin); + int end = resString.lastIndexOf(jsEnd); + String jsString = null; + if (begin != -1 && end != -1 && begin < end) { + jsString = resString.substring(begin + jsBegin.length(), end); + } + JSONObject js = new JSONObject(jsString); + //获取GTASK_JSON_LISTS + return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); + } catch (ClientProtocolException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new NetworkFailureException("gettasklists: httpget failed"); + } catch (IOException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new NetworkFailureException("gettasklists: httpget failed"); + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("get task lists: handing jasonobject failed"); + } + } + + /* + * 通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务 + */ + public JSONArray getTaskList(String listGid) throws NetworkFailureException { + commitUpdate(); + try { + JSONObject jsPost = new JSONObject(); + JSONArray actionList = new JSONArray(); + JSONObject action = new JSONObject(); + + // action_list + action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); + action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); + action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); //这里设置为传入的listGid + action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); + actionList.put(action); + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + + // client_version + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + + JSONObject jsResponse = postRequest(jsPost); + return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("get task list: handing jsonobject failed"); + } + } + + public Account getSyncAccount() { + return mAccount; + } + + //重置更新的内容 + public void resetUpdateArray() { + mUpdateArray = null; + } +} \ No newline at end of file From 475fe335f5aeee146d4bc23d0a7d7f1767ef28bf Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:47:18 +0800 Subject: [PATCH 40/42] ADD file via upload --- src/gtask/remote/GTaskManager.java | 847 +++++++++++++++++++++++++++++ 1 file changed, 847 insertions(+) create mode 100644 src/gtask/remote/GTaskManager.java diff --git a/src/gtask/remote/GTaskManager.java b/src/gtask/remote/GTaskManager.java new file mode 100644 index 0000000..9cebd81 --- /dev/null +++ b/src/gtask/remote/GTaskManager.java @@ -0,0 +1,847 @@ + +package net.micode.notes.gtask.remote; + +public class GTaskManager { + private static final String TAG = GTaskManager.class.getSimpleName(); + public static final int STATE_SUCCESS = 0; + public static final int STATE_NETWORK_ERROR = 1; + public static final int STATE_INTERNAL_ERROR = 2; + public static final int STATE_SYNC_IN_PROGRESS = 3; + public static final int STATE_SYNC_CANCELLED = 4; + private static GTaskManager mInstance = null; + + private Activity mActivity; + private Context mContext; + private ContentResolver mContentResolver; + private boolean mSyncing; + private boolean mCancelled; + private HashMap mGTaskListHashMap; + private HashMap mGTaskHashMap; + private HashMap mMetaHashMap; + private TaskList mMetaList; + private HashSet mLocalDeleteIdMap; + private HashMap mGidToNid; + private HashMap mNidToGid; + + private GTaskManager() { //对象初始化函数 + mSyncing = false; //正在同步,flase代表未执行 + mCancelled = false; //全局标识,flase代表可以执行 + mGTaskListHashMap = new HashMap(); //<>代表Java的泛型,就是创建一个用类型作为参数的类。 + mGTaskHashMap = new HashMap(); + mMetaHashMap = new HashMap(); + mMetaList = null; + mLocalDeleteIdMap = new HashSet(); + mGidToNid = new HashMap(); //GoogleID to NodeID?? + mNidToGid = new HashMap(); //NodeID to GoogleID???通过hashmap散列表建立映射 + } + + /** + * 包含关键字synchronized,语言级同步,指明该函数可能运行在多线程的环境下。 + * 功能:类初始化函数 + * @author TTS + * @return GtaskManger + */ + public static synchronized GTaskManager getInstance() { //可能运行在多线程环境下,使用语言级同步--synchronized + if (mInstance == null) { + mInstance = new GTaskManager(); + } + return mInstance; + } + + /** + * 包含关键字synchronized,语言级同步,指明该函数可能运行在多线程的环境下。 + * @author TTS + * @param activity + */ + public synchronized void setActivityContext(Activity activity) { + // used for getting auth token + mActivity = activity; + } + + /** + * 核心函数 + * 功能:实现了本地同步操作和远端同步操作 + * @author TTS + * @param context-----获取上下文 + * @param asyncTask-------用于同步的异步操作类 + * @return int + */ + public int sync(Context context, GTaskASyncTask asyncTask) { //核心函数 + if (mSyncing) { + Log.d(TAG, "Sync is in progress"); //创建日志文件(调试信息),debug + return STATE_SYNC_IN_PROGRESS; + } + mContext = context; + mContentResolver = mContext.getContentResolver(); + mSyncing = true; + mCancelled = false; + mGTaskListHashMap.clear(); + mGTaskHashMap.clear(); + mMetaHashMap.clear(); + mLocalDeleteIdMap.clear(); + mGidToNid.clear(); + mNidToGid.clear(); + + try { + GTaskClient client = GTaskClient.getInstance(); //getInstance即为创建一个实例,client--客户机 + client.resetUpdateArray(); //JSONArray类型,reset即置为NULL + + // login google task + if (!mCancelled) { + if (!client.login(mActivity)) { + throw new NetworkFailureException("login google task failed"); + } + } + + // get the task list from google + asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); + initGTaskList(); //获取Google上的JSONtasklist转为本地TaskList + + // do content sync work + asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); + syncContent(); + } catch (NetworkFailureException e) { //分为两种异常,此类异常为网络异常 + Log.e(TAG, e.toString()); //创建日志文件(调试信息),error + return STATE_NETWORK_ERROR; + } catch (ActionFailureException e) { //此类异常为操作异常 + Log.e(TAG, e.toString()); + return STATE_INTERNAL_ERROR; + } catch (Exception e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + return STATE_INTERNAL_ERROR; + } finally { + mGTaskListHashMap.clear(); + mGTaskHashMap.clear(); + mMetaHashMap.clear(); + mLocalDeleteIdMap.clear(); + mGidToNid.clear(); + mNidToGid.clear(); + mSyncing = false; + } + + return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; + } + + /** + *功能:初始化GtaskList,获取Google上的JSONtasklist转为本地TaskList。 + *获得的数据存储在mMetaList,mGTaskListHashMap,mGTaskHashMap + *@author TTS + *@exception NetworkFailureException + *@return void + */ + private void initGTaskList() throws NetworkFailureException { + if (mCancelled) + return; + GTaskClient client = GTaskClient.getInstance(); //getInstance即为创建一个实例,client应指远端客户机 + try { + //Json对象是Name Value对(即子元素)的无序集合,相当于一个Map对象。JsonObject类是bantouyan-json库对Json对象的抽象,提供操纵Json对象的各种方法。 + //其格式为{"key1":value1,"key2",value2....};key 必须是字符串。 + //因为ajax请求不刷新页面,但配合js可以实现局部刷新,因此json常常被用来作为异步请求的返回对象使用。 + JSONArray jsTaskLists = client.getTaskLists(); //原注释为get task list------lists??? + + // init meta list first + mMetaList = null; //TaskList类型 + for (int i = 0; i < jsTaskLists.length(); i++) { + JSONObject object = jsTaskLists.getJSONObject(i); //JSONObject与JSONArray一个为对象,一个为数组。此处取出单个JASONObject + String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); + String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); + + if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { + mMetaList = new TaskList(); //MetaList意为元表,Tasklist类型,此处为初始化 + mMetaList.setContentByRemoteJSON(object); //将JSON中部分数据复制到自己定义的对象中相对应的数据:name->mname... + + // load meta data + JSONArray jsMetas = client.getTaskList(gid); //原注释为get action_list------list??? + for (int j = 0; j < jsMetas.length(); j++) { + object = (JSONObject) jsMetas.getJSONObject(j); + MetaData metaData = new MetaData(); //继承自Node + metaData.setContentByRemoteJSON(object); + if (metaData.isWorthSaving()) { //if not worth to save,metadata将不加入mMetaList + mMetaList.addChildTask(metaData); + if (metaData.getGid() != null) { + mMetaHashMap.put(metaData.getRelatedGid(), metaData); + } + } + } + } + } + + // create meta list if not existed + if (mMetaList == null) { + mMetaList = new TaskList(); + mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + + GTaskStringUtils.FOLDER_META); + GTaskClient.getInstance().createTaskList(mMetaList); + } + + // init task list + for (int i = 0; i < jsTaskLists.length(); i++) { + JSONObject object = jsTaskLists.getJSONObject(i); + String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); //通过getString函数传入本地某个标志数据的名称,获取其在远端的名称。 + String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); + + if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX) + && !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + + GTaskStringUtils.FOLDER_META)) { + TaskList tasklist = new TaskList(); //继承自Node + tasklist.setContentByRemoteJSON(object); + mGTaskListHashMap.put(gid, tasklist); + mGTaskHashMap.put(gid, tasklist); //为什么加两遍??? + + // load tasks + JSONArray jsTasks = client.getTaskList(gid); + for (int j = 0; j < jsTasks.length(); j++) { + object = (JSONObject) jsTasks.getJSONObject(j); + gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); + Task task = new Task(); + task.setContentByRemoteJSON(object); + if (task.isWorthSaving()) { + task.setMetaInfo(mMetaHashMap.get(gid)); + tasklist.addChildTask(task); + mGTaskHashMap.put(gid, task); + } + } + } + } + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + throw new ActionFailureException("initGTaskList: handing JSONObject failed"); + } + } + + /** + * 功能:本地内容同步操作 + * @throws NetworkFailureException + * @return 无返回值 + */ + private void syncContent() throws NetworkFailureException { //本地内容同步操作 + int syncType; + Cursor c = null; //数据库指针 + String gid; //GoogleID?? + Node node; //Node包含Sync_Action的不同类型 + + mLocalDeleteIdMap.clear(); //HashSet类型 + + if (mCancelled) { + return; + } + + // for local deleted note + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, + "(type<>? AND parent_id=?)", new String[] { + String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) + }, null); + if (c != null) { + while (c.moveToNext()) { + gid = c.getString(SqlNote.GTASK_ID_COLUMN); + node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c); + } + + mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); + } + } else { + Log.w(TAG, "failed to query trash folder"); + } + } finally { + if (c != null) { + c.close(); + c = null; + } + } + + // sync folder first + syncFolder(); + + // for note existing in database + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, + "(type=? AND parent_id<>?)", new String[] { + String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER) + }, NoteColumns.TYPE + " DESC"); + if (c != null) { + while (c.moveToNext()) { + gid = c.getString(SqlNote.GTASK_ID_COLUMN); + node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); //通过hashmap建立联系 + mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); //通过hashmap建立联系 + syncType = node.getSyncAction(c); + } else { + if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { + // local add + syncType = Node.SYNC_ACTION_ADD_REMOTE; + } else { + // remote delete + syncType = Node.SYNC_ACTION_DEL_LOCAL; + } + } + doContentSync(syncType, node, c); + } + } else { + Log.w(TAG, "failed to query existing note in database"); + } + + } finally { + if (c != null) { + c.close(); + c = null; + } + } + + // go through remaining items + Iterator> iter = mGTaskHashMap.entrySet().iterator(); //Iterator迭代器 + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + node = entry.getValue(); + doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); + } + + // mCancelled can be set by another thread, so we neet to check one by //thread----线程 + // one + // clear local delete table + if (!mCancelled) { + if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { + throw new ActionFailureException("failed to batch-delete local deleted notes"); + } + } + + // refresh local sync id + if (!mCancelled) { + GTaskClient.getInstance().commitUpdate(); + refreshLocalSyncId(); + } + + } + + /** + * 功能: + * @author TTS + * @throws NetworkFailureException + */ + private void syncFolder() throws NetworkFailureException { + Cursor c = null; + String gid; + Node node; + int syncType; + + if (mCancelled) { + return; + } + + // for root folder + try { + c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, + Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); + if (c != null) { + c.moveToNext(); + gid = c.getString(SqlNote.GTASK_ID_COLUMN); + node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER); + mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid); + // for system folder, only update remote name if necessary + if (!node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) + doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); + } else { + doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); + } + } else { + Log.w(TAG, "failed to query root folder"); + } + } finally { + if (c != null) { + c.close(); + c = null; + } + } + + // for call-note folder + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", + new String[] { + String.valueOf(Notes.ID_CALL_RECORD_FOLDER) + }, null); + if (c != null) { + if (c.moveToNext()) { + gid = c.getString(SqlNote.GTASK_ID_COLUMN); + node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER); + mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid); + // for system folder, only update remote name if + // necessary + if (!node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + + GTaskStringUtils.FOLDER_CALL_NOTE)) + doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); + } else { + doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); + } + } + } else { + Log.w(TAG, "failed to query call note folder"); + } + } finally { + if (c != null) { + c.close(); + c = null; + } + } + + // for local existing folders + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, + "(type=? AND parent_id<>?)", new String[] { + String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER) + }, NoteColumns.TYPE + " DESC"); + if (c != null) { + while (c.moveToNext()) { + gid = c.getString(SqlNote.GTASK_ID_COLUMN); + node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); + mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); + syncType = node.getSyncAction(c); + } else { + if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { + // local add + syncType = Node.SYNC_ACTION_ADD_REMOTE; + } else { + // remote delete + syncType = Node.SYNC_ACTION_DEL_LOCAL; + } + } + doContentSync(syncType, node, c); + } + } else { + Log.w(TAG, "failed to query existing folder"); + } + } finally { + if (c != null) { + c.close(); + c = null; + } + } + + // for remote add folders + Iterator> iter = mGTaskListHashMap.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + gid = entry.getKey(); + node = entry.getValue(); + if (mGTaskHashMap.containsKey(gid)) { + mGTaskHashMap.remove(gid); + doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); + } + } + + if (!mCancelled) + GTaskClient.getInstance().commitUpdate(); + } + + /** + * 功能:syncType分类,addLocalNode,addRemoteNode,deleteNode,updateLocalNode,updateRemoteNode + * @author TTS + * @param syncType + * @param node + * @param c + * @throws NetworkFailureException + */ + private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; + } + + MetaData meta; + switch (syncType) { + case Node.SYNC_ACTION_ADD_LOCAL: + addLocalNode(node); + break; + case Node.SYNC_ACTION_ADD_REMOTE: + addRemoteNode(node, c); + break; + case Node.SYNC_ACTION_DEL_LOCAL: + meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN)); + if (meta != null) { + GTaskClient.getInstance().deleteNode(meta); + } + mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); + break; + case Node.SYNC_ACTION_DEL_REMOTE: + meta = mMetaHashMap.get(node.getGid()); + if (meta != null) { + GTaskClient.getInstance().deleteNode(meta); + } + GTaskClient.getInstance().deleteNode(node); + break; + case Node.SYNC_ACTION_UPDATE_LOCAL: + updateLocalNode(node, c); + break; + case Node.SYNC_ACTION_UPDATE_REMOTE: + updateRemoteNode(node, c); + break; + case Node.SYNC_ACTION_UPDATE_CONFLICT: + // merging both modifications maybe a good idea + // right now just use local update simply + updateRemoteNode(node, c); + break; + case Node.SYNC_ACTION_NONE: + break; + case Node.SYNC_ACTION_ERROR: + default: + throw new ActionFailureException("unkown sync action type"); + } + } + + /** + * 功能:本地增加Node + * @author TTS + * @param node + * @throws NetworkFailureException + */ + private void addLocalNode(Node node) throws NetworkFailureException { + if (mCancelled) { + return; + } + + SqlNote sqlNote; + if (node instanceof TaskList) { + if (node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) { + sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER); + } else if (node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { + sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER); + } else { + sqlNote = new SqlNote(mContext); + sqlNote.setContent(node.getLocalJSONFromContent()); + sqlNote.setParentId(Notes.ID_ROOT_FOLDER); + } + } else { + sqlNote = new SqlNote(mContext); + JSONObject js = node.getLocalJSONFromContent(); + try { + if (js.has(GTaskStringUtils.META_HEAD_NOTE)) { + JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + if (note.has(NoteColumns.ID)) { + long id = note.getLong(NoteColumns.ID); + if (DataUtils.existInNoteDatabase(mContentResolver, id)) { + // the id is not available, have to create a new one + note.remove(NoteColumns.ID); + } + } + } + + if (js.has(GTaskStringUtils.META_HEAD_DATA)) { + JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + for (int i = 0; i < dataArray.length(); i++) { + JSONObject data = dataArray.getJSONObject(i); + if (data.has(DataColumns.ID)) { + long dataId = data.getLong(DataColumns.ID); + if (DataUtils.existInDataDatabase(mContentResolver, dataId)) { + // the data id is not available, have to create + // a new one + data.remove(DataColumns.ID); + } + } + } + + } + } catch (JSONException e) { + Log.w(TAG, e.toString()); + e.printStackTrace(); + } + sqlNote.setContent(js); + + Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); + if (parentId == null) { + Log.e(TAG, "cannot find task's parent id locally"); + throw new ActionFailureException("cannot add local node"); + } + sqlNote.setParentId(parentId.longValue()); + } + + // create the local node + sqlNote.setGtaskId(node.getGid()); + sqlNote.commit(false); + + // update gid-nid mapping + mGidToNid.put(node.getGid(), sqlNote.getId()); + mNidToGid.put(sqlNote.getId(), node.getGid()); + + // update meta + updateRemoteMeta(node.getGid(), sqlNote); + } + + /** + * 功能:update本地node + * @author TTS + * @param node + * ----同步操作的基础数据类型 + * @param c + * ----Cursor + * @throws NetworkFailureException + */ + private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; + } + + SqlNote sqlNote; + // update the note locally + sqlNote = new SqlNote(mContext, c); + sqlNote.setContent(node.getLocalJSONFromContent()); + + Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()) + : new Long(Notes.ID_ROOT_FOLDER); + if (parentId == null) { + Log.e(TAG, "cannot find task's parent id locally"); + throw new ActionFailureException("cannot update local node"); + } + sqlNote.setParentId(parentId.longValue()); + sqlNote.commit(true); + + // update meta info + updateRemoteMeta(node.getGid(), sqlNote); + } + + /** + * 功能:远程增加Node + * 需要updateRemoteMeta + * @author TTS + * @param node + * ----同步操作的基础数据类型 + * @param c + * --Cursor + * @throws NetworkFailureException + */ + private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; + } + + SqlNote sqlNote = new SqlNote(mContext, c); //从本地mContext中获取内容 + Node n; + + // update remotely + if (sqlNote.isNoteType()) { + Task task = new Task(); + task.setContentByLocalJSON(sqlNote.getContent()); + + String parentGid = mNidToGid.get(sqlNote.getParentId()); + if (parentGid == null) { + Log.e(TAG, "cannot find task's parent tasklist"); //调试信息 + throw new ActionFailureException("cannot add remote task"); + } + mGTaskListHashMap.get(parentGid).addChildTask(task); //在本地生成的GTaskList中增加子结点 + + //登录远程服务器,创建Task + GTaskClient.getInstance().createTask(task); + n = (Node) task; + + // add meta + updateRemoteMeta(task.getGid(), sqlNote); + } else { + TaskList tasklist = null; + + // we need to skip folder if it has already existed + String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX; + if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) + folderName += GTaskStringUtils.FOLDER_DEFAULT; + else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER) + folderName += GTaskStringUtils.FOLDER_CALL_NOTE; + else + folderName += sqlNote.getSnippet(); + + //iterator迭代器,通过统一的接口迭代所有的map元素 + Iterator> iter = mGTaskListHashMap.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + String gid = entry.getKey(); + TaskList list = entry.getValue(); + + if (list.getName().equals(folderName)) { + tasklist = list; + if (mGTaskHashMap.containsKey(gid)) { + mGTaskHashMap.remove(gid); + } + break; + } + } + + // no match we can add now + if (tasklist == null) { + tasklist = new TaskList(); + tasklist.setContentByLocalJSON(sqlNote.getContent()); + GTaskClient.getInstance().createTaskList(tasklist); + mGTaskListHashMap.put(tasklist.getGid(), tasklist); + } + n = (Node) tasklist; + } + + // update local note + sqlNote.setGtaskId(n.getGid()); + sqlNote.commit(false); + sqlNote.resetLocalModified(); + sqlNote.commit(true); + + // gid-id mapping //创建id间的映射 + mGidToNid.put(n.getGid(), sqlNote.getId()); + mNidToGid.put(sqlNote.getId(), n.getGid()); + } + + /** + * 功能:更新远端的Node,包含meta更新(updateRemoteMeta) + * @author TTS + * @param node + * ----同步操作的基础数据类型 + * @param c + * --Cursor + * @throws NetworkFailureException + */ + private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; + } + + SqlNote sqlNote = new SqlNote(mContext, c); + + // update remotely + node.setContentByLocalJSON(sqlNote.getContent()); + GTaskClient.getInstance().addUpdateNode(node); //GTaskClient用途为从本地登陆远端服务器 + + // update meta + updateRemoteMeta(node.getGid(), sqlNote); + + // move task if necessary + if (sqlNote.isNoteType()) { + Task task = (Task) node; + TaskList preParentList = task.getParent(); + //preParentList为通过node获取的父节点列表 + + String curParentGid = mNidToGid.get(sqlNote.getParentId()); + //curParentGid为通过光标在数据库中找到sqlNote的mParentId,再通过mNidToGid由long类型转为String类型的Gid + + if (curParentGid == null) { + Log.e(TAG, "cannot find task's parent tasklist"); + throw new ActionFailureException("cannot update remote task"); + } + TaskList curParentList = mGTaskListHashMap.get(curParentGid); + //通过HashMap找到对应Gid的TaskList + + if (preParentList != curParentList) { //????????????? + preParentList.removeChildTask(task); + curParentList.addChildTask(task); + GTaskClient.getInstance().moveTask(task, preParentList, curParentList); + } + } + + // clear local modified flag + sqlNote.resetLocalModified(); + //commit到本地数据库 + sqlNote.commit(true); + } + + /** + * 功能:升级远程meta。 meta---元数据----计算机文件系统管理数据---管理数据的数据。 + * @author TTS + * @param gid + * ---GoogleID为String类型 + * @param sqlNote + * ---同步前的数据库操作,故使用类SqlNote + * @throws NetworkFailureException + */ + private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { + if (sqlNote != null && sqlNote.isNoteType()) { + MetaData metaData = mMetaHashMap.get(gid); + if (metaData != null) { + metaData.setMeta(gid, sqlNote.getContent()); + GTaskClient.getInstance().addUpdateNode(metaData); + } else { + metaData = new MetaData(); + metaData.setMeta(gid, sqlNote.getContent()); + mMetaList.addChildTask(metaData); + mMetaHashMap.put(gid, metaData); + GTaskClient.getInstance().createTask(metaData); + } + } + } + + /** + * 功能:刷新本地,给sync的ID对应上最后更改过的对象 + * @author TTS + * @return void + * @throws NetworkFailureException + */ + private void refreshLocalSyncId() throws NetworkFailureException { + if (mCancelled) { + return; + } + + // get the latest gtask list //获取最近的(最晚的)gtask list + mGTaskHashMap.clear(); + mGTaskListHashMap.clear(); + mMetaHashMap.clear(); + initGTaskList(); + + Cursor c = null; + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, + "(type<>? AND parent_id<>?)", new String[] { + String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) + }, NoteColumns.TYPE + " DESC"); //query语句:五个参数,NoteColumns.TYPE + " DESC"-----为按类型递减顺序返回查询结果。new String[] {String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)}------为选择参数。"(type<>? AND parent_id<>?)"-------指明返回行过滤器。SqlNote.PROJECTION_NOTE--------应返回的数据列的名字。Notes.CONTENT_NOTE_URI--------contentProvider包含所有数据集所对应的uri + if (c != null) { + while (c.moveToNext()) { + String gid = c.getString(SqlNote.GTASK_ID_COLUMN); + Node node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + ContentValues values = new ContentValues(); //在ContentValues中创建键值对。准备通过contentResolver写入数据 + values.put(NoteColumns.SYNC_ID, node.getLastModified()); + mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, //进行批量更改,选择参数为NULL,应该可以用insert替换,参数分别为表名和需要更新的value对象。 + c.getLong(SqlNote.ID_COLUMN)), values, null, null); + } else { + Log.e(TAG, "something is missed"); + throw new ActionFailureException( + "some local items don't have gid after sync"); + } + } + } else { + Log.w(TAG, "failed to query local note to refresh sync id"); + } + } finally { + if (c != null) { + c.close(); + c = null; + } + } + } + + /** + * 功能:获取同步账号,mAccount.name + * @author TTS + * @return String + */ + public String getSyncAccount() { + return GTaskClient.getInstance().getSyncAccount().name; + } + + /** + * 功能:取消同步,置mCancelled为true + * @author TTS + */ + public void cancelSync() { + mCancelled = true; + } +} \ No newline at end of file From b9cecbdcc2a9b771ea8fd4bc470f5299932fddcc Mon Sep 17 00:00:00 2001 From: ph2y8awtk <534528244@qq.com> Date: Mon, 11 Dec 2023 20:47:26 +0800 Subject: [PATCH 41/42] ADD file via upload --- src/gtask/remote/GTaskSyncService.java | 126 +++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/gtask/remote/GTaskSyncService.java diff --git a/src/gtask/remote/GTaskSyncService.java b/src/gtask/remote/GTaskSyncService.java new file mode 100644 index 0000000..1e0fede --- /dev/null +++ b/src/gtask/remote/GTaskSyncService.java @@ -0,0 +1,126 @@ + + +package net.micode.notes.gtask.remote; + +/* + * Service是在一段不定的时间运行在后台,不和用户交互的应用组件 + * 主要方法: + * private void startSync() 启动一个同步工作 + * private void cancelSync() 取消同步 + * public void onCreate() + * public int onStartCommand(Intent intent, int flags, int startId) service生命周期的组成部分,相当于重启service(比如在被暂停之后),而不是创建一个新的service + * public void onLowMemory() 在没有内存的情况下如果存在service则结束掉这的service + * public IBinder onBind() + * public void sendBroadcast(String msg) 发送同步的相关通知 + * public static void startSync(Activity activity) + * public static void cancelSync(Context context) + * public static boolean isSyncing() 判读是否在进行同步 + * public static String getProgressString() 获取当前进度的信息 + */ + +public class GTaskSyncService extends Service { + public final static String ACTION_STRING_NAME = "sync_action_type"; + + public final static int ACTION_START_SYNC = 0; + + public final static int ACTION_CANCEL_SYNC = 1; + + public final static int ACTION_INVALID = 2; + + public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service"; + + public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing"; + + public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg"; + + private static GTaskASyncTask mSyncTask = null; + + private static String mSyncProgress = ""; + + //开始一个同步的工作 + private void startSync() { + if (mSyncTask == null) { + mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { + public void onComplete() { + mSyncTask = null; + sendBroadcast(""); + stopSelf(); + } + }); + sendBroadcast(""); + mSyncTask.execute(); //这个函数让任务是以单线程队列方式或线程池队列方式运行 + } + } + + + private void cancelSync() { + if (mSyncTask != null) { + mSyncTask.cancelSync(); + } + } + + @Override + public void onCreate() { //初始化一个service + mSyncTask = null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Bundle bundle = intent.getExtras(); + if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { + switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) { + //两种情况,开始同步或者取消同步 + case ACTION_START_SYNC: + startSync(); + break; + case ACTION_CANCEL_SYNC: + cancelSync(); + break; + default: + break; + } + return START_STICKY; //等待新的intent来是这个service继续运行 + } + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onLowMemory() { + if (mSyncTask != null) { + mSyncTask.cancelSync(); + } + } + + public IBinder onBind(Intent intent) { //不知道干吗用的 + return null; + } + + public void sendBroadcast(String msg) { + mSyncProgress = msg; + Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); //创建一个新的Intent + intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); //附加INTENT中的相应参数的值 + intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); + sendBroadcast(intent); //发送这个通知 + } + + public static void startSync(Activity activity) {//执行一个service,service的内容里的同步动作就是开始同步 + GTaskManager.getInstance().setActivityContext(activity); + Intent intent = new Intent(activity, GTaskSyncService.class); + intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC); + activity.startService(intent); + } + + public static void cancelSync(Context context) {//执行一个service,service的内容里的同步动作就是取消同步 + Intent intent = new Intent(context, GTaskSyncService.class); + intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); + context.startService(intent); + } + + public static boolean isSyncing() { + return mSyncTask != null; + } + + public static String getProgressString() { + return mSyncProgress; + } +} \ No newline at end of file From 10c373786876d31ce088185d7652e51fc6e4064e Mon Sep 17 00:00:00 2001 From: p7iam4w8v <758483247@qq.com> Date: Mon, 11 Dec 2023 20:49:38 +0800 Subject: [PATCH 42/42] =?UTF-8?q?=E5=B0=8F=E7=B1=B3=E4=BE=BF=E7=AD=BE?= =?UTF-8?q?=E6=B3=9B=E8=AF=BB=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ..._2023317157_小米便签泛读报告.docx | Bin 0 -> 264952 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/姬柱_2023317157_小米便签泛读报告.docx diff --git a/doc/姬柱_2023317157_小米便签泛读报告.docx b/doc/姬柱_2023317157_小米便签泛读报告.docx new file mode 100644 index 0000000000000000000000000000000000000000..2c90bd4415f1f509d3ccaaad3b4318671a412750 GIT binary patch literal 264952 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%0ApxO`)`$MMRV;TX{`aAX5S|leX`@`TZlG)6H`P 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