();
}
@@ -54,9 +47,6 @@ public class Contact {
return sContactCache.get(phoneNumber);
}
- //缓存没有,就查询数据库
- //构造一个SQL查询条件:CALLER_ID_SELECTION中的"+"被替换为电话号码的最小匹配值
- //然后执行查询语句
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
Cursor cursor = context.getContentResolver().query(
@@ -66,13 +56,6 @@ public class Contact {
new String[] { phoneNumber },
null);
- //判断查询结果:
- //查询结果不为空,且能够移动到第一条记录:
- // 那么就尝试从Cursor中获取联系人姓名,并将其存入缓存sContactCache。然后返回联系人姓名。
- // 异常情况:如果在获取字符串时发生数组越界异常,则记录一个错误日志并返回null。
- // 最后都要确保关闭Cursor对象,以避免内存泄漏。
- //如果查询结果为空或者没有记录可以移动到(即没有找到匹配的联系人):
- // 则记录一条调试日志并返回null
if (cursor != null && cursor.moveToFirst()) {
try {
String name = cursor.getString(0);
@@ -89,4 +72,5 @@ public class Contact {
return null;
}
}
-}
\ No newline at end of file
+}
+
diff --git a/src/app/src/main/java/net/micode/notes/data/Notes.java b/src/app/src/main/java/net/micode/notes/data/Notes.java
index a4af9a2..f240604 100644
--- a/src/app/src/main/java/net/micode/notes/data/Notes.java
+++ b/src/app/src/main/java/net/micode/notes/data/Notes.java
@@ -18,12 +18,8 @@ package net.micode.notes.data;
import android.net.Uri;
public class Notes {
- // 用于表示笔记应用中的各种类型、标识符以及Intent的额外数据
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;
@@ -34,20 +30,11 @@ public class Notes {
* {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder
* {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records
*/
- //以下id是系统文件夹的标识符(即系统文件夹的分类)
- //ID_ROOT_FOLDER:默认文件夹
- //ID_TEMPARAY_FOLDER:不属于文件夹的笔记
- //ID_CALL_RECORD_FOLDER:用于存储通话记录,以便返回
- //ID_TRASH_FOLER:垃圾回收站
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;
-
- // 额外的数据键,个人理解为就是定义一些布局的ID
- // 这部分就是用于设置UI界面的一些布局或小组件的id,给它定义成常量了。
- // (这样的封装性可能比较好?因为如果有部分要修改,则直接来这边修改即可,不用在activity部分一个一个修改。)
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";
@@ -59,15 +46,11 @@ public class Notes {
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
- //GPT:Android开发中常见的用于定义内容提供者(Content Provider)URI
- //内容提供者是一种Android组件,它允许应用程序共享和存储数据。这里定义了一个URI来查询数据
/**
* Uri to query all notes and folders
*/
@@ -79,13 +62,6 @@ public class Notes {
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data");
public interface NoteColumns {
- // 雨:这个接口定义了一系列静态的、最终的字符串常量,这些常量代表数据库表中的列名。
- // 作用:用于后面创建数据库的表头
- // 总的属性有:ID、父级ID、创建日期、修改日期、提醒日期、文件(标签)名(摘要?)、小部件ID、小部件类型、背景颜色ID、附件、文件中的标签数量、
- // 文件(标签)类型、最后一个同步ID、本地修改标签、移动前的ID、谷歌任务ID、代码版本信息。
- // GPT提示:在Android开发中,当使用SQLite数据库时,通常会为表中的每一列定义一个常量,以便在代码中引用。
- // 这样做的好处是,如果以后需要更改列名,只需要在一个地方修改,而不需要在整个代码中搜索和替换。
-
/**
* The unique ID for a row
* Type: INTEGER (long)
@@ -121,7 +97,6 @@ public class Notes {
* Folder's name or text content of note
* Type: TEXT
*/
- // 摘要?
public static final String SNIPPET = "snippet";
/**
@@ -165,7 +140,6 @@ public class Notes {
* The last sync id
* Type: INTEGER (long)
*/
- //雨:在数据同步过程中,这个ID可能用来跟踪和识别每次同步操作的唯一性,确保数据的一致性。
public static final String SYNC_ID = "sync_id";
/**
@@ -194,9 +168,6 @@ public class Notes {
}
public interface DataColumns {
- // DataColumns的接口,这个接口包含了一系列静态常量,这些常量代表了数据库表中用于存储数据的列名。
- // 每个常量都有相应的注释,说明该列的作用和数据类型。
-
/**
* The unique ID for a row
* Type: INTEGER (long)
@@ -207,41 +178,33 @@ public class Notes {
* The MIME type of the item represented by this row.
* Type: Text
*/
- //MIME类型是一种标准,用于标识文档、文件或字节流的性质和格式。在数据库中,这个字段可以用来识别不同类型的数据,例如文本、图片、音频或视频等。
public static final String MIME_TYPE = "mime_type";
/**
* The reference id to note that this data belongs to
* Type: INTEGER (long)
*/
- //归属的Note的ID
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";
- // 以下5个是通用数据列,它们的具体意义取决于MIME类型(由MIME_TYPE字段指定)。
- // 不同的MIME类型可能需要存储不同类型的数据,这五个字段提供了灵活性,允许根据MIME类型来存储相应的数据。
- // 读后面的代码感觉这部分是在表示内容的不同状态?
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* integer data type
@@ -278,41 +241,39 @@ public class Notes {
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; //模式?这个被存在DATA1列中
+ public static final String MODE = DATA1;
- public static final int MODE_CHECK_LIST = 1; //所处检查列表模式?
+ public static final int MODE_CHECK_LIST = 1;
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; // 定义了MIME类型,用于标识文本标签的目录
+ 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";// 定义了MIME类型,用于标识文本标签的单个项
+ 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");//文本标签内容提供者(Content Provider)的URI,用于访问文本标签数据
+ 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; //一个字符串常量,表示通话记录的日期
+ public static final String CALL_DATE = DATA1;
/**
* Phone number for this record
* Type: TEXT
*/
- public static final String PHONE_NUMBER = DATA3; //意味着在数据库表中,这个电话号码信息将被存储在DATA3列中
+ public static final String PHONE_NUMBER = DATA3;
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note";// 同样定义了MIME类型,是用于标识通话记录的目录。
+ 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";// 同样定义了MIME类型,是用于标识通话记录的单个项。
+ 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");//定义了通话记录内容提供者的URI,用于访问通话记录数据。
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note");
}
}
diff --git a/src/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java b/src/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java
index 8a03c7d..ffe5d57 100644
--- a/src/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java
+++ b/src/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java
@@ -28,253 +28,188 @@ import net.micode.notes.data.Notes.NoteColumns;
public class NotesDatabaseHelper extends SQLiteOpenHelper {
- // 数据库帮助类,用于管理名为 note.db 的 SQLite 数据库。
-// 它继承自 SQLiteOpenHelper 类,这是 Android提供的一个方便的工具类,用于管理数据库的创建和版本更新.
- // 数据库的基本信息;数据库名称和版本信息(在创建实例对象时会用到)
private static final String DB_NAME = "note.db";
private static final int DB_VERSION = 4;
- //内部接口:个人理解为两个表名,一个note,一个data
public interface TABLE {
public static final String NOTE = "note";
public static final String DATA = "data";
}
- //一个标签,方便日志输出时识别出信息来自哪里
private static final String TAG = "NotesDatabaseHelper";
- //静态所有变量,提供一个全局访问点来获取数据库辅助类的唯一实例,使得在应用的任何地方都可以方便地使用它
private static NotesDatabaseHelper mInstance;
- /* 以下都是一些SQL语句,辅助我们来对数据库进行操作 */
- //创建note表的语句,这里的NoteColumns就是我们刚刚在Notes中定义的一个接口,里面定义了一系列静态的数据库表中的列名
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" +
- ")";
-
- //同上,创建data表的语句,这里的DataColumns就是我们刚刚在Notes中定义的一个接口,里面定义了一系列静态的数据库表中的列名
+ "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 ''" +
- ")";
-
- // 功能简介:
- // 创建一个以note的ID为索引
- // 解读:
- // 用于在TABLE.DATA表上创建一个名为note_id_index的索引。
- // 这个索引是基于DataColumns.NOTE_ID列的。IF NOT EXISTS确保了如果索引已经存在,那么就不会尝试重新创建它,避免了可能的错误。
- // 索引通常用于提高查询性能,特别是在对某个字段进行频繁查询时。
+ "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 + ");";
-
- /* 以下是一些对便签增删改定义的触发器 */
- /* 总结
- * 这些触发器都是用来维护NOTE表和与之相关联的DATA表之间数据一致性的。
- * 当在NOTE表中发生删除或更新操作时,这些触发器会自动执行相应的数据清理或更新操作,确保数据库中的数据保持正确和一致。
- * 特别是在处理文件夹和回收站等逻辑时,这些触发器起到了非常重要的作用,可以自动管理数据的移动和删除。*/
+ "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
*/
- // 功能简介:
- // 添加触发器:增加文件夹的便签个数记录(因为我们会移动便签进入文件夹,这时候文件夹的计数要进行更新)
- // 解读:
- // 定义了一个SQL触发器increase_folder_count_on_update。
- // 触发器是一种特殊的存储过程,它会在指定表上的指定事件(如INSERT、UPDATE、DELETE)发生时自动执行。
- // 这个触发器会在TABLE.NOTE表的NoteColumns.PARENT_ID字段更新后执行。
- // 触发器的逻辑是:当某个笔记的PARENT_ID(即父文件夹ID)被更新时,它会找到对应的文件夹(通过新的PARENT_ID),并将该文件夹的NOTES_COUNT(即笔记数)增加1。
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";
+ "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";
/**
* 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";
+ "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";
/**
* 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";
+ "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";
/**
* 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";
+ "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";
/**
* Update note's content when insert data with type {@link DataConstants#NOTE}
*/
- // 功能简介:
- // 添加触发器:当向DATA表中插入类型为NOTE(便签)的数据时,更新note表对应的笔记内容。
- // 解读:
- // 在DATA表上进行INSERT操作后,如果新插入的数据的MIME_TYPE为NOTE,则触发此操作。
- // 它会更新NOTE表,将与新插入数据相关联的标签的SNIPPET(摘要)字段设置为新插入数据的CONTENT字段的值
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";
+ "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";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has changed
*/
- // 功能简介:
- // 添加触发器:当DATA表中,类型为NOTE(便签)的数据更改时,更新note表对应的笔记内容。
- // 解读:
- // 在DATA表上进行UPDATE操作后,如果更新前的数据的MIME_TYPE为NOTE,则触发此操作。
- // 它会更新NOTE表,将与更新后的数据相关联的笔记的SNIPPET字段设置为新数据的CONTENT字段的值
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";
+ "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";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has deleted
*/
- // 功能简介:
- // 添加触发器:当DATA表中,类型为NOTE(便签)的数据删除时,更新note表对应的笔记内容(置空)。
- // 解读:
- // 在DATA表上进行DELETE操作后,如果删除的数据的MIME_TYPE为NOTE,则触发此操作。
- // 它会更新NOTE表,将与删除的数据相关联的笔记的SNIPPET字段设置为空字符串。
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";
+ "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";
/**
* Delete datas belong to note which has been deleted
*/
- // 功能简介:
- // 添加触发器:当从NOTE表中删除笔记时,删除与该笔记相关联的数据(就是删除data表中为该note的数据)
- // 解读:
- // 在NOTE表上进行DELETE操作后,此触发器被激活。
- // 它会从DATA表中删除所有与已删除的笔记(由old.ID表示)相关联的数据行(通过比较DATA表中的NOTE_ID字段与已删除笔记的ID来实现)
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";
+ "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
*/
- // 功能简介:
- // 添加触发器:当从NOTE表中删除一个文件夹时,删除该文件夹下的所有笔记。
- // 解读:
- // 在NOTE表上进行DELETE操作后,如果删除的是一个文件夹(由old.ID表示)
- // 触发器会删除所有以该文件夹为父级(PARENT_ID)的笔记(通过比较NOTE表中的PARENT_ID字段与已删除文件夹的ID来实现)
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";
+ "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
*/
- // 功能简介:
- // 添加触发器:当某个文件夹被移动到回收站时,移动该文件夹下的所有笔记到回收站
- // 解读:
- // 在NOTE表上进行UPDATE操作后,如果某个文件夹的新PARENT_ID字段值等于回收站的ID(Notes.ID_TRASH_FOLER)
- // 触发器会更新所有以该文件夹为父级(PARENT_ID)的笔记,将它们也移动到回收站。
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";
-
- // 构造器
+ "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);
}
- // 创建note(标签)表
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
@@ -282,9 +217,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
Log.d(TAG, "note table has been created");
}
- // 重新创建或更新与笔记表相关的触发器。
- // 首先,使用DROP TRIGGER IF EXISTS语句删除已存在的触发器。确保在重新创建触发器之前,不存在同名的触发器。
- // 然后,使用db.execSQL()方法执行预定义的SQL语句,这些语句用于创建新的触发器。
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");
@@ -303,17 +235,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}
- /* 以下部分是操作SQLite数据库部分 */
- // 功能简介:
- // 创建通话记录文件夹、默认文件夹、临时文件夹和回收站,并插入相关数据
- // 具体解读:
- // ContentValues是一个用于存储键值对的类,常用于SQLite数据库的插入操作
- // values.put方法可以向ContentValues对象中添加数据。
- // NoteColumns.ID是存储文件夹ID的列名,Notes.ID_CALL_RECORD_FOLDER是通话记录文件夹的ID。
- // NoteColumns.TYPE是存储文件夹类型的列名,Notes.TYPE_SYSTEM表示这是一个系统文件夹。
- // 使用db.insert方法将values中的数据插入到TABLE.NOTE(即标签表)中。
- // 每次插入新数据前,都使用values.clear()方法清除ContentValues对象中的旧数据,确保不会重复插入旧数据。
- // 然后分别创建默认文件夹、临时文件夹和回收站,并以同样的方法插入数据。
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
@@ -327,7 +248,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* root folder which is default folder
*/
- // 创建默认文件夹:重复上述步骤,但这次是为根文件夹插入数据。
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
@@ -336,7 +256,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* 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);
@@ -345,21 +264,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* 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);
}
- //功能简介:
- //创建data(数据)表
- //解读:
- //这个方法用于创建数据表,以及与之相关的触发器。
- //创建数据表:使用db.execSQL方法执行预定义的SQL语句CREATE_DATA_TABLE_SQL,用于创建数据表。
- //重新创建数据表触发器:调用reCreateDataTableTriggers方法,用于删除并重新创建与数据表相关的触发器。
- //创建索引:使用db.execSQL方法执行CREATE_DATA_NOTE_ID_INDEX_SQL语句,为数据表创建索引。
- //记录日志:使用Log.d方法记录一条调试级别的日志,表示数据表已经创建。
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
@@ -367,10 +277,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
Log.d(TAG, "data table has been created");
}
- //和上面的note表的reCreate...同理
- //重新创建或更新与笔记表相关的触发器。
- //首先,使用DROP TRIGGER IF EXISTS语句删除已存在的触发器。确保在重新创建触发器之前,不存在同名的触发器。
- //然后,使用db.execSQL()方法执行预定义的SQL语句,这些语句用于创建新的触发器。
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");
@@ -381,11 +287,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
}
- //解读:
- //synchronized关键字确保在多线程环境下,只有一个线程能够进入这个方法,防止了同时创建多个实例的情况
- //getInstance(Context context)方法使用了单例模式来确保整个应用程序中只有一个NotesDatabaseHelper实例。
- //它首先检查mInstance(类的静态成员变量,没有在代码片段中显示)是否为null。
- //如果是null,则创建一个新的NotesDatabaseHelper实例,并将其赋值给mInstance。最后返回mInstance。
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
@@ -393,19 +294,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
return mInstance;
}
- //功能简介:
- //当数据库首次创建时,onCreate方法会被调用。
- //这里重写onCreate方法,它调用了上述createNoteTable(db)和createDataTable(db)两个方法
- //这样首次创建数据库时就多出了两张表。
@Override
public void onCreate(SQLiteDatabase db) {
createNoteTable(db);
createDataTable(db);
}
- //功能简介:
- //当数据库需要升级时(即数据库的版本号改变),onUpgrade方法会被调用。
- //该方法会根据当前的oldVersion和新的newVersion来执行相应的升级操作
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false;
@@ -433,17 +327,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
reCreateDataTableTriggers(db);
}
- if (oldVersion != newVersion) { //数据库升级失败,抛出一个异常,表示数据库升级失败
+ if (oldVersion != newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails");
}
}
- //功能简介:
- // 将数据库从版本1升级到版本2。
- //解读:
- // 首先,它删除了已经存在的NOTE和DATA表(如果存在的话)。DROP TABLE IF EXISTS语句确保了即使这些表不存在,也不会抛出错误。
- // 然后,它调用了createNoteTable(db)和createDataTable(db)方法来重新创建这两个表。这意味着在升级到版本2时,这两个表的内容会被完全清除,并重新创建新的空表。
private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
@@ -451,12 +340,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
createDataTable(db);
}
- //功能简介:
- // 将数据库从版本2(或可能是跳过版本2的某个状态)升级到版本3。
- //解读:
- // 首先,删除了三个不再使用的触发器(如果存在的话)。触发器是数据库中的一种对象,可以在插入、更新或删除记录时自动执行某些操作。
- // 然后,使用ALTER TABLE语句修改表结构,向NOTE表中添加了一个名为GTASK_ID的新列,并设置默认值为空字符串。
- // 最后,向NOTE表中插入了一条新的系统文件夹记录,表示一个名为“trash folder”的系统文件夹。这可能是用于存储已删除笔记的回收站功能。
private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
@@ -472,10 +355,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.insert(TABLE.NOTE, null, values);
}
- //功能简介:
- // 这个方法负责将数据库从版本3升级到版本4。
- //解读:
- // 它向NOTE表中添加了一个名为VERSION的新列,并设置了默认值为0。这个新列用于记录标签版本信息。
private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
diff --git a/src/app/src/main/java/net/micode/notes/data/NotesProvider.java b/src/app/src/main/java/net/micode/notes/data/NotesProvider.java
index 4e186ed..edb0a60 100644
--- a/src/app/src/main/java/net/micode/notes/data/NotesProvider.java
+++ b/src/app/src/main/java/net/micode/notes/data/NotesProvider.java
@@ -36,24 +36,12 @@ import net.micode.notes.data.NotesDatabaseHelper.TABLE;
public class NotesProvider extends ContentProvider {
-// Android 应用程序中的一部分:内容提供者(ContentProvider)。
-// 内容提供者是 Android 四大组件之一,它允许应用程序之间共享数据。
-
- //概述:
- //NotesProvider的主要功能是作为一个内容提供者,为其他应用程序或组件提供对“Notes”数据的访问。
- //它允许其他应用程序查询、插入、更新或删除标签数据。
- //通过URI匹配,NotesProvider能够区分对哪种数据类型的请求(例如,单独的标签、标签的数据、文件夹操作等),并执行相应的操作。
-
- //用于匹配不同URI的UriMatcher对象,通常用于解析传入的URI,并确定应该执行哪种操作。
private static final UriMatcher mMatcher;
- //NotesDatabaseHelper实类,用来操作SQLite数据库,负责创建、更新和查询数据库。
private NotesDatabaseHelper mHelper;
- //标签,输出日志时用来表示是该类发出的消息
private static final String TAG = "NotesProvider";
- //6个URI的匹配码,用于区分不同的URI类型
private static final int URI_NOTE = 1;
private static final int URI_NOTE_ITEM = 2;
private static final int URI_DATA = 3;
@@ -62,23 +50,13 @@ public class NotesProvider extends ContentProvider {
private static final int URI_SEARCH = 5;
private static final int URI_SEARCH_SUGGEST = 6;
- //进一步定义了URI匹配规则和搜索查询的投影
- //功能概述:
- //初始化了一个UriMatcher对象mMatcher,并添加了一系列的URI匹配规则。
- //解读:
static {
- //创建了一个UriMatcher实例,并设置默认匹配码为NO_MATCH,表示如果没有任何URI匹配,则返回这个码。
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- //添加规则,当URI的authority为Notes.AUTHORITY,路径为note时,返回匹配码URI_NOTE。
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
- //添加规则,当URI的authority为Notes.AUTHORITY,路径为note/后跟一个数字(#代表数字)时,返回匹配码URI_NOTE_ITEM。
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
- //和上面两句同理,但用于匹配数据相关的URI
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM);
- //用于匹配搜索相关的URI
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH);
- //这两行用于匹配搜索建议相关的URI
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
}
@@ -87,66 +65,33 @@ public class NotesProvider extends ContentProvider {
* 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.
*/
- //功能概述:
- //一个 SQL 查询的投影部分,用于定义查询返回的结果集中应该包含哪些列。
- //解读:(每行对应)
- //返回笔记的 ID。
- //笔记的 ID 也被重命名为 SUGGEST_COLUMN_INTENT_EXTRA_DATA,这通常用于 Android 的搜索建议中,作为传递给相关 Intent 的额外数据。
- //对 SNIPPET 列的处理:首先使用 REPLACE 函数将 x'0A'(即换行符 \n)替换为空字符串,然后使用 TRIM 函数删除前后的空白字符,处理后的结果分别重命名为 SUGGEST_COLUMN_TEXT_1
- //对 SNIPPET 列的处理:首先使用 REPLACE 函数将 x'0A'(即换行符 \n)替换为空字符串,然后使用 TRIM 函数删除前后的空白字符,处理后的结果分别重命名为 SUGGEST_COLUMN_TEXT_2
- //返回一个用于搜索建议图标的资源 ID,并命名为 SUGGEST_COLUMN_ICON_1。
- //返回一个固定的 Intent 动作 ACTION_VIEW,并命名为 SUGGEST_COLUMN_INTENT_ACTION。
- //返回一个内容类型,并命名为 SUGGEST_COLUMN_INTENT_DATA。
- private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," //返回笔记的 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;
+ 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;
- //功能概述:
- //完整的 SQL 查询语句,用于从 TABLE.NOTE 表中检索信息
- //解读:
- // 使用上面定义的投影来选择数据。
- // 并指定从哪个表中选择数据。
- //WHERE子句包含三个条件:
- // ①搜索 SNIPPET 列中包含特定模式的行(? 是一个占位符,实际查询时会用具体的值替换)。
- // ②父ID不为回收站的ID:排除那些父 ID 为回收站的行。
- // ③只选择类型为note(标签)的行。
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;
+ + " FROM " + TABLE.NOTE
+ + " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
+ + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER
+ + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
- //重写onCreate方法:
- //getContext() 方法被调用以获取当前组件的上下文(Context),以便 NotesDatabaseHelper 能够访问应用程序的资源和其他功能
- //mHelper用于存储从 NotesDatabaseHelper.getInstance 方法返回的实例。这样,该实例就可以在整个组件的其他方法中被访问和使用。
@Override
public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
- //功能:查询数据
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- //初始化变量:
- //Cursor对象 c,用来存储查询结果
- //使用 NotesDatabaseHelper 的实例 mHelper来获取一个可读的数据库实例
- //定义一个字符串id,用来存储从URI中解析出的ID
+ String sortOrder) {
Cursor c = null;
SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null;
-
- //根据匹配不同的URI来进行不同的查询
switch (mMatcher.match(uri)) {
- // URI_NOTE:查询整个 NOTE 表。
- // URI_NOTE_ITEM:查询 NOTE 表中的特定项。ID 从 URI 的路径段中获取,并添加到查询条件中。
- // URI_DATA:查询整个 DATA 表。
- // URI_DATA_ITEM:查询 DATA 表中的特定项。ID 的获取和处理方式与 URI_NOTE_ITEM 相同。
case URI_NOTE:
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);
@@ -165,12 +110,6 @@ public class NotesProvider extends ContentProvider {
c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
-
- //URI_SEARCH 和 URI_SEARCH_SUGGEST:处理搜索查询。
- // 代码首先检查是否提供了不应与搜索查询一起使用的参数(如 sortOrder, selection, selectionArgs, 或 projection)。
- // 如果提供了这些参数,则抛出一个 IllegalArgumentException。
- // 根据 URI 类型,从 URI 的路径段或查询参数中获取搜索字符串 searchString。
- // 如果 searchString 为空或无效,则返回 null,表示没有搜索结果。
case URI_SEARCH:
case URI_SEARCH_SUGGEST:
if (sortOrder != null || projection != null) {
@@ -191,8 +130,6 @@ public class NotesProvider extends ContentProvider {
return null;
}
- //字符串格式化:格式化后的字符串就会是 "%s%",即包含s是任何文本
- //然后执行原始SQL查询
try {
searchString = String.format("%%%s%%", searchString);
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
@@ -201,31 +138,19 @@ public class NotesProvider extends ContentProvider {
Log.e(TAG, "got exception: " + ex.toString());
}
break;
-
- //未知URI处理:
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
- //如果查询结果不为空(即 Cursor 对象 c 不是 null),则为其设置一个通知 URI。
- //这意味着当与这个 URI 关联的数据发生变化时,任何注册了监听这个 URI 的 ContentObserver 都会被通知。
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
- //功能:插入数据
- //参数:Uri 用来标识要插入数据的表,ContentValues对象包含要插入的键值对
@Override
public Uri insert(Uri uri, ContentValues values) {
- //获取数据库
- //三个长整型变量,分别用来存储数据项ID、便签ID 和插入行的ID
SQLiteDatabase db = mHelper.getWritableDatabase();
long dataId = 0, noteId = 0, insertedId = 0;
-
- //对于 URI_NOTE,将values插入到 TABLE.NOTE 表中,并返回插入行的 ID。
- //对于 URI_DATA,首先检查values是否包含 DataColumns.NOTE_ID,如果包含,则获取其值。如果不包含,记录一条日志信息。然后,将 values 插入到 TABLE.DATA 表中,并返回插入行的 ID。
- //如果 uri 不是已知的 URI 类型,则抛出一个 IllegalArgumentException。
switch (mMatcher.match(uri)) {
case URI_NOTE:
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
@@ -241,10 +166,6 @@ public class NotesProvider extends ContentProvider {
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
-
- //功能:通知变化
- //如果noteId 或 dataId 大于 0(即成功插入了数据),则使用 ContentResolver 的 notifyChange 方法通知监听这些 URI 的观察者,告知数据已经改变。
- //ContentUris.withAppendedId 方法用于在基本 URI 后面追加一个 ID,形成完整的 URI。
// Notify the note uri
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
@@ -257,28 +178,16 @@ public class NotesProvider extends ContentProvider {
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
- //返回包含新插入数据项ID 的 Uri。允许调用者知道新插入的数据项的位置
return ContentUris.withAppendedId(uri, insertedId);
}
- //功能:删除数据项
- //参数:uri:标识要删除数据的表或数据项。 selection:一个可选的 WHERE 子句,用于指定删除条件。 selectionArgs:一个可选的字符串数组,用于替换 selection 中的占位符
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
- //count:记录被删除的行数。
- //id:用于存储从 URI 中解析出的数据项 ID。
- //db:可写的数据库对象,用于执行删除操作。
- //deleteData:一个布尔值,用于标记是否删除了 DATA 表中的数据。
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false;
-
switch (mMatcher.match(uri)) {
- //URI_NOTE: 修改 selection 语句:确保只删除 ID 大于 0 的笔记。然后执行删除操作并返回被删除的行数。
- //URI_NOTE_ITEM: 从 URI 中解析出 ID。检查 ID 是否小于等于 0,如果是,则不执行删除操作;否则执行删除操作并返回被删除的行数
- //URI_DATA: 执行删除操作并返回被删除的行数。设置 deleteData 为 true,表示删除了 DATA 表中的数据。
- //URI_DATA_ITEM: 先从 URI 中解析出 ID,然后执行删除操作并返回被删除的行数,并设置 deleteData 为 true,表示删除了 DATA 表中的数据。
case URI_NOTE:
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
count = db.delete(TABLE.NOTE, selection, selectionArgs);
@@ -309,39 +218,22 @@ public class NotesProvider extends ContentProvider {
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
-
- //如果 count 大于 0,说明有数据被删除。
- //如果 deleteData 为 true,则通知监听 Notes.CONTENT_NOTE_URI 的观察者,数据已改变。
- //通知监听传入 uri 的观察者数据已改变。
if (count > 0) {
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null);
}
-
return count;
}
- //功能:更新数据库的数据
- //参数:uri:标识要更新数据的表或数据项。 values:一个包含新值的键值对集合。
- // selection:一个可选的 WHERE 子句,用于指定更新条件。 selectionArgs:一个可选的字符串数组,用于替换 selection 中的占位符。
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- //count:记录被更新的行数。
- //id:用于存储从 URI 中解析出的数据项 ID。
- //db:可写的 SQLite 数据库对象,用于执行更新操作。
- //updateData:用于标记是否更新了 data 表中的数据。
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean updateData = false;
-
switch (mMatcher.match(uri)) {
- //URI_NOTE:调用 increaseNoteVersion 方法(用于增加便签版本),然后在note表执行更新操作并返回被更新的行数。
- //URI_NOTE_ITEM:从 URI 中解析出 ID,并调用 increaseNoteVersion 方法,传入解析出的 ID,最后在note表执行更新操作并返回被更新的行数。
- //URI_DATA:在data表执行更新操作并返回被更新的行数。设置 updateData 为 true,表示更新了 DATA 表中的数据。
- //URI_DATA_ITEM:从 URI 中解析出 ID。执行更新操作并返回被更新的行数。置 updateData 为 true,表示更新了 DATA 表中的数据。
case URI_NOTE:
increaseNoteVersion(-1, selection, selectionArgs);
count = db.update(TABLE.NOTE, values, selection, selectionArgs);
@@ -366,9 +258,6 @@ public class NotesProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URI " + uri);
}
- //如果 count 大于 0,说明有数据被更新。
- //如果 updateData 为 true,则通知监听 Notes.CONTENT_NOTE_URI 的观察者数据已改变。
- //通知监听传入 uri 的观察者数据已改变。
if (count > 0) {
if (updateData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
@@ -378,12 +267,10 @@ public class NotesProvider extends ContentProvider {
return count;
}
- //解析传入的条件语句:一个 SQL WHERE 子句的一部分
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
- //更新note表的version列,将其值增加 1。
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE ");
diff --git a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java
index a1deb99..64675bd 100644
--- a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java
+++ b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java
@@ -64,23 +64,24 @@ public class GTaskASyncTask extends AsyncTask {
}
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;
if (tickerId != R.string.ticker_success) {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
- NotesPreferenceActivity.class), PendingIntent.FLAG_IMMUTABLE);
+ NotesPreferenceActivity.class), 0);
+
} else {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
- NotesListActivity.class), PendingIntent.FLAG_IMMUTABLE);
- }
- Notification.Builder builder = new Notification.Builder(mContext)
- .setAutoCancel(true)
- .setContentTitle(mContext.getString(R.string.app_name))
- .setContentText(content)
- .setContentIntent(pendingIntent)
- .setWhen(System.currentTimeMillis())
- .setOngoing(true);
- Notification notification=builder.getNotification();
+ NotesListActivity.class), 0);
+ };
+ /*
+ notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
+ pendingIntent);
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
+ */
}
@Override
diff --git a/src/app/src/main/java/net/micode/notes/model/Note.java b/src/app/src/main/java/net/micode/notes/model/Note.java
index b45337e..6706cf6 100644
--- a/src/app/src/main/java/net/micode/notes/model/Note.java
+++ b/src/app/src/main/java/net/micode/notes/model/Note.java
@@ -15,16 +15,15 @@
*/
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;//输出日志,比如说出错、警告等
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.OperationApplicationException;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
@@ -34,21 +33,16 @@ import net.micode.notes.data.Notes.TextNote;
import java.util.ArrayList;
-// 导入所需的类和包
public class Note {
- // 定义一个 ContentValues 对象,用于存储笔记的差异
private ContentValues mNoteDiffValues;
- // 定义一个 NoteData 对象,用于存储笔记数据
private NoteData mNoteData;
- // 定义日志标签
private static final String TAG = "Note";
-
/**
- * 创建一个新的笔记ID,用于在数据库中添加新笔记
+ * 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);
@@ -57,69 +51,58 @@ public class 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, "获取笔记ID错误:" + e.toString());
+ Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
- }//try-catch异常处理
+ }
if (noteId == -1) {
- throw new IllegalStateException("错误的笔记ID:" + noteId);
+ throw new IllegalStateException("Wrong note id:" + noteId);
}
return noteId;
}
- // 构造函数,初始化 mNoteDiffValues 和 mNoteData
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);
}
- // 设置文本数据ID
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}
- // 获取文本数据ID
public long getTextDataId() {
return mNoteData.mTextDataId;
}
- // 设置电话数据ID
public void setCallDataId(long id) {
mNoteData.setCallDataId(id);
}
- // 设置电话数据
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}
- // 检查笔记是否被本地修改
public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
- // 同步笔记
public boolean syncNote(Context context, long noteId) {
if (noteId <= 0) {
- throw new IllegalArgumentException("错误的笔记ID:" + noteId);
+ throw new IllegalArgumentException("Wrong note id:" + noteId);
}
if (!isLocalModified()) {
@@ -127,14 +110,15 @@ public class Note {
}
/**
- * 理论上,一旦数据发生变化,笔记的 LOCAL_MODIFIED 和 MODIFIED_DATE 应该被更新。
- * 为了数据安全,即使更新笔记失败,我们也更新笔记数据信息
+ * 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, "更新笔记错误,不应该发生");
- // 不返回,继续执行
+ Log.e(TAG, "Update note error, should not happen");
+ // Do not return, fall through
}
mNoteDiffValues.clear();
@@ -146,20 +130,17 @@ public class Note {
return true;
}
- // 内部类 NoteData,用于存储和操作笔记数据
private class NoteData {
- // 文本数据ID
private long mTextDataId;
- // 存储文本数据的 ContentValues
+
private ContentValues mTextDataValues;
- // 电话数据ID
+
private long mCallDataId;
- // 存储电话数据的 ContentValues
+
private ContentValues mCallDataValues;
- // 日志标签
+
private static final String TAG = "NoteData";
- // 构造函数,初始化 mTextDataValues 和 mCallDataValues
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
@@ -167,52 +148,48 @@ public class Note {
mCallDataId = 0;
}
- // 检查数据是否被本地修改
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
- // 设置文本数据ID
void setTextDataId(long id) {
- if (id <= 0) {
- throw new IllegalArgumentException("文本数据ID应该大于0");
+ if(id <= 0) {
+ throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;
}
- // 设置电话数据ID
void setCallDataId(long id) {
if (id <= 0) {
- throw new IllegalArgumentException("电话数据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 pushIntoContentResolver(Context context, long noteId) {
- // 检查安全性
+ /**
+ * Check for safety
+ */
if (noteId <= 0) {
- throw new IllegalArgumentException("错误的笔记ID:" + noteId);
- }//判断数据是否合法
+ throw new IllegalArgumentException("Wrong note id:" + noteId);
+ }
ArrayList operationList = new ArrayList();
- ContentProviderOperation.Builder builder = null;//数据库的操作列表
+ ContentProviderOperation.Builder builder = null;
- if (mTextDataValues.size() > 0) {
+ if(mTextDataValues.size() > 0) {
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
if (mTextDataId == 0) {
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
@@ -221,7 +198,7 @@ public class Note {
try {
setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
- Log.e(TAG, "插入新的文本数据失败,笔记ID:" + noteId);
+ Log.e(TAG, "Insert new text data fail with noteId" + noteId);
mTextDataValues.clear();
return null;
}
@@ -232,9 +209,9 @@ public class Note {
operationList.add(builder.build());
}
mTextDataValues.clear();
- }//把文本数据存入DataColumns
+ }
- if (mCallDataValues.size() > 0) {
+ if(mCallDataValues.size() > 0) {
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
if (mCallDataId == 0) {
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
@@ -243,7 +220,7 @@ public class Note {
try {
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
- Log.e(TAG, "插入新的电话数据失败,笔记ID:" + noteId);
+ Log.e(TAG, "Insert new call data fail with noteId" + noteId);
mCallDataValues.clear();
return null;
}
@@ -254,7 +231,7 @@ public class Note {
operationList.add(builder.build());
}
mCallDataValues.clear();
- }//把电话号码数据存入DataColumns
+ }
if (operationList.size() > 0) {
try {
@@ -269,7 +246,7 @@ public class Note {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
}
- }//存储过程中的异常处理
+ }
return null;
}
}
diff --git a/src/app/src/main/java/net/micode/notes/model/WorkingNote.java b/src/app/src/main/java/net/micode/notes/model/WorkingNote.java
index 9eafbe0..a1a2455 100644
--- a/src/app/src/main/java/net/micode/notes/model/WorkingNote.java
+++ b/src/app/src/main/java/net/micode/notes/model/WorkingNote.java
@@ -31,13 +31,14 @@ import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.tool.ResourceParser.NoteBgResources;
+
public class WorkingNote {
// Note for the working note
private Note mNote;
// Note Id
private long mNoteId;
// Note content
- private String mContent;
+ public String mContent;
// Note mode
private int mMode;
@@ -100,7 +101,7 @@ public class WorkingNote {
private static final int NOTE_MODIFIED_DATE_COLUMN = 5;
- // 新建笔记构造函数
+ // New note construct
private WorkingNote(Context context, long folderId) {
mContext = context;
mAlertDate = 0;
@@ -113,7 +114,7 @@ public class WorkingNote {
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
}
- // 已存在笔记构造函数
+ // Existing note construct
private WorkingNote(Context context, long noteId, long folderId) {
mContext = context;
mNoteId = noteId;
@@ -122,13 +123,12 @@ public class WorkingNote {
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);
@@ -139,17 +139,17 @@ public class WorkingNote {
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();
}
+
private void loadNoteData() {
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] {
- String.valueOf(mNoteId)
+ String.valueOf(mNoteId)
}, null);
if (cursor != null) {
@@ -173,10 +173,9 @@ public class WorkingNote {
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) {
+ int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId);
note.setBgColorId(defaultBgColorId);
note.setWidgetId(widgetId);
@@ -188,7 +187,6 @@ public class WorkingNote {
return new WorkingNote(context, id, 0);
}
- // 保存Note
public synchronized boolean saveNote() {
if (isWorthSaving()) {
if (!existInDatabase()) {
@@ -213,11 +211,11 @@ public class WorkingNote {
return false;
}
}
- // 是否在数据库中存在
+
public boolean existInDatabase() {
return mNoteId > 0;
}
- // 是否值得保存
+
private boolean isWorthSaving() {
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) {
@@ -226,12 +224,11 @@ public class WorkingNote {
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;
@@ -241,17 +238,15 @@ public class WorkingNote {
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方法
+ mNoteSettingStatusListener.onWidgetChanged();
}
}
- // 设定背景颜色
+
public void setBgColorId(int id) {
if (id != mBgColorId) {
mBgColorId = id;
@@ -261,8 +256,7 @@ public class WorkingNote {
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
}
}
- // 设定检查列表模式
- // 参数:mode
+
public void setCheckListMode(int mode) {
if (mMode != mode) {
if (mNoteSettingStatusListener != null) {
@@ -272,32 +266,28 @@ public class WorkingNote {
mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
}
}
- // 设定WidgetType
- // 参数:type
+
public void setWidgetType(int type) {
if (type != mWidgetType) {
mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
}
}
- // 设定WidgetId
- // 参数:id
+
public void setWidgetId(int id) {
if (id != mWidgetId) {
mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
}
}
- // 设定WorkingTex
- // 参数:更改的tex
+
public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) {
mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent);
}
}
- // 转变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);
@@ -351,9 +341,7 @@ public class WorkingNote {
public int getWidgetType() {
return mWidgetType;
}
- // 创建接口 NoteSettingChangedListener,便签更新监视
- // 为NoteEditActivity提供接口
- // 提供函数有
+
public interface NoteSettingChangedListener {
/**
* Called when the background color of current note has just changed
diff --git a/src/app/src/main/java/net/micode/notes/tool/DataUtils.java b/src/app/src/main/java/net/micode/notes/tool/DataUtils.java
index e175100..2a14982 100644
--- a/src/app/src/main/java/net/micode/notes/tool/DataUtils.java
+++ b/src/app/src/main/java/net/micode/notes/tool/DataUtils.java
@@ -72,7 +72,7 @@ public class DataUtils {
return false;
}
- public static void moveNoteToFolder(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
+ 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);
diff --git a/src/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/src/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java
index 96a9ff8..1db4ec3 100644
--- a/src/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java
+++ b/src/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java
@@ -22,19 +22,30 @@ import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.SearchManager;
import android.appwidget.AppWidgetManager;
+import android.content.ContentResolver;
import android.content.ContentUris;
+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.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.Paint;
+import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.style.BackgroundColorSpan;
+import android.text.style.ImageSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -47,6 +58,7 @@ import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -65,6 +77,7 @@ import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
+import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -149,6 +162,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private String mUserQuery;
private Pattern mPattern;
+
+ private final int PHOTO_REQUEST=1;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -159,8 +175,28 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return;
}
initResources();
+
+ final ImageButton add_img_btn = (ImageButton) findViewById(R.id.add_img_btn);
+ //为点击图片按钮设置监听器
+ add_img_btn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Log.d(TAG, "onClick: click add image button");
+ //ACTION_GET_CONTENT: 允许用户选择特殊种类的数据,并返回(特殊种类的数据:照一张相片或录一段音)
+ Intent loadImage = new Intent(Intent.ACTION_GET_CONTENT);
+ //Category属性用于指定当前动作(Action)被执行的环境.
+ //CATEGORY_OPENABLE; 用来指示一个ACTION_GET_CONTENT的intent
+ loadImage.addCategory(Intent.CATEGORY_OPENABLE);
+ loadImage.setType("image/*");
+ startActivityForResult(loadImage, PHOTO_REQUEST);
+ }
+ });
+
}
+
+
+
/**
* 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
@@ -293,6 +329,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* is not ready
*/
showAlertHeader();
+ //
+ convertToImage();
+ //
}
private void showAlertHeader() {
@@ -311,7 +350,47 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE);
};
}
-
+ //
+ private void convertToImage() {
+ NoteEditText noteEditText = (NoteEditText) findViewById(R.id.note_edit_view); //获取当前的edit
+ Editable editable = noteEditText.getText();//1.获取text
+ String noteText = editable.toString(); //2.将note内容转换为字符串
+ int length = editable.length(); //内容的长度
+ //3.截取img片段 [local]+uri+[local],提取uri
+ for (int i = 0; i < length; i++) {
+ for (int j = i; j < length; j++) {
+ String img_fragment = noteText.substring(i, j + 1); //img_fragment:关于图片路径的片段
+ if (img_fragment.length() > 15 && img_fragment.endsWith("[/local]") && img_fragment.startsWith("[local]")) {
+ int limit = 7; //[local]为7个字符
+ //[local][/local]共15个字符,剩下的为真正的path长度
+ int len = img_fragment.length() - 15;
+ //从[local]之后的len个字符就是path
+ String path = img_fragment.substring(limit, limit + len);//获取到了图片路径
+ Bitmap bitmap = null;
+ Log.d(TAG, "图片的路径是:" + path);
+ try {
+ bitmap = BitmapFactory.decodeFile(path);//将图片路径解码为图片格式
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (bitmap != null) { //若图片存在
+ Log.d(TAG, "图片不为null");
+ ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
+ //4.创建一个SpannableString对象,以便插入用ImageSpan对象封装的图像
+ String ss = "[local]" + path + "[/local]";
+ SpannableString spannableString = new SpannableString(ss);
+ //5.将指定的标记对象附加到文本的开始...结束范围
+ spannableString.setSpan(imageSpan, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ Log.d(TAG, "Create spannable string success!");
+ Editable edit_text = noteEditText.getEditableText();
+ edit_text.delete(i, i + len + 15); //6.删掉图片路径的文字
+ edit_text.insert(i, spannableString); //7.在路径的起始位置插入图片
+ }
+ }
+ }
+ }
+ }
+ //
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
@@ -358,8 +437,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|| ev.getX() > (x + view.getWidth())
|| ev.getY() < y
|| ev.getY() > (y + view.getHeight())) {
- return false;
- }
+ return false;
+ }
return true;
}
@@ -418,7 +497,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {
- mWorkingNote.getWidgetId()
+ mWorkingNote.getWidgetId()
});
sendBroadcast(intent);
@@ -779,6 +858,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));
mEditTextList.setVisibility(View.GONE);
mNoteEditor.setVisibility(View.VISIBLE);
+ //
+ convertToImage();
+ //
}
}
@@ -870,4 +952,144 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show();
}
+ //获取文件的real path
+ public String getPath(final Context context, final Uri uri) {
+
+ final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+
+ // DocumentProvider
+ if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+ // ExternalStorageProvider
+// if (isExternalStorageDocument(uri)) {
+// final String docId = DocumentsContract.getDocumentId(uri);
+// final String[] split = docId.split(":");
+// final String type = split[0];
+//
+// if ("primary".equalsIgnoreCase(type)) {
+// return Environment.getExternalStorageDirectory() + "/" + split[1];
+// }
+// }
+// // DownloadsProvider
+// else if (isDownloadsDocument(uri)) {
+// final String id = DocumentsContract.getDocumentId(uri);
+// final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
+// return getDataColumn(context, contentUri, null, null);
+// }
+ // MediaProvider
+// else
+ if (isMediaDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ Uri contentUri = null;
+ if ("image".equals(type)) {
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ }
+
+ final String selection = "_id=?";
+ final String[] selectionArgs = new String[]{split[1]};
+
+ return getDataColumn(context, contentUri, selection, selectionArgs);
+ }
+ }
+ // Media
+ else if ("content".equalsIgnoreCase(uri.getScheme())) {
+ return getDataColumn(context, uri, null, null);
+ }
+ // File
+ else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ }
+ return null;
+ }
+
+
+ //获取数据列_获取此 Uri 的数据列的值。这对MediaStore Uris 和其他基于文件的 ContentProvider。
+ public String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
+
+ Cursor cursor = null;
+ final String column = "_data";
+ final String[] projection = {column};
+
+ try {
+ cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ final int column_index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(column_index);
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ return null;
+ }
+
+
+ //是否为外部存储文件
+// public boolean isExternalStorageDocument(Uri uri) {
+// return "com.android.externalstorage.documents".equals(uri.getAuthority());
+// }
+//
+// //是否为下载文件
+// public boolean isDownloadsDocument(Uri uri) {
+// return "com.android.providers.downloads.documents".equals(uri.getAuthority());
+// }
+
+ //是否为媒体文件
+ public boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+
+ protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ super.onActivityResult(requestCode, resultCode, intent);
+ ContentResolver resolver = getContentResolver();
+ switch (requestCode) {
+ case PHOTO_REQUEST:
+ Uri originalUri = intent.getData(); //1.获得图片的真实路径
+ Bitmap bitmap = null;
+ try {
+ bitmap = BitmapFactory.decodeStream(resolver.openInputStream(originalUri));//2.解码图片
+ } catch (FileNotFoundException e) {
+ Log.d(TAG, "onActivityResult: get file_exception");
+ e.printStackTrace();
+ }
+
+ if (bitmap != null) {
+ //3.根据Bitmap对象创建ImageSpan对象
+ Log.d(TAG, "onActivityResult: bitmap is not null");
+ ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
+ String path = getPath(this, originalUri);
+ //4.使用[local][/local]将path括起来,用于之后方便识别图片路径在note中的位置
+ String img_fragment = "[local]" + path + "[/local]";
+ //创建一个SpannableString对象,以便插入用ImageSpan对象封装的图像
+ SpannableString spannableString = new SpannableString(img_fragment);
+ spannableString.setSpan(imageSpan, 0, img_fragment.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ //5.将选择的图片追加到EditText中光标所在位置
+ NoteEditText e = (NoteEditText) findViewById(R.id.note_edit_view);
+ int index = e.getSelectionStart(); //获取光标所在位置
+ Log.d(TAG, "Index是: " + index);
+ Editable edit_text = e.getEditableText();
+ edit_text.insert(index, spannableString); //将图片插入到光标所在位置
+
+ mWorkingNote.mContent = e.getText().toString();
+ //6.把改动提交到数据库中,两个数据库表都要改的
+ ContentResolver contentResolver = getContentResolver();
+ ContentValues contentValues = new ContentValues();
+ final long id = mWorkingNote.getNoteId();
+ contentValues.put("snippet", mWorkingNote.mContent);
+ contentResolver.update(Uri.parse("content://micode_notes/note"), contentValues, "_id=?", new String[]{"" + id});
+ ContentValues contentValues1 = new ContentValues();
+ contentValues1.put("content", mWorkingNote.mContent);
+ contentResolver.update(Uri.parse("content://micode_notes/data"), contentValues1, "mime_type=? and note_id=?", new String[]{"vnd.android.cursor.item/text_note", "" + id});
+
+ } else {
+ Toast.makeText(NoteEditActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ //
}
diff --git a/src/app/src/main/java/net/micode/notes/ui/NoteEditText.java b/src/app/src/main/java/net/micode/notes/ui/NoteEditText.java
index 2afe2a8..f9eb76f 100644
--- a/src/app/src/main/java/net/micode/notes/ui/NoteEditText.java
+++ b/src/app/src/main/java/net/micode/notes/ui/NoteEditText.java
@@ -7,7 +7,7 @@
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
+ * 1Unless 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
@@ -82,136 +82,232 @@ public class NoteEditText extends EditText {
mIndex = 0;
}
+ /**
+ * 设置索引值
+ * 该方法用于从外部更新对象的索引状态
+ *
+ * @param index 新的索引值,用于替换当前对象的索引
+ */
public void setIndex(int index) {
mIndex = index;
}
+ /**
+ * 设置文本视图变化监听器
+ * 用于在文本视图的内容发生变化时通知监听器
+ *
+ * @param listener 实现了OnTextViewChangeListener接口的监听器实例
+ */
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
mOnTextViewChangeListener = listener;
}
+ /**
+ * 构造函数,用于在 XML 布局中实例化 NoteEditText 组件。
+ *
+ * @param context 上下文对象,包含应用环境信息
+ * @param attrs 从 XML 布局文件中解析的属性集合
+ */
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.editTextStyle);
}
+ /**
+ * 构造函数,用于在 XML 布局中实例化 NoteEditText 组件,并允许指定默认样式。
+ *
+ * @param context 上下文对象,包含应用环境信息
+ * @param attrs 从 XML 布局文件中解析的属性集合
+ * @param defStyle 默认样式资源 ID,用于自定义组件外观
+ */
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
+ /**
+ * 处理触摸事件以实现特定的交互逻辑
+ * 当用户触摸屏幕时,此方法被调用,用于处理触摸事件
+ * 特别地,当触摸动作为按下时,它会计算触摸位置,并更新文本选择
+ *
+ * @param event 触摸事件,包含触摸动作、位置等信息
+ * @return 返回true表示事件已被处理,false表示未处理
+ */
@Override
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 layout = getLayout();
+ // 根据垂直位置计算触摸点所在的文本行
int line = layout.getLineForVertical(y);
+ // 根据水平位置计算触摸点所在的文本偏移量
int off = layout.getOffsetForHorizontal(line, x);
+ // 更新文本选择
Selection.setSelection(getText(), off);
break;
}
+ // 调用父类的onTouchEvent方法以处理其他触摸事件
return super.onTouchEvent(event);
}
+ /**
+ * 重写onKeyDown方法以处理特定的键盘事件
+ *
+ * @param keyCode 键盘事件的键码
+ * @param event 键盘事件的对象
+ * @return 如果事件被处理返回true,否则返回false
+ */
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
+ // 根据不同的键码做相应的处理
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
+ // 当检测到ENTER键时,如果mOnTextViewChangeListener不为空,则不处理事件,交由其他处理程序处理
if (mOnTextViewChangeListener != null) {
return false;
}
break;
case KeyEvent.KEYCODE_DEL:
+ // 当检测到DEL键时,记录删除操作前的光标位置
mSelectionStartBeforeDelete = getSelectionStart();
break;
default:
+ // 对于其他键码,不做特殊处理
break;
}
+ // 对于未特殊处理的键码,调用父类的方法处理
return super.onKeyDown(keyCode, event);
}
+ /**
+ * 处理键盘按键释放事件
+ *
+ * @param keyCode 按键代码,标识哪个键被释放
+ * @param event 键盘事件对象,包含更多关于该事件的详细信息
+ * @return 如果事件被处理,返回true;否则返回false
+ */
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
+ // 根据按键代码处理不同的按键事件
switch(keyCode) {
case KeyEvent.KEYCODE_DEL:
+ // 处理删除键释放事件
if (mOnTextViewChangeListener != null) {
+ // 如果删除前光标位置为0且不是第一个文本框,则通知监听器进行删除操作
if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
return true;
}
} else {
+ // 如果监听器未设置,则记录日志
Log.d(TAG, "OnTextViewChangeListener was not seted");
}
break;
case KeyEvent.KEYCODE_ENTER:
+ // 处理回车键释放事件
if (mOnTextViewChangeListener != null) {
+ // 获取当前光标位置并分离出光标后的文本,然后设置文本框内容为光标前的文本
int selectionStart = getSelectionStart();
String text = getText().subSequence(selectionStart, length()).toString();
setText(getText().subSequence(0, selectionStart));
+ // 通知监听器进行回车操作处理
mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text);
} else {
+ // 如果监听器未设置,则记录日志
Log.d(TAG, "OnTextViewChangeListener was not seted");
}
break;
default:
+ // 对于其他按键事件,不做任何处理
break;
}
+ // 如果上述条件都不满足,则调用父类的onKeyUp方法处理事件
return super.onKeyUp(keyCode, event);
}
+ /**
+ * 当视图焦点改变时调用的方法
+ *
+ * @param focused 表示视图是否获得了焦点
+ * @param direction 表示焦点移动的方向
+ * @param previouslyFocusedRect 表示之前获得焦点的视图的矩形区域
+ */
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+ // 如果有注册的文本视图变更监听器
if (mOnTextViewChangeListener != null) {
+ // 如果视图失去焦点且文本为空,则调用监听器的onTextChange方法,参数为false
if (!focused && TextUtils.isEmpty(getText())) {
mOnTextViewChangeListener.onTextChange(mIndex, false);
} else {
+ // 否则,调用监听器的onTextChange方法,参数为true
mOnTextViewChangeListener.onTextChange(mIndex, true);
}
}
+ // 调用父类的onFocusChanged方法,确保焦点改变的默认行为得以执行
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
+ /**
+ * 重写创建上下文菜单的方法
+ * 此方法用于在长按文本时创建上下文菜单,根据选中的文本部分是否包含URL来决定菜单项
+ * 如果选中的文本中仅包含一个URL,则在菜单中添加一个相应的选项,点击可跳转到该链接
+ */
@Override
protected void onCreateContextMenu(ContextMenu menu) {
+ // 检查当前文本是否为Spanned类型,以支持富文本
if (getText() instanceof Spanned) {
+ // 获取选中文本的起始和结束位置
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
+ // 确定选中文本的最小和最大位置,以处理选中区域
int min = Math.min(selStart, selEnd);
int max = Math.max(selStart, selEnd);
+ // 获取选中文本范围内的所有URLSpan对象
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
+ // 如果选中的文本中仅有一个URL,则进一步处理
if (urls.length == 1) {
int defaultResId = 0;
+ // 遍历预定义的schema-action资源映射,查找匹配的URL schema
for(String schema: sSchemaActionResMap.keySet()) {
+ // 如果URL包含当前schema,则获取对应的资源ID,并停止遍历
if(urls[0].getURL().indexOf(schema) >= 0) {
defaultResId = sSchemaActionResMap.get(schema);
break;
}
}
+ // 如果没有找到匹配的schema,则使用默认的“其他”资源
if (defaultResId == 0) {
defaultResId = R.string.note_link_other;
}
+ // 在上下文菜单中添加一个菜单项,并设置点击事件处理
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
- // goto a new intent
+ // 点击菜单项时,触发URL的onClick事件,通常会启动一个新的Activity
urls[0].onClick(NoteEditText.this);
return true;
}
});
}
}
+ // 调用父类方法,确保菜单被正确创建
super.onCreateContextMenu(menu);
}
}
diff --git a/src/app/src/main/java/net/micode/notes/ui/NoteItemData.java b/src/app/src/main/java/net/micode/notes/ui/NoteItemData.java
index 0f5a878..33c3ae6 100644
--- a/src/app/src/main/java/net/micode/notes/ui/NoteItemData.java
+++ b/src/app/src/main/java/net/micode/notes/ui/NoteItemData.java
@@ -76,39 +76,76 @@ public class NoteItemData {
private boolean mIsOneNoteFollowingFolder;
private boolean mIsMultiNotesFollowingFolder;
- public NoteItemData(Context context, Cursor cursor) {
- 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)) {
- mName = Contact.getContact(context, mPhoneNumber);
- if (mName == null) {
- mName = mPhoneNumber;
- }
+ /**
+ * NoteItemData 的构造函数,用于从数据库 Cursor 中初始化 NoteItemData 对象。
+ *
+ * @param context 上下文对象,用于获取内容解析器和联系人信息。
+ * @param cursor 数据库查询结果的 Cursor,包含笔记的相关信息。
+ */
+public NoteItemData(Context context, Cursor cursor) {
+ // 从 Cursor 中提取笔记的 ID
+ mId = cursor.getLong(ID_COLUMN);
+
+ // 从 Cursor 中提取笔记的提醒日期
+ mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN);
+
+ // 从 Cursor 中提取笔记的背景颜色 ID
+ mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN);
+
+ // 从 Cursor 中提取笔记的创建日期
+ mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN);
+
+ // 从 Cursor 中提取笔记是否包含附件的信息,并转换为布尔值
+ mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0) ? true : false;
+
+ // 从 Cursor 中提取笔记的最后修改日期
+ mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN);
+
+ // 从 Cursor 中提取笔记下的子笔记数量
+ mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN);
+
+ // 从 Cursor 中提取笔记的父级 ID(即所属文件夹的 ID)
+ mParentId = cursor.getLong(PARENT_ID_COLUMN);
+
+ // 从 Cursor 中提取笔记的摘要信息,并移除标记符号(TAG_CHECKED 和 TAG_UNCHECKED)
+ mSnippet = cursor.getString(SNIPPET_COLUMN);
+ mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace(NoteEditActivity.TAG_UNCHECKED, "");
+
+ // 从 Cursor 中提取笔记的类型(如普通笔记、文件夹等)
+ mType = cursor.getInt(TYPE_COLUMN);
+
+ // 从 Cursor 中提取笔记的小部件 ID
+ mWidgetId = cursor.getInt(WIDGET_ID_COLUMN);
+
+ // 从 Cursor 中提取笔记的小部件类型
+ mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN);
+
+ // 初始化电话号码为空字符串
+ mPhoneNumber = "";
+
+ // 如果笔记属于通话记录文件夹,则获取其对应的电话号码
+ if (mParentId == Notes.ID_CALL_RECORD_FOLDER) {
+ mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId);
+ if (!TextUtils.isEmpty(mPhoneNumber)) {
+ // 根据电话号码获取联系人姓名
+ mName = Contact.getContact(context, mPhoneNumber);
+ if (mName == null) {
+ // 如果未找到联系人姓名,则使用电话号码作为名称
+ mName = mPhoneNumber;
}
}
+ }
- if (mName == null) {
- mName = "";
- }
- checkPostion(cursor);
+ // 如果 mName 仍为 null,则将其设置为空字符串
+ if (mName == null) {
+ mName = "";
}
+ // 检查笔记在 Cursor 中的位置信息(如是否为第一个、最后一个等)
+ checkPostion(cursor);
+}
+
+
private void checkPostion(Cursor cursor) {
mIsLastItem = cursor.isLast() ? true : false;
mIsFirstItem = cursor.isFirst() ? true : false;
@@ -158,61 +195,131 @@ public class NoteItemData {
return mIsOnlyOneItem;
}
- public long getId() {
- return mId;
- }
+ /**
+ * 获取笔记的唯一标识符。
+ *
+ * @return 笔记的 ID。
+ */
+public long getId() {
+ return mId;
+}
- public long getAlertDate() {
- return mAlertDate;
- }
+/**
+ * 获取笔记的提醒日期。
+ *
+ * @return 提醒日期,如果未设置则返回 0。
+ */
+public long getAlertDate() {
+ return mAlertDate;
+}
- public long getCreatedDate() {
- return mCreatedDate;
- }
+/**
+ * 获取笔记的创建日期。
+ *
+ * @return 创建日期的时间戳。
+ */
+public long getCreatedDate() {
+ return mCreatedDate;
+}
- public boolean hasAttachment() {
- return mHasAttachment;
- }
+/**
+ * 检查笔记是否包含附件。
+ *
+ * @return 如果包含附件则返回 true,否则返回 false。
+ */
+public boolean hasAttachment() {
+ return mHasAttachment;
+}
- public long getModifiedDate() {
- return mModifiedDate;
- }
+/**
+ * 获取笔记的最后修改日期。
+ *
+ * @return 最后修改日期的时间戳。
+ */
+public long getModifiedDate() {
+ return mModifiedDate;
+}
- public int getBgColorId() {
- return mBgColorId;
- }
+/**
+ * 获取笔记的背景颜色 ID。
+ *
+ * @return 背景颜色 ID。
+ */
+public int getBgColorId() {
+ return mBgColorId;
+}
- public long getParentId() {
- return mParentId;
- }
+/**
+ * 获取笔记的父级 ID,即所属文件夹的 ID。
+ *
+ * @return 父级 ID。
+ */
+public long getParentId() {
+ return mParentId;
+}
- public int getNotesCount() {
- return mNotesCount;
- }
+/**
+ * 获取笔记下的子笔记数量。
+ *
+ * @return 子笔记数量。
+ */
+public int getNotesCount() {
+ return mNotesCount;
+}
- public long getFolderId () {
- return mParentId;
- }
+/**
+ * 获取笔记的文件夹 ID,等同于 getParentId() 方法。
+ *
+ * @return 文件夹 ID。
+ */
+public long getFolderId() {
+ return mParentId;
+}
- public int getType() {
- return mType;
- }
+/**
+ * 获取笔记的类型。
+ *
+ * @return 笔记类型,如普通笔记、文件夹等。
+ */
+public int getType() {
+ return mType;
+}
- public int getWidgetType() {
- return mWidgetType;
- }
+/**
+ * 获取笔记的小部件类型。
+ *
+ * @return 小部件类型。
+ */
+public int getWidgetType() {
+ return mWidgetType;
+}
- public int getWidgetId() {
- return mWidgetId;
- }
+/**
+ * 获取笔记的小部件 ID。
+ *
+ * @return 小部件 ID。
+ */
+public int getWidgetId() {
+ return mWidgetId;
+}
- public String getSnippet() {
- return mSnippet;
- }
+/**
+ * 获取笔记的摘要信息。
+ *
+ * @return 笔记摘要。
+ */
+public String getSnippet() {
+ return mSnippet;
+}
- public boolean hasAlert() {
- return (mAlertDate > 0);
- }
+/**
+ * 检查笔记是否设置了提醒。
+ *
+ * @return 如果设置了提醒则返回 true,否则返回 false。
+ */
+public boolean hasAlert() {
+ return (mAlertDate > 0);
+}
public boolean isCallRecord() {
return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber));
diff --git a/src/app/src/main/java/net/micode/notes/ui/NotesListActivity.java b/src/app/src/main/java/net/micode/notes/ui/NotesListActivity.java
index 8493bc1..b08d2d4 100644
--- a/src/app/src/main/java/net/micode/notes/ui/NotesListActivity.java
+++ b/src/app/src/main/java/net/micode/notes/ui/NotesListActivity.java
@@ -79,7 +79,7 @@ import java.io.InputStreamReader;
import java.util.HashSet;
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener {
- private int mode =-1;
+ private int mode=-1;
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
private static final int FOLDER_LIST_QUERY_TOKEN = 1;
@@ -141,7 +141,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
super.onCreate(savedInstanceState);
setContentView(R.layout.note_list);
initResources();
-
getWindow().setBackgroundDrawableResource(R.drawable.fly);
getWindow().setBackgroundDrawableResource(R.drawable.pink);
getWindow().setBackgroundDrawableResource(R.drawable.falus);
@@ -477,16 +476,15 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
new AsyncTask>() {
protected HashSet doInBackground(Void... unused) {
HashSet widgets = mNotesListAdapter.getSelectedWidget();
- if (!isSyncMode()) {
- // if not synced, delete notes directly
+ if (mCurrentFolderId == Notes.ID_TRASH_FOLER){ // 只需要修改这里
+ // if in trash, really delete notes
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
+ // move notes to trash
if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter
.getSelectedItemIds(), Notes.ID_TRASH_FOLER)) {
Log.e(TAG, "Move notes to trash folder error, should not happens");
@@ -785,7 +783,6 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
menu.findItem(R.id.menu_falus).setVisible(false);
else if(mode==1)
menu.findItem(R.id.menu_pink).setVisible(false);
-
return true;
}
@@ -807,6 +804,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
getWindow().setBackgroundDrawableResource(R.drawable.fly);
break;
}
+ case R.id.menu_trash: {
+ openTrashFolder();
+ break;
+ }
case R.id.menu_new_folder: {
showCreateOrModifyFolderDialog(true);
break;
@@ -843,7 +844,18 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
return true;
}
-
+ private void openTrashFolder() {
+ mCurrentFolderId = Notes.ID_TRASH_FOLER;
+ startAsyncNotesListQuery();
+ // 正常打开文件夹
+ mState = ListEditState.SUB_FOLDER;
+ // 将顶部栏设置为 data.getSnippet 文件夹名称
+ mTitleBar.setText(NotesListActivity.this
+ .getString(R.string.menu_trash));
+ // 不显示底部的“写便签”
+ mAddNewNote.setVisibility(View.GONE);
+ mTitleBar.setVisibility(View.VISIBLE);
+ }
@Override
public boolean onSearchRequested() {
startSearch(null, false, null /* appData */, false);
diff --git a/src/app/src/main/res/drawable/ic_launcher_foreground.xml b/src/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
similarity index 100%
rename from src/app/src/main/res/drawable/ic_launcher_foreground.xml
rename to src/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
diff --git a/src/app/src/main/res/drawable-hdpi/fly.png b/src/app/src/main/res/drawable/falus.png
similarity index 100%
rename from src/app/src/main/res/drawable-hdpi/fly.png
rename to src/app/src/main/res/drawable/falus.png
diff --git a/src/app/src/main/res/drawable-hdpi/pink.png b/src/app/src/main/res/drawable/fly.png
similarity index 100%
rename from src/app/src/main/res/drawable-hdpi/pink.png
rename to src/app/src/main/res/drawable/fly.png
diff --git a/src/app/src/main/res/drawable-hdpi/falus.png b/src/app/src/main/res/drawable/pink.png
similarity index 100%
rename from src/app/src/main/res/drawable-hdpi/falus.png
rename to src/app/src/main/res/drawable/pink.png
diff --git a/src/app/src/main/res/layout/activity_main.xml b/src/app/src/main/res/layout/activity_main.xml
index 86a5d97..17eab17 100644
--- a/src/app/src/main/res/layout/activity_main.xml
+++ b/src/app/src/main/res/layout/activity_main.xml
@@ -2,7 +2,6 @@
diff --git a/src/app/src/main/res/layout/note_edit.xml b/src/app/src/main/res/layout/note_edit.xml
index 10b2aa7..1a7d78c 100644
--- a/src/app/src/main/res/layout/note_edit.xml
+++ b/src/app/src/main/res/layout/note_edit.xml
@@ -115,7 +115,14 @@
android:background="@drawable/bg_color_btn_mask" />
-
+
-
+
+
diff --git a/src/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/src/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/src/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/src/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 74%
rename from src/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
rename to src/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index 6f3b755..eca70cf 100644
--- a/src/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
+++ b/src/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -2,5 +2,4 @@
-
\ No newline at end of file
diff --git a/src/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/src/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml
similarity index 100%
rename from src/app/src/main/res/mipmap-anydpi/ic_launcher.xml
rename to src/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml
diff --git a/src/app/src/main/res/values-night/themes.xml b/src/app/src/main/res/values-night/themes.xml
index d2c68d1..16fd7ac 100644
--- a/src/app/src/main/res/values-night/themes.xml
+++ b/src/app/src/main/res/values-night/themes.xml
@@ -1,7 +1,16 @@
-
\ No newline at end of file
diff --git a/src/app/src/main/res/values/colors.xml b/src/app/src/main/res/values/colors.xml
index 123ffbf..c640cde 100644
--- a/src/app/src/main/res/values/colors.xml
+++ b/src/app/src/main/res/values/colors.xml
@@ -17,4 +17,11 @@
#335b5b5b
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FFFFFFFF
+ #FF03DAC5
+ #FF018786
+ #FF000000
diff --git a/src/app/src/main/res/values/strings.xml b/src/app/src/main/res/values/strings.xml
index 6152ac8..01976a8 100644
--- a/src/app/src/main/res/values/strings.xml
+++ b/src/app/src/main/res/values/strings.xml
@@ -130,6 +130,7 @@
Notes
set
cancel
+ Trash Folder
- %1$s result for \"%2$s\"
diff --git a/src/app/src/main/res/values/styles.xml b/src/app/src/main/res/values/styles.xml
index 2e81057..c1eddb2 100644
--- a/src/app/src/main/res/values/styles.xml
+++ b/src/app/src/main/res/values/styles.xml
@@ -49,7 +49,7 @@
@@ -63,7 +63,6 @@
\ No newline at end of file
diff --git a/src/app/src/main/res/values/themes.xml b/src/app/src/main/res/values/themes.xml
index 7c616ff..3cd0742 100644
--- a/src/app/src/main/res/values/themes.xml
+++ b/src/app/src/main/res/values/themes.xml
@@ -1,9 +1,16 @@
-
-
-
\ No newline at end of file
diff --git a/src/build.gradle b/src/build.gradle
new file mode 100644
index 0000000..accb42d
--- /dev/null
+++ b/src/build.gradle
@@ -0,0 +1,15 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:7.4.2' // 使用较新的稳定版本
+ }
+}
+
+plugins {
+ id 'com.android.application' version '7.4.1' apply false
+ id 'com.android.library' version '7.4.1' apply false
+}
diff --git a/src/build.gradle.kts b/src/build.gradle.kts
deleted file mode 100644
index 3756278..0000000
--- a/src/build.gradle.kts
+++ /dev/null
@@ -1,4 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-plugins {
- alias(libs.plugins.android.application) apply false
-}
\ No newline at end of file
diff --git a/src/desktop.ini b/src/desktop.ini
new file mode 100644
index 0000000..935532c
--- /dev/null
+++ b/src/desktop.ini
@@ -0,0 +1,6 @@
+[.ShellClassInfo]
+IconResource=D:\edge\Folder11-Ico-main\Folder11-Ico-main\ico\xiaomi.ico,0
+[ViewState]
+Mode=
+Vid=
+FolderType=Generic
diff --git a/src/gradle.properties b/src/gradle.properties
index 00d252e..3e927b1 100644
--- a/src/gradle.properties
+++ b/src/gradle.properties
@@ -8,8 +8,8 @@
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. For more details, visit
-# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
@@ -18,5 +18,4 @@ android.useAndroidX=true
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
-android.nonTransitiveRClass=true
-android.nonFinalResIds=false
\ No newline at end of file
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/src/gradle/libs.versions.toml b/src/gradle/libs.versions.toml
deleted file mode 100644
index ebd5258..0000000
--- a/src/gradle/libs.versions.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[versions]
-agp = "8.8.0"
-junit = "4.13.2"
-junitVersion = "1.1.5"
-espressoCore = "3.5.1"
-appcompat = "1.6.1"
-material = "1.10.0"
-activity = "1.8.0"
-constraintlayout = "2.1.4"
-firebaseInappmessaging = "21.0.2"
-
-[libraries]
-junit = { group = "junit", name = "junit", version.ref = "junit" }
-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
-material = { group = "com.google.android.material", name = "material", version.ref = "material" }
-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
-firebase-inappmessaging = { group = "com.google.firebase", name = "firebase-inappmessaging", version.ref = "firebaseInappmessaging" }
-
-[plugins]
-android-application = { id = "com.android.application", version.ref = "agp" }
-
diff --git a/src/gradle/wrapper/gradle-wrapper.properties b/src/gradle/wrapper/gradle-wrapper.properties
index 1a44cad..0f4d300 100644
--- a/src/gradle/wrapper/gradle-wrapper.properties
+++ b/src/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Mar 14 10:46:03 GMT+08:00 2025
+#Tue Feb 25 19:27:53 GMT+08:00 2025
distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionPath=wrapper/dists
-distributionUrl=https\://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.10.2-bin.zip
-zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/src/httpcomponents-client-4.5.14-bin/LICENSE.txt b/src/httpcomponents-client-4.5.14-bin/LICENSE.txt
deleted file mode 100644
index 32f01ed..0000000
--- a/src/httpcomponents-client-4.5.14-bin/LICENSE.txt
+++ /dev/null
@@ -1,558 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
-=========================================================================
-
-This project includes Public Suffix List copied from
-
-licensed under the terms of the Mozilla Public License, v. 2.0
-
-Full license text:
-
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
- means each individual or legal entity that creates, contributes to
- the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
- means the combination of the Contributions of others (if any) used
- by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
- means Source Code Form to which the initial Contributor has attached
- the notice in Exhibit A, the Executable Form of such Source Code
- Form, and Modifications of such Source Code Form, in each case
- including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- (a) that the initial Contributor has attached the notice described
- in Exhibit B to the Covered Software; or
-
- (b) that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the
- terms of a Secondary License.
-
-1.6. "Executable Form"
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
- means a work that combines Covered Software with other material, in
- a separate file or files, that is not Covered Software.
-
-1.8. "License"
- means this document.
-
-1.9. "Licensable"
- means having the right to grant, to the maximum extent possible,
- whether at the time of the initial grant or subsequently, any and
- all of the rights conveyed by this License.
-
-1.10. "Modifications"
- means any of the following:
-
- (a) any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered
- Software; or
-
- (b) any new file in Source Code Form that contains any Covered
- Software.
-
-1.11. "Patent Claims" of a Contributor
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the
- License, by the making, using, selling, offering for sale, having
- made, import, or transfer of either its Contributions or its
- Contributor Version.
-
-1.12. "Secondary License"
- means either the GNU General Public License, Version 2.0, the GNU
- Lesser General Public License, Version 2.1, the GNU Affero General
- Public License, Version 3.0, or any later versions of those
- licenses.
-
-1.13. "Source Code Form"
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that
- controls, is controlled by, or is under common control with You. For
- purposes of this definition, "control" means (a) the power, direct
- or indirect, to cause the direction or management of such entity,
- whether by contract or otherwise, or (b) ownership of more than
- fifty percent (50%) of the outstanding shares or beneficial
- ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
- for sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
- or
-
-(b) for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
- Form, as described in Section 3.1, and You must inform recipients of
- the Executable Form how they can obtain a copy of such Source Code
- Form by reasonable means in a timely manner, at a charge no more
- than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter
- the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-* *
-* 6. Disclaimer of Warranty *
-* ------------------------- *
-* *
-* Covered Software is provided under this License on an "as is" *
-* basis, without warranty of any kind, either expressed, implied, or *
-* statutory, including, without limitation, warranties that the *
-* Covered Software is free of defects, merchantable, fit for a *
-* particular purpose or non-infringing. The entire risk as to the *
-* quality and performance of the Covered Software is with You. *
-* Should any Covered Software prove defective in any respect, You *
-* (not any Contributor) assume the cost of any necessary servicing, *
-* repair, or correction. This disclaimer of warranty constitutes an *
-* essential part of this License. No use of any Covered Software is *
-* authorized under this License except under this disclaimer. *
-* *
-************************************************************************
-
-************************************************************************
-* *
-* 7. Limitation of Liability *
-* -------------------------- *
-* *
-* Under no circumstances and under no legal theory, whether tort *
-* (including negligence), contract, or otherwise, shall any *
-* Contributor, or anyone who distributes Covered Software as *
-* permitted above, be liable to You for any direct, indirect, *
-* special, incidental, or consequential damages of any character *
-* including, without limitation, damages for lost profits, loss of *
-* goodwill, work stoppage, computer failure or malfunction, or any *
-* and all other commercial damages or losses, even if such party *
-* shall have been informed of the possibility of such damages. This *
-* limitation of liability shall not apply to liability for death or *
-* personal injury resulting from such party's negligence to the *
-* extent applicable law prohibits such limitation. Some *
-* jurisdictions do not allow the exclusion or limitation of *
-* incidental or consequential damages, so this exclusion and *
-* limitation may not apply to You. *
-* *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
- This Source Code Form is "Incompatible With Secondary Licenses", as
- defined by the Mozilla Public License, v. 2.0.
diff --git a/src/httpcomponents-client-4.5.14-bin/NOTICE.txt b/src/httpcomponents-client-4.5.14-bin/NOTICE.txt
deleted file mode 100644
index 10a2916..0000000
--- a/src/httpcomponents-client-4.5.14-bin/NOTICE.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Apache HttpComponents Client
-Copyright 1999-2021 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-
diff --git a/src/httpcomponents-client-4.5.14-bin/RELEASE_NOTES.txt b/src/httpcomponents-client-4.5.14-bin/RELEASE_NOTES.txt
deleted file mode 100644
index c1f0a0f..0000000
--- a/src/httpcomponents-client-4.5.14-bin/RELEASE_NOTES.txt
+++ /dev/null
@@ -1,2613 +0,0 @@
-Release 4.5.14
--------------------
-
-This is a maintenance release that fixes several minor bugs reported discovered since
-the 4.5.13 release.
-
-
-Changelog:
--------------------
-
-* HTTPCLIENT-2206: Corrected resource de-allocation by fluent response objects.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-2174: URIBuilder to return a new empty list instead of unmodifiable
- Collections#emptyList.
- Contributed by Oleg Kalnichevski
-
-* Don't retry requests in case of NoRouteToHostException.
- Contributed by Jaikiran Pai
-
-* HTTPCLIENT-2144: RequestBuilder fails to correctly copy charset of requests with
- form url-encoded body.
- Contributed by Oleg Kalnichevski
-
-* PR #269: 4.5.x use array fill and more.
- - Use Arrays.fill().
- - Remove redundant modifiers.
- - Use Collections.addAll() and Collection.addAll() APIs instead of loops.
- - Remove redundant returns.
- - No need to explicitly declare an array when calling a vararg method.
- - Remote extra semicolons (;).
- - Use a 'L' instead of 'l' to make long literals more readable.
- Contributed by Gary Gregory
-
-* PublicSuffixListParser.parseByType(Reader) allocates but does not use a 256 char
- StringBuilder.
- Contributed by Gary Gregory
-
-
-
-Release 4.5.13
--------------------
-
-This is a maintenance release that fixes incorrect handling of malformed authority component
-in request URIs.
-
-
-Changelog:
--------------------
-
-* Incorrect handling of malformed authority component by URIUtils#extractHost.
- Contributed by Oleg Kalnichevski
-
-* Avoid updating Content-Length header in a 304 response.
- Contributed by Dirk Henselin
-
-* Bug fix: BasicExpiresHandler is annotated as immutable but is not (#239)
- Contributed by Gary Gregory
-
-* HTTPCLIENT-2076: Fixed NPE in LaxExpiresHandler (#222).
- Contributed by heejeongkim
-
-
-Release 4.5.12
--------------------
-
-This is a maintenance release that fixes a regression introduced by the previous release
-that caused rejection of certificates with non-standard domains.
-
-Changelog:
--------------------
-
-* HTTPCLIENT-2053: Add SC_PERMANENT_REDIRECT (308) to DefaultRedirectStrategy
- Contributed by Michael Osipov
-
-* HTTPCLIENT-2052: Fixed redirection of entity enclosing requests with non-repeatable entities
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-2047: Fixed regression in DefaultHostnameVerifier causing rejection of certificates
- with non-standard domains.
- Contributed by Oleg Kalnichevski
-
-* Bug fix: Fixed handling of private domains by PublicSuffixMatcher
- Contributed by Oleg Kalnichevski
-
-
-Release 4.5.11
--------------------
-
-This is a maintenance release that fixes a number defects discovered since 4.5.10
-and upgrades HttpCore dependency to version 4.4.13.
-
-
-Changelog:
--------------------
-
-* Improved domain name normalization by DefaultHostnameVerifier.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-2033: Connection managers to immediately shut down all leased connection upon shutdown.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-2020: DefaultBackoffStrategy to support TOO_MANY_REQUESTS (429).
- Contributed by Michael Osipov
-
-* HTTPCLIENT-2030: Fixed PublicSuffixMatcher#getDomainRoot behavior with invalid hostnames.
- Contributed by Niels Basjes
-
-* HTTPCLIENT-2029: URIBuilder to support parsing of non-UTF8 URIs.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-2026: Fixed URIBuilder#isOpaque() logic.
- Contributed by Oleg Kalnichevski
-
-* Updated text in pool stats description
- Contributed by chao chang
-
-* HTTPCLIENT-2023: Allow nested arrays and all primitive types in DefaultHttpCacheEntrySerializer.
- Contributed by Olof Larsson
-
-* Fixed fallback PublicSuffixMatcher instance.
- Contributed by Ryan Schmitt
-
-* Added family property #145.
- Contributed by behrangsa
-
-
-Release 4.5.10
--------------------
-
-This is a maintenance release that fixes a number defects discovered since 4.5.9
-and upgrades HttpCore dependency to version 4.4.12.
-
-
-Changelog:
--------------------
-
-* Refactor DefaultRedirectStrategy for subclassing.
- Contributed by Gary Gregory
-
-* Improved handling of request cancellation.
- Contributed by Oleg Kalnichevski
-
-* Fixed concurrent use of threading unsafe HttpUriRequest messages.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1997: Return the last domain segment instead of normalized domain name
- from PublicSuffixMatcher#getDomainRoot in case there is no match.
- Contributed by jeromedemangel
-
-* Preserve original encoding of the URI path component if the URI is valid.
- Contributed by Oleg Kalnichevski
-
-
-Release 4.5.9
--------------------
-
-This is a maintenance release that fixes a number defects discovered since 4.5.8.
-
-
-Changelog:
--------------------
-
-* HTTPCLIENT-1991: incorrect handling of non-standard DNS entries by PublicSuffixMatcher
- Contributed by Oleg Kalnichevski
-
-* Fix bug in URIBuilder#isPathEmpty method to verify if encodedPath is an empty string
- Contributed by Varun Nandi
-
-* HTTPCLIENT-1984: Add normalize URI to RequestConfig copy constructor
- Contributed by Matt Nelson
-
-* HTTPCLIENT-1976: Unsafe deserialization in DefaultHttpCacheEntrySerializer
- Contributed by Artem Smotrakov
-
-
-
-Release 4.5.8
--------------------
-
-This is a maintenance release that makes request URI normalization configurable on per request basis
-and also ports several improvements in URI handling from HttpCore master.
-
-
-Changelog:
--------------------
-
-* HTTPCLIENT-1969: Filter out weak cipher suites.
- Contributed by Artem Smotrakov
-
-* HTTPCLIENT-1968: Preserve escaped PATHSAFE characters when normalizing URI path segments.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1968: URIBuilder to split path component into path segments when digesting a URI
- (ported from HttpCore master).
- Contributed by Oleg Kalnichevski
-
-* Improved cache key generation (ported from HttpCore master).
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1968: added utility methods to parse and format URI path segments (ported
- from HttpCore master).
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1968: Make normalization of URI paths optional.
- Contributed by Tamas Cservenak
-
-* Some well known proxies respond with Content-Length=0, when returning 304. For robustness, always use the
- cached entity's content length, as modern browsers do.
- Contributed by Author: Jayson Raymond
-
-
-
-Release 4.5.7
--------------------
-
-This is a maintenance release that corrects Automatic-Module-Name definitions added in the previous
-release and fixes a number of minor defects discovered since 4.5.6.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-Changelog:
--------------------
-
-* Upgraded HttpCore to version 4.4.11
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1960: URIBuilder incorrect handling of multiple leading slashes in path component
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1958: PoolingHttpClientConnectionManager to throw ExecutionException in case of a lease operation
- cancellation instead of InterruptedException.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1952: Allow default User Agent to be disabled.
- Contributed by Michael Osipov
-
-* HTTPCLIENT-1956: CONNECT overwrites the main request object in the HTTP context when requests are executed
- via a proxy tunnel.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1940: deprecated SSLSocketFactory made to rethrow SocketTimeoutException as
- ConnectTimeoutException for consistency with non-deprecated code.
- Contributed by Oleg Kalnichevski
-
-* Fixed regression in BasicCookieStore serialization.
- Contributed by Author: Mark Mielke
-
-* HTTPCLIENT-1929: Corrected Automatic-Module-Name entries for HttpClient Fluent, HttpClient Windows
- and HttpClient Cache.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1927: URLEncodedUtils#parse breaks at double quotes when parsing unquoted values.
- Contributed by Oleg Kalnichevski
-
-* HTTPCLIENT-1939: Update Apache Commons Codec from 1.10 to 1.11
- Contributed by Gary Gregory
-
-
-Release 4.5.6
--------------------
-
-This is a maintenance release that adds Automatic-Module-Name to the manifest for compatibility
-with Java 9 Platform Module System and fixes a number of issues discovered since 4.5.5
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1882=: reset authentication state on I/O or runtime error for connection based
- authentication schemes (such as NTLM)
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1924]: HttpClient to shut down the connection manager if a fatal error occurs
- in the course of a request execution.
- Contributed by Oleg Kalnichevski
-
-* Add Automatic-Module-Name in manifest so Java9 modular applications can depend on this library
- Contributed by Varun Nandi
-
-* [HTTPCLIENT-1923]: fixed incorrect connection close on shutdown + fixed corresponding test
- Contributed by Aleksei Arsenev
-
-* [HTTPCLIENT-1906]: certificates containing alternative subject names other than DNS and IP
- (such as RFC822) get rejected as invalid
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1904]: check cookie domain for null
- Contributed by Hans-Peter Keck
-
-* [HTTPCLIENT-1900]: proxy protocol processor does not post-process CONNECT response messages
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1911]: Failing tests on Fedora 28 due to weak encryption algorithms in test
- keystore.
- Contributed by Gary Gregory and Michael Simacek
-
-
-Release 4.5.5
--------------------
-
-HttpClient 4.5.5 (GA) is a maintenance release that fixes a regression introduced
-by the previous release causing a NPE in SystemDefaultCredentialsProvider.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1690] Avoid merging Content-Encoding headers coming with 304 status to cache entry.
- Contributed by Sudheera Palihakkara
-
-* [HTTPCLIENT-1888] Regression in SystemDefaultCredentialsProvider#getCredentials causing NPE.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1886] Update HttpClient 4.5.x from HttpCore 4.4.7 to 4.4.9
- Contributed by Gary Gregory
-
-* [HTTPCLIENT-1889] org.apache.http.client.utils.URLEncodedUtils.parse()
- should return a new ArrayList when there are no query parameters.
- Contributed by Gary Gregory
-
-
-Release 4.5.4
--------------------
-
-HttpClient 4.5.4 (GA) is a maintenance release that fixes a number of defects found since 4.5.3.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1883] SystemDefaultCredentialsProvider to use https.proxy* system properties
- for origins with port 443.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1881] Allow truncated NTLM packets to work with this client.
- Contributed by Karl Wright
-
-* [HTTPCLIENT-1855] Disabled caching of DIGEST auth scheme instances due to unreliability of nonce counter
- when the auth cache is shared by multiple sessions.
- Contributed by Oleg Kalnichevski
-
-* BasicCookieStore uses a ReentrantReadWriteLock to avoid synchronization on #getCookies/#toString
- while maintaining thread safety.
- Contributed by Carter Kozak
-
-* [HTTPCLIENT-1865] DefaultServiceUnavailableRetryStrategy does not respect HttpEntity#isRepeatable.
- Contributed by Tomas Celaya
-
-* [HTTPCLIENT-1859] Encode Content-Disposition name and filename elements appropriately.
- Contributed by Karl Wright
-
-* Avoid fetching the cached entity twice on cache hit.
- Contributed by Leandro Nunes
-
-* [HTTPCLIENT-1835] #evictExpiredConnections no longer causes the #evictIdleConnections behaviour
- to be implicitly enabled.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1831= URIBuilder should not prepend a leading slash to relative URIs.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1833] Fix Windows Negotiate-NTLM handling of proxies.
- Contributed by Roman Stoffel
-
-* [HTTPCLIENT-1817] Add a "Trust All" TrustStrategy implementation.
- Contributed by Gary Gregory
-
-* [HTTPCLIENT-1816] Update Apache Commons Codec 1.9 to 1.10.
- Contributed by Gary Gregory
-
-* [HTTPCLIENT-1836] DefaultHostnameVerifier#getSubjectAltNames(X509Certificate) throws java.lang.ClassCastException.
- Contributed by Gary Gregory , Ilian Iliev
-
-* [HTTPCLIENT-1845]: Extract InputStreamFactory classes out of GzipDecompressingEntity and
- DeflateDecompressingEntity for reuse and to create less garbage.
- Contributed by Gary Gregory
-
-* [HTTPCLIENT-1847] Update Ehcache from 2.6.9 to 2.6.11.
- Contributed by Gary Gregory
-
-* [HTTPCLIENT-1848] Update spymemcached from 2.11.4 to 2.12.3.
- Contributed by Gary Gregory
-
-* [HTTPCLIENT-1849] Update JNA from 4.1.0 to 4.4.0.
- Contributed by Gary Gregory
-
-* [HTTPCLIENT-1850] Update SLF4J from 1.7.6 to 1.7.25.
- Contributed by Gary Gregory
-
-
-Release 4.5.3
--------------------
-
-HttpClient 4.5.3 (GA) is a maintenance release that fixes a number of defects found since 4.5.2.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1803] Improved handling of malformed paths by URIBuilder.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1802] Do not attempt to match SSL host to subject CN if subject alternative name of any type are given.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1788] RFC 6265 policy must not reject cookies with paths that are no prefix of the uri path.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1792] SSLConnectionSocketFactory to throw SSLPeerUnverifiedException with a better error message
- when hostname verification fails.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1779] [OSGi] support NTLM proxy authentication.
- Contributed by Julian Sedding
-
-* [HTTPCLIENT-1773] [OSGi] HttpProxyConfigurationActivator does not unregister HttpClientBuilderFactory.
- Contributed by Julian Sedding
-
-* [HTTPCLIENT-1771] improve OSGi webconsole display for org.apache.http.proxyconfigurator.
- Contributed by Julian Sedding
-
-* [HTTPCLIENT-1770] OSGi metatype for org.apache.http.proxyconfigurator missing factoryPid.
- Contributed by Julian Sedding
-
-* [HTTPCLIENT-1767] Null pointer dereference in EofSensorInputStream and ResponseEntityProxy.
- Contributed by Peter Ansell
-
-* Support changing system default ProxySelector.
- Contributed by Robin Stevens
-
-* All services registered in the OSGi service registry provide the whole bundle header dictionary as vendor
- property value.
- Contributed by Christoph Fiehe
-
-* [HTTPCLIENT-1750] OSGi support for CachingHttpClientBuilder.
- Contributed by Justin Edelson
-
-* [HTTPCLIENT-1749] OSGi client builder to use weak references to track HttpClient instances.
- Contributed by Justin Edelson
-
-* [HTTPCLIENT-1747] apply RequestConfig defaults when using HttpParams values in backward compatibility mode.
- Contributed by Oleg Kalnichevski
-
-* Override LaxRedirectStrategy's INSTANCE field.
- Contributed by Eric Wu
-
-* [HTTPCLIENT-1736] do not request cred delegation by default when using Kerberos auth.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1744] normalize hostname and certificate CN when matching to CN.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1732] SystemDefaultCredentialsProvider to take http.proxyHost and http.proxyPort system
- properties into account.
- Contributed by Oleg Kalnichevski
-
-* Revert "HTTPCLIENT-1712: SPNego schemes to take service scheme into account when generating auth token".
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1727] AbstractHttpClient#createClientConnectionManager does not account for context class loader.
- Contributed by Charles Allen
-
-* [HTTPCLIENT-1726:] Copy the SNI fix from SSLConnectionSocketFactory to the deprecated SSLSocketFactory class.
- Contributed by David Black
-
-
-Release 4.5.2
--------------------
-
-HttpClient 4.5.2 (GA) is a maintenance release that fixes a number of minor defects found since 4.5.1.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1710, HTTPCLIENT-1718, HTTPCLEINT-1719] OSGi container compatibility improvements.
- Contributed by 212427891
-
-* [HTTPCLIENT-1717] Make fluent API Content#Content(byte[], ContentType) public.
- Contributed by Cash Costello
-
-* [HTTPCLIENT-1715] NTLMEngineImpl#Type1Message not thread safe but declared as a constant.
- Contributed by Olivier Lafontaine , Gary Gregory
-
-* [HTTPCLIENT-1714] Add HttpClientBuilder#setDnsResolver(DnsResolver).
- Contributed by Alexis Thaveau
-
-* [HTTPCLIENT-1712] SPNego schemes to take service scheme into account when generating auth token.
- Contributed by Georg Romstorfer
-
-* [HTTPCLIENT-1700] Netscape draft, browser compatibility, RFC 2109, RFC 2965 and default cookie
- specs to ignore cookies with empty name for consistency with RFC 6265 specs.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1704] IgnoreSpec#match to always return false.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1550] Fixed 'deflate' zlib header check.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1698] Fixed matching of IPv6 addresses by DefaultHostnameVerifier
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1695] RFC 6265 compliant cookie spec to ignore cookies with empty name / missing
- value.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1216] Removed ThreadLocal subclass from DateUtils.
- Contributed by Jochen Kemnade
-
-* [HTTPCLIENT-1685] PublicSuffixDomainFilter to ignore local hosts and local domains.
- Contributed by Oleg Kalnichevski
-
-
-
-Release 4.5.1
--------------------
-
-HttpClient 4.5.1 (GA) is a maintenance release that fixes a number of minor defects found since 4.5.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1680] redirect of a POST request causes ClientProtocolException.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1673] org.apache.http.entity.mime.content.* missing from OSGi exports.
- Contributed by Benson Margulies
-
-* [HTTPCLIENT-1668] Fluent request incorrectly handles connect timeout setting.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1667] RequestBuilder does not take charset into account when creating
- UrlEncodedFormEntity.
- Contributed by Sergey Smith
-
-* [HTTPCLIENT-1655] HttpClient sends RST instead of FIN ACK sequence when using non-persistant
- connections.
- Contributed by Oleg Kalnichevski
-
-
-
-Release 4.5
--------------------
-
-HttpClient 4.5 (GA) is a minor feature release that includes several incremental enhancements
-to the exisitng functionality such as support for private domains in the Mozilla Public Suffix List.
-
-Changelog:
--------------------
-
-* Reduced default validate after inactivity setting from 5 sec to 2 sec
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1649] Fixed serialization of auth schemes
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1645]: Fluent requests to inherit config parameters of the executor.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1640]: RFC6265 lax cookie policy fails to parse 'max-age' attribute.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1633]: RFC6265CookieSpecProvider compatibility level setting has no effect.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1613]: Support for private domains in Mozilla Public Suffix List.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1651]: Add ability to disable content compression on a request basis
- Contributed by Michael Osipov
-
-* [HTTPCLIENT-1654]: Deprecate/remove RequestConfig#decompressionEnabled in favor of #contentCompressionEnabled
- Contributed by Michael Osipov
-
-
-
-Release 4.4.1
--------------------
-
-HttpClient 4.4.1 (GA) is a maintenance release that fixes a number of defects in new functionality
-introduced in version 4.4.
-
-Users of HttpClient 4.4 are encouraged to upgrade.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-Changelog:
--------------------
-
-* Marked RFC 2109, RFC 2965, Netscape draft cookie specs as obsolete
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1633] RFC6265CookieSpecProvider compatibility level setting has no effect.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1628]: Auth cache can fail when domain name contains uppercase characters.
- Contributed by Dennis Ju
-
-* [HTTPCLIENT-1609] Stale connection check in PoolingHttpClientConnectionManager has no effect.
- Internal connection pool does not correctly implement connection validation.
- Contributed by Charles Lip
-
-
-
-Release 4.4 Final
--------------------
-
-This is the first stable (GA) release of HttpClient 4.4. Notable features and enhancements included
-in 4.4 series are:
-
-* Support for the latest HTTP state management specification (RFC 6265). Please note that the old
-cookie policy is still used by default for compatibility reasons. RFC 6265 compliant cookie
-policies need to be explicitly configured by the user. Please also note that as of next feature
-release support for Netscape draft, RFC 2109 and RFC 2965 cookie policies will be deprecated
-and disabled by default. It is recommended to use RFC 6265 compliant policies for new applications
-unless compatibility with RFC 2109 and RFC 2965 is required and to migrate existing applications
-to the default cookie policy.
-
-* Enhanced, redesigned and rewritten default SSL hostname verifier with improved RFC 2818
-compliance
-
-* Default SSL hostname verifier and default cookie policy now validate certificate identity
-and cookie domain of origin against the public suffix list maintained by Mozilla.org
-
-
-* More efficient stale connection checking: indiscriminate connection checking which results
-in approximately 20 to 50 ms overhead per request has been deprecated in favor of conditional
-connection state validation (persistent connections are to be re-validated only if a specified
-period inactivity has elapsed)
-
-* Authentication cache thread-safety: authentication cache used by HttpClient is now thread-safe
-and can be shared by multiple threads in order to re-use authentication state for subsequent
-requests
-
-* Native Windows Negotiate and NTLM via SSPI through JNA: when running on Windows OS HttpClient
-configured to use native NTLM or SPNEGO authentication schemes can make use of platform specific
-functionality via JNA and current user credentials. This functionality is still considered
-experimental, known to have compatibility issues and subject to change without prior notice.
-Use at your discretion.
-
-This release also includes all fixes from the stable 4.3.x release branch.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-
-Changelog:
--------------------
-
-* Support for the latest HTTP state management specification (RFC 6265).
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1515] Caching of responses to HEAD requests
- Contributed by Tyrone Cutajar and
- Francois-Xavier Bonnet
-
-* [HTTPCLIENT-1560] Native Windows auth improvements
- Contributed by Michael Osipov
-
-* Update Apache Commons Logging version from 1.1.3 to 1.2.
- Contributed by Gary Gregory
-
-* Update Apache Commons Codec version from 1.6 to 1.9.
- Contributed by Gary Gregory
-
-* Update Ehcache version from 2.2.0 to 2.6.9.
- Contributed by Gary Gregory
-
-* Update Ehcache version from 2.2.0 to 2.6.9.
- Contributed by Gary Gregory
-
-* Update Spymemcached version from 2.6 to 2.11.4.
- Contributed by Gary Gregory
-
-* Update SLF4J version from 1.5.11 to 1.7.7.
- Contributed by Gary Gregory
-
-
-
-
-
-Release 4.4 BETA1
--------------------
-
-This is the first BETA release of HttpClient 4.4. Notable features and enhancements included
-in 4.4 series are:
-
-* Enhanced redesigned and rewritten default SSL hostname verifier with improved RFC 2818
-compliance
-
-* Default SSL hostname verifier and default cookie policy now validate certificate identity
-and cookie domain of origin against the public suffix list maintained by Mozilla.org
-
-
-* Native windows Negotiate/NTLM via JNA: when running on Windows OS HttpClient configured to use
-native NTLM or SPNEGO authentication schemes can make use of platform specific functionality
-via JNA and current user system credentials
-
-* More efficient stale connection checking: indiscriminate connection checking which results
-in approximately 20 to 50 ms overhead per request has been deprecated in favor of conditional
-connection state validation (persistent connections are to be re-validated only if a specified
-period inactivity has elapsed)
-
-* Authentication cache thread-safety: authentication caches used by HttpClient is now thread-safe
-and can be shared by multiple threads in order to re-use authentication state for subsequent
-requests
-
-This release also includes all fixes from the stable 4.3.x release branch.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1547] HttpClient OSGi bundle doesn't import the package "javax.naming".
- Contributed by Willem Jiang
-
-* [HTTPCLIENT-1541] Use correct (HTTP/hostname) service principal name for Windows native
- Negotiate/NTLM auth schemes.
- Contributed by Ka-Lok Fung
-
-* Improved compliance with RFC 2818: default hostname verifier to ignore the common name of the
- certificate subject if alternative subject names (dNSName or iPAddress) are present.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1540] Support delegated credentials (ISC_REQ_DELEGATE) by Native windows
- native Negotiate/NTLM auth schemes.
- Contributed by Ka-Lok Fung
-
-
-
-Release 4.4 ALPHA1
--------------------
-
-This is the first ALPHA release of HttpClient 4.4. Notable features and enhancements included
-in the 4.4 branch are:
-
-* More efficient stale connection checking: indiscriminate connection checking which results
-in approximately 20 to 50 ms overhead per request has been deprecated in favor of conditional
-connection state validation (persistent connections are to be re-validated only if a specified
-period inactivity has elapsed)
-
-* Native windows Negotiate/NTLM via JNA: when running on Windows OS HttpClient configured to use
-native NTLM or SPNEGO authentication schemes can make use of platform specific functionality
-via JNA and current user system credentials
-
-* Authentication cache thread-safety: authentication caches used by HttpClient is now thread-safe
-and can be shared by multiple threads in order to re-use authentication state for subsequent
-requests
-
-This release also includes all fixes from the stable 4.3.x release branch.
-
-Please note that as of 4.4, HttpClient requires Java 1.6 or newer.
-
-Please note that new features included in this release are still considered experimental and
-their API may change in the future 4.4 alpha and beta releases.
-
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1493] Indiscriminate connection checking has been deprecated in favor of conditional
- connection state validation. Persistent connections are to be re-validated only after a defined
- period inactivity prior to being leased to the consumer.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1519] Use the original HttpHost instance passed as a parameter to
- HttpClient#execute when generating 'Host' request header.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1491] Enable provision of Service Principal Name in Windows native
- auth scheme.
- Contributed by Malcolm Smith
-
-* [HTTPCLIENT-1403] Pluggable content decoders.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1466] FileBodyPart#generateContentType() ignores custom ContentType values.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1461] fixed performance degradation in gzip encoded content processing
- introduced by HTTPCLIENT-1432.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1457] Incorrect handling of Windows (NT) credentials by
- SystemDefaultCredentialsProvider.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1456] Request retrial after status 503 causes ClientProtocolException.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1454] Make connection operator APIs public.
- Contributed by Tamas Cservenak
-
-* Update JUnit to version 4.11 from 4.9
- Contributed by Gary Gregory
-
-
-
-Release 4.3.4
--------------------
-
-HttpClient 4.3.4 (GA) is a maintenance release that improves performance in high concurrency
-scenarios. This version replaces dynamic proxies with custom proxy classes and eliminates thread
-contention in java.reflect.Proxy.newInstance() when leasing connections from the connection pool
-and processing response messages.
-
-
-Changelog:
--------------------
-
-* Replaced dynamic proxies with custom proxy classes to reduce thread contention.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1484] GzipCompressingEntity should not close the underlying output stream
- if the entity has not been fully written out due to an exception.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1474] Fixed broken entity enclosing requests in HC Fluent.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1470] CachingExec(ClientExecChain, HttpCache, CacheConfig, AsynchronousValidator)
- throws NPE if config is null
-
-
-
-
-Release 4.3.3
--------------------
-
-HttpClient 4.3.3 (GA) is a bug fix release that fixes a regression introduced by the previous
-release causing a significant performance degradation in compressed content processing.
-
-Users of HttpClient 4.3 are encouraged to upgrade.
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1466] FileBodyPart#generateContentType() ignores custom ContentType values.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1453] Thread safety regression in PoolingHttpClientConnectionManager
- #closeExpiredConnections that can lead to ConcurrentModificationException.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1461] fixed performance degradation in compressed content processing
- introduced by HTTPCLIENT-1432.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1457] Incorrect handling of Windows (NT) credentials by
- SystemDefaultCredentialsProvider.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1456] Request retrial after status 503 causes ClientProtocolException.
- Contributed by Oleg Kalnichevski
-
-
-Release 4.3.2
--------------------
-
-HttpClient 4.3.2 (GA) is a maintenance release that delivers a number of improvements
-as well as bug fixes for issues reported since 4.3.1 release. SNI support for
-Oracle JRE 1.7+ is being among the most notable improvements.
-
-Users of HttpClient 4.3 are encouraged to upgrade.
-
-Changelog:
--------------------
-
-* [HTTPCLIENT-1447] Clients created with HttpClients.createMinimal do not work with absolute URIs
- Contributed by Joseph Walton
-
-* [HTTPCLIENT-1446] NTLM proxy + BASIC target auth fails with 'Unexpected state:
- MSG_TYPE3_GENERATED'.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1443] HttpCache uses the physical host instead of the virtual host as a cache key.
- Contributed by Francois-Xavier Bonnet
-
-* [HTTPCLIENT-1442] Authentication header set by the user gets removed in case
- of proxy authentication (affects plan HTTP requests only).
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1441] Caching AsynchronousValidationRequest leaks connections.
- Contributed by Dominic Tootell
-
-* [HTTPCLIENT-1440] 'file' scheme in redirect location URI causes NPE.
- Contributed by James Leigh
-
-* [HTTPCLIENT-1437] Made Executor#execute thread safe.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1119] SNI support (Oracle Java 1.7+ only).
- Contributed by Bruno Harbulot
-
-* [HTTPCLIENT-1435] Fluent Executor ignores custom request properties.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1432] Lazy decompressing of HttpEntity#getContent() to avoid EOFException
- in case of an empty response with 'Content-Encoding: gzip' header.
- Contributed by Yihua Huang
-
-* [HTTPCLIENT-1431] (Regression) deprecated connection manager cannot be used with
- a custom LayeredSchemeSocketFactory.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1425] Fixed socket closed exception thrown by caching HttpClient when the origin
- server sends a long chunked response.
- Contributed by James Leigh
-
-* [HTTPCLIENT-1417] Fixed NPE in BrowserCompatSpec#formatCookies caused by version 1
- cookies with null cookie value.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1416] Fixed NPE in CachingHttpClientBuilder#build().
- Contributed by Oleg Kalnichevski
-
-
-
-Release 4.3.1
--------------------
-
-HttpClient 4.3.1 (GA) is a bug fix release that addresses a number of issues reported since
-release 4.3.
-
-Users of HttpClient 4.3 are strongly encouraged to upgrade.
-
-Changelog
--------------------
-
-* [HTTPCLIENT-1410] Browser compatible hostname verifier no longer rejects
- *.co., *.gov., *.info., etc as invalid.
- Contributed by Oleg Kalnichevski
-
-* Ensure X509HostnameVerifier is never null.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1405] CONNECT HTTP/1.1 requests lack mandatory 'Host' header.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1402] Cache default User-Agent value.
- Contributed by yuexiaojun
-
-* [HTTPCLIENT-1398] Fixed invalid OSGi metadata caused by corrupted Maven bundle plugin metadata.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1399] Fixed NPE in RequestBuilder.
- Contributed by Oleg Kalnichevski
-
-
-
-
-Release 4.3 Final
--------------------
-
-This is the first stable (GA) release of HttpClient 4.3. The most notable enhancements included
-in this release are:
-
-* Support for Java 7 try-with-resources for resource management (connection release.)
-
-* Added fluent Builder classes for HttpEntity, HttpRequest, HttpClient and SSLContext instances.
-
-* Deprecation of preference and configuration API based on HttpParams interface in favor of
-constructor injection and plain configuration objects.
-
-* Reliance on object immutability instead of access synchronization for thread safety.
-Several old classes whose instances can be shared by multiple request exchanges have
-been replaced by immutable equivalents.
-
-* DefaultHttpClient, DecompressingHttpClient, CachingHttpClient and similar classes are
-deprecated in favor of builder classes that produce immutable HttpClient instances.
-
-* HttpClient builders now dynamically construct a request execution pipeline tailored
-specifically to the user configuration by physically excluding unnecessary protocol components.
-
-* There is now an option to construct a minimal HttpClient implementation that can only execute
-basic HTTP message exchanges without redirects, authentication, state management or proxy support.
-This feature might be of particular use in web crawler development.
-
-* There is now option to avoid strict URI syntax for request URIs by executing HTTP requests
-with an explicitly specified target host. HttpClient will no longer attempt to parse the request
-URI if it does not need to extract the target host from it.
-
-This release also includes all fixes from the stable 4.2.x release branch.
-
-
-Changelog
--------------------
-* [HTTPCLIENT-1371] Weak ETag Validation is Useful On PUT With If-Match
- Contributed by James Leigh
-
-* [HTTPCLIENT-1394] Support for Native windows Negotiate/NTLM via JNA
- Contributed by Ryan McKinley
-
-* [HTTPCLIENT-1384] Expose CacheInvalidator interface.
- Contributed by Nicolas Richeton
-
-* [HTTPCLIENT-1385] Fixed path normalization in CacheKeyGenerator
- Contributed by James Leigh
-
-* [HTTPCLIENT-1370] Response to non-GET requests should never be cached with the default
- ResponseCachingPolicy
- Contributed by James Leigh
-
-* [HTTPCLIENT-1373] OPTIONS and TRACE should not invalidate cache
- Contributed by James Leigh
-
-* [HTTPCLIENT-1383] HttpClient enters an infinite loop during NTLM authentication if the opposite
- endpoint keeps responding with a type 2 NTLM response after type 3 MTLM message has already been
- sent by the client.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1372] Refactor HttpMultipart, and add RFC6532 mode, so that headers in post
- are no longer constrained to ASCII values.
- Contributed by Karl Wright
-
-* [HTTPCLIENT-1377] User principal for non-NTLM authentication is incorrectly generated when using
- user credentials are specified as NTCredentials
- Contributed by Gary Gregory
-
-
-
-Release 4.3 BETA2
--------------------
-
-This is the second BETA release of HttpClient 4.3. The most notable features and improvements
-in the 4.3 branch are: Support for Java 7 try-with-resources for resource management (connection
-release); fluent Builder classes for HttpEntity, HttpRequest and HttpClient instances, deprecation
-of preference and configuration API based on HttpParams interface in favor of constructor injection
-and plain configuration objects, reliance on object immutability instead of access synchronization
-for thread safety.
-
-This release also includes all fixes from the stable 4.2.x release branch.
-
-Changelog
--------------------
-
-
-* [HTTPCLIENT-1366] org.apache.http.client.utils.URLEncodedUtils should parse the semicolon as a query parameter separator.
- Contributed by Gary Gregory
-
-* [HTTPCLIENT-1365] NPE when ManagedHttpClientConnectionFactory.create(ConnectionConfig) is called with null.
- Contributed by Gary Gregory
-
-* [HTTPCLIENT-1362] Better error messages for connect timed out and connection refused
- exceptions.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1360] separate out DeflateInputStream as an independent class,
- so it can be used by others.
- Contributed by Karl Wright
-
-* [HTTPCLIENT-1359] repeated requests using the same context fail if they redirect.
- Contributed by James Leigh
-
-* [HTTPCLIENT-1354] do not quote algorithm parameter in DIGEST auth response.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1351] Added utility method to resolve final location from original request,
- target host and a list of redirects.
- Contributed by James Leigh
-
-* [HTTPCLIENT-1344] Userinfo credentials in URI should not default to preemptive BASIC
- authentication.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1345] Useinfo credentials ignored in redirect location header.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1294] HttpClient to rewrite host name of the redirect location URI in order
- to avoid circular redirect exception due to host name case mismatch.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1264] Add support for multiple levels of browser compatibility
- to BrowserCompatSpec and BrowserCompatSpecFactory. Include constructor
- argument for IE medium-security compatibility.
- Contributed by Karl Wright (kwright at apache.org)
-
-* [HTTPCLIENT-1349] SSLSocketFactory incorrectly identifies key passed with keystore as
- the keystore password.
- Contributed by David Graff
-
-* [HTTPCLIENT-1346] Ensure propagation of SSL handshake exceptions.
- Contributed by Pasi Eronen
-
-* [HTTPCLIENT-1343] SSLSocketFactory optional parameters for supported SSL protocols and cipher
- suites.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1238] Contribute Bundle Activator And Central Proxy Configuration.
- Contributed by Simone Tripodi
-
-* [HTTPCLIENT-1299] (regression) cache incorrectly disposes of the underlying cache resource
- when storing variant entry.
- Contributed by James Leigh
-
-* [HTTPCLIENT-1342] Redirects with underscore character in the location hostname cause
- "java.lang.IllegalArgumentException: Host name may not be null".
- Contributed by Oleg Kalnichevski
-
-
-
-Release 4.3 BETA1
--------------------
-
-This is the first BETA release of HttpClient 4.3. The 4.3 branch enhances HttpClient in several
-key areas and includes several notable features and improvements: Support for Java 7
-try-with-resources for resource management (connection release); fluent Builder classes for
-HttpEntity, HttpRequest and HttpClient instances, deprecation of preference and configuration API
-based on HttpParams interface in favor of constructor injection and plain configuration objects,
-reliance on object immutability instead of access synchronization for thread safety.
-
-This release also includes all fixes from the stable 4.2.x release branch.
-
-
-Changelog
--------------------
-
-* [HTTPCLIENT-1317] InetAddressUtils should handle IPv6 Addresses with Embedded IPv4 Addresses
- Contributed Sebastian Bazley .
-
-* [HTTPCLIENT-1320] Leverage javax.net.ssl.SSLSocketFactory#getDefault() to initialize SSL context
- based on system defaults instead of using an internal custom routine.
- Contributed by Abe Backus and Oleg Kalnichevski
-
-* [HTTPCLIENT-1316] Certificate verification rejects IPv6 addresses which are not String-equal.
- Contributed Sebastian Bazley .
-
-* [HTTPCLIENT-1307] Future based asynchronous request execution.
- Contributed by Jilles van Gurp
-
-* [HTTPCLIENT-1313] Fixed IllegalStateException in deprecated ThreadSafeClientConnManager.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1298] Add AsynchronousValidator in HttpClientBuilder's list of closeable objects.
- Contributed by Martin Meinhold
-
-
-
-Release 4.3 ALPHA1
--------------------
-
-This is the first ALPHA release of HttpClient 4.3. The 4.3 branch enhances HttpClient in several
-key areas and includes several notable features and improvements: Support for Java 7
-try-with-resources for resource management (connection release); fluent Builder classes for
-HttpEntity, HttpRequest and HttpClient instances, deprecation of preference and configuration API
-based on HttpParams interface in favor of constructor injection and plain configuration objects,
-reliance on object immutability instead of access synchronization for thread safety.
-
-We are kindly asking all upstream projects to review API changes and help us improve
-the APIs by providing feedback and sharing ideas on dev@hc.apache.org.
-
-This release also includes all fixes from the stable 4.2.x release branch.
-
-Please note that new features included in this release are still considered experimental and
-their API may change in the future 4.3 alpha and beta releases.
-
-
-Changelog
--------------------
-
-* [HTTPCLIENT-1250] Allow query string to be ignored when determining cacheability for
- HTTP 1.0 responses.
- Contributed by Don Brown
-
-* [HTTPCLIENT-1261] Make SystemDefaultHttpClient honor http.agent system property.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-900] Don't enforce URI syntax for messages with an explicit target host.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1190] HttpClient cache does not support "Vary: Cookie"
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1259] Calling #abort() on requests executed with DecompressingHttpClient has no
- effect.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1253] URIBuilder setParameter() method could exceed the HTTP header size.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1216] Added method to force clean thread-local used by DateUtils.
- Contributed by Oleg Kalnichevski
-
-
-Release 4.2.3
--------------------
-
-HttpClient 4.2.3 (GA) is a bug fix release that addresses a number of issues reported since
-release 4.2.2. This release also includes a thoroughly reworked NTLM authentication engine
-which should result in a better compatibility with the newest Microsoft products.
-
-Users of HttpClient 4.x are advised to upgrade.
-
-Changelog
--------------------
-
-* [HTTPCLIENT-1296] NPE gets thrown if you combine a default host with a virtual host
- that has a -1 value for the port.
- Contributed by Karl Wright
-
-* [HTTPCLIENT-1290] 304 cached response never reused with If-modified-since conditional
- requests.
- Contributed by Francois-Xavier Bonnet
-
-* [HTTPCLIENT-1291] Absolute request URIs without an explicitly specified path are rewritten
- to have "/" path).
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1286] Request URI rewriting is inconsistent - URI fragments are not removed
- from absolute request URIs.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1284] HttpClient incorrectly generates Host header when physical connection
- route differs from the host name specified in the request URI.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1293] Kerberos and SPNego auth schemes use incorrect authorization header name
- when authenticating with a proxy.
- Contributed by Oleg Kalnichevski
-
-* [HTTPCLIENT-1283] NTLM needs to use Locale-independent form of
- toUpperCase().
- Contributed by Karl Wright
-
-* [HTTPCLIENT-1279] Target host responding with status 407 (proxy authentication required)
- causes an NPE.
- Contributed by Oleg Kalnichevski