();
}
@@ -45,6 +38,9 @@ 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(
@@ -54,7 +50,14 @@ public class Contact {
new String[] { phoneNumber },
null);
- if (cursor != null && cursor.moveToFirst()) {
+ //判断查询结果:
+ //查询结果不为空,且能够移动到第一条记录:
+ // 那么就尝试从Cursor中获取联系人姓名,并将其存入缓存sContactCache。然后返回联系人姓名。
+ // 异常情况:如果在获取字符串时发生数组越界异常,则记录一个错误日志并返回null。
+ // 最后都要确保关闭Cursor对象,以避免内存泄漏。
+ //如果查询结果为空或者没有记录可以移动到(即没有找到匹配的联系人):
+ // 则记录一条调试日志并返回null
+ if (cursor != null &cursor.moveToFirst()) {
try {
String name = cursor.getString(0);
sContactCache.put(phoneNumber, name);
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/data/Notes.java b/src/Notesmaster/app/src/main/java/net/micode/notes/data/Notes.java
index f240604..db86757 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/data/Notes.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/data/Notes.java
@@ -20,9 +20,11 @@ import android.net.Uri;
public class Notes {
public static final String AUTHORITY = "micode_notes";
public static final String TAG = "Notes";
- public static final int TYPE_NOTE = 0;
- public static final int TYPE_FOLDER = 1;
- public static final int TYPE_SYSTEM = 2;
+ /*定义基本信息*/
+ public static final int TYPE_NOTE = 0;
+ public static final int TYPE_FOLDER = 1;
+ public static final int TYPE_SYSTEM = 2;
+ /*定义了note表中,类型行的3种取值*/
/**
* Following IDs are system folders' identifiers
@@ -30,10 +32,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
*/
- public static final int ID_ROOT_FOLDER = 0;
- public static final int ID_TEMPARAY_FOLDER = -1;
- public static final int ID_CALL_RECORD_FOLDER = -2;
- public static final int ID_TRASH_FOLER = -3;
+ public static final 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;/*垃圾回收站*/
+ /* 定义了4种类型文件*/
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";
@@ -42,15 +45,16 @@ public class Notes {
public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id";
public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date";
- public static final int TYPE_WIDGET_INVALIDE = -1;
- public static final int TYPE_WIDGET_2X = 0;
- public static final int TYPE_WIDGET_4X = 1;
+ public static final int TYPE_WIDGET_INVALIDE = -1;
+ public static final int TYPE_WIDGET_2X = 0;
+ public static final int TYPE_WIDGET_4X = 1;
+ /*设置ui界面的一些小布局或小组件的id*/
public static class DataConstants {
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
}
-
+ /*定义了两种数据类型:文本便签和通话记录*/
/**
* Uri to query all notes and folders
*/
@@ -61,6 +65,7 @@ public class Notes {
*/
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data");
+ /*定义了一个url来查询数据*/
public interface NoteColumns {
/**
* The unique ID for a row
@@ -165,115 +170,63 @@ public class Notes {
* Type : INTEGER (long)
*/
public static final String VERSION = "version";
- }
+ }/*这个接口定义了很多字符串常量,这些常量代表数据库表中的列名*/
public interface DataColumns {
- /**
- * The unique ID for a row
- * Type: INTEGER (long)
- */
- public static final String ID = "_id";
- /**
- * The MIME type of the item represented by this row.
- * Type: Text
- */
+ public static final String ID = "_id";
+ //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";
- /**
- * Generic data column, the meaning is {@link #MIMETYPE} specific, used for
- * integer data type
- * Type: INTEGER
- */
- public static final String DATA1 = "data1";
+ // 以下5个是通用数据列,它们的具体意义取决于MIME类型(由MIME_TYPE字段指定)。
+ // 不同的MIME类型可能需要存储不同类型的数据,这5个字段提供了灵活性,允许根据MIME类型来存储相应的数据。
+ // 读后面的代码感觉这部分是在表示内容的不同状态?
- /**
- * Generic data column, the meaning is {@link #MIMETYPE} specific, used for
- * integer data type
- * Type: INTEGER
- */
+ public static final String DATA1 = "data1";
public static final String DATA2 = "data2";
-
- /**
- * Generic data column, the meaning is {@link #MIMETYPE} specific, used for
- * TEXT data type
- * Type: TEXT
- */
public static final String DATA3 = "data3";
-
- /**
- * Generic data column, the meaning is {@link #MIMETYPE} specific, used for
- * TEXT data type
- * Type: TEXT
- */
public static final String DATA4 = "data4";
-
- /**
- * Generic data column, the meaning is {@link #MIMETYPE} specific, used for
- * TEXT data type
- * Type: TEXT
- */
public static final String DATA5 = "data5";
}
+ //以下是文本便签的定义
public static final class TextNote implements DataColumns {
- /**
- * Mode to indicate the text in check list mode or not
- * Type: Integer 1:check list mode 0: normal mode
- */
+ //模式?这个被存在DATA1列中
public static final String MODE = DATA1;
-
+ //所处检查列表模式?
public static final int MODE_CHECK_LIST = 1;
-
+ // 定义了MIME类型,用于标识文本标签的目录
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note";
-
+ // 定义了MIME类型,用于标识文本标签的单个项
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/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;
-
- /**
- * Phone number for this record
- * Type: TEXT
- */
+ //意味着在数据库表中,这个电话号码信息将被存储在DATA3列中
public static final String PHONE_NUMBER = DATA3;
-
+ // 同样定义了MIME类型,是用于标识通话记录的目录。
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note";
-
+ // 同样定义了MIME类型,是用于标识通话记录的单个项。
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note";
-
+ //定义了通话记录内容提供者的URI,用于访问通话记录数据。
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note");
}
}
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java b/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java
index ffe5d57..10501d0 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java
@@ -1,19 +1,3 @@
-/*
- * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
package net.micode.notes.data;
import android.content.ContentValues;
@@ -28,188 +12,253 @@ 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" +
- ")";
-
+ "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中定义的一个接口,里面定义了一系列静态的数据库表中的列名
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 ''" +
- ")";
-
+ "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确保了如果索引已经存在,那么就不会尝试重新创建它,避免了可能的错误。
+ // 索引通常用于提高查询性能,特别是在对某个字段进行频繁查询时。
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
- "CREATE INDEX IF NOT EXISTS note_id_index ON " +
- TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
-
+ "CREATE INDEX IF NOT EXISTS note_id_index ON " +
+ TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
+
+ /* 以下是一些对便签增删改定义的触发器 */
+ /* 总结
+ * 这些触发器都是用来维护NOTE表和与之相关联的DATA表之间数据一致性的。
+ * 当在NOTE表中发生删除或更新操作时,这些触发器会自动执行相应的数据清理或更新操作,确保数据库中的数据保持正确和一致。
+ * 特别是在处理文件夹和回收站等逻辑时,这些触发器起到了非常重要的作用,可以自动管理数据的移动和删除。*/
/**
* 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);
@@ -217,6 +266,9 @@ 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");
@@ -235,6 +287,17 @@ 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();
@@ -248,6 +311,7 @@ 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);
@@ -256,6 +320,7 @@ 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);
@@ -264,12 +329,21 @@ 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);
@@ -277,6 +351,10 @@ 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");
@@ -287,6 +365,11 @@ 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);
@@ -294,12 +377,19 @@ 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;
@@ -327,12 +417,17 @@ 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);
@@ -340,6 +435,12 @@ 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");
@@ -355,6 +456,10 @@ 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/Notesmaster/app/src/main/java/net/micode/notes/data/NotesProvider.java b/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesProvider.java
index edb0a60..302847a 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesProvider.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/data/NotesProvider.java
@@ -1,22 +1,8 @@
-/*
- * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
package net.micode.notes.data;
+import static android.os.Build.VERSION_CODES.R;
+
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentUris;
@@ -29,19 +15,31 @@ import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
-import net.micode.notes.R;
+
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
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;
@@ -50,13 +48,23 @@ 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);
}
@@ -65,33 +73,66 @@ 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.
*/
- 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 查询的投影部分,用于定义查询返回的结果集中应该包含哪些列。
+ //解读:(每行对应)
+ //返回笔记的 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 + " 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) {
+ String sortOrder) {
+ //初始化变量:
+ //Cursor对象 c,用来存储查询结果
+ //使用 NotesDatabaseHelper 的实例 mHelper来获取一个可读的数据库实例
+ //定义一个字符串id,用来存储从URI中解析出的ID
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);
@@ -110,6 +151,12 @@ 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) {
@@ -130,6 +177,8 @@ public class NotesProvider extends ContentProvider {
return null;
}
+ //字符串格式化:格式化后的字符串就会是 "%s%",即包含s是任何文本
+ //然后执行原始SQL查询
try {
searchString = String.format("%%%s%%", searchString);
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
@@ -138,19 +187,31 @@ 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);
@@ -166,6 +227,10 @@ 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(
@@ -178,16 +243,28 @@ 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);
@@ -218,22 +295,39 @@ 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);
@@ -258,6 +352,9 @@ 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);
@@ -267,10 +364,12 @@ 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/Notesmaster/app/src/main/java/net/micode/notes/gtask/data/MetaData.java b/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/data/MetaData.java
index 3a2050b..f0cfe51 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/data/MetaData.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/data/MetaData.java
@@ -26,11 +26,20 @@ import org.json.JSONObject;
public class MetaData extends Task {
+ /*
+ *功能描述,得到类的简写名称存入字符串TAG中
+ * 实现过程:调用getSimpleName()函数
+ */
private final static String TAG = MetaData.class.getSimpleName();
private String mRelatedGid = null;
+ /*
+ *功能描述:得到类的简写名称存入字符串TAG中
+ * 实现过程:调用JSONObject库函数put(),Task类中的setNotes()和setName()函数
+ */
public void setMeta(String gid, JSONObject metaInfo) {
+ //对函数块进行注释
try {
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
} catch (JSONException e) {
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java b/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java
index a1deb99..a822216 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java
@@ -24,7 +24,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.ui.NotesListActivity;
import net.micode.notes.ui.NotesPreferenceActivity;
@@ -64,22 +64,21 @@ 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);
+ NotesListActivity.class), 0);
}
- 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();
+// notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
+// pendingIntent);
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
}
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java b/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java
index d2b4082..64c486d 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java
@@ -24,7 +24,7 @@ import android.content.Context;
import android.database.Cursor;
import android.util.Log;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/tool/BackupUtils.java b/src/Notesmaster/app/src/main/java/net/micode/notes/tool/BackupUtils.java
index 39f6ec4..276d246 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/tool/BackupUtils.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/tool/BackupUtils.java
@@ -23,7 +23,7 @@ import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/tool/ResourceParser.java b/src/Notesmaster/app/src/main/java/net/micode/notes/tool/ResourceParser.java
index 1ad3ad6..2942b59 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/tool/ResourceParser.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/tool/ResourceParser.java
@@ -19,7 +19,7 @@ package net.micode.notes.tool;
import android.content.Context;
import android.preference.PreferenceManager;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.ui.NotesPreferenceActivity;
public class ResourceParser {
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/AlarmAlertActivity.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/AlarmAlertActivity.java
index 85723be..f029dc2 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/AlarmAlertActivity.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/AlarmAlertActivity.java
@@ -33,7 +33,7 @@ import android.provider.Settings;
import android.view.Window;
import android.view.WindowManager;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DateTimePicker.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DateTimePicker.java
index 496b0cd..222897a 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DateTimePicker.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DateTimePicker.java
@@ -19,7 +19,7 @@ package net.micode.notes.ui;
import java.text.DateFormatSymbols;
import java.util.Calendar;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import android.content.Context;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java
index 2c47ba4..08c5625 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DateTimePickerDialog.java
@@ -18,7 +18,7 @@ package net.micode.notes.ui;
import java.util.Calendar;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.ui.DateTimePicker;
import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DropdownMenu.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DropdownMenu.java
index 613dc74..4e7648a 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DropdownMenu.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/DropdownMenu.java
@@ -25,7 +25,7 @@ import android.widget.Button;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
-import net.micode.notes.R;
+import com.example.notes_master.R;
public class DropdownMenu {
private Button mButton;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java
index 96b77da..e7a9c62 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/FoldersListAdapter.java
@@ -24,7 +24,7 @@ import android.widget.CursorAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java
index 96a9ff8..a78a689 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditActivity.java
@@ -52,7 +52,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.model.WorkingNote;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditText.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditText.java
index 2afe2a8..a219c46 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditText.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NoteEditText.java
@@ -32,7 +32,7 @@ import android.view.MenuItem.OnMenuItemClickListener;
import android.view.MotionEvent;
import android.widget.EditText;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import java.util.HashMap;
import java.util.Map;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListActivity.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListActivity.java
index e843aec..771e08a 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListActivity.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListActivity.java
@@ -60,7 +60,7 @@ import android.widget.PopupMenu;
import android.widget.TextView;
import android.widget.Toast;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.remote.GTaskSyncService;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListItem.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListItem.java
index 1221e80..1a68f3c 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListItem.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesListItem.java
@@ -24,7 +24,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.ResourceParser.NoteItemBgResources;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java
index 07c5f7e..6cc9c6d 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/ui/NotesPreferenceActivity.java
@@ -42,7 +42,7 @@ import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.remote.GTaskSyncService;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider.java b/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider.java
index ec6f819..d3d36e9 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider.java
@@ -25,7 +25,7 @@ import android.database.Cursor;
import android.util.Log;
import android.widget.RemoteViews;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.tool.ResourceParser;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_2x.java b/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_2x.java
index adcb2f7..21106cb 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_2x.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_2x.java
@@ -19,7 +19,7 @@ package net.micode.notes.widget;
import android.appwidget.AppWidgetManager;
import android.content.Context;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser;
diff --git a/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_4x.java b/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_4x.java
index c12a02e..74dfd99 100644
--- a/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_4x.java
+++ b/src/Notesmaster/app/src/main/java/net/micode/notes/widget/NoteWidgetProvider_4x.java
@@ -19,7 +19,7 @@ package net.micode.notes.widget;
import android.appwidget.AppWidgetManager;
import android.content.Context;
-import net.micode.notes.R;
+import com.example.notes_master.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser;
diff --git a/src/Notesmaster/app/src/test/java/com/example/notes_master/ExampleUnitTest.java b/src/Notesmaster/app/src/test/java/com/example/notes_master/ExampleUnitTest.java
new file mode 100644
index 0000000..49061ea
--- /dev/null
+++ b/src/Notesmaster/app/src/test/java/com/example/notes_master/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.notes_master;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/src/Notesmaster/gradle/wrapper/gradle-wrapper.jar b/src/Notesmaster/gradle/wrapper/gradle-wrapper.jar
index e708b1c..2c35211 100644
Binary files a/src/Notesmaster/gradle/wrapper/gradle-wrapper.jar and b/src/Notesmaster/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/src/Notesmaster/gradle/wrapper/gradle-wrapper.properties b/src/Notesmaster/gradle/wrapper/gradle-wrapper.properties
index 4b2a487..09523c0 100644
--- a/src/Notesmaster/gradle/wrapper/gradle-wrapper.properties
+++ b/src/Notesmaster/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
-#Sat Nov 02 13:12:10 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
\ No newline at end of file
+zipStorePath=wrapper/dists
diff --git a/src/Notesmaster/gradlew b/src/Notesmaster/gradlew
index 4f906e0..f5feea6 100644
--- a/src/Notesmaster/gradlew
+++ b/src/Notesmaster/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
#
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,69 +15,104 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,88 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=`expr $i + 1`
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- 0) set -- ;;
- 1) set -- "$args0" ;;
- 2) set -- "$args0" "$args1" ;;
- 3) set -- "$args0" "$args1" "$args2" ;;
- 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=`save "$@"`
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
exec "$JAVACMD" "$@"
diff --git a/src/Notesmaster/gradlew.bat b/src/Notesmaster/gradlew.bat
index 107acd3..9d21a21 100644
--- a/src/Notesmaster/gradlew.bat
+++ b/src/Notesmaster/gradlew.bat
@@ -13,8 +13,10 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +27,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/src/Notesmaster/settings.gradle.kts b/src/Notesmaster/settings.gradle.kts
index bcbfede..5f507de 100644
--- a/src/Notesmaster/settings.gradle.kts
+++ b/src/Notesmaster/settings.gradle.kts
@@ -21,3 +21,4 @@ dependencyResolutionManagement {
rootProject.name = "Notes-master"
include(":app")
+include(":app")