diff --git a/doc/实践模板-开源软件泛读、标注和维护报告文档.docx b/doc/实践模板-开源软件泛读、标注和维护报告文档.docx
deleted file mode 100644
index 4ef4e20..0000000
Binary files a/doc/实践模板-开源软件泛读、标注和维护报告文档.docx and /dev/null differ
diff --git a/doc/开源软件泛读、标注和维护报告文档.docx b/doc/开源软件泛读、标注和维护报告文档.docx
new file mode 100644
index 0000000..d05c01f
Binary files /dev/null and b/doc/开源软件泛读、标注和维护报告文档.docx differ
diff --git a/doc/开源软件的质量分析报告文档.docx b/doc/开源软件的质量分析报告文档.docx
new file mode 100644
index 0000000..178130b
Binary files /dev/null and b/doc/开源软件的质量分析报告文档.docx differ
diff --git a/doc/阅读维护开源软件的团队自评报告.xlsx b/doc/阅读维护开源软件的团队自评报告.xlsx
new file mode 100644
index 0000000..2be6a67
Binary files /dev/null and b/doc/阅读维护开源软件的团队自评报告.xlsx differ
diff --git a/doc/阅读维护开源软件的汇报.pptx b/doc/阅读维护开源软件的汇报.pptx
new file mode 100644
index 0000000..263ec80
Binary files /dev/null and b/doc/阅读维护开源软件的汇报.pptx differ
diff --git a/src/xiaomi/Notes-master/AndroidManifest.xml b/src/xiaomi/Notes-master/AndroidManifest.xml
index e5c7d47..9aa7f84 100644
--- a/src/xiaomi/Notes-master/AndroidManifest.xml
+++ b/src/xiaomi/Notes-master/AndroidManifest.xml
@@ -1,26 +1,10 @@
-
-
-
+ android:versionName="0.1">
-
+
@@ -33,8 +17,49 @@
+ android:icon="@drawable/icon_app_new"
+ android:label="@string/app_name">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+ android:theme="@style/NoteTheme">
+
+
-
+
+
-
+
@@ -81,13 +104,13 @@
+ android:label="@string/app_widget2x2">
@@ -100,8 +123,7 @@
-
+ android:label="@string/app_widget4x4">
@@ -112,39 +134,32 @@
android:name="android.appwidget.provider"
android:resource="@xml/widget_4x_info" />
-
-
+
-
-
+ android:name=".ui.AlarmReceiver"
+ android:process=":remote">
-
-
+ android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar">
-
+ android:theme="@android:style/Theme.Holo.Light">
-
+ android:name=".gtask.remote.GTaskSyncService"
+ android:exported="false">
-
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/res/color/primary_text_dark.xml b/src/xiaomi/Notes-master/res/color/primary_text_dark.xml
index 7c85459..8ad98e3 100644
--- a/src/xiaomi/Notes-master/res/color/primary_text_dark.xml
+++ b/src/xiaomi/Notes-master/res/color/primary_text_dark.xml
@@ -1,4 +1,4 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/res/layout/activity_set_loginpassword.xml b/src/xiaomi/Notes-master/res/layout/activity_set_loginpassword.xml
new file mode 100644
index 0000000..9653362
--- /dev/null
+++ b/src/xiaomi/Notes-master/res/layout/activity_set_loginpassword.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/res/layout/activity_splash.xml b/src/xiaomi/Notes-master/res/layout/activity_splash.xml
new file mode 100644
index 0000000..532f72e
--- /dev/null
+++ b/src/xiaomi/Notes-master/res/layout/activity_splash.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/res/layout/note_edit.xml b/src/xiaomi/Notes-master/res/layout/note_edit.xml
index 10b2aa7..1b5c0f2 100644
--- a/src/xiaomi/Notes-master/res/layout/note_edit.xml
+++ b/src/xiaomi/Notes-master/res/layout/note_edit.xml
@@ -31,6 +31,17 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content">
+
+
+
+
+
+ android:layout_height="fill_parent">
+
+
+ />
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/res/menu/note_list.xml b/src/xiaomi/Notes-master/res/menu/note_list.xml
index 42ea736..ab67553 100644
--- a/src/xiaomi/Notes-master/res/menu/note_list.xml
+++ b/src/xiaomi/Notes-master/res/menu/note_list.xml
@@ -32,8 +32,33 @@
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/xiaomi/Notes-master/res/values-night/themes.xml b/src/xiaomi/Notes-master/res/values-night/themes.xml
new file mode 100644
index 0000000..41acc3a
--- /dev/null
+++ b/src/xiaomi/Notes-master/res/values-night/themes.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/res/values-zh-rCN/strings.xml b/src/xiaomi/Notes-master/res/values-zh-rCN/strings.xml
index 09f75ed..821d70c 100644
--- a/src/xiaomi/Notes-master/res/values-zh-rCN/strings.xml
+++ b/src/xiaomi/Notes-master/res/values-zh-rCN/strings.xml
@@ -122,5 +122,19 @@
%1$s 条符合“%2$s”的搜索结果
-
+ 撤销
+ //中文
+ 提示
+ 您不能再执行撤销了
+ 您还没有输入任何内容
+ 朗读
+ 设置字体
+ 切换背景1
+ 切换背景2
+ 切换背景3
+ 私密模式
+ 退出私密模式
+ 新建登录密码
+ 删除登录密码
+ 修改登录密码
diff --git a/src/xiaomi/Notes-master/res/values-zh-rTW/strings.xml b/src/xiaomi/Notes-master/res/values-zh-rTW/strings.xml
index 3c41894..e29b79b 100644
--- a/src/xiaomi/Notes-master/res/values-zh-rTW/strings.xml
+++ b/src/xiaomi/Notes-master/res/values-zh-rTW/strings.xml
@@ -1,4 +1,4 @@
-
+
-
+NotesNotes 2x2Notes 4x4
@@ -39,6 +38,12 @@
/MIUI/notes/notes_%s.txt
+
+
+ Switch_to_picture1
+ Switch_to_picture2
+ Switch_to_picture3
+
(%d)New FolderExport text
@@ -127,9 +132,26 @@
setcancel
- %1$s result for \"%2$s\"
+ %1$s result for \"%2$s\"
- %1$s results for \"%2$s\"
+ %1$s results for \"%2$s\"
+ FullscreenActivity
+ Dummy Button
+ 写下你的快乐
+ SplashActivity
+
+
+ Revoke
+ Set font
+ voice speech
+ Tips
+ You can not revoke any more
+ You haven not input anything
+ Set_secret
+ Quit_secret
+ CreateLogin
+ Deletelogin
+ Changelogin
diff --git a/src/xiaomi/Notes-master/res/values/styles.xml b/src/xiaomi/Notes-master/res/values/styles.xml
index d750e65..fd4c3ff 100644
--- a/src/xiaomi/Notes-master/res/values/styles.xml
+++ b/src/xiaomi/Notes-master/res/values/styles.xml
@@ -16,18 +16,22 @@
-->
+
+
+
+
@@ -64,6 +68,15 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/res/values/themes.xml b/src/xiaomi/Notes-master/res/values/themes.xml
new file mode 100644
index 0000000..d28505f
--- /dev/null
+++ b/src/xiaomi/Notes-master/res/values/themes.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/compiler.xml b/src/xiaomi/Notes-master/src/.idea/compiler.xml
new file mode 100644
index 0000000..b589d56
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/deploymentTargetDropDown.xml b/src/xiaomi/Notes-master/src/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 0000000..1bd7da7
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/gradle.xml b/src/xiaomi/Notes-master/src/.idea/gradle.xml
new file mode 100644
index 0000000..ae388c2
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/gradle.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/jarRepositories.xml b/src/xiaomi/Notes-master/src/.idea/jarRepositories.xml
new file mode 100644
index 0000000..a5f05cd
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/misc.xml b/src/xiaomi/Notes-master/src/.idea/misc.xml
index 6e86672..22fd288 100644
--- a/src/xiaomi/Notes-master/src/.idea/misc.xml
+++ b/src/xiaomi/Notes-master/src/.idea/misc.xml
@@ -1,5 +1,7 @@
-
-
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.androidTest.iml b/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.androidTest.iml
new file mode 100644
index 0000000..a926faa
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.androidTest.iml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.iml b/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.iml
new file mode 100644
index 0000000..2eca338
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.iml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.main.iml b/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.main.iml
new file mode 100644
index 0000000..0c29fd6
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.main.iml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.unitTest.iml b/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.unitTest.iml
new file mode 100644
index 0000000..592ad00
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/modules/app/note.app.unitTest.iml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/modules/note.iml b/src/xiaomi/Notes-master/src/.idea/modules/note.iml
new file mode 100644
index 0000000..f7c4b58
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/modules/note.iml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint.xml b/src/xiaomi/Notes-master/src/.idea/sonarlint.xml
new file mode 100644
index 0000000..0274d16
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/1/0141ed096ee7cdbb52dc6a8b0e8eae49847eb64a b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/1/0141ed096ee7cdbb52dc6a8b0e8eae49847eb64a
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/2/023468cfdd0b71d4098903b9070e364658e2fbcf b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/2/023468cfdd0b71d4098903b9070e364658e2fbcf
new file mode 100644
index 0000000..74887fa
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/2/023468cfdd0b71d4098903b9070e364658e2fbcf
@@ -0,0 +1,20 @@
+
+F
+java:S1604"(Make this anonymous inner class a lambda(î81
+] java:S125""; it is deprecated.(܃81
+T
+java:S1874k"7Remove this use of "getNotification"; it is deprecated.(81
+m
+java:S1874"JDon't override a deprecated method or explicitly mark it as "@Deprecated".(ë81
+m
+java:S1874"JDon't override a deprecated method or explicitly mark it as "@Deprecated".(ች81
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/2/0268ec648e2fc0139b30ed13396174b7392c1ae2 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/2/0268ec648e2fc0139b30ed13396174b7392c1ae2
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/5/059344fcf15ea97de6a49cb73ae11dae7df3bf9c b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/5/059344fcf15ea97de6a49cb73ae11dae7df3bf9c
new file mode 100644
index 0000000..5548b5f
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/5/059344fcf15ea97de6a49cb73ae11dae7df3bf9c
@@ -0,0 +1,5 @@
+
+f java:S117%"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+l java:S116"WRename this field "trans_result" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(ų
+h java:S100!"NRename this method name to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+c java:S100%"NRename this method name to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/8/08b014011bf36107e05430e2372a86de8048f107 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/8/08b014011bf36107e05430e2372a86de8048f107
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/8/08c35f02f11c35ae9ebf8db0a482054dfa1cf493 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/8/08c35f02f11c35ae9ebf8db0a482054dfa1cf493
new file mode 100644
index 0000000..c100822
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/8/08c35f02f11c35ae9ebf8db0a482054dfa1cf493
@@ -0,0 +1,11 @@
+
+s
+java:S4144"\Update this method so that its implementation is not identical to "getParentId" on line 185.(
+>
+java:S1125T"(Remove the unnecessary boolean literals.(
+m
+java:S3776p"RRefactor this method to reduce its Cognitive Complexity from 18 to the 15 allowed.(
+C
+java:S1125q"(Remove the unnecessary boolean literals.(
+>
+java:S1125r"(Remove the unnecessary boolean literals.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/f/0f0f0549145d0e2bfb972ba1ed2e2c38bfd6d1b1 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/0/f/0f0f0549145d0e2bfb972ba1ed2e2c38bfd6d1b1
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/0/102ed1bbec66cf4d2c859a294d53f757520c9c3a b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/0/102ed1bbec66cf4d2c859a294d53f757520c9c3a
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/7/175d8fa829f0a7ced6aa11970f112de6ad144628 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/7/175d8fa829f0a7ced6aa11970f112de6ad144628
new file mode 100644
index 0000000..9c3a0d2
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/7/175d8fa829f0a7ced6aa11970f112de6ad144628
@@ -0,0 +1,2 @@
+
+a java:S101"MRename this class name to match the regular expression '^[A-Z][a-zA-Z0-9]*$'.(u
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/e/1eb2363b523dbcae43d3c6e4790c64436af61b13 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/e/1eb2363b523dbcae43d3c6e4790c64436af61b13
new file mode 100644
index 0000000..0ec5756
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/e/1eb2363b523dbcae43d3c6e4790c64436af61b13
@@ -0,0 +1,25 @@
+
+}
+java:S1192A"[Define a constant instead of duplicating this literal " TEXT NOT NULL DEFAULT ''," 5 times.(81
+j
+java:S1192e"HDefine a constant instead of duplicating this literal " BEGIN " 4 times.(81
+h
+java:S1192t"FDefine a constant instead of duplicating this literal "=old." 6 times.(81
+j
+java:S1192"GDefine a constant instead of duplicating this literal " BEGIN" 6 times.(81
+{
+java:S1192:"^Define a constant instead of duplicating this literal " INTEGER NOT NULL DEFAULT 0," 11 times.(81
+f
+java:S1192h"IDefine a constant instead of duplicating this literal " WHERE " 8 times.(랰81
+c
+java:S1192h"FDefine a constant instead of duplicating this literal "=new." 6 times.(랰81
+o
+java:S1192"RDefine a constant instead of duplicating this literal " AFTER DELETE ON " 3 times.(B81
+j
+java:S1192g"HDefine a constant instead of duplicating this literal " SET " 8 times.(˓81
+g
+java:S1192f"JDefine a constant instead of duplicating this literal " UPDATE " 8 times.(81
+
+java:S1192="yDefine a constant instead of duplicating this literal " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," 4 times.(81
+`
+java:S1214-"CMove constants defined in this interfaces to another class or enum.(81
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/f/1f37b3287e9e1f293b5edaa624e3963f9b0959e3 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/1/f/1f37b3287e9e1f293b5edaa624e3963f9b0959e3
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/2/8/283f16cc23da56ca65616082bc810304d3511d0a b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/2/8/283f16cc23da56ca65616082bc810304d3511d0a
new file mode 100644
index 0000000..6180d5c
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/2/8/283f16cc23da56ca65616082bc810304d3511d0a
@@ -0,0 +1,39 @@
+
+t
+java:S22930"YReplace the type specification in this constructor call with the diamond operator ("<>").(ə
+o
+java:S2293]"YReplace the type specification in this constructor call with the diamond operator ("<>").(
+v
+java:S2293m"YReplace the type specification in this constructor call with the diamond operator ("<>").(Ȫ8ƙ1
+J
+java:S1066U"/Merge this if statement with the enclosing one.(ڧ
+
+java:S1319\"mThe return type of this method should be an interface such as "Set" rather than the implementation "HashSet".(
+
+java:S1319l"mThe return type of this method should be an interface such as "Set" rather than the implementation "HashSet".(
+j
+java:S1104*"TMake widgetId a static final constant or non-public and provide accessors if needed.(ǎ
+q
+java:S1104+"VMake widgetType a static final constant or non-public and provide accessors if needed.(漬
+C
+java:S5411_"(Use a primitive boolean expression here.(ɯ
+C
+java:S5411o"(Use a primitive boolean expression here.(ɯ
+D
+java:S5411"(Use a primitive boolean expression here.(
+7
+java:S1116,"Remove this empty statement.(
+D
+java:S1874/".Remove this use of ""; it is deprecated.(
+J
+java:S2864^"4Iterate over the "entrySet" instead of the "keySet".(
+B
+java:S1125_"'Remove the unnecessary boolean literal.(ɯ
+J
+java:S2864n"4Iterate over the "entrySet" instead of the "keySet".(
+B
+java:S1125o"'Remove the unnecessary boolean literal.(ɯ
+A
+java:S1168|"+Return an empty collection instead of null.(
+C
+java:S1125"'Remove the unnecessary boolean literal.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/2/b/2b687ab930681e3885683578d43df600a0a20982 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/2/b/2b687ab930681e3885683578d43df600a0a20982
new file mode 100644
index 0000000..7dba34d
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/2/b/2b687ab930681e3885683578d43df600a0a20982
@@ -0,0 +1,2 @@
+
+b java:S101"MRename this class name to match the regular expression '^[A-Z][a-zA-Z0-9]*$'.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/2/b/2bfc771e07e87c37d3a76a2c815bc8fb30649798 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/2/b/2bfc771e07e87c37d3a76a2c815bc8fb30649798
new file mode 100644
index 0000000..ca059b8
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/2/b/2bfc771e07e87c37d3a76a2c815bc8fb30649798
@@ -0,0 +1,10 @@
+
+>
+java:S1604/"(Make this anonymous inner class a lambda(˽
+h java:S100("NRename this method name to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+
+java:S3923P"]This conditional operation returns the same value whether the condition is "true" or "false".(81
+W
+java:S1874P"5Remove this use of "FORMAT_24HOUR"; it is deprecated.(81
+W
+java:S1874P"5Remove this use of "FORMAT_24HOUR"; it is deprecated.(81
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/1/3187a48b72709826e298c008a0076f24e6739bb9 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/1/3187a48b72709826e298c008a0076f24e6739bb9
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/2/32360bf24febc78f20db52498c7576b3d8650d56 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/2/32360bf24febc78f20db52498c7576b3d8650d56
new file mode 100644
index 0000000..700f7d0
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/2/32360bf24febc78f20db52498c7576b3d8650d56
@@ -0,0 +1,31 @@
+
+{
+java:S2293B"YReplace the type specification in this constructor call with the diamond operator ("<>").(л8٢1
+{
+java:S2293{"YReplace the type specification in this constructor call with the diamond operator ("<>").(л8٢1
+|
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(ª8٢1
+i
+java:S1192V"GDefine a constant instead of duplicating this literal "%s: %s" 4 times.(8٢1
+k
+java:S1192"HDefine a constant instead of duplicating this literal "=? AND " 4 times.(8٢1
+
+java:S1319"mThe return type of this method should be an interface such as "Set" rather than the implementation "HashSet".(8٢1
+[
+java:S2589"8Remove this expression which always evaluates to "false"(Ύ8Ԥ1
+\
+java:S1118-":Add a private constructor to hide the implicit public one.(8Dž٢1
+[
+java:S1155=">Use isEmpty() to check whether the collection is empty or not.(8˅٢1
+a
+java:S2147W"DCombine this catch with the one at line 85, which has the same body.(暩8ͅ٢1
+c
+java:S2147"ECombine this catch with the one at line 141, which has the same body.(暩8х٢1
+r
+java:S3252"OUse static access with "net.micode.notes.data.Notes$DataColumns" for "NOTE_ID".(8ׅ٢1
+t
+java:S3252"QUse static access with "net.micode.notes.data.Notes$DataColumns" for "MIME_TYPE".(8٢1
+m
+java:S3252"OUse static access with "net.micode.notes.data.Notes$DataColumns" for "NOTE_ID".(ʹ8م٢1
+t
+java:S3252"QUse static access with "net.micode.notes.data.Notes$DataColumns" for "MIME_TYPE".(8م٢1
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/3/332c6f3d75926e4702a2bec3dcc4f101b096d5a2 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/3/332c6f3d75926e4702a2bec3dcc4f101b096d5a2
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/5/35a9534af99716b62a1b2f926cda2640ed66437c b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/5/35a9534af99716b62a1b2f926cda2640ed66437c
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/7/37550df0e109549c2d1812a772295c27266c06ab b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/7/37550df0e109549c2d1812a772295c27266c06ab
new file mode 100644
index 0000000..23d2090
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/7/37550df0e109549c2d1812a772295c27266c06ab
@@ -0,0 +1,7 @@
+
+z
+java:S1149"_Replace the synchronized class "StringBuffer" by an unsynchronized one such as "StringBuilder".(쭊
+U
+java:S1118":Add a private constructor to hide the implicit public one.(
+N
+java:S4719"9Replace charset name argument with StandardCharsets.UTF_8(Ðm
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/a/3aac5305cb73bfbdeb8078cd264d04323fa80e92 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/a/3aac5305cb73bfbdeb8078cd264d04323fa80e92
new file mode 100644
index 0000000..24fb08d
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/a/3aac5305cb73bfbdeb8078cd264d04323fa80e92
@@ -0,0 +1,3 @@
+
+O
+java:S59932"9Change the visibility of this constructor to "protected".(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/d/3d0874cd378575c7e6e0973b184f167b3941748f b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/d/3d0874cd378575c7e6e0973b184f167b3941748f
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/e/3e688be40dc69cfd1062f41d0fc27fe261a26710 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/e/3e688be40dc69cfd1062f41d0fc27fe261a26710
new file mode 100644
index 0000000..9739a47
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/e/3e688be40dc69cfd1062f41d0fc27fe261a26710
@@ -0,0 +1,29 @@
+
+g
+java:S1301"KReplace this "switch" statement by "if" statements to increase readability.(۫
+X
+java:S18747"=Remove this use of "FLAG_SHOW_WHEN_LOCKED"; it is deprecated.(
+Q
+java:S1874;";Remove this use of "FLAG_TURN_SCREEN_ON"; it is deprecated.(
+Z
+java:S1874="?Remove this use of "FLAG_LAYOUT_INSET_DECOR"; it is deprecated.(
+H
+java:S1874X"2Remove this use of "isScreenOn"; it is deprecated.(
+O
+java:S1874b":Remove this use of "setAudioStreamType"; it is deprecated.(0
+U
+java:S1874d":Remove this use of "setAudioStreamType"; it is deprecated.(Ũ
+`
+java:S2147n"ECombine this catch with the one at line 107, which has the same body.(
+[
+java:S2147q"ECombine this catch with the one at line 110, which has the same body.(
+[
+java:S2147t"ECombine this catch with the one at line 113, which has the same body.(ﭣ
+M
+java:S1135l"2Complete the task associated to this TODO comment.(̐
+M
+java:S1135o"2Complete the task associated to this TODO comment.(̐
+M
+java:S1135r"2Complete the task associated to this TODO comment.(̐
+M
+java:S1135u"2Complete the task associated to this TODO comment.(̐
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/f/3f52e8daf4bdfa7bee6741acd1bf90ffe7709f9a b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/3/f/3f52e8daf4bdfa7bee6741acd1bf90ffe7709f9a
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/4/3/4382a5e52a040a8135b4c0fc2653f95c42c8766b b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/4/3/4382a5e52a040a8135b4c0fc2653f95c42c8766b
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/4/5/4529b3a97b0f3b19b895aa06f23bed63ff38a312 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/4/5/4529b3a97b0f3b19b895aa06f23bed63ff38a312
new file mode 100644
index 0000000..1917e5d
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/4/5/4529b3a97b0f3b19b895aa06f23bed63ff38a312
@@ -0,0 +1,29 @@
+
+|
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(各81
+i
+java:S2184"FCast one of the operands of this multiplication operation to a "long".(⣛81
+[
+java:S1874S"9Remove this use of "DefaultHttpClient"; it is deprecated.(믥8ٵ1
+P
+java:S1874"2Remove this use of "HttpParams"; it is deprecated.(ֶ81
+U
+java:S1874"7Remove this use of "BasicHttpParams"; it is deprecated.(ֶ81
+_
+java:S1874"").(
+D
+java:S1604"(Make this anonymous inner class a lambda(
+m
+java:S1301h"KReplace this "switch" statement by "if" statements to increase readability.(81
+M
+java:S1135c"2Complete the task associated to this TODO comment.(
+C java:S131h""Add a default case to this switch.(8ȕ1
+^
+java:S1126"BReplace this if-then-else statement by a single method invocation.(忥
+P
+java:S2864"4Iterate over the "entrySet" instead of the "keySet".(Κ
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/7/577f30d26378ec8a2bd2e4a43f3c79b3f04c402c b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/7/577f30d26378ec8a2bd2e4a43f3c79b3f04c402c
new file mode 100644
index 0000000..c0ce420
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/7/577f30d26378ec8a2bd2e4a43f3c79b3f04c402c
@@ -0,0 +1,145 @@
+
+L
+java:S3740l"/Provide the parametrized type for this generic.(Ȁ81
+M
+java:S3740"/Provide the parametrized type for this generic.(81
+{
+java:S2293z"YReplace the type specification in this constructor call with the diamond operator ("<>").(ӏ81
+|
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(81
+|
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(81
+w
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(81
+w
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(艥81
+f
+java:S1192"HDefine a constant instead of duplicating this literal "[local]" 3 times.(81
+g
+java:S1192"IDefine a constant instead of duplicating this literal "[/local]" 3 times.(81
+n java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+s java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+s java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+s java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+n java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+n java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+n java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(ţ81
+E
+java:S1604"(Make this anonymous inner class a lambda(81
+K
+java:S1604"(Make this anonymous inner class a lambda(81
+F
+java:S1604"(Make this anonymous inner class a lambda(81
+K
+java:S1604"(Make this anonymous inner class a lambda(81
+F
+java:S1604"(Make this anonymous inner class a lambda(Ư81
+K
+java:S1604"(Make this anonymous inner class a lambda(81
+K
+java:S1604"(Make this anonymous inner class a lambda(81
+K
+java:S1604"(Make this anonymous inner class a lambda(ö81
+K
+java:S1604"(Make this anonymous inner class a lambda(81
+K
+java:S1604"(Make this anonymous inner class a lambda(81
+F
+java:S1604"(Make this anonymous inner class a lambda(ά81
+F
+java:S1604"(Make this anonymous inner class a lambda(81
+F
+java:S1604
+"(Make this anonymous inner class a lambda(ߒ81
+n
+java:S1301"KReplace this "switch" statement by "if" statements to increase readability.(81
+x
+java:S1104q"VMake tvModified a static final constant or non-public and provide accessors if needed.(ԣ81
+y
+java:S1104s"WMake ivAlertIcon a static final constant or non-public and provide accessors if needed.(න81
+y
+java:S1104u"WMake tvAlertDate a static final constant or non-public and provide accessors if needed.(81
+z
+java:S1104w"XMake ibSetBgColor a static final constant or non-public and provide accessors if needed.(81
+y java:S116"\Rename this field "restore_translate" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+u java:S116"XRename this field "PHOTO_REQUEST" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+y java:S116"\Rename this field "MAX_OF_RVOKE_TIME" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(խ81
+?
+java:S1170"!Make this final field static too.(81
+?
+java:S1170"!Make this final field static too.(խ81
+u
+java:S1450"WRemove the "mPattern" field and declare it as a local variable in the relevant methods.(81
+m
+java:S1149l"PReplace the synchronized class "Stack" by an unsynchronized one such as "Deque".(Ȁ81
+n
+java:S1149"PReplace the synchronized class "Stack" by an unsynchronized one such as "Deque".(81
+e
+java:S5361"HReplace this call to "replaceAll()" by a call to the "replace()" method.(v81
+L
+java:S2140")Use "java.util.Random.nextInt()" instead.(81
+e
+java:S5361"HReplace this call to "replaceAll()" by a call to the "replace()" method.(v81
+L
+java:S2140")Use "java.util.Random.nextInt()" instead.(81
+p
+java:S3252"MUse static access with "android.text.Spanned" for "SPAN_EXCLUSIVE_EXCLUSIVE".(81
+X
+java:S1161":Add the "@Override" annotation above this method signature(81
+j
+java:S3252"MUse static access with "android.text.Spanned" for "SPAN_EXCLUSIVE_EXCLUSIVE".(T81
+u
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 26 to the 15 allowed.(ݨ81
+^
+java:S1874"@Remove this use of "SOFT_INPUT_ADJUST_RESIZE"; it is deprecated.(ѯ81
+c
+java:S1874"@Remove this use of "SOFT_INPUT_ADJUST_RESIZE"; it is deprecated.(ң81
+V
+java:S1874"9Remove this use of "setTextAppearance"; it is deprecated.((81
+R
+java:S2864"4Iterate over the "entrySet" instead of the "keySet".(ԇ81
+U
+java:S1135"2Complete the task associated to this TODO comment.(81
+?
+java:S1116"Remove this empty statement.(81
+_
+java:S1126"AReplace this if-then-else statement by a single return statement.(81
+?
+java:S1116"Remove this empty statement.(81
+W
+java:S1874"9Remove this use of "PreferenceManager"; it is deprecated.(81
+a
+java:S1874"CRemove this use of "getDefaultSharedPreferences"; it is deprecated.(81
+
+java:S1186"Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.(81
+
+java:S1186"Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.(ʥ81
+9
+java:S3626"Remove this redundant jump.(݅81
+
+java:S1186"Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.(81
+> java:S131""Add a default case to this switch.(V81
+W
+java:S1874"9Remove this use of "setTextAppearance"; it is deprecated.(81
+m
+java:S1874"JDon't override a deprecated method or explicitly mark it as "@Deprecated".(81
+X
+java:S1874"5Remove this use of "onBackPressed"; it is deprecated.(81
+N
+java:S1874 "0Remove this use of "getColor"; it is deprecated.(81
+k
+java:S3252 "MUse static access with "android.text.Spanned" for "SPAN_INCLUSIVE_EXCLUSIVE".(81
+\
+java:S1874
+"9Remove this use of "setTextAppearance"; it is deprecated.(81
+[
+java:S1874
+"=Remove this use of "EXTRA_SHORTCUT_INTENT"; it is deprecated.(ð81
+Y
+java:S1874
+";Remove this use of "EXTRA_SHORTCUT_NAME"; it is deprecated.(81
+b
+java:S1874
+"DRemove this use of "EXTRA_SHORTCUT_ICON_RESOURCE"; it is deprecated.(Ǿ81
+S
+java:S1068"5Remove this unused "MAX_OF_RVOKE_TIME" private field.(խ81
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/8/58052a8597c5f01595e1c849728bcae66c27a1a6 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/8/58052a8597c5f01595e1c849728bcae66c27a1a6
new file mode 100644
index 0000000..07745a6
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/8/58052a8597c5f01595e1c849728bcae66c27a1a6
@@ -0,0 +1,5 @@
+
+3
+java:S2386$"Make this member "protected".(
+h
+java:S3776H"RRefactor this method to reduce its Cognitive Complexity from 19 to the 15 allowed.(ʃ
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/8/5836a695995df8fadacfa6409fe8d21d88946842 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/8/5836a695995df8fadacfa6409fe8d21d88946842
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/b/5b5ea9e282b6b4d24438f217e6084a02a5631461 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/b/5b5ea9e282b6b4d24438f217e6084a02a5631461
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/c/5c5b5eab7e2212ceb1df9a9df360f7b74086f035 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/c/5c5b5eab7e2212ceb1df9a9df360f7b74086f035
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/d/5dfe6902d8ec740690f88d644e74362c3be08fad b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/d/5dfe6902d8ec740690f88d644e74362c3be08fad
new file mode 100644
index 0000000..505f811
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/d/5dfe6902d8ec740690f88d644e74362c3be08fad
@@ -0,0 +1,9 @@
+
+m
+java:S37763"RRefactor this method to reduce its Cognitive Complexity from 16 to the 15 allowed.(
+O
+java:S1874?"9Remove this use of "setTextAppearance"; it is deprecated.(
+O
+java:S1874F"9Remove this use of "setTextAppearance"; it is deprecated.(
+O
+java:S1874P"9Remove this use of "setTextAppearance"; it is deprecated.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/f/5f6162ca79fcea353b280c5dc84973a9c37d2c74 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/5/f/5f6162ca79fcea353b280c5dc84973a9c37d2c74
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/7/67def85328d91007d9c01c410f35fe30f09e547a b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/7/67def85328d91007d9c01c410f35fe30f09e547a
new file mode 100644
index 0000000..7ab336d
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/7/67def85328d91007d9c01c410f35fe30f09e547a
@@ -0,0 +1,24 @@
+
+k
+java:S1192"PDefine a constant instead of duplicating this literal "user management" 3 times.(
+k java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+C
+java:S1604%"(Make this anonymous inner class a lambda(
+p java:S116"VRename this field "lg_password" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(ǝ
+m java:S116"SRename this field "lg_login" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+U
+java:S1161":Add the "@Override" annotation above this method signature(
+B
+java:S1125"'Remove the unnecessary boolean literal.(
+[
+java:S1874!"@Remove this use of "SOFT_INPUT_ADJUST_RESIZE"; it is deprecated.(
+B
+java:S1125)"'Remove the unnecessary boolean literal.(
+B
+java:S1125)"'Remove the unnecessary boolean literal.(
+>
+java:S11726"(Remove this unused method parameter "v".(醆
+B
+java:S11259"'Remove the unnecessary boolean literal.(
+B
+java:S11259"'Remove the unnecessary boolean literal.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/a/6a65e747031f27aef20597b4181148a9fbf963d5 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/a/6a65e747031f27aef20597b4181148a9fbf963d5
new file mode 100644
index 0000000..e73c6ad
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/a/6a65e747031f27aef20597b4181148a9fbf963d5
@@ -0,0 +1,13 @@
+
+i
+java:S1192"MDefine a constant instead of duplicating this literal "Unknown URI " 4 times.(
+M
+java:S1153"1Directly append the argument of String.valueOf().(ߦ
+
+java:S3008O"eRename this field "NOTES_SNIPPET_SEARCH_QUERY" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+Z
+java:S1659"CDeclare "noteId" and all following declarations on a separate line.(؆
+T
+java:S2130"8Use "Long.parseLong" for this string-to-long conversion.(
+N
+java:S1135"2Complete the task associated to this TODO comment.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/c/6cbf8bd9aa98eff862b1dc067330ba66ba4493aa b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/c/6cbf8bd9aa98eff862b1dc067330ba66ba4493aa
new file mode 100644
index 0000000..bdfcc68
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/c/6cbf8bd9aa98eff862b1dc067330ba66ba4493aa
@@ -0,0 +1,11 @@
+
+>
+java:S1604C"(Make this anonymous inner class a lambda(
+C
+java:S1604L"(Make this anonymous inner class a lambda(Ҵѝ
+C
+java:S1604v"(Make this anonymous inner class a lambda(ё
+?
+java:S1604"(Make this anonymous inner class a lambda(
+V
+java:S3398"?Move this method into the anonymous class declared at line 118.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/d/6ddcb085768c932a738db492683008cbdb890323 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/6/d/6ddcb085768c932a738db492683008cbdb890323
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/7/8/78b400021a4b67de1cb9c996b2d32e042fc1fec3 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/7/8/78b400021a4b67de1cb9c996b2d32e042fc1fec3
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/7/c/7cca4a2d94815c47d6a1ce79d4f7ac1c41c7b766 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/7/c/7cca4a2d94815c47d6a1ce79d4f7ac1c41c7b766
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/7/e/7e6c62cbf2db3592d39ae44d7f78b9e37151187e b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/7/e/7e6c62cbf2db3592d39ae44d7f78b9e37151187e
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/7/876016634c6642b35109680ccac740dc8271b236 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/7/876016634c6642b35109680ccac740dc8271b236
new file mode 100644
index 0000000..8075051
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/7/876016634c6642b35109680ccac740dc8271b236
@@ -0,0 +1,11 @@
+
+F
+java:S1066"/Merge this if statement with the enclosing one.(
+3
+java:S2386A"Make this member "protected".(
+8
+java:S2386K"Make this member "protected".(㳎
+X
+java:S1126"AReplace this if-then-else statement by a single return statement.(
+?
+java:S1125"(Remove the unnecessary boolean literals.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/c/8c55c3ccc257e5907959013f99656e4c8ec3903e b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/c/8c55c3ccc257e5907959013f99656e4c8ec3903e
new file mode 100644
index 0000000..0aaf4bc
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/c/8c55c3ccc257e5907959013f99656e4c8ec3903e
@@ -0,0 +1,2 @@
+
+R xml:S5594J"1Implement permissions on this exported component.(81
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/c/8ccff78d0b5f6e2c2b5ae03eaa6292c9713ee7d6 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/c/8ccff78d0b5f6e2c2b5ae03eaa6292c9713ee7d6
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/c/8cf262ff863a428f83cbb01e6c2c868635cf7758 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/8/c/8cf262ff863a428f83cbb01e6c2c868635cf7758
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/3/934a4e2abf19d28a53f6aeb1dcd99248c44b6892 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/3/934a4e2abf19d28a53f6aeb1dcd99248c44b6892
new file mode 100644
index 0000000..f6fc1de
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/3/934a4e2abf19d28a53f6aeb1dcd99248c44b6892
@@ -0,0 +1,5 @@
+
+2
+java:S2386+"Make this member "protected".(X
+n
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 16 to the 15 allowed.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/6/969faa2a5d9f5e8390e958d2c07f2cfd54676e6b b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/6/969faa2a5d9f5e8390e958d2c07f2cfd54676e6b
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/7/97872a23506db5ffaa04e04bd96b003493352c30 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/7/97872a23506db5ffaa04e04bd96b003493352c30
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/a/9a3a19793537958b8b1b03a81985999e22705a2f b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/a/9a3a19793537958b8b1b03a81985999e22705a2f
new file mode 100644
index 0000000..8d3183b
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/a/9a3a19793537958b8b1b03a81985999e22705a2f
@@ -0,0 +1,11 @@
+
+{
+java:S2293<"YReplace the type specification in this constructor call with the diamond operator ("<>").(81
+W
+java:S1118%":Add a private constructor to hide the implicit public one.(81
+x
+java:S3252*"VUse static access with "android.provider.ContactsContract$DataColumns" for "MIMETYPE".(81
+y
+java:S3252+"\Use static access with "android.provider.ContactsContract$DataColumns" for "RAW_CONTACT_ID".(81
+{
+java:S3252G"^Use static access with "android.provider.ContactsContract$ContactsColumns" for "DISPLAY_NAME".(81
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/b/9b09a4d37e3aec64adadab801bb8fec4165ad88f b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/b/9b09a4d37e3aec64adadab801bb8fec4165ad88f
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/b/9b9043453e9b19b073719a8b4a2a505b6be3e813 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/b/9b9043453e9b19b073719a8b4a2a505b6be3e813
new file mode 100644
index 0000000..3286f29
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/9/b/9b9043453e9b19b073719a8b4a2a505b6be3e813
@@ -0,0 +1,14 @@
+
+C
+java:S1604 "(Make this anonymous inner class a lambda(Ț
+R
+java:S2589,"7Remove this expression which always evaluates to "true"(
+[
+java:S1874"@Remove this use of "SOFT_INPUT_ADJUST_RESIZE"; it is deprecated.(ң
+B
+java:S1125%"'Remove the unnecessary boolean literal.(
+B
+java:S1125("'Remove the unnecessary boolean literal.(
+B
+java:S1125,"'Remove the unnecessary boolean literal.(
+V java:S125>"":Add a private constructor to hide the implicit public one.(͓81
+e
+java:S1214Q"CMove constants defined in this interfaces to another class or enum.(⸫81
+a
+java:S1214"CMove constants defined in this interfaces to another class or enum.(81
+]
+java:S1118":Add a private constructor to hide the implicit public one.(81
+X
+java:S1118":Add a private constructor to hide the implicit public one.(߀81
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/a/7/a776bfcfd1e96d15feaf2298b0b92948bb96533f b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/a/7/a776bfcfd1e96d15feaf2298b0b92948bb96533f
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/a/8/a87f8f57552c5dfdfa05925191567fb8f803b5e9 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/a/8/a87f8f57552c5dfdfa05925191567fb8f803b5e9
new file mode 100644
index 0000000..e1c0301
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/a/8/a87f8f57552c5dfdfa05925191567fb8f803b5e9
@@ -0,0 +1,32 @@
+
+f java:S117)"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+f java:S117*"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(Ӏ
+k java:S117+"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(ۉ
+e java:S1170"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+C
+java:S1604&"(Make this anonymous inner class a lambda(
+M
+java:S2589<"7Remove this expression which always evaluates to "true"(嚹
+M
+java:S2589<"7Remove this expression which always evaluates to "true"(嚹
+p java:S116"VRename this field "OldPassword" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+k java:S116"VRename this field "NewPassword" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(
+k java:S116"VRename this field "AckPassword" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(ć
+l java:S116"WRename this field "Acknowledged" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(ХӃ
+[
+java:S1874"@Remove this use of "SOFT_INPUT_ADJUST_RESIZE"; it is deprecated.(ң
+=
+java:S11251"'Remove the unnecessary boolean literal.(줗
+=
+java:S11251"'Remove the unnecessary boolean literal.(줗
+=
+java:S11251"'Remove the unnecessary boolean literal.(줗
+B
+java:S11254"'Remove the unnecessary boolean literal.(Ö
+B
+java:S11258"'Remove the unnecessary boolean literal.(饎
+=
+java:S1125<"'Remove the unnecessary boolean literal.(嚹
+=
+java:S1125<"'Remove the unnecessary boolean literal.(嚹
+V java:S125J"").(艥8ҍ1
+i
+java:S1192"FDefine a constant instead of duplicating this literal " DESC" 3 times.(ͨ8Ӎ1
+m java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(#8Ս1
+n java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+n java:S117"QRename this local variable to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(Œ81
+E
+java:S1604"(Make this anonymous inner class a lambda(̺V8֍1
+F
+java:S1604"(Make this anonymous inner class a lambda(ά8֍1
+F
+java:S1604"(Make this anonymous inner class a lambda(ܴ8֍1
+K
+java:S1604"(Make this anonymous inner class a lambda(8֍1
+F
+java:S1604"(Make this anonymous inner class a lambda(8֍1
+F
+java:S1604"(Make this anonymous inner class a lambda(۱8֍1
+F
+java:S1604"(Make this anonymous inner class a lambda(ά8֍1
+K
+java:S1604"(Make this anonymous inner class a lambda(81
+K
+java:S1604"(Make this anonymous inner class a lambda(81
+t
+java:S1104W"WMake secret_mode a static final constant or non-public and provide accessors if needed.(8؍1
+N
+java:S1444W"1Make this "public static secret_mode" field final(8؍1
+s
+java:S3008W"VRename this field "secret_mode" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(8я1
+>
+java:S1116f"Remove this empty statement.(8ޏ1
+h
+java:S1124"EReorder the modifiers to comply with the Java Language Specification.(8ޏ1
+b
+java:S1124"EReorder the modifiers to comply with the Java Language Specification.(Ѿk8ޏ1
+u
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 17 to the 15 allowed.(81
+9
+java:S3626"Remove this redundant jump.(݅81
+9
+java:S3626"Remove this redundant jump.(݅81
+9
+java:S3626"Remove this redundant jump.(݅81
+W
+java:S1874"9Remove this use of "PreferenceManager"; it is deprecated.(81
+a
+java:S1874"CRemove this use of "getDefaultSharedPreferences"; it is deprecated.(81
+U
+java:S1135"2Complete the task associated to this TODO comment.(̐81
+M
+java:S2093"*Change this "try" to a try-with-resources.(81
+v
+java:S1450"XRemove the "mMoveMenu" field and declare it as a local variable in the relevant methods.(81
+u
+java:S3252"RUse static access with "android.widget.AbsListView" for "MultiChoiceModeListener".(81
+U
+java:S1135"2Complete the task associated to this TODO comment.(81
+U
+java:S1135"2Complete the task associated to this TODO comment.(81
+\
+java:S1874"9Remove this use of "getDefaultDisplay"; it is deprecated.(ĸ81
+T
+java:S1874"1Remove this use of "getHeight"; it is deprecated.(81
+?
+java:S1116"Remove this empty statement.(81
+p
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 20 to the 15 allowed.(81
+J
+java:S1874".Remove this use of ""; it is deprecated.(?81
+F java:S108")Either remove or fill this block of code.(ʥ81
+h
+java:S1874"JDon't override a deprecated method or explicitly mark it as "@Deprecated".(Ϳ81
+R
+java:S1874"/Remove this use of "execute"; it is deprecated.(嫏81
+Z
+java:S1874"7Remove this use of "toggleSoftInput"; it is deprecated.(81
+V
+java:S1874"3Remove this use of "SHOW_FORCED"; it is deprecated.(81
+o
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 17 to the 15 allowed.(#81
+U
+java:S1135"2Complete the task associated to this TODO comment.(81
+e
+java:S1126"BReplace this if-then-else statement by a single method invocation.(玒81
+U
+java:S1135"2Complete the task associated to this TODO comment.(81
+m
+java:S1874"JDon't override a deprecated method or explicitly mark it as "@Deprecated".(81
+X
+java:S1874"5Remove this use of "onBackPressed"; it is deprecated.(81
+p java:S100"NRename this method name to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+k java:S100"NRename this method name to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(ޭ81
+p java:S100"NRename this method name to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(81
+p
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 32 to the 15 allowed.(81
+E
+java:S1125"'Remove the unnecessary boolean literal.(ݳ81
+T
+java:S2696"6Make the enclosing method "static" or remove this set.(܁81
+T
+java:S2696"6Make the enclosing method "static" or remove this set.(81
+
+java:S1186"Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.(81
+Q
+java:S1874".Remove this use of ""; it is deprecated.(Ч81
+m
+java:S1874"JDon't override a deprecated method or explicitly mark it as "@Deprecated".(ች81
+R
+java:S1874"/Remove this use of "execute"; it is deprecated.(嫏81
+o
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 18 to the 15 allowed.(b81
+R
+java:S3398"/Move this method into "BackgroundQueryHandler".(81
+C
+java:S3398"%Move this method into "ModeCallback".(81
+H
+java:S3398"%Move this method into "ModeCallback".(81
+N
+java:S3398"0Move this method into "OnListItemClickListener".(81
+
+java:S6541"A "Brain Method" was detected. Refactor it to reduce at least one of the following metrics: LOC from 91 to 64, Complexity from 21 to 14, Nesting Level from 3 to 2, Number of Variables from 10 to 6.(81
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/b/8/b8499f45785f72f4359de65db54397412dc27996 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/b/8/b8499f45785f72f4359de65db54397412dc27996
new file mode 100644
index 0000000..47bc148
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/b/8/b8499f45785f72f4359de65db54397412dc27996
@@ -0,0 +1,13 @@
+
+C
+java:S1604"(Make this anonymous inner class a lambda(
+q java:S116"WRename this field "Acknowledged" to match the regular expression '^[a-z][a-zA-Z0-9]*$'.(σ
+[
+java:S1874"@Remove this use of "SOFT_INPUT_ADJUST_RESIZE"; it is deprecated.(ң
+B
+java:S1125 "'Remove the unnecessary boolean literal.(
+=
+java:S1125%"'Remove the unnecessary boolean literal.(٨
+=
+java:S1125%"'Remove the unnecessary boolean literal.(٨
+V java:S125:"
+java:S1604)"(Make this anonymous inner class a lambda(ʩ
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/1/d1d5c2a21bcee2c42fb71e493be5fa068951f155 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/1/d1d5c2a21bcee2c42fb71e493be5fa068951f155
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/2/d2281fbb3027de2722081a53408dd77628bf080e b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/2/d2281fbb3027de2722081a53408dd77628bf080e
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/5/d523c5f9a544775535a62275862e5be71ba0775f b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/5/d523c5f9a544775535a62275862e5be71ba0775f
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/6/d6094f02d3b882a8697c1462f3a5861b9b883946 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/6/d6094f02d3b882a8697c1462f3a5861b9b883946
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/8/d817b9340a5ced71d122f66b8d29cf7d6dfa79ab b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/8/d817b9340a5ced71d122f66b8d29cf7d6dfa79ab
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/a/da57ce446af85bbd9aefee65e969869f0cff78b0 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/a/da57ce446af85bbd9aefee65e969869f0cff78b0
new file mode 100644
index 0000000..1d90a67
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/a/da57ce446af85bbd9aefee65e969869f0cff78b0
@@ -0,0 +1,59 @@
+
+?
+java:S1604"(Make this anonymous inner class a lambda(
+?
+java:S1604"(Make this anonymous inner class a lambda(ܨ
+?
+java:S1604"(Make this anonymous inner class a lambda(ܨ
+?
+java:S1604"(Make this anonymous inner class a lambda(ά
+?
+java:S1604"(Make this anonymous inner class a lambda(څ
+?
+java:S1604"(Make this anonymous inner class a lambda(
+?
+java:S1604"(Make this anonymous inner class a lambda(î
+?
+java:S1604"(Make this anonymous inner class a lambda(î
+g
+java:S1301"KReplace this "switch" statement by "if" statements to increase readability.(崡
+U
+java:S18743":Remove this use of "PreferenceActivity"; it is deprecated.(
+P
+java:S1874@":Remove this use of "PreferenceCategory"; it is deprecated.(Θ
+`
+java:S1874I"JDon't override a deprecated method or explicitly mark it as "@Deprecated".(Θ
+K
+java:S1874J"0Remove this use of "onCreate"; it is deprecated.(ȢՖ
+P
+java:S1874P":Remove this use of "PreferenceCategory"; it is deprecated.(
+L
+java:S1874P"6Remove this use of "findPreference"; it is deprecated.(
+I
+java:S1874X"3Remove this use of "getListView"; it is deprecated.(د
+h
+java:S3776\"RRefactor this method to reduce its Cognitive Complexity from 20 to the 15 allowed.(٫
+`
+java:S1874x"JDon't override a deprecated method or explicitly mark it as "@Deprecated".(
+G
+java:S1874|"1Remove this use of "onDestroy"; it is deprecated.(ʷ
+H
+java:S1874"1Remove this use of "removeAll"; it is deprecated.(
+N
+java:S1874"2Remove this use of "Preference"; it is deprecated.(
+N
+java:S1874"2Remove this use of "Preference"; it is deprecated.(
+G
+java:S1874"0Remove this use of "setTitle"; it is deprecated.(
+N
+java:S1874"2Remove this use of "setSummary"; it is deprecated.(
+[
+java:S1874"DRemove this use of "setOnPreferenceClickListener"; it is deprecated.(
+N
+java:S1874"2Remove this use of "Preference"; it is deprecated.(
+Q
+java:S1874"5Remove this use of "addPreference"; it is deprecated.(ن
+a
+java:S1874"JDon't override a deprecated method or explicitly mark it as "@Deprecated".(
+Q
+java:S1161":Add the "@Override" annotation above this method signature(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/c/dcbf3204de74b48a299a1133f01f78857e115ba2 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/c/dcbf3204de74b48a299a1133f01f78857e115ba2
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/d/dd970bd8ce083850fca1d4d159647ccd110e57cb b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/d/dd970bd8ce083850fca1d4d159647ccd110e57cb
new file mode 100644
index 0000000..5405687
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/d/dd970bd8ce083850fca1d4d159647ccd110e57cb
@@ -0,0 +1,15 @@
+
+u
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(л
+j
+java:S1192?"ODefine a constant instead of duplicating this literal "Wrong note id:" 3 times.(
+O
+java:S2589"8Remove this expression which always evaluates to "false"(
+\
+java:S1126}"AReplace this if-then-else statement by a single return statement.(Ʒ
+i
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 23 to the 15 allowed.(
+U
+java:S1155">Use isEmpty() to check whether the collection is empty or not.(
+\
+java:S2147"ECombine this catch with the one at line 242, which has the same body.(暩
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/e/de9bd32c86ad3a18c044f9da0ae3a85c009232b0 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/d/e/de9bd32c86ad3a18c044f9da0ae3a85c009232b0
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/e/0/e094aec5c3e1b6f44539adff3114f5a1ad603ddc b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/e/0/e094aec5c3e1b6f44539adff3114f5a1ad603ddc
new file mode 100644
index 0000000..2f95060
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/e/0/e094aec5c3e1b6f44539adff3114f5a1ad603ddc
@@ -0,0 +1,9 @@
+
+t
+java:S2293*"YReplace the type specification in this constructor call with the diamond operator ("<>").(ʩ
+
+java:S1319"pThe return type of this method should be an interface such as "List" rather than the implementation "ArrayList".(ﷺ
+\
+java:S2259"@A "NullPointerException" could be thrown; "js" is nullable here.(
+r
+java:S3923"[Remove this conditional structure or edit its code blocks so that they're not all the same.(ԡ
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/e/4/e4a661e5de29d26ae56c43e59869580039c078be b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/e/4/e4a661e5de29d26ae56c43e59869580039c078be
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/0/f07866736216be0ee2aba49e392191aeae700a35
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/0/f087b1ba1b9c91b7293fea0fb071eaed62a42137 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/0/f087b1ba1b9c91b7293fea0fb071eaed62a42137
new file mode 100644
index 0000000..d710d2d
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/0/f087b1ba1b9c91b7293fea0fb071eaed62a42137
@@ -0,0 +1,25 @@
+
+g
+java:S1124$"EReorder the modifiers to comply with the Java Language Specification.(֖81
+g
+java:S1124&"EReorder the modifiers to comply with the Java Language Specification.(Ų81
+g
+java:S1124("EReorder the modifiers to comply with the Java Language Specification.(ز81
+g
+java:S1124*"EReorder the modifiers to comply with the Java Language Specification.(81
+b
+java:S1124,"EReorder the modifiers to comply with the Java Language Specification.(ճ81
+b
+java:S1124."EReorder the modifiers to comply with the Java Language Specification.(ߪ81
+b
+java:S11240"EReorder the modifiers to comply with the Java Language Specification.(81
+X
+java:S2696?"6Make the enclosing method "static" or remove this set.(Ȇ81
+S
+java:S2696@"6Make the enclosing method "static" or remove this set.(81
+L
+java:S1874E"/Remove this use of "execute"; it is deprecated.(81
+S
+java:S2696T"6Make the enclosing method "static" or remove this set.(81
+S
+java:S2696"6Make the enclosing method "static" or remove this set.(81
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/1/f1226eeacd46c914d51f3d1a6d6f27377490d2a4 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/1/f1226eeacd46c914d51f3d1a6d6f27377490d2a4
new file mode 100644
index 0000000..0b77e0d
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/1/f1226eeacd46c914d51f3d1a6d6f27377490d2a4
@@ -0,0 +1,15 @@
+
+u
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(
+u
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(
+u
+java:S2293"YReplace the type specification in this constructor call with the diamond operator ("<>").(
+2
+java:S2386."Make this member "protected".(u
+n
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 91 to the 15 allowed.(
+h
+java:S3776"RRefactor this method to reduce its Cognitive Complexity from 32 to the 15 allowed.(
+
+java:S6541"A "Brain Method" was detected. Refactor it to reduce at least one of the following metrics: LOC from 116 to 64, Complexity from 51 to 14, Nesting Level from 6 to 2, Number of Variables from 23 to 6.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/4/f4a01d6a4fcb971362ec00a83903fd3902f52164 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/4/f4a01d6a4fcb971362ec00a83903fd3902f52164
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/7/f79cc2688e29fcbc286fda14ae07b27c9e83690f b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/7/f79cc2688e29fcbc286fda14ae07b27c9e83690f
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/8/f880b4c44bb5d5a1db0a68dac9a41bede6b8374c b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/8/f880b4c44bb5d5a1db0a68dac9a41bede6b8374c
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/9/f9357c93c5b5b86ae4f3363d3fe76860a1007f91 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/9/f9357c93c5b5b86ae4f3363d3fe76860a1007f91
new file mode 100644
index 0000000..e69de29
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/9/f9f49497f95afd327db7a7a512612aa1089003d4 b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/9/f9f49497f95afd327db7a7a512612aa1089003d4
new file mode 100644
index 0000000..fafb6c2
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/f/9/f9f49497f95afd327db7a7a512612aa1089003d4
@@ -0,0 +1,7 @@
+
+3
+java:S2386!"Make this member "protected".(Ꙗ
+D
+java:S1874*".Remove this use of ""; it is deprecated.(ж
+M
+java:S1135+"2Complete the task associated to this TODO comment.(
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/index.pb b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/index.pb
new file mode 100644
index 0000000..709eca6
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/.idea/sonarlint/issuestore/index.pb
@@ -0,0 +1,179 @@
+
+u
+Eapp/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java,f\0\f087b1ba1b9c91b7293fea0fb071eaed62a42137
+k
+;app/src/main/java/net/micode/notes/ui/NoteEditActivity.java,5\7\577f30d26378ec8a2bd2e4a43f3c79b3f04c402c
+l
+ sContactCache;//定义了一个静态的HashMap变量sContactCache
private static final String TAG = "Contact";//定义了一个静态的字符串常量TAG
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
- + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
- + " AND " + Data.RAW_CONTACT_ID + " IN "
+ + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ + " AND " + Data.RAW_CONTACT_ID + " IN "
+ "(SELECT raw_contact_id "
+ " FROM phone_lookup"
+ " WHERE min_match = '+')";
/*
*声明了一个字符串常量CALLER_ID_SELECTION,
*其中使用了函数调用PHONE_NUMBERS_EQUAL用来匹配电话号码,同时还使用了条件语句限制数据类型为电话号码联系人ID.
- */
+ */
/**
* 该方法定义了一个getContact,通过给定的电话号码实现获取联系人信息的功能。
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java b/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java
index 50c84e5..988f767 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java
@@ -53,168 +53,168 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static NotesDatabaseHelper mInstance;
private static final String CREATE_NOTE_TABLE_SQL =
- "CREATE TABLE " + TABLE.NOTE + "(" +
- NoteColumns.ID + " INTEGER PRIMARY KEY," +
- NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
- NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
- NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
- NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
- NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
- NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
- NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
- ")";//这是用于创建便签表的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" +
+ ")";//这是用于创建便签表的SQL语句,定义了便签表的结构,包含便签各种属性和字段,存储了用户创建的所有便签的信息。
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 ''" +
- ")";//这是用于定义数据表结构的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 ''" +
+ ")";//这是用于定义数据表结构的SQL语句,存储了与便签相关的数据信息,包括了各种附加数据,用来扩展便签功能。
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 + ");";
/**
* 当将便签移动到文件夹时,通过增加文件夹的便签数量来实现
*/
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";
/**
* 将便签从文件夹中移出时,通过减少文件夹的便签数量来实现
*/
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";
/**
* 当向文件夹中插入新的便签时,通过增加文件夹的便签数量来实现
*/
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";
/**
* 当从文件夹中删除便签时,通过减少文件夹的便签数量来实现
*/
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";
/**
* 当插入新的数据类型时,需要更新便签的内容{@link DataConstants#NOTE}
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
- "CREATE TRIGGER update_note_content_on_insert " +
- " AFTER INSERT ON " + TABLE.DATA +
- " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
- " BEGIN" +
- " UPDATE " + TABLE.NOTE +
- " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
- " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
- " END";
+ "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
*/
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
*/
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";
/**
* 删除已经被删除的便签所关联的数据
*/
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";
/**
* 删除已经被删除的文件夹所包含的便签
*/
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";
/**
* 将已经被移动到回收站文件夹的文件夹中的便签也一并移动到回收站文件夹
*/
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);
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesProvider.java b/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesProvider.java
index d7b3880..3dd6e4e 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesProvider.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesProvider.java
@@ -29,22 +29,14 @@ 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;
+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;//定义了一个枚举类型,表示数据库表的名称。
-/**
- * @Package: net.micode.notes.data
- * @ClassName: NotesProvider
- * @Description:
- * 这个类是对ContentProvider类的扩展,功能是提供小米便签应用程序的数据,
- * 在类当中实现了数据库的增添删减修改查找操作,并且可以处理与搜索有关的查询。
- * @Author: Dong Jiaqi
- * @CreateDate: 12/23/2023 23:27 PM
- */
-public class NotesProvider extends ContentProvider {
- private static final UriMatcher mMatcher;
+
+public class NotesProvider extends ContentProvider {//android中的ContentProvider类
+ private static final UriMatcher mMatcher;//riMatcher是Android中的一个类,用于匹配URI。
private NotesDatabaseHelper mHelper;
@@ -58,70 +50,54 @@ public class NotesProvider extends ContentProvider {
private static final int URI_SEARCH = 5;
private static final int URI_SEARCH_SUGGEST = 6;
- /**
- * 定义了一个静态代码块,初始化UriMatcher对象并且添加匹配规则
- * 调用了addURI()方法,向mMatcher这一个UriMatcher对象中添加了一系列匹配规则
- */
static {
- mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ mMatcher = new UriMatcher(UriMatcher.NO_MATCH);//
+ //创建一个UriMatcher对象mMatcher,初始值为UriMatcher.NO_MATCH,表示没有任何匹配规则。
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
+ //第一个参数是authority(授权),第二个参数是路径,第三个参数是匹配的URI类型。
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
- }
+ }//根据不同的URI路径,确定应该调用哪个处理程序来处理请求
+ //例如,当用户访问"http://example.com/note"时,mMatcher会匹配到第一个规则
/**
* 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;
-
+ 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查询语句,以便在数据库中搜索和检索相关笔记。
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
- + " FROM " + TABLE.NOTE
+ + " FROM " + TABLE.NOTE//从名为TABLE.NOTE的表中检索数据
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE;
-
- /**
- * onCreate()方法的功能是在应用程序启动时进行初始化数据库帮助类
- * @return 返回true表示创建成功
- */
+ //是一个SQL查询语句,用于从数据库中检索与给定搜索条件匹配的笔记
@Override
public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
- /**
- * query()方法用于执行查询操作,根据传入的URI参数,选择执行不同的查询语句返回
- * @param uri 要查询数据的URI,用来确定要操作的表和行
- * @param projection 表示查询返回的列的数组,可以指定查询结果中包含的列
- * @param selection 表示用于筛选的条件
- * @param selectionArgs 表示selection中的占位符的值
- * @param sortOrder 表示查询结果的排序顺序
- * @return 返回查询结果的游标(Cursor)对象(c)
- */
@Override
+ //查询uri在数据库的位置
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor c = null;
+ //获取可读数据库
SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null;
- /**
- * 这是一个switch语句块,用来针对不同的URI进行不同的操作。
- * 对于3种类型的URI,进行了不同的操作,如果URI不匹配这任何一种情况,就视为ILLegalArgumentException异常,表示URI不被支持或不合法
- * 这个语句块的目的是为了处理不同类型的URI,并且根据URI类型执行相应的数据库查询操作,属于典型的Android ContentProvider的逻辑处理代码
- */
switch (mMatcher.match(uri)) {
+ //匹配数据库中相应条目
case URI_NOTE:
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);
@@ -143,6 +119,7 @@ public class NotesProvider extends ContentProvider {
case URI_SEARCH:
case URI_SEARCH_SUGGEST:
if (sortOrder != null || projection != null) {
+ //异常情况
throw new IllegalArgumentException(
"do not specify sortOrder, selection, selectionArgs, or projection" + "with this query");
}
@@ -160,11 +137,6 @@ public class NotesProvider extends ContentProvider {
return null;
}
- /**
- * 这个语句块是在处理 URI_SEARCH 和 URI_SEARCH_SUGGEST 的情况下执行的,主要功能是执行数据库的原始查询(rawQuery)操作,用于搜索符合指定条件的数据,并将结果存储在 Cursor 对象中。
- * 如果在执行数据库查询时发生 IllegalStateException 异常,那么异常信息会被捕获,并通过 Log.e() 方法记录下来,方便在日志中进行查看和分析。
- * 目的是为了在执行数据库查询时,确保搜索关键词被正确地格式化并传入查询语句中,同时也确保在出现数据库查询异常时能够进行相应的异常处理和记录。
- */
try {
searchString = String.format("%%%s%%", searchString);
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
@@ -182,17 +154,13 @@ public class NotesProvider extends ContentProvider {
return c;
}
- /**
- * 用于执行插入操作,根据传入的URI参数,选择在不同的表中进行插入
- * @param uri 传入数据的URI,用来确定要操作的表和行
- * @param values 表示要插入的数据集合
- * @return 返回插入数据的URI,即ContentUris.withAppendedId(uri, insertedId)
- */
@Override
+ //插入uri
public Uri insert(Uri uri, ContentValues values) {
- SQLiteDatabase db = mHelper.getWritableDatabase();
- long dataId = 0, noteId = 0, insertedId = 0;
+ SQLiteDatabase db = mHelper.getWritableDatabase();//获取可写的数据库
+ long dataId = 0, noteId = 0, insertedId = 0;//初始化
switch (mMatcher.match(uri)) {
+ //新增条目
case URI_NOTE:
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
@@ -208,6 +176,7 @@ public class NotesProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify the note uri
+ //通知Android系统中的Notes应用程序,某个笔记或数据已经发生了变化
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
@@ -218,18 +187,15 @@ public class NotesProvider extends ContentProvider {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
-
+ //它通过调用getContentResolver().notifyChange()方法来实现这个功能。
+ //在这段代码中,首先检查noteId和dataId是否大于0,以确保它们是有效的ID。然后,使用ContentUris.withAppendedId()方法来构建对应的URI,
+ // 其中Notes.CONTENT_NOTE_URI和Notes.CONTENT_DATA_URI分别表示笔记和数据的URI。
+ // 最后,调用getContext().getContentResolver().notifyChange()方法并传入构建好的URI,以通知系统该URI所对应的资源已经发生了变化。
return ContentUris.withAppendedId(uri, insertedId);
}
- /**
- * 执行删除操作,根据传入URI参数,选择在不同的表中执行删除操作
- * @param uri 传入数据的URI,用来确定要操作的表和行
- * @param selection 表示删除的条件
- * @param selectionArgs 表示selection中的占位符的值
- * @return 返回收到影响的内容行数
- */
@Override
+ //删除一个uri,操作与上面差不多
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
@@ -266,6 +232,7 @@ public class NotesProvider extends ContentProvider {
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
+ //通知系统相关数据已经发生变化,以便进行相应的更新或处理。
if (count > 0) {
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
@@ -275,25 +242,13 @@ public class NotesProvider extends ContentProvider {
return count;
}
- /**
- * 执行更新操作,根据传入URI参数,在不同的表中进行更新
- * @param uri 传入数据的URI,用来确定要操作的表和行
- * @param values 表示要更新的数据集合
- * @param selection 表示用于筛选的条件
- * @param selectionArgs 表示selection中的占位符的值
- * @return 返回收到影响的行数
- */
@Override
+ //更新uri
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean updateData = false;
- /**
- * 这个语句块根据传入的 URI(Uniform Resource Identifier)进行匹配,并执行相应的操作。
- * 目的是根据传入的 URI 执行相应的数据库更新操作。根据不同的 URI,可以实现对不同表和记录的更新操作。
- * 通过 switch-case 结构,可以清晰地处理不同的情况,并执行相应的操作,同时也提供了一个默认的处理方式来处理未知的 URI。
- */
switch (mMatcher.match(uri)) {
case URI_NOTE:
increaseNoteVersion(-1, selection, selectionArgs);
@@ -328,23 +283,13 @@ public class NotesProvider extends ContentProvider {
return count;
}
- /**
- * 用于解析查询条件,将其转换为SQL语句中的WHERE子句
- * @param selection 表示用来解析的条件
- * @return 返回转换后的字符串
- */
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
-
- /**
- * 用于增加便签的版本号
- * @param id 要增加版本号的便签的ID
- * @param selection 查询选择条件,用来筛选要增加版本号的便签
- * @param selectionArgs 表示占位符参数
- */
+ //这段代码是一个私有方法,用于增加笔记的版本号。
+ // 它接受三个参数:id(笔记的ID)、selection(查询条件)和selectionArgs(查询条件的参数)
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
- StringBuilder sql = new StringBuilder(120);
+ StringBuilder sql = new StringBuilder(120);//sql对象,构建SQL语句
sql.append("UPDATE ");
sql.append(TABLE.NOTE);
sql.append(" SET ");
@@ -352,12 +297,14 @@ public class NotesProvider extends ContentProvider {
sql.append("=" + NoteColumns.VERSION + "+1 ");
if (id > 0 || !TextUtils.isEmpty(selection)) {
- sql.append(" WHERE ");
+ sql.append(" WHERE ");//那么在WHERE子句中添加相应的条件
}
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
+ ////将笔记ID等于给定id的条件添加到WHERE子句中
}
if (!TextUtils.isEmpty(selection)) {
+ //那么将解析后的查询条件添加到WHERE子句中。
String selectString = id > 0 ? parseSelection(selection) : selection;
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args);
@@ -368,10 +315,6 @@ public class NotesProvider extends ContentProvider {
mHelper.getWritableDatabase().execSQL(sql.toString());
}
- /**
- * 该方法根据需要自行补充实现,给开源后其他软件工程师留下了增添空间
- * @param uri 数据的URI
- */
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/MetaData.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/MetaData.java
index 1699caa..3a2050b 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/MetaData.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/MetaData.java
@@ -24,33 +24,13 @@ import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
-/**
- * @Package: net.micode.notes.gtask.data
- * @ClassName: MetaData
- * @Description:
- * MetaData类继承自 Task 类。它用于处理任务的元数据信息,并封装了一些操作元数据的方法。
- * 这个类用于管理任务的元数据信息,包括相关的 GID,在设置和获取元数据的同时,还提供了判断任务是否值得保存的方法,以及根据远程 JSON 数据设置任务内容的方法。
- * 同时,限制了部分方法的访问,以确保其按照预期的方式被使用。
- * @Author: Dong Jiaqi
- * @CreateDate: 12/24/2023 9:53 AM
- */
+
public class MetaData extends Task {
private final static String TAG = MetaData.class.getSimpleName();
private String mRelatedGid = null;
- /**
- * 作用是将给定的 GID 和其他元数据信息添加到任务的注释信息中,并设置任务的名称为固定的值。
- * @param gid 表示任务的全局唯一标识符(Global Task ID),是一个字符串类型的参数。
- * @param metaInfo 表示元数据信息,是一个 JSONObject 对象,包含任务的其他相关信息。
- */
public void setMeta(String gid, JSONObject metaInfo) {
- /**
- * 这个语句块作用是向 metaInfo 这个 JSONObject 对象中添加一个键值对,其中键是 GTaskStringUtils.META_HEAD_GTASK_ID,值是变量 gid。
- * 使用了 try-catch 块来捕获可能抛出的 JSONException 异常。
- * 为什么要这么写呢:
- * 因为在 Java 中,JSONObject 的 put 方法声明了可能抛出 JSONException 异常。这意味着在调用 put 方法时,需要进行异常处理,否则会导致编译错误。因此,为了保证程序的健壮性,开发者通常会在调用可能会引发异常的方法时使用 try-catch 块进行异常处理,以防止程序异常终止。
- */
try {
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
} catch (JSONException e) {
@@ -60,29 +40,19 @@ public class MetaData extends Task {
setName(GTaskStringUtils.META_NOTE_NAME);
}
- //作用是获取任务的相关 GID,并返回其字符串形式。
public String getRelatedGid() {
- return mRelatedGid;//返回值是一个字符串类型的变量 mRelatedGid,表示相关 GID(Global Task ID)。mRelatedGid 是一个成员变量,它保存了在任务的元数据信息中提取出来的相关 GID。
+ return mRelatedGid;
}
- //作用是判断任务是否值得保存。它通过检查任务的注释信息是否为null来确定任务是否值得保存。
@Override
public boolean isWorthSaving() {
- return getNotes() != null;//如果注释信息不为null,则返回true,表示任务值得保存;反之,如果注释信息为null,则返回false,表示任务不值得保存。
+ return getNotes() != null;
}
- /**
- * 功能是从远程 JSON 对象中获取任务的内容,包括基本的任务属性和元数据信息,并将其存储到当前的 Task 对象中。
- * @param js JSONObject 对象,表示从远程服务器获取的任务信息。
- */
@Override
public void setContentByRemoteJSON(JSONObject js) {
super.setContentByRemoteJSON(js);
if (getNotes() != null) {
- /**
- * 这个语句块作用是从任务的注释信息中提取相关 GID,并将其保存到变量 mRelatedGid 中。
- * 使用try-catch块是为了处理可能抛出的异常,确保程序稳定性
- */
try {
JSONObject metaInfo = new JSONObject(getNotes().trim());
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
@@ -96,7 +66,7 @@ public class MetaData extends Task {
@Override
public void setContentByLocalJSON(JSONObject js) {
// this function should not be called
- throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");//抛出一个IllegalAccessError异常,并且提供异常的详细描述信息
+ throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
}
@Override
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Node.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Node.java
index c2a5253..63950e0 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Node.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Node.java
@@ -20,33 +20,24 @@ import android.database.Cursor;
import org.json.JSONObject;
-/**
- * @Package: net.micode.notes.gtask.data
- * @ClassName: Node
- * @Description:
- * Node类是一个抽象类,定义了一些常量字段以及一些方法,还定义了节点对象的基本属性和操作,
- * * 同时提供了抽象方法来处理节点内容的设置和同步操作的创建按,以及普通方法来设置和获取节点的属性。
- * @Author: Dong Jiaqi
- * @CreateDate: 12/24/2023 10:23 AM
- */
public abstract class Node {
- public static final int SYNC_ACTION_NONE = 0;//表示没有同步操作。
+ public static final int SYNC_ACTION_NONE = 0;
- public static final int SYNC_ACTION_ADD_REMOTE = 1;//表示远程添加操作。
+ public static final int SYNC_ACTION_ADD_REMOTE = 1;
- public static final int SYNC_ACTION_ADD_LOCAL = 2;//表示本地添加操作。
+ public static final int SYNC_ACTION_ADD_LOCAL = 2;
- public static final int SYNC_ACTION_DEL_REMOTE = 3;//表示远程删除操作。
+ public static final int SYNC_ACTION_DEL_REMOTE = 3;
- public static final int SYNC_ACTION_DEL_LOCAL = 4;//表示本地删除操作。
+ public static final int SYNC_ACTION_DEL_LOCAL = 4;
- public static final int SYNC_ACTION_UPDATE_REMOTE = 5;//表示远程更新操作。
+ public static final int SYNC_ACTION_UPDATE_REMOTE = 5;
- public static final int SYNC_ACTION_UPDATE_LOCAL = 6;//表示本地更新操作。
+ public static final int SYNC_ACTION_UPDATE_LOCAL = 6;
- public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;//表示更新冲突操作。
+ public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;
- public static final int SYNC_ACTION_ERROR = 8;//表示同步错误操作。
+ public static final int SYNC_ACTION_ERROR = 8;
private String mGid;
@@ -75,66 +66,34 @@ public abstract class Node {
public abstract int getSyncAction(Cursor c);
- /**
- * 设置节点对象的全局唯一标识符(gid)。
- * @param gid 表示要设置的全局唯一标识符,它是一个字符串类型的参数。可以是任意有效的字符串,用于对节点进行唯一标识和区分。
- */
public void setGid(String gid) {
this.mGid = gid;
}
- /**
- * 设置节点对象的名称。它通过将传入的字符串参数 name 赋值给节点对象的成员变量 mName 来实现。
- * @param name 表示要设置的节点名称,它是一个字符串类型的参数。可以是任意有效的字符串,用于标识节点的名称或描述。
- */
public void setName(String name) {
this.mName = name;
}
- /**
- * 设置节点对象的最后修改时间。它通过将传入的长整型参数 lastModified 赋值给节点对象的成员变量 mLastModified 来实现。
- * @param lastModified 表示要设置的节点的最后修改时间,它是一个长整型参数,用来记录节点对象的最后修改时间
- */
public void setLastModified(long lastModified) {
this.mLastModified = lastModified;
}
- /**
- * 设置节点对象的删除状态。它通过将传入的布尔类型参数 deleted 赋值给节点对象的成员变量 mDeleted 来实现。
- * @param deleted 表示要设置的节点的删除状态,它是一个布尔类型的参数。当该参数为 true 时,表示节点被标记为已删除;当该参数为 false 时,表示节点未被删除。
- */
public void setDeleted(boolean deleted) {
this.mDeleted = deleted;
}
- /**
- * 获取节点对象的全局唯一标识符(gid)。它通过返回节点对象的成员变量 mGid 的值来实现。
- * @return this.mGid表示节点的全局唯一标识符。这是一个字符串类型的返回值,用于表示节点对象的唯一标识符。
- */
public String getGid() {
return this.mGid;
}
- /**
- * 获取节点对象的名称。它通过返回节点对象的成员变量 mName 的值来实现。
- * @return this.mName表示节点的名称。这是一个字符串类型的返回值,用于表示节点对象的名称或描述。
- */
public String getName() {
return this.mName;
}
- /**
- * 获取节点对象的最后修改时间。它通过返回节点对象的成员变量 mLastModified 的值来实现。
- * @return this.mLastModified表示节点的最后修改时间。这是一个长整型的返回值
- */
public long getLastModified() {
return this.mLastModified;
}
- /**
- * 获取节点对象的删除状态。它通过返回节点对象的成员变量 mDeleted 的布尔值来实现。
- * @return 表示节点的删除状态。当返回值为 true 时,表示节点已被标记为已删除;当返回值为 false 时,表示节点未被删除。
- */
public boolean getDeleted() {
return this.mDeleted;
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlData.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlData.java
index 60f3022..d3ec3be 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlData.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlData.java
@@ -34,33 +34,26 @@ import net.micode.notes.gtask.exception.ActionFailureException;
import org.json.JSONException;
import org.json.JSONObject;
-/**
- * @Package: net.micode.notes.gtask.data
- * @ClassName: SqlData
- * @Description:
- * 封装了对数据库中数据的读取、更新和提交操作,可以用于管理和操作数据库中的数据。
- * @Author: Dong Jiaqi
- * @CreateDate: 12/24/2023 10:58 AM
- */
+
public class SqlData {
private static final String TAG = SqlData.class.getSimpleName();
- private static final int INVALID_ID = -99999;//定义了一个名为 INVALID_ID 的私有静态整型常量,并赋值为 -99999,被用来表示无效的 ID 值。
+ private static final int INVALID_ID = -99999;
public static final String[] PROJECTION_DATA = new String[] {
DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,
DataColumns.DATA3
- };//定义了一个名为 PROJECTION_DATA 的字符串数组,其中包含了一组列名
+ };
- public static final int DATA_ID_COLUMN = 0;//表示数据的 ID 在数据列中的索引位置,即第一列。
+ public static final int DATA_ID_COLUMN = 0;
- public static final int DATA_MIME_TYPE_COLUMN = 1;//表示数据的 MIME 类型在数据列中的索引位置,即第二列。
+ public static final int DATA_MIME_TYPE_COLUMN = 1;
- public static final int DATA_CONTENT_COLUMN = 2;//表示数据的内容在数据列中的索引位置,即第三列。
+ public static final int DATA_CONTENT_COLUMN = 2;
- public static final int DATA_CONTENT_DATA_1_COLUMN = 3;//表示数据的内容数据1在数据列中的索引位置,即第四列。
+ public static final int DATA_CONTENT_DATA_1_COLUMN = 3;
- public static final int DATA_CONTENT_DATA_3_COLUMN = 4;//表示数据的内容数据3在数据列中的索引位置,即第五列。
+ public static final int DATA_CONTENT_DATA_3_COLUMN = 4;
private ContentResolver mContentResolver;
@@ -78,54 +71,36 @@ public class SqlData {
private ContentValues mDiffDataValues;
- /**
- * 构造函数,接收一个Context对象作为参数,并初始化成员变量。
- * @param context 用于获取应用程序的上下文信息,以便后续操作数据库。
- */
public SqlData(Context context) {
- mContentResolver = context.getContentResolver();//这是构造方法的定义,表明这是一个公共的构造方法,并且接受一个 Context 类型的参数。
+ mContentResolver = context.getContentResolver();
mIsCreate = true;
mDataId = INVALID_ID;
mDataMimeType = DataConstants.NOTE;
- mDataContent = "";//成员变量初始化
+ mDataContent = "";
mDataContentData1 = 0;
mDataContentData3 = "";
- mDiffDataValues = new ContentValues();//创建新的ContentValues对象
+ mDiffDataValues = new ContentValues();
}
- /**
- * 构造函数,接收一个Context对象和一个Cursor对象作为参数,并根据Cursor对象加载成员变量的值。
- * @param context 用于获取应用程序的上下文信息,以便后续操作数据库;
- * @param c Cursor 对象用于获取数据库中的数据。
- */
public SqlData(Context context, Cursor c) {
mContentResolver = context.getContentResolver();
mIsCreate = false;
- loadFromCursor(c);//调用 loadFromCursor() 方法,将传入的 Cursor 对象作为参数,以从 Cursor 对象中加载数据库中的数据到 SqlData 对象的成员变量中。
+ loadFromCursor(c);
mDiffDataValues = new ContentValues();
}
- /**
- * 从传入的 Cursor 对象中加载数据,并将数据赋值给 SqlData 对象的各个成员变量。
- * @param c Cursor 对象用于获取数据库中的数据
- */
private void loadFromCursor(Cursor c) {
- mDataId = c.getLong(DATA_ID_COLUMN);//从 Cursor 对象中获取指定列索引为 DATA_ID_COLUMN 的长整型数据,并赋值给 mDataId 成员变量。
- mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);//从 Cursor 对象中获取指定列索引为 DATA_MIME_TYPE_COLUMN 的字符串数据,并赋值给 mDataMimeType 成员变量。
+ mDataId = c.getLong(DATA_ID_COLUMN);
+ mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);
mDataContent = c.getString(DATA_CONTENT_COLUMN);
mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);
mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);
}
- /**
- * 根据传入的JSON对象设置成员变量的值。根据JSON对象中的字段值判断是否需要更新成员变量,并将需要更新的值存储在mDiffDataValues对象中。
- * @param js JSONObject对象用于获取数据
- * @throws JSONException 抛出的异常
- */
public void setContent(JSONObject js) throws JSONException {
- long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;//检查 JSON 对象 js 中是否包含名为 DataColumns.ID 的字段,如果包含则将其转换为 long 类型并赋给 dataId,否则将 INVALID_ID 赋给 dataId。
- if (mIsCreate || mDataId != dataId) {//检查是否正在创建新数据(mIsCreate 为 true),或者已有数据的 dataId 是否与新获取的 dataId 不同。
- mDiffDataValues.put(DataColumns.ID, dataId);//如果满足条件,则将 DataColumns.ID 和对应的 dataId 放入 mDiffDataValues 中。
+ long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;
+ if (mIsCreate || mDataId != dataId) {
+ mDiffDataValues.put(DataColumns.ID, dataId);
}
mDataId = dataId;
@@ -155,53 +130,42 @@ public class SqlData {
mDataContentData3 = dataContentData3;
}
- /**
- * 将成员变量的值转换为JSON对象并返回。
- * @return JSONObject 对象包含了 SqlData 对象中各个成员变量的值,使用相应的键值表示。如果当前对象是新创建的,则打印错误日志并返回 null。
- * @throws JSONException 抛出的异常
- */
public JSONObject getContent() throws JSONException {
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
JSONObject js = new JSONObject();
- js.put(DataColumns.ID, mDataId);//将类的成员变量 mDataId 的值存储到 js 对象中,使用键名 DataColumns.ID。
- js.put(DataColumns.MIME_TYPE, mDataMimeType);//将类的成员变量 mDataMimeType 的值存储到 js 对象中,使用键名 DataColumns.MIME_TYPE
+ js.put(DataColumns.ID, mDataId);
+ js.put(DataColumns.MIME_TYPE, mDataMimeType);
js.put(DataColumns.CONTENT, mDataContent);
js.put(DataColumns.DATA1, mDataContentData1);
js.put(DataColumns.DATA3, mDataContentData3);
return js;
}
- /**
- * 提交数据的更改到数据库中。如果是新创建的数据,则将数据插入数据库并获取其ID;如果是已存在的数据,则根据mDiffDataValues对象中的差异字段值更新数据库中对应的记录。
- * @param noteId 便签的ID,表示要提交数据的便签的ID
- * @param validateVersion 布尔值,表示是否需要验证版本号
- * @param version 长整型数,表示版本号
- */
public void commit(long noteId, boolean validateVersion, long version) {
- if (mIsCreate) {//如果数据是新创建的
+ if (mIsCreate) {
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {
mDiffDataValues.remove(DataColumns.ID);
}
- mDiffDataValues.put(DataColumns.NOTE_ID, noteId); //设置便签的ID
- Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);//向数据库中插入数据
+ mDiffDataValues.put(DataColumns.NOTE_ID, noteId);
+ Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);
try {
mDataId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");
}
- } else {//如果不是新创建的数据
+ } else {
if (mDiffDataValues.size() > 0) {
int result = 0;
- if (!validateVersion) {//如果不用验证版本,直接更新数据
+ if (!validateVersion) {
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null);
- } else {//如果要验证版本,根据版本号更新数据
+ } else {
result = mContentResolver.update(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues,
" ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE
@@ -215,14 +179,10 @@ public class SqlData {
}
}
- mDiffDataValues.clear();//提交后清空数据
+ mDiffDataValues.clear();
mIsCreate = false;
}
- /**
- * 返回成员变量mDataId的值。
- * @return 成员信息的ID
- */
public long getId() {
return mDataId;
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java
index d2ebbd3..1d0f45b 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java
@@ -37,14 +37,7 @@ import org.json.JSONObject;
import java.util.ArrayList;
-/**
- * @Package: net.micode.notes.gtask.data
- * @ClassName: SqlNote
- * @Description:
- * SqlNote类包含用于处理小米便签的数据库操作,是一个用于管理便签数据的工具类
- * @Author: Dong Jiaqi
- * @CreateDate: 12/24/2023 17:18 PM
- */
+
public class SqlNote {
private static final String TAG = SqlNote.class.getSimpleName();
@@ -59,9 +52,9 @@ public class SqlNote {
NoteColumns.VERSION
};
- public static final int ID_COLUMN = 0;//便签的ID列的索引为0
+ public static final int ID_COLUMN = 0;
- public static final int ALERTED_DATE_COLUMN = 1;//提醒日期列的索引为1
+ public static final int ALERTED_DATE_COLUMN = 1;
public static final int BG_COLOR_ID_COLUMN = 2;
@@ -127,12 +120,8 @@ public class SqlNote {
private ContentValues mDiffNoteValues;
- private ArrayList mDataList;//用Java中的ArrayList类定义了一个SqlData对象 mDataList,用于存储从数据库查询中返回的便签数据
+ private ArrayList mDataList;
- /**
- * 构造方法,用来创建一个新的SqlNote对象,初始化新的 SqlNote 对象,并将其成员变量设置为默认值。
- * @param context 要使用到的上下文对象
- */
public SqlNote(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
@@ -154,50 +143,33 @@ public class SqlNote {
mDataList = new ArrayList();
}
- /**
- * 另外一个构造方法,用于创建一个新的 SqlNote 对象,并从给定的 Cursor 中加载数据。
- * @param context 要使用的上下文对象
- * @param c 要加载数据的游标对象
- */
public SqlNote(Context context, Cursor c) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);
mDataList = new ArrayList();
- if (mType == Notes.TYPE_NOTE)
+ if (mType == Notes.TYPE_NOTE) {
loadDataContent();
+ }
mDiffNoteValues = new ContentValues();
}
- /**
- * 另一个构造方法,用于创建一个新的 SqlNote 对象,并从给定的 ID 加载数据。
- * @param context 要使用的上下文对象
- * @param id 要加载数据的便签的ID
- */
public SqlNote(Context context, long id) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(id);
mDataList = new ArrayList();
- if (mType == Notes.TYPE_NOTE)
+ if (mType == Notes.TYPE_NOTE) {
loadDataContent();
+ }
mDiffNoteValues = new ContentValues();
}
- /**
- * 通过笔记 ID 从数据库中加载便签数据,并将其存储在 SqlNote 对象的成员变量中
- * @param id 要加载数据的便签 ID
- */
private void loadFromCursor(long id) {
Cursor c = null;
- /**
- * try-finally语句块 用于在加载笔记数据后正确地关闭游标,以确保资源的释放。
- * 这么写是为了避免在发生异常或错误时,游标未被关闭而导致资源泄漏。
- * 通过在 finally 块中关闭游标,可以确保无论查询是否成功,都会正确地释放资源。
- */
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
new String[] {
@@ -210,15 +182,12 @@ public class SqlNote {
Log.w(TAG, "loadFromCursor: cursor = null");
}
} finally {
- if (c != null)
+ if (c != null) {
c.close();
+ }
}
}
- /**
- * 从游标中加载便签数据,并将其存储在 SqlNote 对象的成员变量中。
- * @param c 要从中加载数据的游标
- */
private void loadFromCursor(Cursor c) {
mId = c.getLong(ID_COLUMN);
mAlertDate = c.getLong(ALERTED_DATE_COLUMN);
@@ -234,17 +203,9 @@ public class SqlNote {
mVersion = c.getLong(VERSION_COLUMN);
}
- /**
- * 根据特定笔记 ID 加载与之关联的数据内容,并将其存储在数据列表中供进一步操作和展示。
- * 通过查询数据库,遍历游标并创建相应的数据对象,可以方便地加载数据内容并进行后续处理。
- */
private void loadDataContent() {
Cursor c = null;
mDataList.clear();
- /**
- * 从数据库中查询与指定笔记 ID 相关联的数据内容,并将查询结果存储在 mDataList 列表中。
- * 这种写法可以保证在出现异常时,也能正确地关闭游标,避免资源泄露和其他问题。
- */
try {
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
"(note_id=?)", new String[] {
@@ -263,24 +224,13 @@ public class SqlNote {
Log.w(TAG, "loadDataContent: cursor = null");
}
} finally {
- if (c != null)
+ if (c != null) {
c.close();
+ }
}
}
-
- /**
- * 根据传入的JSONObject对象设置内容。
- * 根据JSONObject中的不同字段值更新类中的属性,并将差异值存储在mDiffNoteValues中。
- * @param js 包含要设置的内容的JSONObject对象。
- * @return 如果成功设置内容,则返回true;否则返回false
- */
public boolean setContent(JSONObject js) {
- /**
- * try块中的代码用于解析JSON对象并获取其中的数据。如果解析过程中发生了JSONException异常,那么程序会跳转到catch块中,并执行其中的代码。
- * catch块中的代码主要用于打印异常信息并返回一个布尔值false,以表示解析失败。
- * 这样能够通过捕获异常并进行适当的处理,可以避免程序崩溃或产生不可预料的结果。
- */
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
@@ -291,14 +241,14 @@ public class SqlNote {
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate || !mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
- }//判断是否需要更新笔记的摘要(snippet)。它通过比较当前对象的mSnippet属性和传入的参数snippet,如果两者不相等,则将新的摘要值存储在mDiffNoteValues中。
+ }
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type);
- }//检查是否正在创建新的笔记(mIsCreate为true),或者当前笔记的类型与传入的类型值不相等(mType != type)。如果满足其中一个条件,就会将新的类型值存储在mDiffNoteValues中。
+ }
mType = type;
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
@@ -413,10 +363,6 @@ public class SqlNote {
return true;
}
- /**
- * 将当前对象的属性值转换为一个JSON对象并返回。
- * @return 返回转换后的JSONObject对象作为结果
- */
public JSONObject getContent() {
try {
JSONObject js = new JSONObject();
@@ -465,74 +411,39 @@ public class SqlNote {
return null;
}
- /**
- * 设置当前对象的父级ID属性,并将该属性的值存储到mDiffNoteValues中。
- * @param id long类型,表示要设置的父级ID
- */
public void setParentId(long id) {
mParentId = id;
mDiffNoteValues.put(NoteColumns.PARENT_ID, id);
}
- /**
- * 将指定的Google Tasks任务的ID(gid)放入mDiffNoteValues中,以便后续判断属性变化时进行处理。
- * @param gid 字符串类型,表示要设置的Google Tasks任务的ID
- */
public void setGtaskId(String gid) {
mDiffNoteValues.put(NoteColumns.GTASK_ID, gid);
}
- /**
- * 将指定的同步ID(syncId)放入mDiffNoteValues中,以便后续判断属性变化时进行处理。
- * @param syncId long类型,表示要设置的同步ID
- */
public void setSyncId(long syncId) {
mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId);
}
- /**
- * 将当前对象的本地修改状态重置为未修改。
- */
public void resetLocalModified() {
mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0);
}
- /**
- * 获取当前对象ID属性值,将其作为结果返回
- * @return 当前对象的ID属性值
- */
public long getId() {
return mId;
}
- /**
- * 获取当前对象的父级ID属性值,并返回该值。
- * @return 当前对象的父级ID属性值
- */
public long getParentId() {
return mParentId;
}
- /**
- * 获取当前对象的摘要属性值,并返回该值。
- * @return 当前对象的摘要属性值
- */
public String getSnippet() {
return mSnippet;
}
- /**
- * 判断当前对象是否为“便签”类型。
- * @return 布尔类型的数据,表示当前对象是否为“便签”类型。如果是便签类型,则返回true;否则返回false。
- */
public boolean isNoteType() {
return mType == Notes.TYPE_NOTE;
}
- /**
- * 将当前对象所代表的笔记或文件夹信息提交到数据库中进行保存,并更新当前对象的属性值。
- * @param validateVersion 布尔类型的数据,表示是否需要验证版本信息。如果为true,则在更新时需要比较版本号;否则不需要比较版本号。
- */
public void commit(boolean validateVersion) {
if (mIsCreate) {
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
@@ -589,8 +500,9 @@ public class SqlNote {
// refresh local info
loadFromCursor(mId);
- if (mType == Notes.TYPE_NOTE)
+ if (mType == Notes.TYPE_NOTE) {
loadDataContent();
+ }
mDiffNoteValues.clear();
mIsCreate = false;
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Task.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Task.java
index 4fd9506..6a19454 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Task.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Task.java
@@ -31,16 +31,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
-/**
- * @Package: net.micode.notes.gtask.data
- * @ClassName: Task
- * @Description:
- * Task类继承自Node类。该类用于表示一个任务,在Google任务管理系统中使用。
- * 它包含了一些任务的属性和方法,例如任务是否已完成、笔记内容、元数据等。
- * 另外,该类还提供了一些用于生成和解析JSON格式数据的方法,以便与Google任务管理系统进行交互。
- * @Author: Dong Jiaqi
- * @CreateDate: 12/24/2023 19:48 PM
- */
+
public class Task extends Node {
private static final String TAG = Task.class.getSimpleName();
@@ -54,27 +45,17 @@ public class Task extends Node {
private TaskList mParent;
- /**
- * 构造方法在对象创建时被调用,用于初始化对象的属性。
- * 所有属性都被初始化为初始值或者null。
- */
public Task() {
- super();//调用父类Node的构造方法确保父类的属性得到正确初始化
- mCompleted = false;//任务完成状态设置为未完成
- mNotes = null;//暂时没有便签笔记
- mPriorSibling = null;//当前任务没有前节点
- mParent = null;//当前任务没有父节点
- mMetaInfo = null;//当前任务没有元数据信息
+ super();
+ mCompleted = false;
+ mNotes = null;
+ mPriorSibling = null;
+ mParent = null;
+ mMetaInfo = null;
}
- /**
- * 用于生成一个表示创建任务操作的JSON对象。
- * 如果在生成JSON对象的过程中发生异常,将会抛出一个ActionFailureException异常,并打印错误信息。
- * @param actionId 表示操作的唯一标识符。
- * @return 生成的JSONObject对象,包含了表示创建任务操作的各个字段和对应的值。
- */
public JSONObject getCreateAction(int actionId) {
- JSONObject js = new JSONObject();//创建一个空的JSONObject对象。
+ JSONObject js = new JSONObject();
try {
// action_type
@@ -116,17 +97,12 @@ public class Task extends Node {
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
- throw new ActionFailureException("fail to generate task-create jsonobject");//抛出异常
+ throw new ActionFailureException("fail to generate task-create jsonobject");
}
return js;
}
- /**
- * 用于生成一个表示更新任务操作的JSON对象。
- * @param actionId 表示操作的唯一标识符。
- * @return 生成的JSONObject对象,包含了表示更新任务操作的各个字段和对应的值。
- */
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
@@ -159,11 +135,6 @@ public class Task extends Node {
return js;
}
- /**
- * 用于根据传入的JSONObject对象设置任务的各个字段值。
- * 保持任务对象的状态与传入的JSON数据一致。
- * @param js 表示一个JSONObject对象,包含了任务的各个字段和对应的值。
- */
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
@@ -204,25 +175,17 @@ public class Task extends Node {
}
}
- /**
- * 用于根据传入的本地JSONObject对象设置任务的名称,从而与本地数据保持一致。
- * @param js 包含了本地数据的各个字段和对应的值。
- */
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
}
- /**
- * 根据传入的JSONObject对象解析任务的名称字段,并将其设置为任务对象的名称。
- * 同时,还会检查便签的类型,只有当类型为普通便签时才会继续设置任务名称。
- */
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
- if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {//检查便签类型是不是普通便签
+ if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {
Log.e(TAG, "invalid type");
return;
}
@@ -241,11 +204,6 @@ public class Task extends Node {
}
}
- /**
- * 根据任务对象的内容生成一个本地的JSONObject对象。
- * @return 对于新创建的任务:返回构造好的JSONObject对象js。
- * 对于已同步的任务:返回mMetaInfo对象本身。
- */
public JSONObject getLocalJSONFromContent() {
String name = getName();
try {
@@ -289,10 +247,6 @@ public class Task extends Node {
}
}
- /**
- * 设置任务的元数据。
- * @param metaData MetaData对象,表示任务的元数据。
- */
public void setMetaInfo(MetaData metaData) {
if (metaData != null && metaData.getNotes() != null) {
try {
@@ -304,16 +258,6 @@ public class Task extends Node {
}
}
- /**
- * 根据传入的Cursor对象和任务的元数据判断同步操作的类型。
- * @param c Cursor对象c,用于查询本地数据库中的任务数据。
- * @return 整数,表示同步操作的类型
- * SYNC_ACTION_NONE:无需同步
- * SYNC_ACTION_UPDATE_LOCAL:需要更新本地任务
- * SYNC_ACTION_UPDATE_REMOTE:需要更新远程任务
- * SYNC_ACTION_UPDATE_CONFLICT:存在冲突,需要解决
- * SYNC_ACTION_ERROR:同步出错
- */
public int getSyncAction(Cursor c) {
try {
JSONObject noteInfo = null;
@@ -367,80 +311,39 @@ public class Task extends Node {
return SYNC_ACTION_ERROR;
}
- /**
- * 判断当前任务是否值得保存。
- * @return 类型为boolean,true表示任务值得保存,false表示任务不值得保存。
- */
public boolean isWorthSaving() {
return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)
|| (getNotes() != null && getNotes().trim().length() > 0);
}
- /**
- * 设置当前任务的完成状态。
- * 调用这个方法,可以更新当前任务的完成状态,以便在应用程序中进行相应的展示或处理。
- * @param completed boolean类型的参数,用来表示当前任务的完成状态。
- */
public void setCompleted(boolean completed) {
this.mCompleted = completed;
}
- /**
- * 设置当前任务的备注信息。
- * 调用这个方法,可以更新当前任务的备注信息,以便在应用程序中进行相应的展示或处理。
- * @param notes String类型的参数,用来表示当前任务的备注信息。
- */
public void setNotes(String notes) {
this.mNotes = notes;
}
- /**
- * 设置当前任务的前一个兄弟任务。
- * 调用这个方法,可以建立任务之间的关联关系,例如设置任务的顺序、父子关系等。
- * @param priorSibling Task类型的参数,表示当前任务的前一个兄弟任务。
- */
public void setPriorSibling(Task priorSibling) {
this.mPriorSibling = priorSibling;
}
- /**
- * 设置当前任务的父任务列表。
- * 调用这个方法,可以建立任务之间的关联关系,例如设置任务的层级结构、父子关系等。
- * @param parent TaskList类型的参数,表示当前任务所属的父任务列表。
- */
public void setParent(TaskList parent) {
this.mParent = parent;
}
- /**
- * 获取当前任务的完成状态。
- * 调用这个方法,可以获取当前任务是否已经完成,以便在应用程序中进行相应的展示或处理。
- * @return 类型为boolean,true表示任务已完成,false表示任务未完成。
- */
public boolean getCompleted() {
return this.mCompleted;
}
- /**
- * 获取当前任务的备注信息。
- * @return 类型为String,表示当前任务的备注信息。如果任务没有备注信息,则返回一个空字符串。
- */
public String getNotes() {
return this.mNotes;
}
- /**
- * 获取当前任务的前一个兄弟任务。
- * @return 类型为Task,表示当前任务的前一个兄弟任务。如果当前任务没有前一个兄弟任务,则返回null。
- */
public Task getPriorSibling() {
return this.mPriorSibling;
}
- /**
- * 获取当前任务所属的父任务列表。
- * @return 类型为TaskList,表示当前任务所属的父任务列表。如果当前任务没有父任务列表,则返回null。
- */
public TaskList getParent() {
return this.mParent;
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/TaskList.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/TaskList.java
index b3d810b..cd71d29 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/TaskList.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/TaskList.java
@@ -30,36 +30,19 @@ import org.json.JSONObject;
import java.util.ArrayList;
-/**
- * @Package: net.micode.notes.gtask.data
- * @ClassName: TaskList
- * @Description:
- * TaskList继承自Node类。该类表示一个任务列表,具有管理任务列表及其子任务的功能。
- * 提供了创建、更新、删除任务列表以及管理子任务的方法,可以通过JSON对象进行远程和本地数据的转换,并提供了一系列对子任务进行操作的方法。
- * @Author: Dong Jiaqi
- * @CreateDate: 12/24/2023 20:48 PM
- */
public class TaskList extends Node {
- private static final String TAG = TaskList.class.getSimpleName();//私有静态常量,用于在日志和调试中标识类名。
+ private static final String TAG = TaskList.class.getSimpleName();
- private int mIndex;//私有整型变量,表示任务列表的索引。
+ private int mIndex;
- private ArrayList mChildren;//私有ArrayList,存储Task对象,表示该任务列表下的子任务列表。
+ private ArrayList mChildren;
- /**
- * 构造方法,初始化一个空的任务列表,初始化mChildren为一个空的Task列表,将mIndex设置为1。
- */
public TaskList() {
super();
mChildren = new ArrayList();
mIndex = 1;
}
- /**
- * 根据给定的actionId创建一个用于创建任务列表的JSONObject对象。
- * @param actionId 整型参数,表示操作的ID。
- * @return 表示创建操作的JSONObject对象。
- */
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
@@ -91,11 +74,6 @@ public class TaskList extends Node {
return js;
}
- /**
- * 根据给定的actionId创建一个用于更新任务列表的JSONObject对象。
- * @param actionId 整型参数,表示操作的ID。
- * @return 表示更新操作的JSONObject对象。
- */
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
@@ -125,10 +103,6 @@ public class TaskList extends Node {
return js;
}
- /**
- * 根据远程传入的JSON对象设置任务列表的内容。
- * @param js 表示从远程服务器返回的JSONObject对象,包含了任务列表的属性。
- */
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
@@ -155,10 +129,6 @@ public class TaskList extends Node {
}
}
- /**
- * 根据本地JSON对象设置任务列表的内容。
- * @param js 表示从远程服务器返回的JSONObject对象,包含了任务列表的属性。
- */
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
@@ -171,13 +141,14 @@ public class TaskList extends Node {
String name = folder.getString(NoteColumns.SNIPPET);
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name);
} else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
- if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER)
+ if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) {
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT);
- else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER)
+ } else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) {
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE);
- else
+ } else {
Log.e(TAG, "invalid system folder");
+ }
} else {
Log.e(TAG, "error type");
}
@@ -187,10 +158,6 @@ public class TaskList extends Node {
}
}
- /**
- * 根据任务列表的内容生成本地JSON对象。
- * @return 表示本地的JSONObject对象,包含了任务列表的属性信息。
- */
public JSONObject getLocalJSONFromContent() {
try {
JSONObject js = new JSONObject();
@@ -217,17 +184,6 @@ public class TaskList extends Node {
}
}
- /**
- * 根据数据库游标中的信息确定同步操作的类型。
- * @param c 表示一个Cursor对象,包含了当前任务列表的属性信息。
- * @return 表示同步操作的代码
- * SYNC_ACTION_NONE(不执行任何操作)
- * SYNC_ACTION_UPDATE_LOCAL(更新本地)
- * SYNC_ACTION_ERROR(同步操作出错)
- * SYNC_ACTION_UPDATE_REMOTE(当前任务列表的同步ID是否与最后修改时间相同,更新远程)
- * SYNC_ACTION_UPDATE_REMOTE(当前任务列表的同步ID是否与最后修改时间不相同,更新远程)
- * SYNC_ACTION_ERROR(同步操作出错)
- */
public int getSyncAction(Cursor c) {
try {
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
@@ -261,19 +217,10 @@ public class TaskList extends Node {
return SYNC_ACTION_ERROR;
}
- /**
- * 获取子任务的数量。
- * @return 子任务的数量
- */
public int getChildTaskCount() {
return mChildren.size();
}
- /**
- * 向任务列表中添加一个子任务。
- * @param task 表示要添加的子任务
- * @return boolean:表示是否成功将子任务添加到当前任务中,如果添加成功则返回true,否则返回false
- */
public boolean addChildTask(Task task) {
boolean ret = false;
if (task != null && !mChildren.contains(task)) {
@@ -288,12 +235,6 @@ public class TaskList extends Node {
return ret;
}
- /**
- * 在指定位置添加一个子任务。
- * @param task 表示要插入的子任务。
- * @param index 表示要插入的位置索引,从0开始计数。
- * @return boolean:表示是否成功将子任务插入到当前任务中的指定位置,如果插入成功则返回true,否则返回false。
- */
public boolean addChildTask(Task task, int index) {
if (index < 0 || index > mChildren.size()) {
Log.e(TAG, "add child task: invalid index");
@@ -320,11 +261,6 @@ public class TaskList extends Node {
return true;
}
- /**
- * 从任务列表中移除一个子任务。
- * @param task 表示要移除的子任务
- * @return boolean:表示是否成功从当前任务中移除了指定的子任务,如果移除成功则返回true,否则返回false。
- */
public boolean removeChildTask(Task task) {
boolean ret = false;
int index = mChildren.indexOf(task);
@@ -346,12 +282,6 @@ public class TaskList extends Node {
return ret;
}
- /**
- * 移动指定子任务到新的位置。
- * @param task 表示要移动的子任务
- * @param index 表示要移动到的位置索引,从0开始计数。
- * @return boolean:表示是否成功将子任务移动到指定位置,如果移动成功则返回true,否则返回false
- */
public boolean moveChildTask(Task task, int index) {
if (index < 0 || index >= mChildren.size()) {
@@ -370,11 +300,6 @@ public class TaskList extends Node {
return (removeChildTask(task) && addChildTask(task, index));
}
- /**
- * 根据全局唯一标识符查找子任务。
- * @param gid 表示要查找的子任务的gid(全局唯一标识符)
- * @return Task:如果找到具有匹配gid的子任务,则返回该子任务对象;如果未找到匹配的子任务,则返回null
- */
public Task findChildTaskByGid(String gid) {
for (int i = 0; i < mChildren.size(); i++) {
Task t = mChildren.get(i);
@@ -385,20 +310,10 @@ public class TaskList extends Node {
return null;
}
- /**
- * 获取指定子任务在任务列表中的索引。
- * @param task 表示要获取索引位置的子任务对象。
- * @return int:表示指定子任务在当前任务的子任务列表中的索引位置,如果子任务存在于列表中则返回其索引位置(从0开始计数),如果子任务不存在于列表中则返回-1。
- */
public int getChildTaskIndex(Task task) {
return mChildren.indexOf(task);
}
- /**
- * 根据索引获取子任务。
- * @param index 表示要获取子任务的索引位置,从0开始计数。
- * @return Task:表示位于指定索引位置的子任务对象,如果索引位置有效则返回该子任务对象,否则返回null。
- */
public Task getChildTaskByIndex(int index) {
if (index < 0 || index >= mChildren.size()) {
Log.e(TAG, "getTaskByIndex: invalid index");
@@ -407,11 +322,6 @@ public class TaskList extends Node {
return mChildren.get(index);
}
- /**
- * 根据全局唯一标识符获取子任务。
- * @param gid 表示要查找的子任务的gid
- * @return Task:如果找到具有匹配gid的子任务,则返回匹配的子任务对象;如果未找到匹配的子任务,则返回null
- */
public Task getChilTaskByGid(String gid) {
for (Task task : mChildren) {
if (task.getGid().equals(gid))
@@ -420,26 +330,14 @@ public class TaskList extends Node {
return null;
}
- /**
- * 获取任务列表的子任务列表。
- * @return ArrayList:表示当前任务的子任务列表,即包含所有子任务的ArrayList对象。
- */
public ArrayList getChildTaskList() {
return this.mChildren;
}
- /**
- * 设置任务列表的索引。
- * @param index 表示要设置的索引值
- */
public void setIndex(int index) {
this.mIndex = index;
}
- /**
- * 获取任务列表的索引。
- * @return 表示当前对象的索引值
- */
public int getIndex() {
return this.mIndex;
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/exception/ActionFailureException.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/exception/ActionFailureException.java
index 15504be..b82bd8a 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/exception/ActionFailureException.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/exception/ActionFailureException.java
@@ -15,14 +15,34 @@
*/
package net.micode.notes.gtask.exception;
-
+/**
+ * @aPackage : net.micode.notes.gtask.exception
+ * @aClassName: ActionFailureException
+ * @Description:
+ * 该类是一个名为 ActionFailureException的公共类,该类继承自 RuntimeException 类
+ * RuntimeException 是Java中的一个异常类,它是所有运行时异常的父类。
+ * 当程序在运行过程中遇到无法处理的错误或异常情况时,会抛出 RuntimeException 类型的异常
+ * 作用:
+ * 通过继承的方式,ActionFailureException 类可以自定义自己的异常行为和处理方式
+ * 以便更精确地描述和处理这种特定类型的异常
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/24/2023 19:31 PM
+ */
public class ActionFailureException extends RuntimeException {
private static final long serialVersionUID = 4425249765923293627L;
-
+ /*
+ * serialVersionUID相当于java类的身份证。主要用于版本控制。
+ * serialVersionUID作用是序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。
+ */
public ActionFailureException() {
super();
}
-
+ /*
+ * 在JAVA类中使用super来引用父类的成分,用this来引用当前对象.
+ * 如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象。
+ * 怎么去引用里面的父类对象呢?使用super来引用
+ * 也就是说,此处super()以及super (paramString)可认为是Exception ()和Exception (paramString)
+ */
public ActionFailureException(String paramString) {
super(paramString);
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/exception/NetworkFailureException.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/exception/NetworkFailureException.java
index b08cfb1..90a60f4 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/exception/NetworkFailureException.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/exception/NetworkFailureException.java
@@ -15,14 +15,30 @@
*/
package net.micode.notes.gtask.exception;
-
+/**
+ * @aPackage : net.micode.notes.gtask.exception
+ * @aClassName: NetworkFailureException
+ * @Description:
+ * 该类继承自Java的内置异常类 Exception
+ * 在Java中,异常(Exception)是一种用于处理程序运行时可能出现的错误情况的对象
+ * 当程序在运行过程中遇到无法处理的错误或异常情况时,会抛出 RuntimeException 类型的异常
+ * 作用:
+ * 通过继承Exception类,可以自定义自己的异常类型,以便更好地描述和处理特定类型的错误
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/24/2023 19:31 PM
+ */
public class NetworkFailureException extends Exception {
private static final long serialVersionUID = 2107610287180234136L;
-
+ /*
+ * serialVersionUID相当于java类的身份证。主要用于版本控制。
+ * serialVersionUID作用是序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。
+ */
public NetworkFailureException() {
super();
}
-
+ /*
+ super()含义与ActionFailureException类的相同
+ */
public NetworkFailureException(String paramString) {
super(paramString);
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java
index b3b61e7..9a48e8e 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java
@@ -27,8 +27,19 @@ import android.os.AsyncTask;
import net.micode.notes.R;
import net.micode.notes.ui.NotesListActivity;
import net.micode.notes.ui.NotesPreferenceActivity;
-
-
+/**
+ * @aPackage : net.micode.notes.gtask.remote
+ * @aClassName: GTaskASyncTask
+ * @Description:
+ * 异步操作类,实现GTask的异步操作过程
+ * 主要方法:
+ * showNotification(int tickerId, String content) 向用户提示当前同步的状态,是一个用于交互的方法
+ * doInBackground(Void... unused) 此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间
+ * onProgressUpdate(String... progress) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
+ * onPostExecute(Integer result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/24/2023 19:31 PM
+ */
public class GTaskASyncTask extends AsyncTask {
private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;
@@ -48,6 +59,9 @@ public class GTaskASyncTask extends AsyncTask {
public GTaskASyncTask(Context context, OnCompleteListener listener) {
mContext = context;
mOnCompleteListener = listener;
+ /*
+ 获取系统服务中的NotificationManager对象,并将其赋值给成员变量mNotifiManager。这个对象用于管理应用程序的通知
+ */
mNotifiManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
mTaskManager = GTaskManager.getInstance();
@@ -57,18 +71,19 @@ public class GTaskASyncTask extends AsyncTask {
mTaskManager.cancelSync();
}
- public void publishProgess(String message) {
+ public void publishProgess(String message) {//发布进度单位,系统将会调用onProgressUpdate()方法更新这些值
publishProgress(new String[] {
message
});
}
- private void showNotification(int tickerId, String content) {
- Notification notification = new Notification(R.drawable.notification, mContext
- .getString(tickerId), System.currentTimeMillis());
- notification.defaults = Notification.DEFAULT_LIGHTS;
- notification.flags = Notification.FLAG_AUTO_CANCEL;
- PendingIntent pendingIntent;
+ /**
+ * 该函数用于向用户提示当前同步的状态,是一个用于交互的方法
+ * 两个参数:一个整数类型的tickerId,表示通知的唯一标识符
+ * 和一个字符串类型的content,表示通知的内容,可以是任何文本信息,例如消息、警告或其他相关信息
+ */
+ private void showNotification(int tickerId, String content) {
+ PendingIntent pendingIntent;//一个描述了想要启动一个Activity、Broadcast或是Service的意图
if (tickerId != R.string.ticker_success) {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesPreferenceActivity.class), 0);
@@ -77,16 +92,41 @@ public class GTaskASyncTask extends AsyncTask {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesListActivity.class), 0);
}
- notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
- pendingIntent);
+ /*
+ 如果同步不成功,那么从系统取得一个用于启动一个NotesPreferenceActivity的PendingIntent对象
+ 如果同步成功,那么从系统取得一个用于启动一个NotesListActivity的PendingIntent对象
+ */
+
+ 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();
+ //通过NotificationManager对象的notify()方法来执行一个notification的消息
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
}
+ /**
+ *用于在后台线程中执行耗时操作具体来说,它的作用是在后台线程中同步数据
+ * 它是一个受保护的方法,返回类型为Integer。该方法接受一个可变参数unused,表示没有使用到的参数
+ */
@Override
protected Integer doInBackground(Void... unused) {
publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity
.getSyncAccountName(mContext)));
+ /*
+ publishProgess用于更新进度信息,NotesPreferenceActivity.getSyncAccountName(mContext)来生成进度信息
+ 利用getString,把进程信息的内容传进sync_progress_login中
+
+ */
return mTaskManager.sync(mContext, this);
+ /*
+ 进行后台同步具体操作
+ sync方法接受两个参数:一个是上下文对象mContext,另一个是当前对象this
+ */
}
@Override
@@ -97,6 +137,15 @@ public class GTaskASyncTask extends AsyncTask {
}
}
+ /**
+ * 用于在执行完后台任务后更新UI,显示结果
+ * 根据不同的执行结果,代码会调用showNotification方法来显示相应的通知信息
+ * 显示的不同结果:
+ * 如果结果为GTaskManager.STATE_SUCCESS,则显示成功同步的通知
+ * 如果结果为GTaskManager.STATE_NETWORK_ERROR,则显示网络错误的通知
+ * 如果结果为GTaskManager.STATE_INTERNAL_ERROR,则显示内部错误的通知
+ * 如果结果为GTaskManager.STATE_SYNC_CANCELLED,则显示同步取消的通知
+ */
@Override
protected void onPostExecute(Integer result) {
if (result == GTaskManager.STATE_SUCCESS) {
@@ -111,6 +160,9 @@ public class GTaskASyncTask extends AsyncTask {
showNotification(R.string.ticker_cancel, mContext
.getString(R.string.error_sync_cancelled));
}
+ /*
+ 如果存在mOnCompleteListener对象,代码还会创建一个新的线程来执行mOnCompleteListener.onComplete()方法,以完成一次操作
+ */
if (mOnCompleteListener != null) {
new Thread(new Runnable() {
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java
index c67dfdf..2a1ca23 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java
@@ -59,7 +59,15 @@ import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
-
+/**
+ * @aPackage : net.micode.notes.gtask.remote
+ * @aClassName: GTaskClient
+ * @Description:
+ * 主要功能:实现GTASK的登录操作,进行GTASK任务的创建,创建任务列表,从网络上获取任务和任务列表的内容
+ * 主要使用类或技术:accountManager JSONObject HttpParams authToken Gid
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/24/2023 19:31 PM
+ */
public class GTaskClient {
private static final String TAG = GTaskClient.class.getSimpleName();
@@ -102,6 +110,10 @@ public class GTaskClient {
mUpdateArray = null;
}
+ /* 用来获取的实例化对象
+ * 使用 getInstance()
+ * 返回mInstance这个实例化对象
+ */
public static synchronized GTaskClient getInstance() {
if (mInstance == null) {
mInstance = new GTaskClient();
@@ -109,42 +121,50 @@ public class GTaskClient {
return mInstance;
}
+
+ /*用来实现登录操作的函数,传入的参数是一个Activity
+ * 设置登录操作限制时间,如果超时则需要重新登录
+ * 有两种登录方式,使用用户自己的URL登录或者使用谷歌官方的URL登录
+ * 返回true或者false,即最后是否登陆成功
+ */
public boolean login(Activity activity) {
- // we suppose that the cookie would expire after 5 minutes
- // then we need to re-login
+ //判断距离最后一次登录操作是否超过5分钟
final long interval = 1000 * 60 * 5;
if (mLastLoginTime + interval < System.currentTimeMillis()) {
mLoggedin = false;
}
- // need to re-login after account switch
+ // need to re-login after account switch 也就是重新登录
if (mLoggedin
&& !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity
.getSyncAccountName(activity))) {
mLoggedin = false;
}
+ //如果没超过时间,则不需要重新登录
if (mLoggedin) {
Log.d(TAG, "already logged in");
return true;
}
- mLastLoginTime = System.currentTimeMillis();
- String authToken = loginGoogleAccount(activity, false);
+ mLastLoginTime = System.currentTimeMillis();//更新最后登录时间,改为系统当前的时间
+ String authToken = loginGoogleAccount(activity, false);//判断是否登录到谷歌账户
if (authToken == null) {
Log.e(TAG, "login google account failed");
return false;
}
// login with custom domain if necessary
+ //尝试使用用户自己的域名登录
+ //将用户账号名改为统一格式(小写)后判断是否为一个谷歌账号地址
if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase()
.endsWith("googlemail.com"))) {
StringBuilder url = new StringBuilder(GTASK_URL).append("a/");
int index = mAccount.name.indexOf('@') + 1;
String suffix = mAccount.name.substring(index);
url.append(suffix + "/");
- mGetUrl = url.toString() + "ig";
- mPostUrl = url.toString() + "r/ig";
+ mGetUrl = url.toString() + "ig";//设置用户对应的getUrl
+ mPostUrl = url.toString() + "r/ig";//设置用户对应的postUrl
if (tryToLoginGtask(activity, authToken)) {
mLoggedin = true;
@@ -152,6 +172,7 @@ public class GTaskClient {
}
// try to login with google official url
+ //如果用户账户无法登录,则使用谷歌官方的URI进行登录
if (!mLoggedin) {
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
@@ -164,10 +185,15 @@ public class GTaskClient {
return true;
}
+ /*具体实现登录谷歌账户的方法
+ * 使用令牌机制
+ * 使用AccountManager来管理注册账号
+ * 返回值是账号的令牌
+ */
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
- String authToken;
- AccountManager accountManager = AccountManager.get(activity);
- Account[] accounts = accountManager.getAccountsByType("com.google");
+ String authToken; //令牌,是登录操作保证安全性的一个方法
+ AccountManager accountManager = AccountManager.get(activity);//AccountManager这个类给用户提供了集中注册账号的接口
+ Account[] accounts = accountManager.getAccountsByType("com.google");//获取全部以com.google结尾的account
if (accounts.length == 0) {
Log.e(TAG, "there is no available google account");
@@ -176,6 +202,7 @@ public class GTaskClient {
String accountName = NotesPreferenceActivity.getSyncAccountName(activity);
Account account = null;
+ //遍历获得的accounts信息,寻找已经记录过的账户信息
for (Account a : accounts) {
if (a.name.equals(accountName)) {
account = a;
@@ -190,11 +217,13 @@ public class GTaskClient {
}
// get the token now
+ //获取选中账号的令牌
AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account,
"goanna_mobile", null, activity, null, null);
try {
Bundle authTokenBundle = accountManagerFuture.getResult();
authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
+ //如果是invalidateToken,那么需要调用invalidateAuthToken(String, String)方法废除这个无效token
if (invalidateToken) {
accountManager.invalidateAuthToken("com.google", authToken);
loginGoogleAccount(activity, false);
@@ -207,10 +236,13 @@ public class GTaskClient {
return authToken;
}
+
+ //尝试登陆Gtask,这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法
private boolean tryToLoginGtask(Activity activity, String authToken) {
if (!loginGtask(authToken)) {
- // maybe the auth token is out of date, now let's invalidate the
+ // maybe the auth token is out of authTokedate, now let's invalidate the
// token and try again
+ //删除过一个无效的authToken,申请一个新的后再次尝试登陆
authToken = loginGoogleAccount(activity, true);
if (authToken == null) {
Log.e(TAG, "login google account failed");
@@ -225,25 +257,27 @@ public class GTaskClient {
return true;
}
+ //实现登录GTask的具体操作
private boolean loginGtask(String authToken) {
int timeoutConnection = 10000;
- int timeoutSocket = 15000;
- HttpParams httpParameters = new BasicHttpParams();
- HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
- HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
+ int timeoutSocket = 15000; //socket是一种通信连接实现数据的交换的端口
+ HttpParams httpParameters = new BasicHttpParams(); //实例化一个新的HTTP参数类
+ HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);//设置连接超时时间
+ HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);//设置设置端口超时时间
mHttpClient = new DefaultHttpClient(httpParameters);
- BasicCookieStore localBasicCookieStore = new BasicCookieStore();
+ BasicCookieStore localBasicCookieStore = new BasicCookieStore(); //设置本地cookie
mHttpClient.setCookieStore(localBasicCookieStore);
HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);
// login gtask
try {
- String loginUrl = mGetUrl + "?auth=" + authToken;
- HttpGet httpGet = new HttpGet(loginUrl);
+ String loginUrl = mGetUrl + "?auth=" + authToken; //设置登录的url
+ HttpGet httpGet = new HttpGet(loginUrl); //通过登录的uri实例化网页上资源的查找
HttpResponse response = null;
response = mHttpClient.execute(httpGet);
// get the cookie now
+ //获取CookieStore里存放的cookie,看如果存有“GTL(不知道什么意思)”,则说明有验证成功的有效的cookie
List cookies = mHttpClient.getCookieStore().getCookies();
boolean hasAuthCookie = false;
for (Cookie cookie : cookies) {
@@ -256,6 +290,7 @@ public class GTaskClient {
}
// get the client version
+ //获取client的内容,具体操作是在返回的Content中截取从_setup(开始到)}中间的字符串内容,也就是gtask_url的内容
String resString = getResponseContent(response.getEntity());
String jsBegin = "_setup(";
String jsEnd = ")}";
@@ -280,10 +315,24 @@ public class GTaskClient {
return true;
}
+ /*实例化创建一个用于向网络传输数据的对象
+ * 使用HttpPost类
+ * 返回一个httpPost实例化对象,但里面还没有内容
+ */
private int getActionId() {
return mActionId++;
}
+ /*通过URL获取响应后返回的数据,也就是网络上的数据和资源
+ * 使用getContentEncoding()获取网络上的资源和数据
+ * 返回值就是获取到的资源
+ */
+
+
+ /*实例化创建一个用于向网络传输数据的对象
+ * 使用HttpPost类
+ * 返回一个httpPost实例化对象,但里面还没有内容
+ */
private HttpPost createHttpPost() {
HttpPost httpPost = new HttpPost(mPostUrl);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
@@ -291,6 +340,10 @@ public class GTaskClient {
return httpPost;
}
+ /*通过URL获取响应后返回的数据,也就是网络上的数据和资源
+ * 使用getContentEncoding()获取网络上的资源和数据
+ * 返回值就是获取到的资源
+ */
private String getResponseContent(HttpEntity entity) throws IOException {
String contentEncoding = null;
if (entity.getContentEncoding() != null) {
@@ -299,9 +352,9 @@ public class GTaskClient {
}
InputStream input = entity.getContent();
- if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
+ if (contentEncoding != null && "gzip".equalsIgnoreCase(contentEncoding)) {
input = new GZIPInputStream(entity.getContent());
- } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
+ } else if (contentEncoding != null && "deflate".equalsIgnoreCase(contentEncoding)) {
Inflater inflater = new Inflater(true);
input = new InflaterInputStream(entity.getContent(), inflater);
}
@@ -323,43 +376,57 @@ public class GTaskClient {
}
}
- private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
- if (!mLoggedin) {
- Log.e(TAG, "please login first");
- throw new ActionFailureException("not logged in");
- }
-
- HttpPost httpPost = createHttpPost();
- try {
- LinkedList list = new LinkedList();
- list.add(new BasicNameValuePair("r", js.toString()));
- UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
- httpPost.setEntity(entity);
-
- // execute the post
- HttpResponse response = mHttpClient.execute(httpPost);
- String jsString = getResponseContent(response.getEntity());
- return new JSONObject(jsString);
-
- } catch (ClientProtocolException e) {
- Log.e(TAG, e.toString());
- e.printStackTrace();
- throw new NetworkFailureException("postRequest failed");
- } catch (IOException e) {
- Log.e(TAG, e.toString());
- e.printStackTrace();
- throw new NetworkFailureException("postRequest failed");
- } catch (JSONException e) {
- Log.e(TAG, e.toString());
- e.printStackTrace();
- throw new ActionFailureException("unable to convert response content to jsonobject");
- } catch (Exception e) {
- Log.e(TAG, e.toString());
- e.printStackTrace();
- throw new ActionFailureException("error occurs when posting request");
- }
- }
-
+ /*通过JSON发送请求
+ * 请求的具体内容在json的实例化对象js中然后传入
+ * 利用UrlEncodedFormEntity entity和httpPost.setEntity(entity)方法把js中的内容放置到httpPost中
+ * 执行请求后使用getResponseContent方法得到返回的数据和资源
+ * 将资源再次放入json后返回
+ */
+ private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
+ if (!mLoggedin) {//未登录
+ Log.e(TAG, "please login first");
+ throw new ActionFailureException("not logged in");
+ }
+
+ //实例化一个httpPost的对象用来向服务器传输数据,在这里就是发送请求,而请求的内容在js里
+ HttpPost httpPost = createHttpPost();
+ try {
+ LinkedList list = new LinkedList();
+ list.add(new BasicNameValuePair("r", js.toString()));
+ UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); //UrlEncodedFormEntity()的形式比较单一,是普通的键值对
+ httpPost.setEntity(entity);
+
+ // execute the post
+ //执行这个请求
+ HttpResponse response = mHttpClient.execute(httpPost);
+ String jsString = getResponseContent(response.getEntity());
+ return new JSONObject(jsString);
+
+ } catch (ClientProtocolException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new NetworkFailureException("postRequest failed");
+ } catch (IOException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new NetworkFailureException("postRequest failed");
+ } catch (JSONException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("unable to convert response content to jsonobject");
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("error occurs when posting request");
+ }
+ }
+
+ /*创建单个任务
+ * 传入参数是一个.gtask.data.Task包里Task类的对象
+ * 利用json获取Task里的内容,并且创建相应的jsPost
+ * 利用postRequest得到任务的返回信息
+ * 使用task.setGid设置task的new_ID
+ */
public void createTask(Task task) throws NetworkFailureException {
commitUpdate();
try {
@@ -386,6 +453,9 @@ public class GTaskClient {
}
}
+ /*
+ * 创建一个任务列表,与createTask几乎一样,区别就是最后设置的是tasklist的gid
+ */
public void createTaskList(TaskList tasklist) throws NetworkFailureException {
commitUpdate();
try {
@@ -412,6 +482,11 @@ public class GTaskClient {
}
}
+ /*
+ * 同步更新操作
+ * 使用JSONObject进行数据存储,使用jsPost.put,Put的信息包括UpdateArray和ClientVersion
+ * 使用postRequest发送这个jspost,进行处理
+ */
public void commitUpdate() throws NetworkFailureException {
if (mUpdateArray != null) {
try {
@@ -433,6 +508,10 @@ public class GTaskClient {
}
}
+ /*
+ * 添加更新的事项
+ * 调用commitUpdate()实现
+ */
public void addUpdateNode(Node node) throws NetworkFailureException {
if (node != null) {
// too many update items may result in an error
@@ -441,12 +520,19 @@ public class GTaskClient {
commitUpdate();
}
- if (mUpdateArray == null)
+ if (mUpdateArray == null) {
mUpdateArray = new JSONArray();
+ }
mUpdateArray.put(node.getUpdateAction(getActionId()));
}
}
+ /*
+ * 移动task,比如讲task移动到不同的task列表中去
+ * 通过getGid获取task所属列表的gid
+ * 通过JSONObject.put(String name, Object value)函数设置移动后的task的相关属性值,从而达到移动的目的
+ * 最后还是通过postRequest进行更新后的发送
+ */
public void moveTask(Task task, TaskList preParent, TaskList curParent)
throws NetworkFailureException {
commitUpdate();
@@ -463,15 +549,17 @@ public class GTaskClient {
if (preParent == curParent && task.getPriorSibling() != null) {
// put prioring_sibing_id only if moving within the tasklist and
// it is not the first one
+ //设置优先级ID,只有当移动是发生在文件中
action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());
}
- action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());
- action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());
+ action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); //设置移动前所属列表
+ action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); //设置当前所属列表
if (preParent != curParent) {
// put the dest_list only if moving between tasklists
action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());
}
actionList.put(action);
+ //最后将ACTION_LIST加入到jsPost中
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
@@ -486,6 +574,11 @@ public class GTaskClient {
}
}
+ /*
+ * 删除操作节点
+ * 还是利用JSON
+ * 删除过后使用postRequest发送删除后的结果
+ */
public void deleteNode(Node node) throws NetworkFailureException {
commitUpdate();
try {
@@ -494,7 +587,7 @@ public class GTaskClient {
// action_list
node.setDeleted(true);
- actionList.put(node.getUpdateAction(getActionId()));
+ actionList.put(node.getUpdateAction(getActionId()));//这里会获取到删除操作的ID,加入到actionLiast中
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
@@ -509,6 +602,11 @@ public class GTaskClient {
}
}
+ /*
+ * 获取任务列表
+ * 首先通过GetURI使用getResponseContent从网上获取数据
+ * 然后筛选出"_setup("到)}的部分,并且从中获取GTASK_JSON_LISTS的内容返回
+ */
public JSONArray getTaskLists() throws NetworkFailureException {
if (!mLoggedin) {
Log.e(TAG, "please login first");
@@ -521,6 +619,7 @@ public class GTaskClient {
response = mHttpClient.execute(httpGet);
// get the task list
+ //筛选工作,把筛选出的字符串放入jsString
String resString = getResponseContent(response.getEntity());
String jsBegin = "_setup(";
String jsEnd = ")}";
@@ -531,6 +630,8 @@ public class GTaskClient {
jsString = resString.substring(begin + jsBegin.length(), end);
}
JSONObject js = new JSONObject(jsString);
+
+ //获取GTASK_JSON_LISTS
return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS);
} catch (ClientProtocolException e) {
Log.e(TAG, e.toString());
@@ -547,6 +648,9 @@ public class GTaskClient {
}
}
+ /*
+ * 通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务
+ */
public JSONArray getTaskList(String listGid) throws NetworkFailureException {
commitUpdate();
try {
@@ -558,7 +662,7 @@ public class GTaskClient {
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL);
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
- action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid);
+ action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); //这里设置为传入的listGid
action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false);
actionList.put(action);
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
@@ -579,6 +683,7 @@ public class GTaskClient {
return mAccount;
}
+ //重置更新的内容
public void resetUpdateArray() {
mUpdateArray = null;
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java
index d2b4082..4b1c4f6 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java
@@ -46,8 +46,14 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
-
-
+/**
+ * @aPackage : net.micode.notes.gtask.remote
+ * @aClassName: GTaskManager
+ * @Description:
+ * GTask管理者,提供同步本地和远端的任务,初始化任务列表,同步内容、文件夹,添加、更新本地和远端结点,刷新本地同步任务D等功能
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/24/2023 19:31 PM
+ */
public class GTaskManager {
private static final String TAG = GTaskManager.class.getSimpleName();
@@ -73,49 +79,67 @@ public class GTaskManager {
private boolean mCancelled;
- private HashMap mGTaskListHashMap;
+ private HashMap mGTaskListHashMap = new HashMap<>();
- private HashMap mGTaskHashMap;
+ private HashMap mGTaskHashMap = new HashMap<>();
- private HashMap mMetaHashMap;
+ private HashMap mMetaHashMap = new HashMap<>();
- private TaskList mMetaList;
+ private TaskList mMetaList = null;
- private HashSet mLocalDeleteIdMap;
+ private HashSet mLocalDeleteIdMap = new HashSet<>();
- private HashMap mGidToNid;
+ private HashMap mGidToNid = new HashMap<>();
- private HashMap mNidToGid;
+ private HashMap mNidToGid = new HashMap<>();
private GTaskManager() {
mSyncing = false;
mCancelled = false;
- mGTaskListHashMap = new HashMap();
- mGTaskHashMap = new HashMap();
- mMetaHashMap = new HashMap();
- mMetaList = null;
- mLocalDeleteIdMap = new HashSet();
- mGidToNid = new HashMap();
- mNidToGid = new HashMap();
}
- public static synchronized GTaskManager getInstance() {
+ /**
+ * 包含关键字synchronized,语言级同步,指明该函数可能运行在多线程的环境下。
+ * 功能:类初始化函数
+ * @return GtaskManger
+ */
+ public static synchronized GTaskManager getInstance() {//可能运行在多线程环境下,使用语言级同步--synchronized
if (mInstance == null) {
mInstance = new GTaskManager();
}
return mInstance;
}
+ /**
+ * 包含关键字synchronized,语言级同步,指明该函数可能运行在多线程的环境下。
+ * @param activity
+ */
public synchronized void setActivityContext(Activity activity) {
- // used for getting authtoken
+ // used for getting auth token
mActivity = activity;
}
- public int sync(Context context, GTaskASyncTask asyncTask) {
+ /**
+ * 核心函数
+ * 功能:实现了本地同步操作和远端同步操作,用于同步Google任务列表
+ * @param context-----获取上下文
+ * @param asyncTask-------用于同步的异步操作类
+ * @return int
+ */
+ public int sync(Context context, GTaskASyncTask asyncTask) { //核心函数
+ /*检查是否已经在进行同步操作(mSyncing为true)
+ 如果是,则记录一条调试日志并返回STATE_SYNC_IN_PROGRESS状态,表示同步正在进行中
+ */
if (mSyncing) {
Log.d(TAG, "Sync is in progress");
return STATE_SYNC_IN_PROGRESS;
}
+
+ /*
+ 将传入的context赋值给成员变量mContext,并获取其内容解析器(ContentResolver)赋值给成员变量mContentResolver
+ 将mSyncing设置为true,表示开始同步操作,将mCancelled设置为false,表示同步未被取消
+ 清空所有与任务相关的数据结构(如任务列表、任务映射、元数据映射等)
+ */
mContext = context;
mContentResolver = mContext.getContentResolver();
mSyncing = true;
@@ -127,9 +151,16 @@ public class GTaskManager {
mGidToNid.clear();
mNidToGid.clear();
+ /**
+ *创建一个GTaskClient实例
+ * 重置更新数组
+ * 登录Google任务。如果登录失败,抛出NetworkFailureException异常
+ * 从Google获取任务列表,并将其转换为本地任务列表
+ * 执行内容同步工作
+ */
try {
- GTaskClient client = GTaskClient.getInstance();
- client.resetUpdateArray();
+ GTaskClient client = GTaskClient.getInstance();//getInstance即为创建一个实例,client--客户机
+ client.resetUpdateArray();//JSONArray类型,reset即置为NULL
// login google task
if (!mCancelled) {
@@ -140,15 +171,15 @@ public class GTaskManager {
// get the task list from google
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list));
- initGTaskList();
+ initGTaskList(); //获取Google上的JSONtasklist转为本地TaskList
// do content sync work
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing));
syncContent();
- } catch (NetworkFailureException e) {
- Log.e(TAG, e.toString());
+ } catch (NetworkFailureException e) { //分为两种异常,此类异常为网络异常
+ Log.e(TAG, e.toString()); //创建日志文件(调试信息),error
return STATE_NETWORK_ERROR;
- } catch (ActionFailureException e) {
+ } catch (ActionFailureException e) { //此类异常为操作异常
Log.e(TAG, e.toString());
return STATE_INTERNAL_ERROR;
} catch (Exception e) {
@@ -164,36 +195,54 @@ public class GTaskManager {
mNidToGid.clear();
mSyncing = false;
}
-
+ //根据mCancelled的值返回相应的状态(STATE_SYNC_CANCELLED表示同步已取消,STATE_SUCCESS表示同步成功)
return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS;
}
+ /**
+ *功能:初始化GtaskList,获取Google上的JSONtasklist转为本地TaskList。
+ *获得的数据存储在mMetaList,mGTaskListHashMap,mGTaskHashMap
+ *@exception NetworkFailureException
+ *@return void
+ */
private void initGTaskList() throws NetworkFailureException {
- if (mCancelled)
+ if (mCancelled) {
return;
+ }
+ //getInstance即为创建一个实例,client应指远端客户机,用于与远程服务器进行通信
GTaskClient client = GTaskClient.getInstance();
try {
- JSONArray jsTaskLists = client.getTaskLists();
+ /*Json对象是Name Value对(即子元素)的无序集合,相当于一个Map对象。JsonObject类是bantouyan-json库对Json对象的抽象,提供操纵Json对象的各种方法。
+ 其格式为{"key1":value1,"key2",value2....};key 必须是字符串。
+ 因为ajax请求不刷新页面,但配合js可以实现局部刷新,因此json常常被用来作为异步请求的返回对象使用
+ */
+ JSONArray jsTaskLists = client.getTaskLists(); //通过调用client.getTaskLists()方法获取远程服务器上的任务列表,并将其存储在JSONArray对象jsTaskLists中
// init meta list first
mMetaList = null;
+ /*
+ 遍历jsTaskLists中的每个元素,将其转换为JSONObject对象,并从中提取任务列表的ID和名称
+ */
for (int i = 0; i < jsTaskLists.length(); i++) {
- JSONObject object = jsTaskLists.getJSONObject(i);
+ JSONObject object = jsTaskLists.getJSONObject(i); //JSONObject与JSONArray一个为对象,一个为数组。此处取出单个JASONObject
String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);
String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);
- if (name
- .equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) {
- mMetaList = new TaskList();
- mMetaList.setContentByRemoteJSON(object);
+ /*
+ 如果任务列表的名称以特定的前缀开头且不等于元数据文件夹的前缀,则创建一个新的TaskList对象,并将其添加到本地的任务列表映射中
+ 同时,加载该任务列表的元数据,并将其添加到元数据列表映射中
+ */
+ if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) {
+ mMetaList = new TaskList(); //MetaList意为元表,Tasklist类型,此处为初始化
+ mMetaList.setContentByRemoteJSON(object); //将JSON中部分数据复制到自己定义的对象中相对应的数据:name->mname...
// load meta data
JSONArray jsMetas = client.getTaskList(gid);
for (int j = 0; j < jsMetas.length(); j++) {
object = (JSONObject) jsMetas.getJSONObject(j);
- MetaData metaData = new MetaData();
+ MetaData metaData = new MetaData(); //继承自Node
metaData.setContentByRemoteJSON(object);
- if (metaData.isWorthSaving()) {
+ if (metaData.isWorthSaving()) { //if not worth to save,metadata将不加入mMetaList
mMetaList.addChildTask(metaData);
if (metaData.getGid() != null) {
mMetaHashMap.put(metaData.getRelatedGid(), metaData);
@@ -203,7 +252,10 @@ public class GTaskManager {
}
}
- // create meta list if not existed
+ /*
+ 如果本地没有元数据列表,则创建一个新的元数据列表,并将其设置为默认名称
+ 然后,使用GTaskClient.getInstance().createTaskList(mMetaList)方法将元数据列表上传到远程服务器
+ */
if (mMetaList == null) {
mMetaList = new TaskList();
mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
@@ -211,16 +263,22 @@ public class GTaskManager {
GTaskClient.getInstance().createTaskList(mMetaList);
}
- // init task list
+ /*
+ 最后,再次遍历jsTaskLists中的每个元素,将其转换为JSONObject对象,并从中提取任务列表的ID和名称
+ */
for (int i = 0; i < jsTaskLists.length(); i++) {
JSONObject object = jsTaskLists.getJSONObject(i);
- String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);
+ String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); //通过getString函数传入本地某个标志数据的名称,获取其在远端的名称。
String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);
+ /*
+ 如果任务列表的名称以特定的前缀开头且不等于元数据文件夹的前缀,则创建一个新的TaskList对象,并将其添加到本地的任务列表映射中
+ 同时,加载该任务列表的任务,并将其添加到任务列表映射中
+ */
if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)
&& !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX
- + GTaskStringUtils.FOLDER_META)) {
- TaskList tasklist = new TaskList();
+ + GTaskStringUtils.FOLDER_META)) {
+ TaskList tasklist = new TaskList(); //继承自Node
tasklist.setContentByRemoteJSON(object);
mGTaskListHashMap.put(gid, tasklist);
mGTaskHashMap.put(gid, tasklist);
@@ -240,26 +298,40 @@ public class GTaskManager {
}
}
}
+
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("initGTaskList: handing JSONObject failed");
+ /*
+ 如果在处理过程中发生任何JSONException异常,将记录错误日志并抛出一个ActionFailureException异常
+ */
}
}
- private void syncContent() throws NetworkFailureException {
+ /**
+ * 功能:本地内容同步操作
+ * @throws NetworkFailureException
+ * @return 无返回值
+ */
+ private void syncContent() throws NetworkFailureException { //本地内容同步操作
int syncType;
- Cursor c = null;
- String gid;
- Node node;
+ Cursor c = null; //数据库指针
+ String gid; //GoogleID
+ Node node; //Node包含Sync_Action的不同类型
- mLocalDeleteIdMap.clear();
+ mLocalDeleteIdMap.clear(); //HashSet类型
if (mCancelled) {
return;
}
- // for local deleted note
+ /*
+ 查询本地已删除的笔记(即类型不是系统类型且父ID是垃圾文件夹的笔记),并将查询结果存储在游标c中
+ 遍历游标,获取每个笔记的Google ID(gid)和对应的节点(node)
+ 如果节点不为空,则从mGTaskHashMap中移除该节点,并调用doContentSync()方法进行同步操作
+ 同时,将该笔记的ID添加到mLocalDeleteIdMap中
+ */
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type<>? AND parent_id=?)", new String[] {
@@ -286,10 +358,15 @@ public class GTaskManager {
}
}
- // sync folder first
+ //同步文件夹
syncFolder();
- // for note existing in database
+ /*
+ 查询数据库中存在的笔记(即类型是系统类型且父ID不是垃圾文件夹的笔记),并将查询结果存储在游标c中
+ 遍历游标,获取每个笔记的Google ID(gid)和对应的节点(node)
+ 如果节点不为空,则从mGTaskHashMap中移除该节点,并通过hashmap建立联系
+ 然后根据节点的同步操作类型(syncType),调用doContentSync()方法进行同步操作
+ */
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type=? AND parent_id<>?)", new String[] {
@@ -301,8 +378,8 @@ public class GTaskManager {
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
- mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN));
- mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid);
+ mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); //通过hashmap建立联系
+ mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); //通过hashmap建立联系
syncType = node.getSyncAction(c);
} else {
if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {
@@ -327,23 +404,25 @@ public class GTaskManager {
}
// go through remaining items
- Iterator> iter = mGTaskHashMap.entrySet().iterator();
+ Iterator> iter = mGTaskHashMap.entrySet().iterator(); //Iterator迭代器
while (iter.hasNext()) {
Map.Entry entry = iter.next();
node = entry.getValue();
doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);
}
- // mCancelled can be set by another thread, so we neet to check one by
- // one
- // clear local delete table
+ /*如果mCancelled为假,首先调用DataUtils.batchDeleteNotes()方法批量删除本地已删除的笔记
+ 若删除失败,则抛出ActionFailureException异常
+ */
if (!mCancelled) {
if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) {
throw new ActionFailureException("failed to batch-delete local deleted notes");
}
}
- // refresh local sync id
+ /*
+ 用于提交更新并且刷新本地同步ID
+ */
if (!mCancelled) {
GTaskClient.getInstance().commitUpdate();
refreshLocalSyncId();
@@ -351,6 +430,14 @@ public class GTaskManager {
}
+ /**
+ * 功能:
+ * 同步文件夹
+ * 先查询根文件夹、电话记录文件夹和本地存在的文件夹,然后根据查询结果执行相应的同步操作
+ * 最后,会遍历远程添加的文件夹,并将它们添加到本地
+ * 在整个过程中,如果遇到网络故障,会抛出NetworkFailureException异常
+ * @throws NetworkFailureException
+ */
private void syncFolder() throws NetworkFailureException {
Cursor c = null;
String gid;
@@ -375,8 +462,9 @@ public class GTaskManager {
mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid);
// for system folder, only update remote name if necessary
if (!node.getName().equals(
- GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT))
+ GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) {
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
+ }
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);
}
@@ -394,7 +482,7 @@ public class GTaskManager {
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)",
new String[] {
- String.valueOf(Notes.ID_CALL_RECORD_FOLDER)
+ String.valueOf(Notes.ID_CALL_RECORD_FOLDER)
}, null);
if (c != null) {
if (c.moveToNext()) {
@@ -408,8 +496,9 @@ public class GTaskManager {
// necessary
if (!node.getName().equals(
GTaskStringUtils.MIUI_FOLDER_PREFFIX
- + GTaskStringUtils.FOLDER_CALL_NOTE))
+ + GTaskStringUtils.FOLDER_CALL_NOTE)) {
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
+ }
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);
}
@@ -472,10 +561,19 @@ public class GTaskManager {
}
}
- if (!mCancelled)
+ if (!mCancelled) {
GTaskClient.getInstance().commitUpdate();
+ }
}
+ /**
+ * 功能:
+ * 根据传入的同步类型(syncType)对节点(Node)进行相应的操作
+ * @param syncType
+ * @param node
+ * @param c
+ * @throws NetworkFailureException
+ */
private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
@@ -522,6 +620,14 @@ public class GTaskManager {
}
}
+ /**
+ * 功能:将一个本地节点(Node)添加到数据库中
+ * 首先检查是否已经取消操作,如果是,则直接返回
+ * 否则,根据节点的类型(TaskList或其他类型),创建一个新的SqlNote对象,并设置其内容和父ID
+ * 接下来,将新创建的SqlNote对象提交到数据库中,并更新gid-nid映射以及元数据。
+ * @param node
+ * @throws NetworkFailureException
+ */
private void addLocalNode(Node node) throws NetworkFailureException {
if (mCancelled) {
return;
@@ -596,6 +702,14 @@ public class GTaskManager {
updateRemoteMeta(node.getGid(), sqlNote);
}
+ /**
+ * 功能:update本地node
+ * @param node
+ * ----同步操作的基础数据类型
+ * @param c
+ * ----Cursor
+ * @throws NetworkFailureException
+ */
private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
@@ -619,12 +733,21 @@ public class GTaskManager {
updateRemoteMeta(node.getGid(), sqlNote);
}
+ /**
+ * 功能:远程增加Node
+ * 需要updateRemoteMeta
+ * @param node
+ * ----同步操作的基础数据类型
+ * @param c
+ * --Cursor
+ * @throws NetworkFailureException
+ */
private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
}
- SqlNote sqlNote = new SqlNote(mContext, c);
+ SqlNote sqlNote = new SqlNote(mContext, c); //从本地mContext中获取内容
Node n;
// update remotely
@@ -634,11 +757,12 @@ public class GTaskManager {
String parentGid = mNidToGid.get(sqlNote.getParentId());
if (parentGid == null) {
- Log.e(TAG, "cannot find task's parent tasklist");
+ Log.e(TAG, "cannot find task's parent tasklist"); //调试信息
throw new ActionFailureException("cannot add remote task");
}
- mGTaskListHashMap.get(parentGid).addChildTask(task);
+ mGTaskListHashMap.get(parentGid).addChildTask(task); //在本地生成的GTaskList中增加子结点
+ //登录远程服务器,创建Task
GTaskClient.getInstance().createTask(task);
n = (Node) task;
@@ -649,13 +773,15 @@ public class GTaskManager {
// we need to skip folder if it has already existed
String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX;
- if (sqlNote.getId() == Notes.ID_ROOT_FOLDER)
+ if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) {
folderName += GTaskStringUtils.FOLDER_DEFAULT;
- else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER)
+ } else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER) {
folderName += GTaskStringUtils.FOLDER_CALL_NOTE;
- else
+ } else {
folderName += sqlNote.getSnippet();
+ }
+ //iterator迭代器,通过统一的接口迭代所有的map元素
Iterator> iter = mGTaskListHashMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = iter.next();
@@ -687,11 +813,19 @@ public class GTaskManager {
sqlNote.resetLocalModified();
sqlNote.commit(true);
- // gid-id mapping
+ // gid-id mapping //创建id间的映射
mGidToNid.put(n.getGid(), sqlNote.getId());
mNidToGid.put(sqlNote.getId(), n.getGid());
}
+ /**
+ * 功能:更新远端的Node,包含meta更新(updateRemoteMeta)
+ * @param node
+ * ----同步操作的基础数据类型
+ * @param c
+ * --Cursor
+ * @throws NetworkFailureException
+ */
private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException {
if (mCancelled) {
return;
@@ -701,7 +835,7 @@ public class GTaskManager {
// update remotely
node.setContentByLocalJSON(sqlNote.getContent());
- GTaskClient.getInstance().addUpdateNode(node);
+ GTaskClient.getInstance().addUpdateNode(node); //GTaskClient用途为从本地登陆远端服务器
// update meta
updateRemoteMeta(node.getGid(), sqlNote);
@@ -710,14 +844,17 @@ public class GTaskManager {
if (sqlNote.isNoteType()) {
Task task = (Task) node;
TaskList preParentList = task.getParent();
+ //preParentList为通过node获取的父节点列表
String curParentGid = mNidToGid.get(sqlNote.getParentId());
+ //curParentGid为通过光标在数据库中找到sqlNote的mParentId,再通过mNidToGid由long类型转为String类型的Gid
+
if (curParentGid == null) {
Log.e(TAG, "cannot find task's parent tasklist");
throw new ActionFailureException("cannot update remote task");
}
TaskList curParentList = mGTaskListHashMap.get(curParentGid);
-
+ //通过HashMap找到对应Gid的TaskList
if (preParentList != curParentList) {
preParentList.removeChildTask(task);
curParentList.addChildTask(task);
@@ -725,11 +862,19 @@ public class GTaskManager {
}
}
- // clear local modified flag
sqlNote.resetLocalModified();
+ //commit到本地数据库
sqlNote.commit(true);
}
+ /**
+ * 功能:升级远程meta。 meta---元数据----计算机文件系统管理数据---管理数据的数据。
+ * @param gid
+ * ---GoogleID为String类型
+ * @param sqlNote
+ * ---同步前的数据库操作,故使用类SqlNote
+ * @throws NetworkFailureException
+ */
private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException {
if (sqlNote != null && sqlNote.isNoteType()) {
MetaData metaData = mMetaHashMap.get(gid);
@@ -746,12 +891,17 @@ public class GTaskManager {
}
}
+ /**
+ * 功能:刷新本地,给sync的ID对应上最后更改过的对象
+ * @return void
+ * @throws NetworkFailureException
+ */
private void refreshLocalSyncId() throws NetworkFailureException {
if (mCancelled) {
return;
}
- // get the latest gtask list
+ //获取最近的(最晚的)gtask list
mGTaskHashMap.clear();
mGTaskListHashMap.clear();
mMetaHashMap.clear();
@@ -762,16 +912,16 @@ public class GTaskManager {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type<>? AND parent_id<>?)", new String[] {
String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)
- }, NoteColumns.TYPE + " DESC");
+ }, NoteColumns.TYPE + " DESC"); //query语句:五个参数,NoteColumns.TYPE + " DESC"-----为按类型递减顺序返回查询结果。new String[] {String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)}------为选择参数。"(type<>? AND parent_id<>?)"-------指明返回行过滤器。SqlNote.PROJECTION_NOTE--------应返回的数据列的名字。Notes.CONTENT_NOTE_URI--------contentProvider包含所有数据集所对应的uri
if (c != null) {
while (c.moveToNext()) {
String gid = c.getString(SqlNote.GTASK_ID_COLUMN);
Node node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
- ContentValues values = new ContentValues();
+ ContentValues values = new ContentValues(); //在ContentValues中创建键值对。准备通过contentResolver写入数据
values.put(NoteColumns.SYNC_ID, node.getLastModified());
- mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,
+ mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, //进行批量更改,选择参数为NULL,应该可以用insert替换,参数分别为表名和需要更新的value对象。
c.getLong(SqlNote.ID_COLUMN)), values, null, null);
} else {
Log.e(TAG, "something is missed");
@@ -790,10 +940,18 @@ public class GTaskManager {
}
}
+ /**
+ * 功能:获取同步账号,mAccount.name
+ * @return String
+ */
public String getSyncAccount() {
return GTaskClient.getInstance().getSyncAccount().name;
}
+ /**
+ * 功能:取消同步,置mCancelled为true
+ * @author TTS
+ */
public void cancelSync() {
mCancelled = true;
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java
index cca36f7..b210494 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java
@@ -22,7 +22,16 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
-
+/**
+ * @aPackage : net.micode.notes.gtask.remote
+ * @aClassName: GTaskSyncService
+ * @Description:
+ * 该类继承了Service父类,Service是在一段不定的时间运行在后台,不和用户交互的应用组件
+ * 作用:
+ * GTask同步服务,用于提供同步服务(开始、取消同步),发送广播
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/24/2023 20:15 PM
+ */
public class GTaskSyncService extends Service {
public final static String ACTION_STRING_NAME = "sync_action_type";
@@ -42,20 +51,28 @@ public class GTaskSyncService extends Service {
private static String mSyncProgress = "";
+ /**
+ *功能:用于自动一个同步任务
+ */
private void startSync() {
+ /*
+ 如果mSyncTask为null,则创建一个新的GTaskASyncTask对象,并将其赋值给mSyncTask
+ 这个新对象的构造函数接受两个参数:当前对象(this)和一个Lambda表达式
+ */
if (mSyncTask == null) {
- mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() {
- public void onComplete() {
- mSyncTask = null;
- sendBroadcast("");
- stopSelf();
- }
+ mSyncTask = new GTaskASyncTask(this, () -> {
+ mSyncTask = null;
+ sendBroadcast("");
+ stopSelf();
});
sendBroadcast("");
mSyncTask.execute();
}
}
+ /**
+ * 功能:取消同步任务,以避免不必要的资源占用和潜在的错误
+ */
private void cancelSync() {
if (mSyncTask != null) {
mSyncTask.cancelSync();
@@ -67,11 +84,20 @@ public class GTaskSyncService extends Service {
mSyncTask = null;
}
+ /**
+ * 功能:
+ * 用于处理启动服务时的命令
+ * @param intent
+ * @param flags
+ * @param startId
+ * @return int
+ */
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bundle bundle = intent.getExtras();
if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) {
switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) {
+ //两种情况,开始同步或者取消同步
case ACTION_START_SYNC:
startSync();
break;
@@ -86,6 +112,9 @@ public class GTaskSyncService extends Service {
return super.onStartCommand(intent, flags, startId);
}
+ /**
+ * 功能:用于处理低内存情况,当系统内存不足时,该方法会被调用
+ */
@Override
public void onLowMemory() {
if (mSyncTask != null) {
@@ -97,24 +126,36 @@ public class GTaskSyncService extends Service {
return null;
}
+ /**
+ * 功能:发送一个广播消息,通知其他组件或服务有关同步任务的状态和进度信息
+ * @param msg
+ */
public void sendBroadcast(String msg) {
mSyncProgress = msg;
Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME);
intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null);
intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg);
- sendBroadcast(intent);
+ sendBroadcast(intent);//将intent对象发送出去,以便其他组件或服务可以接收到这个广播消息并进行相应的处理
}
+ /**
+ * 功能:启动一个名为GTaskSyncService的服务来进行同步操作
+ * @param activity
+ */
public static void startSync(Activity activity) {
GTaskManager.getInstance().setActivityContext(activity);
Intent intent = new Intent(activity, GTaskSyncService.class);
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC);
- activity.startService(intent);
+ activity.startService(intent);//启动GTaskSyncService服务,之后服务就会开始执行同步操作
}
+ /**
+ * 功能:取消正在进行的同步操作
+ * @param context
+ */
public static void cancelSync(Context context) {
Intent intent = new Intent(context, GTaskSyncService.class);
- intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC);
+ intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC);//向Intent对象添加额外的数据
context.startService(intent);
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/model/WorkingNote.java b/src/xiaomi/Notes-master/src/net/micode/notes/model/WorkingNote.java
index be081e4..855585b 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/model/WorkingNote.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/model/WorkingNote.java
@@ -280,7 +280,9 @@ public class WorkingNote {
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
}
}
-
+ public void setmContent(String text){
+ mContent = text;
+ }
public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) {
mContent = text;
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/tool/BackupUtils.java b/src/xiaomi/Notes-master/src/net/micode/notes/tool/BackupUtils.java
index 39f6ec4..1028880 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/tool/BackupUtils.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/tool/BackupUtils.java
@@ -34,53 +34,90 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
-
+/**
+ * @aPackage : net.micode.notes.tool
+ * @aClassName: BackupUtils
+ * @Description:
+ * 主要功能:备份工具类,用于数据备份读取、显示
+ * 使用单例模式,确保在整个应用程序只有一个实例
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/23/2023 10:31 AM
+ */
public class BackupUtils {
private static final String TAG = "BackupUtils";
// Singleton stuff
private static BackupUtils sInstance;
+ /**
+ * 作用:用于获取BackupUtils类的实例
+ * 使用synchronized关键字确保在多线程环境下的安全性
+ * @param context
+ * @return sInstance
+ */
public static synchronized BackupUtils getInstance(Context context) {
if (sInstance == null) {
- sInstance = new BackupUtils(context);
+ sInstance = new BackupUtils(context);//创建一个新的BackupUtils实例并将其赋值给sInstance
}
return sInstance;
}
/**
- * Following states are signs to represents backup or restore
- * status
+ * 下列状态是表示备份或还原状态的状态
*/
- // Currently, the sdcard is not mounted
+ // 当前SD卡未挂载
public static final int STATE_SD_CARD_UNMOUONTED = 0;
- // The backup file not exist
+
+ // 备份文件不存在
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
- // The data is not well formated, may be changed by other programs
+
+ //数据格式错误
public static final int STATE_DATA_DESTROIED = 2;
- // Some run-time exception which causes restore or backup fails
+
+ // 系统错误
public static final int STATE_SYSTEM_ERROR = 3;
- // Backup or restore success
+
+ // 备份或恢复成功
public static final int STATE_SUCCESS = 4;
private TextExport mTextExport;
+ /**
+ * 作用:接收一个Context参数,并使用该参数创建一个TextExport实例
+ * @param context
+ */
private BackupUtils(Context context) {
mTextExport = new TextExport(context);
}
+ /**
+ * 作用: 用于检查外部存储是否可用
+ * @return boolean
+ */
private static boolean externalStorageAvailable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
+ /**
+ * 作用:用于将数据导出到文本文件。
+ * @return int
+ */
public int exportToText() {
return mTextExport.exportToText();
}
+ /**
+ * 作用:用于获取导出的文本文件名
+ * @return String
+ */
public String getExportedTextFileName() {
return mTextExport.mFileName;
}
+ /**
+ * 作用:用于获取导出的文本文件目录
+ * @return String
+ */
public String getExportedTextFileDir() {
return mTextExport.mFileDirectory;
}
@@ -125,6 +162,10 @@ public class BackupUtils {
private String mFileName;
private String mFileDirectory;
+ /**
+ * 作用:接收一个Context对象作为参数,并初始化一些成员变量,如TEXT_FORMAT、mContext、mFileName和mFileDirectory
+ * @param context
+ */
public TextExport(Context context) {
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note);
mContext = context;
@@ -132,12 +173,19 @@ public class BackupUtils {
mFileDirectory = "";
}
+ /**
+ * 作用:根据传入的id返回对应的文本格式
+ * @param id
+ * @return String
+ */
private String getFormat(int id) {
return TEXT_FORMAT[id];
}
/**
- * Export the folder identified by folder id to text
+ * 作用:用于将指定文件夹下的所有笔记导出为文本文件
+ * @param folderId
+ * @param ps
*/
private void exportFolderToText(String folderId, PrintStream ps) {
// Query notes belong to this folder
@@ -146,6 +194,9 @@ public class BackupUtils {
folderId
}, null);
+ /*
+ 查询该文件夹下的所有笔记,然后遍历每个笔记,打印其最后修改日期和内容
+ */
if (notesCursor != null) {
if (notesCursor.moveToFirst()) {
do {
@@ -155,7 +206,7 @@ public class BackupUtils {
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// Query data belong to this note
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
- exportNoteToText(noteId, ps);
+ exportNoteToText(noteId, ps);//将笔记的内容导出为文本
} while (notesCursor.moveToNext());
}
notesCursor.close();
@@ -163,9 +214,12 @@ public class BackupUtils {
}
/**
- * Export note identified by id to a print stream
+ * 作用:将指定ID的笔记导出到文本文件中,包括电话记录和普通笔记的内容
+ * @param noteId
+ * @param ps
*/
private void exportNoteToText(String noteId, PrintStream ps) {
+ //查询与给定noteId相关的数据,并将结果存储在Cursor对象dataCursor中
Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI,
DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] {
noteId
@@ -175,6 +229,9 @@ public class BackupUtils {
if (dataCursor.moveToFirst()) {
do {
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
+ /*
+ 表示该记录是一个电话记录,此时,获取电话记录中的电话号码、通话日期和位置信息,并将其格式化后输出到PrintStream对象ps中
+ */
if (DataConstants.CALL_NOTE.equals(mimeType)) {
// Print phone number
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER);
@@ -194,7 +251,7 @@ public class BackupUtils {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
location));
}
- } else if (DataConstants.NOTE.equals(mimeType)) {
+ } else if (DataConstants.NOTE.equals(mimeType)) {//表示该记录是一个普通笔记,此时,获取笔记的内容,并将其格式化后输出到PrintStream对象ps中
String content = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(content)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
@@ -205,7 +262,7 @@ public class BackupUtils {
}
dataCursor.close();
}
- // print a line separator between note
+ // 向PrintStream对象ps中写入一个换行符,用于分隔不同笔记之间的内容
try {
ps.write(new byte[] {
Character.LINE_SEPARATOR, Character.LETTER_NUMBER
@@ -216,14 +273,21 @@ public class BackupUtils {
}
/**
- * Note will be exported as text which is user readable
+ * 作用:将笔记导出到文本文件中
+ * @return int
*/
public int exportToText() {
+ /*
+ 如果外部存储未挂载,则记录一条日志并返回一个表示外部存储未挂载的状态码(STATE_SD_CARD_UNMOUONTED)
+ */
if (!externalStorageAvailable()) {
Log.d(TAG, "Media was not mounted");
return STATE_SD_CARD_UNMOUONTED;
}
-
+ /*
+ 获取一个用于输出到文本文件的打印流(PrintStream),并将其赋值给变量ps
+ 如果获取打印流失败,则记录一条错误日志并返回一个表示系统错误的状态码(STATE_SYSTEM_ERROR)
+ */
PrintStream ps = getExportToTextPrintStream();
if (ps == null) {
Log.e(TAG, "get print stream error");
@@ -237,7 +301,9 @@ public class BackupUtils {
+ NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null);
+
if (folderCursor != null) {
+
if (folderCursor.moveToFirst()) {
do {
// Print folder's name
@@ -247,6 +313,7 @@ public class BackupUtils {
} else {
folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET);
}
+ //将格式化后的文件夹名称写入打印流ps
if (!TextUtils.isEmpty(folderName)) {
ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName));
}
@@ -264,6 +331,10 @@ public class BackupUtils {
NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
+ "=0", null, null);
+ /*如果noteCursor不为空,则遍历查询结果
+ 将格式化后的笔记修改日期写入打印流ps
+ 获取笔记的ID,并调用exportNoteToText方法将笔记的内容导出到文本文件中
+ */
if (noteCursor != null) {
if (noteCursor.moveToFirst()) {
do {
@@ -283,16 +354,21 @@ public class BackupUtils {
}
/**
- * Get a print stream pointed to the file {@generateExportedTextFile}
+ * 作用:建一个用于导出文本的PrintStream对象
+ * @return PrintStream
*/
private PrintStream getExportToTextPrintStream() {
+ //生成一个文件,该文件位于SD卡上
File file = generateFileMountedOnSDcard(mContext, R.string.file_path,
R.string.file_name_txt_format);
+ /*
+ 表示创建文件失败,此时会记录一条错误日志(Log.e(TAG, "create file to exported failed"))
+ */
if (file == null) {
Log.e(TAG, "create file to exported failed");
return null;
}
- mFileName = file.getName();
+ mFileName = file.getName();//文件名赋值给成员变量mFileName
mFileDirectory = mContext.getString(R.string.file_path);
PrintStream ps = null;
try {
@@ -310,19 +386,27 @@ public class BackupUtils {
}
/**
- * Generate the text file to store imported data
+ * 作用:用于在Android设备上生成一个文件
+ * @param context
+ * @param filePathResId
+ * @param fileNameFormatResId
+ * @return File
*/
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder();
- sb.append(Environment.getExternalStorageDirectory());
- sb.append(context.getString(filePathResId));
+ sb.append(Environment.getExternalStorageDirectory()); //获取外部存储设备的根目录
+ sb.append(context.getString(filePathResId)); //根据传入的filePathResId参数,将指定的路径添加到根目录下
File filedir = new File(sb.toString());
+ //根据传入的fileNameFormatResId参数和当前日期时间,生成文件名,并将其添加到目录路径中
sb.append(context.getString(
fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd),
System.currentTimeMillis())));
File file = new File(sb.toString());
-
+ /*
+ 尝试创建文件所在的目录(如果不存在),并创建文件本身(如果不存在)
+ 如果成功创建了文件,返回该文件的引用;否则,返回null
+ */
try {
if (!filedir.exists()) {
filedir.mkdir();
@@ -338,7 +422,7 @@ public class BackupUtils {
}
return null;
+ }
}
-}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/tool/DataUtils.java b/src/xiaomi/Notes-master/src/net/micode/notes/tool/DataUtils.java
index 2a14982..4065280 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/tool/DataUtils.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/tool/DataUtils.java
@@ -33,21 +33,38 @@ import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
import java.util.ArrayList;
import java.util.HashSet;
-
+/**
+ * @aPackage : net.micode.notes.tool
+ * @aClassName: DataUtils
+ * @Description:
+ * 主要功能:实现便签数据处理工具类,封装如查找、移动、删除数据等操作
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/30/2023 08:31 AM
+ */
public class DataUtils {
public static final String TAG = "DataUtils";
+
+ /**
+ * 作用:用于批量删除笔记
+ * @param resolver
+ * @param ids
+ * @return boolean
+ */
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet ids) {
+ //判断ids是否为空
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
}
+ //判断ids大小是否为0
if (ids.size() == 0) {
Log.d(TAG, "no id is in the hashset");
return true;
}
-
+ //创建类存储删除的动作
ArrayList operationList = new ArrayList();
+ //遍历ID,如果发现是根文件夹,则不删除
for (long id : ids) {
if(id == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Don't delete system folder root");
@@ -57,9 +74,10 @@ public class DataUtils {
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
operationList.add(builder.build());
}
+ //批量删除操作
try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
- if (results == null || results.length == 0 || results[0] == null) {
+ if (results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
}
@@ -72,14 +90,29 @@ public class DataUtils {
return false;
}
+ /**
+ * 作用:将一个笔记从一个文件夹移动到另一个文件夹
+ * @param resolver
+ * @param id
+ * @param srcFolderId
+ * @param 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);
values.put(NoteColumns.LOCAL_MODIFIED, 1);
+ //对需要移动的便签进行数据更新,然后用update实现
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
}
+ /**
+ * 作用:用于将一组笔记(由id集合表示)批量移动到指定的文件夹
+ * @param resolver
+ * @param ids
+ * @param folderId
+ * @return boolean
+ */
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids,
long folderId) {
if (ids == null) {
@@ -89,13 +122,15 @@ public class DataUtils {
ArrayList operationList = new ArrayList();
for (long id : ids) {
+ //通过withAppendedId方法,为该Uri加上ID
ContentProviderOperation.Builder builder = ContentProviderOperation
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
builder.withValue(NoteColumns.PARENT_ID, folderId);
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
operationList.add(builder.build());
- }
+ }//将ids里包含的每一列的数据逐次加入到operationList中,等待最后的批量处理
+ //使用ContentResolver的applyBatch方法执行批量更新操作
try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
if (results == null || results.length == 0 || results[0] == null) {
@@ -112,39 +147,50 @@ public class DataUtils {
}
/**
- * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}}
+ * 作用 :获取除系统文件夹之外的所有文件夹数量
+ * @param resolver
+ * @return count
*/
public static int getUserFolderCount(ContentResolver resolver) {
Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { "COUNT(*)" },
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
+ //筛选条件:源文件不为trash folder,即垃圾文件
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
null);
int count = 0;
- if(cursor != null) {
- if(cursor.moveToFirst()) {
- try {
- count = cursor.getInt(0);
- } catch (IndexOutOfBoundsException e) {
- Log.e(TAG, "get folder count failed:" + e.toString());
- } finally {
- cursor.close();
- }
+ if(cursor != null && cursor.moveToFirst()) {
+ try {
+ //获取文件夹的数量,并将其赋值给count变量
+ count = cursor.getInt(0);
+ } catch (IndexOutOfBoundsException e) {
+ Log.e(TAG, "get folder count failed:" + e.toString());
+ } finally {
+ cursor.close();
}
}
return count;
}
+ /**
+ * 作用:用于检查一个笔记是否在Note数据库中可见
+ * @param resolver
+ * @param noteId
+ * @param type
+ * @return boolean
+ */
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null,
+ //查询条件:type符合,且不属于垃圾文件夹
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
new String [] {String.valueOf(type)},
null);
boolean exist = false;
if (cursor != null) {
+ //用getCount函数判断cursor是否为空
if (cursor.getCount() > 0) {
exist = true;
}
@@ -153,6 +199,12 @@ public class DataUtils {
return exist;
}
+ /**
+ * 作用:用于检查一个笔记是否存在于Note数据库中
+ * @param resolver
+ * @param noteId
+ * @return boolean
+ */
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null, null, null);
@@ -167,6 +219,12 @@ public class DataUtils {
return exist;
}
+ /**
+ * 作用:用于检查给定的数据ID是否存在于数据数据库中(检查方法同上)
+ * @param resolver
+ * @param dataId
+ * @return boolean
+ */
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
null, null, null, null);
@@ -181,6 +239,12 @@ public class DataUtils {
return exist;
}
+ /**
+ * 作用:用于检查给定的文件夹名称是否在Notes数据库中可见
+ * @param resolver
+ * @param name
+ * @return boolean
+ */
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
@@ -188,6 +252,7 @@ public class DataUtils {
" AND " + NoteColumns.SNIPPET + "=?",
new String[] { name }, null);
boolean exist = false;
+ //通过名字查询文件是否存在
if(cursor != null) {
if(cursor.getCount() > 0) {
exist = true;
@@ -197,7 +262,14 @@ public class DataUtils {
return exist;
}
+ /**
+ * 作用:用于从Notes数据库中获取指定文件夹ID下的所有小部件属性
+ * @param resolver
+ * @param folderId
+ * @return HashSet
+ */
public static HashSet getFolderNoteWidget(ContentResolver resolver, long folderId) {
+ //查询条件:父ID是传入的folderId
Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
NoteColumns.PARENT_ID + "=?",
@@ -211,6 +283,10 @@ public class DataUtils {
do {
try {
AppWidgetAttribute widget = new AppWidgetAttribute();
+ /*
+ 0对应NoteColumns.WIDGET_ID
+ 1行应的NoteColumns.WIDGET_TYPE
+ */
widget.widgetId = c.getInt(0);
widget.widgetType = c.getInt(1);
set.add(widget);
@@ -224,6 +300,12 @@ public class DataUtils {
return set;
}
+ /**
+ * 作用:用于根据笔记ID获取通话记录中的电话号码
+ * @param resolver
+ * @param noteId
+ * @return String
+ */
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.PHONE_NUMBER },
@@ -243,6 +325,13 @@ public class DataUtils {
return "";
}
+ /**
+ * 作用:用于根据电话号码和通话日期从Android的ContentResolver中查询Notes数据库中的记录
+ * @param resolver
+ * @param phoneNumber
+ * @param callDate
+ * @return long
+ */
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.NOTE_ID },
@@ -264,7 +353,14 @@ public class DataUtils {
return 0;
}
+ /**
+ * 作用:根据给定的noteId从ContentResolver中获取对应的笔记片段(snippet)
+ * @param resolver
+ * @param noteId
+ * @return String
+ */
public static String getSnippetById(ContentResolver resolver, long noteId) {
+ //查询条件:noteId
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String [] { NoteColumns.SNIPPET },
NoteColumns.ID + "=?",
@@ -282,6 +378,11 @@ public class DataUtils {
throw new IllegalArgumentException("Note is not found with id: " + noteId);
}
+ /**
+ * 作用:对输入的字符串进行处理,返回处理后的字符串
+ * @param snippet
+ * @return String
+ */
public static String getFormattedSnippet(String snippet) {
if (snippet != null) {
snippet = snippet.trim();
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java b/src/xiaomi/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java
index 666b729..85480ee 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java
@@ -15,9 +15,19 @@
*/
package net.micode.notes.tool;
+/**
+ * @aPackage : net.micode.notes.tool
+ * @aClassName: GTaskStringUtils
+ * @Description:
+ * 主要功能:同步中使用的字符串工具类,为jsonObject提供string对象
+ * 定义了很多的静态字符串,目的就是为了提供jsonObject中相应字符串的"key"。把这些静态的定义单独写到了一个类里面,方便查看管理
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/30/2023 10:31 AM
+ */
public class GTaskStringUtils {
+
public final static String GTASK_JSON_ACTION_ID = "action_id";
public final static String GTASK_JSON_ACTION_LIST = "action_list";
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/tool/ResourceParser.java b/src/xiaomi/Notes-master/src/net/micode/notes/tool/ResourceParser.java
index 1ad3ad6..552bb89 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/tool/ResourceParser.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/tool/ResourceParser.java
@@ -21,7 +21,22 @@ import android.preference.PreferenceManager;
import net.micode.notes.R;
import net.micode.notes.ui.NotesPreferenceActivity;
-
+/**
+ * @aPackage : net.micode.notes.tool
+ * @aClassName: ResourceParser
+ * @Description:
+ * 主要功能:界面元素的解析工具类,利用R.java这个类来获取资源供程序调用
+ * 字面意义是资源分析器,实际上就是获取资源并且在程序中使用,比如颜色图片等
+ * 实现方法:实现方法:主要利用R.java这个类,其中包括
+ * R.id 组件资源引用
+ * R.drawable 图片资源 (被使用)
+ * R.layout 布局资源
+ * R.menu 菜单资源
+ * R.String 文字资源
+ * R.style 主题资源 (被使用)
+ * @aAuthor: Li Qiushi
+ * @createdate: 12/30/2023 10:31 AM
+ */
public class ResourceParser {
public static final int YELLOW = 0;
@@ -39,6 +54,9 @@ public class ResourceParser {
public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM;
+ /**
+ * 提供两个静态方法,用于根据给定的索引值获取相应的背景图像资源ID
+ */
public static class NoteBgResources {
private final static int [] BG_EDIT_RESOURCES = new int [] {
R.drawable.edit_yellow,
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/translate/BaiduTranslateService.java b/src/xiaomi/Notes-master/src/net/micode/notes/translate/BaiduTranslateService.java
new file mode 100644
index 0000000..8e26c2c
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/translate/BaiduTranslateService.java
@@ -0,0 +1,24 @@
+package net.micode.notes.translate;
+
+import retrofit2.Call;
+import retrofit2.http.Field;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.POST;
+//源URL https://fanyi-api.baidu.com/api/trans/vip/translate
+//参数如下
+// String q 英文单词/中文
+// String from 原始语种 zh中文/eh英文
+// String to 目标语种 zh中文/eh英文
+// String from zh中文/eh英文
+// String appid 你的appid
+// String salt 随机数(整形转字符串)
+// String sign 签名 32位字母小写MD5编码的 appid+q+salt+密钥
+public interface BaiduTranslateService {
+ //翻译接口
+ //表示提交表单数据,@Field注解键名
+ //适用于数据量少的情况
+ @POST("translate")
+ @FormUrlEncoded
+ Call translate(@Field("q") String q, @Field("from") String from, @Field("to") String to, @Field("appid") String appid, @Field("salt") String salt,
+ @Field("sign") String sign);
+}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/translate/MD5Utils.java b/src/xiaomi/Notes-master/src/net/micode/notes/translate/MD5Utils.java
new file mode 100644
index 0000000..ecd9e6e
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/translate/MD5Utils.java
@@ -0,0 +1,35 @@
+package net.micode.notes.translate;
+
+import java.security.MessageDigest;
+
+/**
+ * 加密解密工具类(对字符串加密) MD5加密
+ */
+public class MD5Utils {
+
+ /**
+ * MD5加密算法使用 对字符串加密
+ *
+ * @param info 参数为需要加密的String
+ * @return 返回加密后的String
+ */
+ public static String getMD5Code(String info) {
+ try {
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ md5.update(info.getBytes("utf-8"));//设置编码格式
+ byte[] encryption = md5.digest();
+ StringBuffer stringBuffer = new StringBuffer();
+ for (int i = 0; i < encryption.length; i++) {
+ if (Integer.toHexString(0xff & encryption[i]).length() == 1) {
+ stringBuffer.append("0").append(Integer.toHexString(0xff & encryption[i]));
+ } else {
+ stringBuffer.append(Integer.toHexString(0xff & encryption[i]));
+ }
+ }
+ return stringBuffer.toString();
+ } catch (Exception e) {
+ return "MD5加密异常";
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/translate/RespondBean.java b/src/xiaomi/Notes-master/src/net/micode/notes/translate/RespondBean.java
new file mode 100644
index 0000000..eddfe3d
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/translate/RespondBean.java
@@ -0,0 +1,65 @@
+package net.micode.notes.translate;
+
+import java.util.List;
+
+public class RespondBean {
+
+ /**
+ * from : zh
+ * to : en
+ * trans_result : [{"src":"你好","dst":"Hello"}]
+ */
+
+ private String from;
+ private String to;
+ private List trans_result;
+
+ public String getFrom() {
+ return from;
+ }
+
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ public String getTo() {
+ return to;
+ }
+
+ public void setTo(String to) {
+ this.to = to;
+ }
+
+ public List getTrans_result() {
+ return trans_result;
+ }
+
+ public void setTrans_result(List trans_result) {
+ this.trans_result = trans_result;
+ }
+
+ public static class TransResultBean {
+ /**
+ * src : 你好
+ * dst : Hello
+ */
+ private String src;
+ private String dst;
+
+ public String getSrc() {
+ return src;
+ }
+
+ public void setSrc(String src) {
+ this.src = src;
+ }
+
+ public String getDst() {
+ return dst;
+ }
+
+ public void setDst(String dst) {
+ this.dst = dst;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java
index ca89c22..6609d84 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java
@@ -55,14 +55,16 @@ import java.io.IOException;
* @UpdateRemark: 更新说明:
* @Version: 1.0
*/
+
+
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
- private long mNoteId; //文本在数据库存储中的ID号
- private String mSnippet; //闹钟提示时出现的文本片段
+ private long mNoteId;//文本在数据库存储中的ID号
+ private String mSnippet;//闹钟提示时出现的文本片段
private static final int SNIPPET_PREW_MAX_LEN = 60;
MediaPlayer mPlayer;
-
- /**
+
+ /**
* @method onCreate
* @description :
* 初始化提醒界面的布局和逻辑。
@@ -78,24 +80,25 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
* @param
* @return
*/
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- //Bundle类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的
+ //Bundle类型的数据与Map类型的数据相似,都是以key-value的形式存储数据的
//onsaveInstanceState方法是用来保存Activity的状态的
//能从onCreate的参数savedInsanceState中获得状态数
requestWindowFeature(Window.FEATURE_NO_TITLE);
- //界面显示——无标题
+ //界面显示——无标题
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
if (!isScreenOn()) {
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
- //保持窗体点亮
+ //保持窗体点亮
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
- //将窗体点亮
+ //将窗体点亮
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
- //允许窗体点亮时锁屏
+ //允许窗体点亮时锁屏
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
}//在手机锁屏后如果到了闹钟提示时间,点亮屏幕
@@ -104,12 +107,12 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
try {
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
- //根据ID从数据库中获取标签的内容;
- //getContentResolver()是实现数据共享,实例存储。
+ //根据ID从数据库中获取标签的内容;
+ //getContentResolver()是实现数据共享,实例存储
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info)
: mSnippet;
- //判断标签片段是否达到符合长度
+ //判断标签片段是否达到符合长度
} catch (IllegalArgumentException e) {
e.printStackTrace();
return;
@@ -118,16 +121,17 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
mPlayer = new MediaPlayer();
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog();
- //弹出对话框
+ //弹出对话框
playAlarmSound();
- //闹钟提示音激发
+ //闹钟提示音激发
} else {
finish();
- //完成闹钟动作
+ //完成闹钟动作
}
}
- /**
+
+ /**
* @method isScreenOn
* @description 判断屏幕是否锁屏,调用系统函数判断
* @date: 2023-12-24 10:45
@@ -140,7 +144,9 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
return pm.isScreenOn();
}
- /**
+
+
+ /**
* @method playAlarmSound
* @description:
* 该段代码的作用是根据用户的设置,播放系统默认的闹钟铃声。
@@ -152,7 +158,7 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
*/
private void playAlarmSound() {
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
- //调用系统的铃声管理URI,得到闹钟提示音
+ //调用系统的铃声管理URI,得到闹钟提示音
int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
@@ -163,19 +169,20 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
try {
mPlayer.setDataSource(this, url);
- //方法:setDataSource(Context context, Uri uri)
+ //方法:setDataSource(Context context, Uri uri)
//解释:无返回值,设置多媒体数据来源【根据 Uri】
mPlayer.prepare();
- //准备同步
+ //准备同步
mPlayer.setLooping(true);
- //设置是否循环播放
+ //设置是否循环播放
mPlayer.start();
- //开始播放
+ //开始播放
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
- //e.printStackTrace()函数功能是抛出异常, 还将显示出更深的调用信息
+ //e.printStackTrace()函数功能是抛出异常, 还将显示出更深的调用信息
//System.out.println(e),这个方法打印出异常,并且输出在哪里出现的异常
+
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -189,7 +196,7 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
- /**
+ /**
* @method showActionDialog
* @description
* 创建一个AlertDialog.Builder对象,并设置对话框的标题为应用的名称(R.string.app_name)。
@@ -202,27 +209,30 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
* @param
* @return
*/
+
private void showActionDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- /*
+ /*
* AlertDialog的构造方法全部是Protected的
* 所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。
* 要创建一个AlertDialog,就要用到AlertDialog.Builder中的create()方法
* 如这里的dialog就是新建了一个AlertDialog
*/
dialog.setTitle(R.string.app_name);
- //为对话框设置标题
+ //为对话框设置标题
dialog.setMessage(mSnippet);
- //为对话框设置内容
+ //为对话框设置内容
dialog.setPositiveButton(R.string.notealert_ok, this);
- //给对话框添加"Yes"按钮
+ //给对话框添加"Yes"按钮
if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this);
}//对话框添加"No"按钮
dialog.show().setOnDismissListener(this);
}
- /**
+
+
+ /**
* @method onClick
* @description :
* 根据点击的按钮类型执行相应的操作,
@@ -234,26 +244,27 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
*/
public void onClick(DialogInterface dialog, int which) {
switch (which) {
- //用which来选择click后下一步的操作
+ //用which来选择click后下一步的操作
case DialogInterface.BUTTON_NEGATIVE:
- //这是取消操作
+ //这是取消操作
Intent intent = new Intent(this, NoteEditActivity.class);
- //实现两个类间的数据传输
+ //实现两个类间的数据传输
intent.setAction(Intent.ACTION_VIEW);
- //设置动作属性
+ //设置动作属性
intent.putExtra(Intent.EXTRA_UID, mNoteId);
- //实现key-value对
+ //实现key-value对
//EXTRA_UID为key;mNoteId为键
startActivity(intent);
- //开始动作
+ //开始动作
break;
default:
- //这是确定操作'
+ //这是确定操作'
break;
}
}
- /**
+
+ /**
* @method onDismiss
* @description 在闹钟提醒对话框消失时,停止闹钟铃声并结束当前Activity的生命周期。
* @date: 2023-12-24 10:57
@@ -263,11 +274,13 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
*/
public void onDismiss(DialogInterface dialog) {
stopAlarmSound();
- //停止闹钟声音
+ //停止闹钟声音
finish();
- //完成该动作
+ //完成该动作
}
- /**
+
+
+ /**
* @method stopAlarmSound
* @description 停止正在播放的闹钟声音,并释放相关的资源。
* @date: 2023-12-24 10:58
@@ -278,9 +291,9 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop();
- //停止播放
+ //停止播放
mPlayer.release();
- //释放MediaPlayer对象
+ //释放MediaPlayer对象
mPlayer = null;
}
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver.java
index 16d229a..bdd8067 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver.java
@@ -27,6 +27,7 @@ import android.database.Cursor;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
+
/**
*
* @ProjectName:
@@ -54,7 +55,7 @@ public class AlarmInitReceiver extends BroadcastReceiver {
private static final int COLUMN_ALERTED_DATE = 1;
- /**
+ /**
* @method onReceive
* @description 是在设备启动后,通过查询数据库找到需要提醒的标签,并设置对应的闹钟。
* 这样,在设备启动完成后,小米便签应用可以重新加载标签的提醒功能,确保按时提醒用户。
@@ -66,18 +67,20 @@ public class AlarmInitReceiver extends BroadcastReceiver {
* 创建PendingIntent:使用getBroadcast()方法创建一个用于启动广播的PendingIntent对象(pendingIntent)
* @return 查询结果将以Cursor对象(c)返回
*/
+
@Override
public void onReceive(Context context, Intent intent) {
long currentDate = System.currentTimeMillis();
- //System.currentTimeMillis()产生一个当前的毫秒
+ //System.currentTimeMillis()产生一个当前的毫秒
//这个毫秒其实就是自1970年1月1日0时起的毫秒数
+
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
new String[] { String.valueOf(currentDate) },
- //将long变量currentDate转化为字符串
+ //将long变量currentDate转化为字符串
null);
- //Cursor在这里的作用是通过查找数据库中的标签内容,找到和当前系统时间相等的标签
+ //Cursor在这里的作用是通过查找数据库中的标签内容,找到和当前系统时间相等的标签
if (c != null) {
if (c.moveToFirst()) {
do {
@@ -93,7 +96,7 @@ public class AlarmInitReceiver extends BroadcastReceiver {
c.close();
}
}
- /*
+/*
* 然而通过网上查找资料发现,对于闹钟机制的启动,通常需要上面的几个步骤
* 如新建Intent、PendingIntent以及AlarmManager等
* 这里就是根据数据库里的闹钟时间创建一个闹钟机制
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmReceiver .java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmReceiver .java
new file mode 100644
index 0000000..b29d722
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmReceiver .java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.micode.notes.ui;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ *
+ * @ProjectName:
+ * @Package: net.micode.notes.ui
+ * @ClassName: AlarmReceiver
+ * @Description: 通过AlarmReceiver类,可以实现小米便签的提醒功能,
+ * 让用户按时收到提醒并进行相应的操作。
+ * @Author: xumingyang
+ * @CreateDate: 2023-12-24 12:46
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2023-12-24 12:46
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+
+
+ /**
+ * @method
+ * @description 段代码是用于在接收到广播时启动AlarmAlertActivity活动,并在新的任务栈中展示该活动
+ * @param *Context context和Intent intent,其中context表示上下文环境,intent表示接收到的广播意图。
+ * @return
+ */
+
+public class AlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ //重写了onReceive()方法,该方法在接收到广播时会被调用
+ intent.setClass(context, AlarmAlertActivity.class);
+ //启动AlarmAlertActivity
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ //activity要存在于activity的栈中,而非activity的途径启动activity时必然不存在一个activity的栈
+ //所以要新起一个栈装入启动的activity
+ context.startActivity(intent);
+ }
+}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmReceiver.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmReceiver.java
index d425245..b29d722 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmReceiver.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/AlarmReceiver.java
@@ -42,14 +42,15 @@ import android.content.Intent;
* @param *Context context和Intent intent,其中context表示上下文环境,intent表示接收到的广播意图。
* @return
*/
+
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- //重写了onReceive()方法,该方法在接收到广播时会被调用
+ //重写了onReceive()方法,该方法在接收到广播时会被调用
intent.setClass(context, AlarmAlertActivity.class);
- ////启动AlarmAlertActivity
+ //启动AlarmAlertActivity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ////activity要存在于activity的栈中,而非activity的途径启动activity时必然不存在一个activity的栈
+ //activity要存在于activity的栈中,而非activity的途径启动activity时必然不存在一个activity的栈
//所以要新起一个栈装入启动的activity
context.startActivity(intent);
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/ChangePassword.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/ChangePassword.java
new file mode 100644
index 0000000..e574088
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/ChangePassword.java
@@ -0,0 +1,81 @@
+package net.micode.notes.ui;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+import net.micode.notes.R;
+
+public class ChangePassword extends Activity{
+ EditText OldPassword;//声明了旧密码的文本编辑框
+ EditText NewPassword;
+ EditText AckPassword;//确认密码
+ Button Acknowledged;//声明了一个确认按钮
+
+ @SuppressLint("MissingInflatedId")//使用注解忽略缺少的布局资源ID的警告。
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);//调用父类的onCreate方法
+ setContentView(R.layout.activity_change_loginpassword);//按照所给的布局文件进行当前页面布局
+
+ //设置软键盘的显示模式,通过findViewById方法来获取布局文件中各种文本编辑框和按钮
+ getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+ | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ OldPassword=(EditText) findViewById(R.id.old_password);
+ NewPassword=(EditText) findViewById(R.id.new_password);
+ AckPassword=(EditText) findViewById(R.id.ack_password);
+ Acknowledged=(Button)findViewById(R.id.Bt_Acknowledged);
+
+ //给确认按钮设置了点击监听
+ Acknowledged.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ String old_password = OldPassword.getText().toString();//获取文本框中输入内容
+ String new_password = NewPassword.getText().toString();
+ String ack_password = AckPassword.getText().toString();
+
+ //用getSharedPreferences方法来获取名为“user management”的对象,用来存储数据
+ //从SharedPreferences中来获取密码值作为登录密码
+ SharedPreferences pref=getSharedPreferences("user management",MODE_PRIVATE);
+ String login_password=pref.getString("password","");
+ if(old_password.equals("")==true || new_password.equals("")==true || ack_password.equals("")==true) {
+ Toast.makeText(ChangePassword.this, "密码不能为空", Toast.LENGTH_SHORT).show();//进行一个消息提示
+ }
+ else if (new_password.equals(ack_password) == false) {
+ Toast.makeText(ChangePassword.this, "新建密码与重复密码不匹配,请重新输入密码", Toast.LENGTH_SHORT).show();
+ AckPassword.setText("");//清空文本框
+ }
+ else if(old_password.equals(login_password) == false){
+ Toast.makeText(ChangePassword.this, "原有密码错误,请重新输入密码", Toast.LENGTH_SHORT).show();
+ OldPassword.setText("");
+ }
+ else if (new_password.equals(ack_password) == true && old_password.equals(login_password) == true){
+ SharedPreferences.Editor editor=getSharedPreferences("user management", MODE_PRIVATE).edit();
+ editor.putString("password",new_password);//把新的密码保存起来
+ editor.apply();//提交修改
+ Toast.makeText(ChangePassword.this, "修改密码成功", Toast.LENGTH_SHORT).show();
+ Intent intent=new Intent(ChangePassword.this,NotesListActivity.class);//创建一个意图对象
+ startActivity(intent);//用该意图对象来启动NotesListActivity类
+ finish();//结束当前的活动
+ }
+ }
+ });
+ }
+/*
+ @Override
+ public void onBackPressed() {
+ Intent intent=new Intent(ChangePassword.this,NotesListActivity.class);
+ startActivity(intent);
+ finish();
+ }
+
+ */
+}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/CreatePassword.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/CreatePassword.java
new file mode 100644
index 0000000..f089fcf
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/CreatePassword.java
@@ -0,0 +1,71 @@
+package net.micode.notes.ui;
+
+import android.annotation.SuppressLint;
+import android.view.View;//可视化界面
+import android.app.Activity;//完成函数周期
+import android.view.WindowManager;
+import android.widget.Button;//实现按钮
+import android.widget.EditText;//输入显示
+import android.widget.Toast;//设计让登录界面无法被跳过
+import android.os.Bundle;//获取输入密码
+import android.content.SharedPreferences;
+import android.content.Intent;//数据交互
+import android.util.Log;
+import net.micode.notes.R;
+
+public class CreatePassword extends Activity {
+ EditText password01;
+ EditText password02;
+ Button registered;
+
+ @SuppressLint("MissingInflatedId")
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_set_loginpassword);
+ getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+ | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ password01=(EditText) findViewById(R.id.rg_password01);
+ password02=(EditText) findViewById(R.id.rg_password02);
+ registered=(Button)findViewById(R.id.rg_registered);
+ registered.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ String text02 = password01.getText().toString();
+ String text03 = password02.getText().toString();
+ if(text02.equals("")==true) {
+ Toast.makeText(CreatePassword.this, "密码不能为空", Toast.LENGTH_SHORT).show();
+ }
+ else if (text02.equals(text03) == false) {
+ Toast.makeText(CreatePassword.this, "密码不匹配,请重新输入密码", Toast.LENGTH_SHORT).show();
+ password02.setText("");
+ }
+ else if (text02.equals(text03) == true){
+ SharedPreferences.Editor editor=getSharedPreferences("user management",
+ MODE_PRIVATE).edit();
+ editor.putBoolean("user",true);//true表示已经设置登录密码
+ editor.putString("password",text02);
+ editor.apply();
+ Log.d("RegisterLoginPassword","password is "+text02);
+ Toast.makeText(CreatePassword.this, "设置密码成功", Toast.LENGTH_SHORT).show();
+ Intent intent=new Intent(CreatePassword.this,NotesListActivity.class);
+ startActivity(intent);
+ finish();
+ }
+
+ }
+ });
+ }
+/*
+ @Override
+ public void onBackPressed() {
+ Intent intent=new Intent(CreatePassword.this,NotesListActivity.class);
+ startActivity(intent);
+ finish();
+ }
+
+
+ */
+
+}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/DateTimePicker.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/DateTimePicker.java
index cc52e91..e81e920 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/DateTimePicker.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/DateTimePicker.java
@@ -42,6 +42,8 @@ import android.widget.NumberPicker;
* @UpdateRemark: 更新说明:
* @Version: 1.0
*/
+
+
public class DateTimePicker extends FrameLayout {
//FrameLayout是布局模板之一
//所有的子元素全部在屏幕的右上方
@@ -61,14 +63,17 @@ public class DateTimePicker extends FrameLayout {
private static final int AMPM_SPINNER_MIN_VAL = 0;
private static final int AMPM_SPINNER_MAX_VAL = 1;
//初始化控件
+
private final NumberPicker mDateSpinner;
private final NumberPicker mHourSpinner;
private final NumberPicker mMinuteSpinner;
private final NumberPicker mAmPmSpinner;
//NumberPicker是数字选择器
//这里定义的四个变量全部是在设置闹钟时需要选择的变量(如日期、时、分、上午或者下午)
+
private Calendar mDate;
//定义了Calendar类型的变量mDate,用于操作时间
+
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];
private boolean mIsAm;
@@ -93,9 +98,9 @@ public class DateTimePicker extends FrameLayout {
//将现在日期的值传递给mDate;updateDateControl是同步操作
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
- //这里是对 小时(Hour) 的监听
-
- /**
+ //这里是对 小时(Hour) 的监听
+
+ /**
* @method onValueChange
* @description 这段代码是一个回调函数,用于监听NumberPicker的数值改变事件。
* 当用户改变了时间选择器中的小时数时,就会触发这个回调函数。
@@ -105,6 +110,7 @@ public class DateTimePicker extends FrameLayout {
* @param *声明一个Calendar的变量cal,便于后续的操作
* @return isdateChanged bool类型 判断是否需要对时间进行调整
*/
+
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
boolean isDateChanged = false;
@@ -114,7 +120,7 @@ public class DateTimePicker extends FrameLayout {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
- //这里是对于12小时制时,晚上11点和12点交替时对日期的更改
+ //这里是对于12小时制时,晚上11点和12点交替时对日期的更改
} else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
@@ -130,7 +136,7 @@ public class DateTimePicker extends FrameLayout {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
- //这里是对于24小时制时,晚上11点和12点交替时对日期的更改
+ //这里是对于24小时制时,晚上11点和12点交替时对日期的更改
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
@@ -138,9 +144,9 @@ public class DateTimePicker extends FrameLayout {
}
}//这里是对于12小时制时,凌晨11点和12点交替时对日期的更改
int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
- //通过数字选择器对newHour的赋值
+ //通过数字选择器对newHour的赋值
mDate.set(Calendar.HOUR_OF_DAY, newHour);
- //通过set函数将新的Hour值传给mDate
+ //通过set函数将新的Hour值传给mDate
onDateTimeChanged();
if (isDateChanged) {
setCurrentYear(cal.get(Calendar.YEAR));
@@ -151,25 +157,27 @@ public class DateTimePicker extends FrameLayout {
};
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
- /**
+ /**
* @method onValueChange
* @description 用于监控 NumberPicker(数字选择器)的数值变化事件。
* 具体来说,这个监听器是用于监听分钟选择器的数值变化。
* @param *三个参数:picker(当前的 NumberPicker 对象)、oldVal(旧值)和 newVal(新值)
*/
+
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0;
- //设置offset,作为小时改变的一个记录数据
+ //设置offset,作为小时改变的一个记录数据
if (oldVal == maxValue && newVal == minValue) {
offset += 1;
} else if (oldVal == minValue && newVal == maxValue) {
offset -= 1;
}
- //如果原值为59,新值为0,则offset加1
+ //如果原值为59,新值为0,则offset加1
//如果原值为0,新值为59,则offset减1
+
if (offset != 0) {
mDate.add(Calendar.HOUR_OF_DAY, offset);
mHourSpinner.setValue(getCurrentHour());
@@ -189,15 +197,16 @@ public class DateTimePicker extends FrameLayout {
};
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
- /**
+ /**
* @method onValueChange
* @description 实现了一个监听器,用于监测用户对NumberPicker控件数值的改变,
* 并根据改变的数值来更新界面上的上午/下午控件
*/
+
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mIsAm = !mIsAm;
- //对AM和PM的监听
+ //对AM和PM的监听
if (mIsAm) {
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);
} else {
@@ -215,22 +224,20 @@ public class DateTimePicker extends FrameLayout {
public DateTimePicker(Context context) {
this(context, System.currentTimeMillis());
- }
- //通过对数据库的访问,获取当前的系统时间
+ }//通过对数据库的访问,获取当前的系统时间
public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context));
- }
- //上面函数的得到的是一个天文数字(1970至今的秒数),需要DateFormat将其变得有意义
+ }//上面函数的得到的是一个天文数字(1970至今的秒数),需要DateFormat将其变得有意义
public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context);
- //获取系统时间
+ //获取系统时间
mDate = Calendar.getInstance();
mInitialising = true;
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY;
inflate(context, R.layout.datetime_picker, this);
- /*
+ /*
* 如果当前Activity里用到别的layout,比如对话框layout
* 还要设置这个layout上的其他组件的内容,就必须用inflate()方法先将对话框的layout找出来
* 然后再用findViewById()找到它上面的其它组件
@@ -271,18 +278,20 @@ public class DateTimePicker extends FrameLayout {
mInitialising = false;
}
- /**
+
+ /**
* @method setEnabled
* @description 这个函数用于统一设置控件及其相关子控件的可用状态,并且会根据传入的参数值进行相应的操作
* @param *布尔值 enabled,用于指定控件是否可用。
* @return 将 mIsEnabled 的值更新为传入的 enabled,以保持状态同步
*/
+
@Override
public void setEnabled(boolean enabled) {
if (mIsEnabled == enabled) {
return;
}
- /*
+ /*
* 如果传入的参数 enabled 与当前的控件可用状态 mIsEnabled 相同,则无需进行任何操作,直接返回。
* 这样可以避免重复设置控件的可用状态。
*/
@@ -292,7 +301,7 @@ public class DateTimePicker extends FrameLayout {
mHourSpinner.setEnabled(enabled);
mAmPmSpinner.setEnabled(enabled);
mIsEnabled = enabled;
- //将 mIsEnabled 的值更新为传入的 enabled,以保持状态同步
+ //将 mIsEnabled 的值更新为传入的 enabled,以保持状态同步
}
@Override
@@ -307,7 +316,7 @@ public class DateTimePicker extends FrameLayout {
*/
public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis();
- }//实现函数——得到当前的秒数
+ }
/**
* Set the current date
@@ -344,6 +353,7 @@ public class DateTimePicker extends FrameLayout {
*
* @return The current year
*/
+
//下面是得到year、month、day等值
public int getCurrentYear() {
return mDate.get(Calendar.YEAR);
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java
index f673733..ee1f339 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java
@@ -60,12 +60,12 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
}
public DateTimePickerDialog(Context context, long date) {
- //对该界面对话框的实例化
+ //对该界面对话框的实例化
super(context);
- //对数据库的操作
+ //对数据库的操作
mDateTimePicker = new DateTimePicker(context);
setView(mDateTimePicker);
- //添加一个子视图
+ //添加一个子视图
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
public void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
@@ -74,21 +74,21 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
mDate.set(Calendar.MINUTE, minute);
- //将视图中的各选项设置为系统当前时间
+ //将视图中的各选项设置为系统当前时间
updateTitle(mDate.getTimeInMillis());
}
});
mDate.setTimeInMillis(date);
- //得到系统时间
+ //得到系统时间
mDate.set(Calendar.SECOND, 0);
- //将秒数设置为0 对日期时间进行标准化处理
+ //将秒数设置为0 对日期时间进行标准化处理
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
- //将日期时间选择器设置为当前设置的日期时间。
+ //将日期时间选择器设置为当前设置的日期时间
setButton(context.getString(R.string.datetime_dialog_ok), this);
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);
- //设置按钮
+ //设置按钮
set24HourView(DateFormat.is24HourFormat(this.getContext()));
- //时间标准化打印
+ //时间标准化打印
updateTitle(mDate.getTimeInMillis());
}
@@ -115,5 +115,4 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
}
}//第一个参数arg0是接收到点击事件的对话框
//第二个参数arg1是该对话框上的按钮
-
}
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/DeletePassword.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/DeletePassword.java
new file mode 100644
index 0000000..d071c91
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/DeletePassword.java
@@ -0,0 +1,65 @@
+package net.micode.notes.ui;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import net.micode.notes.R;
+
+public class DeletePassword extends Activity{
+ EditText password01;
+ Button Acknowledged;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_delete_loginpassword);
+ getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+ | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ password01=(EditText) findViewById(R.id.old_password);
+ Acknowledged=(Button)findViewById(R.id.Bt_Acknowledged);
+ Acknowledged.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ String text02 = password01.getText().toString();
+ if(text02.equals("")==true) {
+ Toast.makeText(DeletePassword.this, "密码不能为空", Toast.LENGTH_SHORT).show();
+ }
+ SharedPreferences pref=getSharedPreferences("user management",MODE_PRIVATE);
+ String password = pref.getString("password","");
+ if(password.equals("")==false&&password.equals(text02)==true){
+ SharedPreferences.Editor editor=getSharedPreferences("user management",
+ MODE_PRIVATE).edit();
+ editor.putBoolean("user",false);//false表示已经设置登录密码
+ editor.putString("password","");
+ editor.apply();
+
+ Toast.makeText(DeletePassword.this, "已经删除登录密码", Toast.LENGTH_SHORT).show();
+ Intent intent=new Intent(DeletePassword.this,NotesListActivity.class);
+ startActivity(intent);
+ finish();
+ }
+ else{
+ Toast.makeText(DeletePassword.this, "密码错误", Toast.LENGTH_SHORT).show();
+ password01.setText("");//把密码框内输入过的错误密码清空
+ }
+ }
+ });
+ }
+/*
+ @Override
+ public void onBackPressed() {
+ Intent intent=new Intent(DeletePassword.this,NotesListActivity.class);
+ startActivity(intent);
+ finish();
+ }
+
+ */
+}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/DropdownMenu.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/DropdownMenu.java
index 7e6e7d0..f4a3b4d 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/DropdownMenu.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/DropdownMenu.java
@@ -44,21 +44,26 @@ import net.micode.notes.R;
* @UpdateRemark: 更新说明:
* @Version: 1.0
*/
+
+
public class DropdownMenu {
private Button mButton;
private PopupMenu mPopupMenu;
//声明一个下拉菜单
+
private Menu mMenu;
+
public DropdownMenu(Context context, Button button, int menuId) {
mButton = button;
mButton.setBackgroundResource(R.drawable.dropdown_icon);
- //设置这个view的背景
+ //设置这个view的背景
mPopupMenu = new PopupMenu(context, mButton);
mMenu = mPopupMenu.getMenu();
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
- //MenuInflater是用来实例化Menu目录下的Menu布局文件
+ //MenuInflater是用来实例化Menu目录下的Menu布局文件
//根据ID来确认menu的内容选项
+
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mPopupMenu.show();
@@ -74,8 +79,8 @@ public class DropdownMenu {
public MenuItem findItem(int id) {
return mMenu.findItem(id);
- }
- //对于菜单选项的初始化,根据索引搜索菜单需要的选项
+ }//对于菜单选项的初始化,根据索引搜索菜单需要的选项
+
public void setTitle(CharSequence title) {
mButton.setText(title);
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/FoldersListAdapter.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/FoldersListAdapter.java
index ac79adf..c7a9ed4 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/FoldersListAdapter.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/FoldersListAdapter.java
@@ -28,26 +28,24 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
-/**
- *
- * @ProjectName:
- * @Package: net.micode.notes.ui
- * @ClassName: FoldersListAdapter
- * @Description: FoldersListAdapter 的作用是作为文件夹列表的适配器,用于管理和显示文件夹列表的数据和视图。
- * @Author: xumingyang
- * @CreateDate: 2023-12-24 14:05
- * @UpdateUser: 更新者:
- * @UpdateDate: 2023-12-24 14:05
- * @UpdateRemark: 更新说明:
- * @Version: 1.0
+
+/**
+ *
+ * @ProjectName:
+ * @Package: net.micode.notes.ui
+ * @ClassName: FoldersListAdapter
+ * @Description: FoldersListAdapter 的作用是作为文件夹列表的适配器,用于管理和显示文件夹列表的数据和视图。
+ * CursorAdapter是Cursor和ListView的接口
+ * FoldersListAdapter继承了CursorAdapter的类
+ * 主要作用是便签数据库和用户的交互
+ * 这里就是用folder(文件夹)的形式展现给用户
+ * @Author: xumingyang
+ * @CreateDate: 2023-12-24 14:05
+ * @UpdateDate: 2023-12-24 14:05
+ * @Version: 1.0
*/
public class FoldersListAdapter extends CursorAdapter {
- /*
- * CursorAdapter是Cursor和ListView的接口
- * FoldersListAdapter继承了CursorAdapter的类
- * 主要作用是便签数据库和用户的交互
- * 这里就是用folder(文件夹)的形式展现给用户
- */
+
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
@@ -56,27 +54,28 @@ public class FoldersListAdapter extends CursorAdapter {
public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1;
- /**
- * @method FoldersListAdapter
- * @description 用于初始化FoldersListAdapter类的实例。这个类可能是用于管理文件夹列表显示的适配器,其中包含了数据库操作相关的功能
- * @param context 参数通常是指当前的上下文
- * c 参数可能是一个用于查询数据库的Cursor对象。
- */
+ /**
+ * @method FoldersListAdapter
+ * @description 用于初始化FoldersListAdapter类的实例。这个类可能是用于管理文件夹列表显示的适配器,其中包含了数据库操作相关的功能
+ * @param context 参数通常是指当前的上下文
+ * c 参数可能是一个用于查询数据库的Cursor对象。
+ */
public FoldersListAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}//数据库操作
- /**
- * @method newView
- * @description 用于创建新的视图用于显示文件夹列表项。
- * @return 将该视图返回给适配器使用
- */
+ /**
+ * @method newView
+ * @description 用于创建新的视图用于显示文件夹列表项。
+ * @return 将该视图返回给适配器使用
+ */
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new FolderListItem(context);
- }//创建一个文件夹,对于各文件夹中子标签的初始化
+ }
+ //将各个布局文件绑定起来
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof FolderListItem) {
@@ -84,23 +83,21 @@ public class FoldersListAdapter extends CursorAdapter {
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
((FolderListItem) view).bind(folderName);
}
- }//将各个布局文件绑定起来
+ }
+ //根据数据库中标签的ID得到标签的各项内容
public String getFolderName(Context context, int position) {
Cursor cursor = (Cursor) getItem(position);
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
- }//根据数据库中标签的ID得到标签的各项内容
-
+ }
private class FolderListItem extends LinearLayout {
private TextView mName;
public FolderListItem(Context context) {
- super(context);
- //操作数据库
- inflate(context, R.layout.folder_list_item, this);
- //根据布局文件的名字等信息将其找出来
+ super(context);//操作数据库
+ inflate(context, R.layout.folder_list_item, this);//根据布局文件的名字等信息将其找出来
mName = (TextView) findViewById(R.id.tv_folder_name);
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/LoginActivity.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/LoginActivity.java
new file mode 100644
index 0000000..81b3d2b
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/LoginActivity.java
@@ -0,0 +1,68 @@
+package net.micode.notes.ui;
+
+import android.view.View;//可视化界面
+import android.app.Activity;//完成函数周期
+import android.view.WindowManager;
+import android.widget.Button;//实现按钮
+import android.widget.EditText;//输入显示
+import android.widget.Toast;//设计让登录界面无法被跳过
+import android.os.Bundle;//获取输入密码
+import android.content.SharedPreferences;
+import android.content.Intent;//数据交互
+import net.micode.notes.R;
+
+public class LoginActivity extends Activity {
+ EditText lg_password;
+ Button lg_login;
+
+ protected void onCreate(Bundle savedInstanceState){
+ super.onCreate(savedInstanceState);
+ SharedPreferences pref = getSharedPreferences("user management", MODE_PRIVATE);
+ boolean User_boolean =pref.getBoolean("user",false);//是否有密码
+
+ //没有密码直接进入
+ if(User_boolean==false){
+ Intent intent=new Intent(LoginActivity.this,NotesListActivity.class);
+ startActivity(intent);
+ finish();
+ }
+
+ setContentView(R.layout.activity_login);
+ getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
+ | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+ );
+ lg_password =(EditText)findViewById(R.id.lg_password);
+ lg_login=(Button)findViewById(R.id.login);
+ lg_login.setOnClickListener(new View.OnClickListener(){
+ public void onClick(View v){
+ SharedPreferences pref=getSharedPreferences("user management",MODE_PRIVATE);
+ String password=pref.getString("password","");
+ if(password.equals("")==false&&password.equals(lg_password.getText().toString())==true){
+ Intent intent=new Intent(LoginActivity.this,NotesListActivity.class);
+ startActivity(intent);
+ finish();
+ }
+ else{
+ Toast.makeText(LoginActivity.this,"密码错误",Toast.LENGTH_SHORT).show();
+ lg_password.setText("");
+ }
+ }
+ });
+ }
+
+ public void onClick(View v) {
+ SharedPreferences pref =getSharedPreferences("user management",MODE_PRIVATE);
+ String password =pref.getString("password","");
+ if(password.equals("")==false && password.equals(lg_password.getText().toString())==true) {
+ Intent intent = new Intent(LoginActivity.this, NotesListActivity.class);
+ startActivity(intent);
+ finish();
+ }
+ else{
+ Toast.makeText(LoginActivity.this,"密码错误",Toast.LENGTH_SHORT).show();
+ lg_password.setText("");
+ }
+
+ }
+}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java
index 78dfae4..4f6220d 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java
@@ -16,25 +16,42 @@
package net.micode.notes.ui;
+
import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
+import android.app.Dialog;
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.graphics.Typeface;
+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.speech.tts.TextToSpeech;
+import android.support.annotation.RequiresApi;
+import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
+import android.text.TextWatcher;
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;
@@ -43,10 +60,12 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
+import android.widget.Button;
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,18 +84,68 @@ 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.Locale;
import java.util.Map;
+import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import net.micode.notes.translate.BaiduTranslateService;
+import net.micode.notes.translate.RespondBean;
+import net.micode.notes.translate.MD5Utils;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+/**
+ *
+ * @ProjectName:
+ * @Package: net.micode.notes.ui
+ * @ClassName: NoteEditActivity
+ * @Description: 编辑小米便签应用中的便签内容。它向用户提供了一个界面,允许用户输入、编辑和保存文本信息。
+ * 具体来说,用户可以在该界面中添加或编辑标题、标签、内容、图片等信息,并将这些信息保存到小米便签数据库中。
+ * 还提供了一些常用的编辑功能,如加粗、倾斜、下划线、字体调整、颜色设置、插入图片等,使得用户可以更加方便地对便签内容进行编辑和美化。
+ * @Author: xumingyang
+ * @CreateDate: 2024-01-03 8:44
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2024-01-03 8:44
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+import android.speech.tts.TextToSpeech.OnInitListener;
+
+/**
+ *
+ * @ProjectName:
+ * @Package: net.micode.notes.ui
+ * @ClassName: NoteEditActivity
+ * @Description: 编辑小米便签应用中的便签内容。它向用户提供了一个界面,允许用户输入、编辑和保存文本信息。
+ * 具体来说,用户可以在该界面中添加或编辑标题、标签、内容、图片等信息,并将这些信息保存到小米便签数据库中。
+ * 还提供了一些常用的编辑功能,如加粗、倾斜、下划线、字体调整、颜色设置、插入图片等,使得用户可以更加方便地对便签内容进行编辑和美化。
+ * @Author: xumingyang
+ * @CreateDate: 2024-01-03 8:44
+ * @UpdateDate: 2024-01-03 8:44
+ * @Version: 1.0
+ */
public class NoteEditActivity extends Activity implements OnClickListener,
NoteSettingChangedListener, OnTextViewChangeListener {
+ //该类主要是针对标签的编辑
+ //继承了系统内部许多和监听有关的类
+ public static void setmChanged(Stack mChanged) {
+ NoteEditActivity.mChanged = mChanged;
+ }
+
private class HeadViewHolder {
public TextView tvModified;
+ public EditText editText1;//新增
+ public TextView textView;//新增
public ImageView ivAlertIcon;
public TextView tvAlertDate;
@@ -84,6 +153,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
public ImageView ibSetBgColor;
}
+ //使用Map实现数据存储
private static final Map sBgSelectorBtnsMap = new HashMap();
static {
sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW);
@@ -91,6 +161,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE);
sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN);
sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE);
+ //put函数是将指定值和指定键相连
}
private static final Map sBgSelectorSelectionMap = new HashMap();
@@ -100,6 +171,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select);
sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select);
sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select);
+ //put函数是将指定值和指定键相连
}
private static final Map sFontSizeBtnsMap = new HashMap();
@@ -122,20 +194,24 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private HeadViewHolder mNoteHeaderHolder;
- private View mHeadViewPanel;
+ private View mHeadViewPanel;//私有化一个界面操作mHeadViewPanel,对表头的操作
- private View mNoteBgColorSelector;
+ private View mNoteBgColorSelector;//私有化一个界面操作mNoteBgColorSelector,对背景颜色的操作
- private View mFontSizeSelector;
+ private View mFontSizeSelector;//私有化一个界面操作mFontSizeSelector,对标签字体的操作
- private EditText mNoteEditor;
+ private EditText mNoteEditor;//声明编辑控件,对文本操作
- private View mNoteEditorPanel;
+ private EditText editText;
+ private TextView textView;
+ private View mNoteEditorPanel;//私有化一个界面操作mNoteEditorPanel,文本编辑的控制板
- private WorkingNote mWorkingNote;
+ private WorkingNote mWorkingNote;//对模板WorkingNote的初始化
private SharedPreferences mSharedPrefs;
- private int mFontSizeId;
+ //私有化SharedPreferences的数据存储方式
+ //它的本质是基于XML文件存储key-value键值对数据
+ private int mFontSizeId;//用于操作字体的大小
private static final String PREFERENCE_FONT_SIZE = "pref_font_size";
@@ -144,78 +220,449 @@ public class NoteEditActivity extends Activity implements OnClickListener,
public static final String TAG_CHECKED = String.valueOf('\u221A');
public static final String TAG_UNCHECKED = String.valueOf('\u25A1');
- private LinearLayout mEditTextList;
+ private LinearLayout mEditTextList;//线性布局
private String mUserQuery;
private Pattern mPattern;
+ private CharSequence restore_translate = null;
+
+ private boolean mIsRvoke = false;
+
+ private TextToSpeech mTTS;
+ private static Stack mChanged;
+ private final int PHOTO_REQUEST = 1;
+ private Dialog alertDialog2;
+ Context context;
+ private static final int MAX_TIME_OF_RVOKE_TIME=100;
+ private final int MAX_OF_RVOKE_TIME=100;
+ public void translateChtoEn() {
+ //准备请求百度翻译接口需要的参数
+ final EditText editable = findViewById(R.id.note_edit_view);
+ String word = editable.getText().toString();
+ word = word.replaceAll("\\n","//");
+ String from = "auto";//源语种 en 英语 zh 中文
+ //String中英文占用一个字节,中文占用两个字节,
+ //利用String的这个存储特性可以用来判断String中有没有中文。
+ // to = "zh"; //没有汉字 英译中
+ String to = "en";//含有汉字 中译英
+ String appid = "20240103001929054";//appid 管理控制台有
+ String salt = (int) (Math.random() * 100 + 1) + "";//随机数这里范围是[0,100]整数无强制要求
+ String key = "Xa_yB5ihrTIaG8Nlv4S6";//密钥 管理控制台有
+ String secretKey = appid + word + salt + key;// secretKey = appid+q+salt+密钥
+ String sign = MD5Utils.getMD5Code(secretKey);// 签名 = secretKey 的MD5加密32位字母小写
+ Log.d(TAG, "secretKey:" + secretKey);
+ Log.d(TAG, "sign: " + sign);
+
+ Retrofit retrofitBaidu = new Retrofit.Builder()
+ .baseUrl("https://fanyi-api.baidu.com/api/trans/vip/")
+ .addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
+ .build();
+ BaiduTranslateService baiduTranslateService =retrofitBaidu.create(BaiduTranslateService.class);
+ retrofit2.Call call = baiduTranslateService.translate(word, from, to, appid, salt, sign);
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ //请求成功
+ Log.d(TAG, "onResponse: 请求成功");
+ RespondBean respondBean = response.body();//返回的JSON字符串对应的对象
+ String result = respondBean.getTrans_result().get(0).getDst();//获取翻译的字符串String
+ editable.setText(result);
+ Log.d(TAG, "中译英结果" + result);
+ }
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ //请求失败 打印异常
+ Log.d(TAG, "onResponse: 请求失败 " + t);
+ }
+ });
+ }
+ public void translateEntoCh() {
+ //准备请求百度翻译接口需要的参数
+ final EditText editable = findViewById(R.id.note_edit_view);
+ String word = editable.getText().toString();
+ word = word.replaceAll("\\n","//");
+ Log.d(TAG, word);
+ String from = "auto";//源语种 en 英语 zh 中文
+ //String中英文占用一个字节,中文占用两个字节,
+ //利用String的这个存储特性可以用来判断String中有没有中文。
+ // to = "zh"; //没有汉字 英译中
+ String to = "zh";//含有汉字 英译中
+ String appid = "20240103001929054";//appid 管理控制台有
+ String salt = (int) (Math.random() * 100 + 1) + "";//随机数这里范围是[0,100]整数无强制要求
+ String key = "Xa_yB5ihrTIaG8Nlv4S6";//密钥 管理控制台有
+ String secretKey = appid + word + salt + key;// secretKey = appid+q+salt+密钥
+ String sign = MD5Utils.getMD5Code(secretKey);// 签名 = secretKey 的MD5加密32位字母小写
+ Log.d(TAG, "secretKey:" + secretKey);
+ Log.d(TAG, "sign: " + sign);
+
+ Retrofit retrofitBaidu = new Retrofit.Builder()
+ .baseUrl("https://fanyi-api.baidu.com/api/trans/vip/")
+ .addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
+ .build();
+ BaiduTranslateService baiduTranslateService =retrofitBaidu.create(BaiduTranslateService.class);
+ retrofit2.Call call = baiduTranslateService.translate(word, from, to, appid, salt, sign);
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ //请求成功
+ Log.d(TAG, "onResponse: 请求成功");
+ RespondBean respondBean = response.body();//返回的JSON字符串对应的对象
+ String result = respondBean.getTrans_result().get(0).getDst();//获取翻译的字符串String
+ editable.setText(result);
+ Log.d(TAG, "英译中结果" + result);
+ }
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ //请求失败 打印异常
+ Log.d(TAG, "onResponse: 请求失败 " + t);
+ }
+ });
+ }
+ public void doTranslate(){
+ final EditText editable = findViewById(R.id.note_edit_view);
+ final Button get_local = findViewById(R.id.translate); //R.id.translate是定义在界面左上角的按钮
+ get_local.setOnClickListener(new OnClickListener() { //如果点击按钮,则触发
+ @Override
+ public void onClick(final View v) {
+ Button trans1 = new Button(NoteEditActivity.this); //三个功能的按钮
+ Button trans2 = new Button(NoteEditActivity.this);
+ Button trans3 = new Button(NoteEditActivity.this);
+ trans1.setText("中文翻译为英文");
+ trans2.setText("英文翻译为中文");
+ trans3.setText("还原");
+ LinearLayout linear = new LinearLayout(NoteEditActivity.this); //定义线性表结构
+ linear.setOrientation(LinearLayout.VERTICAL); //设置为垂直结构
+ linear.addView(trans1); //将三个按钮添加到线性表中
+ linear.addView(trans2);
+ linear.addView(trans3);
+ AlertDialog.Builder builder = new AlertDialog.Builder(NoteEditActivity.this); //定义一个AlertDialog生成器
+ builder.setView(linear); //附上线性表结构
+ builder.setTitle("请选择翻译模式"); //提示语句
+ AlertDialog choose_trans = builder.create(); //生成一个AlertDialog的对话框
+ choose_trans.show(); //展示
+ trans1.setOnClickListener(new OnClickListener() { //如果点击第一个按钮,则触发
+ @Override
+ public void onClick(View v) {
+ restore_translate = editable.getText();
+ Log.d(TAG, "666" + restore_translate);
+ choose_trans.dismiss();
+ if(restore_translate == null){
+ Toast.makeText(NoteEditActivity.this, "当前无可翻译内容", Toast.LENGTH_SHORT).show();
+ }
+ else{
+ translateChtoEn();
+ Toast.makeText(NoteEditActivity.this, "中文翻译为英文", Toast.LENGTH_SHORT).show();
+ }
+
+ }
+ });
+ trans2.setOnClickListener(new OnClickListener(){ //如果点击第二个按钮,则触发
+ @Override
+ public void onClick(View v) {
+ restore_translate = editable.getText();
+ Log.d(TAG, "666" + restore_translate);
+ choose_trans.dismiss();
+ if(restore_translate == null){
+ Toast.makeText(NoteEditActivity.this, "当前无可翻译内容", Toast.LENGTH_SHORT).show();
+ }
+ else{
+ translateEntoCh();
+ Toast.makeText(NoteEditActivity.this, "英文翻译为中文", Toast.LENGTH_SHORT).show();
+ }
+
+ }
+ });
+ trans3.setOnClickListener(new OnClickListener() { //如果点击第三个按钮,则触发
+ @Override
+ public void onClick(View v) {
+ choose_trans.dismiss();
+ Log.d(TAG, "666" + restore_translate);
+ if (restore_translate == null ||
+ restore_translate.toString().equals(editable.getText().toString())) {
+ Toast.makeText(NoteEditActivity.this, "无可还原内容", Toast.LENGTH_SHORT).show();
+ } else {
+ editable.setText(restore_translate);
+ Toast.makeText(NoteEditActivity.this, "已还原", Toast.LENGTH_SHORT).show();//功能语句
+ }
+ }
+ });
+ }
+
+ });
+ }
+
+ //图片地址转换为图片
+ private void convertToImage() {
+ NoteEditText noteEditText = (NoteEditText) findViewById(R.id.note_edit_view);
+ Editable editable = noteEditText.getText();
+ String noteText = editable.toString();
+ int length = editable.length();
+ //对于每个字符,从当前位置开始,向后遍历文本,直到找到与图片标记匹配的子字符串。
+ for (int i = 0; i < length; i++) {
+ for (int j = i; j < length; j++) {
+ String img_fragment = noteText.substring(i, j + 1);
+ //检查其长度是否大于15,且以"[local]"开头,以"[/local]"结尾
+ if (img_fragment.length() > 15 && img_fragment.endsWith("[/local]") && img_fragment.startsWith("[local]")) {
+ int limit = 7;
+ int len = img_fragment.length() - 15;
+ String path = img_fragment.substring(limit, limit + len);
+ Bitmap bitmap = null;
+ Log.d(TAG, "图片的路径是:" + path);
+ try {
+ //BitmapFactory.decodeFile(path)是Android中用于从指定路径加载图片文件并返回一个Bitmap对象的方法
+ bitmap = BitmapFactory.decodeFile(path);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ //如果解码成功(即bitmap不为null),则创建一个新的ImageSpan对象,并将其插入到原始文本中,替换原来的图片标记
+ if (bitmap != null) {
+ Log.d(TAG, "图片不为null");
+ //创建一个SpannableString对象,将字符串ss作为参数传递给构造函数。
+ //SpannableString是一个可编辑的字符串,可以设置文本样式(如颜色、大小等)。
+ ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
+ String ss = "[local]" + path + "[/local]";
+ SpannableString spannableString = new SpannableString(ss);
+ //将ImageSpan对象应用于spannableString,从索引0开始,到字符串长度结束。这样可以将图片显示在指定的文本范围内
+ spannableString.setSpan(imageSpan, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ Log.d(TAG, "Create spannable string success!");
+ //获取noteEditText的可编辑文本内容,并将其赋值给变量edit_text
+ Editable edit_text = noteEditText.getEditableText();
+ edit_text.delete(i, i + len + 15);
+ edit_text.insert(i, spannableString);
+ }
+ }
+ }
+ }
+ }
+
+ //处理返回的数据,并将图片的路径也写入到数据库
+ //当用户在相机应用中选择了一张图片后,该图片的URI会被传递给NoteEditActivity,然后通过这个方法进行处理。
+ @RequiresApi(api = Build.VERSION_CODES.KITKAT)
+ 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();
+ Bitmap bitmap = null;
+ try {
+ bitmap = BitmapFactory.decodeStream(resolver.openInputStream(originalUri));//解码图片
+ } catch (FileNotFoundException e) {
+ Log.d(TAG, "onActivityResult: get file_exception");
+ e.printStackTrace();
+ }
+ if (bitmap != null) {
+ Log.d(TAG, "onActivityResult: bitmap is not null");
+ ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
+ String path = getPath(this, originalUri);
+ String img_fragment = "[local]" + path + "[/local]";
+ SpannableString spannableString = new SpannableString(img_fragment);
+ spannableString.setSpan(imageSpan, 0, img_fragment.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ 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.setmContent(e.getText().toString());
+ ContentResolver contentResolver = getContentResolver();
+ ContentValues contentValues = new ContentValues();
+ final long id = mWorkingNote.getNoteId();
+ contentValues.put("snippet", mWorkingNote.getContent());
+ contentResolver.update(Uri.parse("content://micode_notes/note"), contentValues, "_id=?", new String[]{"" + id});
+ ContentValues contentValues1 = new ContentValues();
+ contentValues1.put("content", mWorkingNote.getContent());
+ 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;
+ }
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.KITKAT)
+ public String getPath(final Context context, final Uri uri) {
+
+ final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+ if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+ 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中获取数据列
+ //Android的ContentResolver类来执行查询操作,通过url来定位和获取上下文数据
+ public String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
+ Cursor cursor = null;
+ final String column = "_data";
+ final String[] projection = {column};
+
+ try {
+ //调用context.getContentResolver().query()方法,传入URI、投影、选择条件、选择参数和排序方式,执行查询操作并将结果存储在cursor中
+ 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 isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @method onCreate
+ * @description 描述一下方法的作用方法的主要作用是初始化Activity的状态、资源和界面,并对便签内容进行处理和计数。
+ */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- this.setContentView(R.layout.note_edit);
+ this.setContentView(R.layout.note_edit); //调用setContentView方法设置当前Activity显示的布局为note_edit.xml文件。
+ setmChanged(new Stack<>() );
+ /*
+ * 判断savedInstanceState是否为空,并调用initActivityState方法初始化Activity的状态。
+ * initActivityState方法会根据传入的Intent信息,判断当前是新建一个便签还是编辑一个已有的便签。
+ */
if (savedInstanceState == null && !initActivityState(getIntent())) {
finish();
return;
}
- initResources();
+
+ initResources();//调用initResources方法初始化Activity中的资源,如绑定控件等。
+ count();//新增文档计数功能
+
+ 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");
+ Intent loadImage = new Intent(Intent.ACTION_GET_CONTENT);
+ 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
*/
+ //用于在Activity被系统销毁后恢复其状态
@Override
+ /**
+ * @method onRestoreInstanceState
+ * @description 该方法的主要作用是在Activity恢复状态时,根据保存的数据重新初始化Activity的状态,
+ * 以保证在Activity被销毁后重新创建时能够正确恢复之前的状态。
+ */
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
+ //将保存在savedInstanceState中的Intent.EXTRA_UID的值作为Long类型的额外数据传递给新的Intent对象。
if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID));
+
+ /*
+ * 调用initActivityState方法,将新的Intent传递进去进行初始化Activity的状态。
+ * 如果initActivityState返回false,说明初始化失败,直接销毁Activity并返回。
+ */
if (!initActivityState(intent)) {
finish();
return;
}
Log.d(TAG, "Restoring from killed activity");
- }
+ }//为防止内存不足时程序的终止,在这里有一个保存现场的函数
}
- private boolean initActivityState(Intent intent) {
+ /**
+ * @method initActivityState
+ * @description 作用是初始化NoteEditActivity的状态。
+ * @param
+ * @return true表示初始化成功 false表示初始化失败
+ */
+ private boolean initActivityState(Intent intent) {//用于实时更新字符数的文本视图
/**
* If the user specified the {@link Intent#ACTION_VIEW} but not provided with id,
* then jump to the NotesListActivity
*/
mWorkingNote = null;
+ //打开某个笔记的操作
if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) {
long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0);
mUserQuery = "";
-
+ //如果用户实例化标签时,系统并未给出标签ID
/**
* Starting from the searched result
*/
+ //根据键值查找ID
if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) {
noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY);
}
-
+ //DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE) 是一个方法调用
+ // 用于检查给定的 noteId 是否存在于笔记数据库中
+ //如果ID在数据库中未找到
if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) {
Intent jump = new Intent(this, NotesListActivity.class);
- startActivity(jump);
+ startActivity(jump);//程序将跳转到上面声明的intent——jump
showToast(R.string.error_note_not_exist);
finish();
return false;
- } else {
+ } else {//ID在数据库中找到
+ //如果指定的笔记 ID 存在于笔记数据库中,则调用 WorkingNote.load() 方法,根据指定的笔记 ID 加载笔记对象,并将结果赋值给 mWorkingNote
mWorkingNote = WorkingNote.load(this, noteId);
if (mWorkingNote == null) {
- Log.e(TAG, "load note failed with note id" + noteId);
+ Log.e(TAG, "load note failed with note id" + noteId); //打印出红色的错误信息
finish();
return false;
}
}
+ //setSoftInputMode——软键盘输入模式
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
} else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) {
+ //需要创建或编辑一个笔记
// New note
+ //从 Intent 中获取一些额外的信息,如文件夹 ID、小部件 ID、小部件类型和背景资源 ID。这些信息用于确定新笔记的位置和外观。
+ /*
+ * intent.getAction()
+ * 大多用于broadcast发送广播时给机制(intent)设置一个action,就是一个字符串
+ * 用户可以通过receive(接受)intent,通过 getAction得到的字符串,来决定做什么
+ */
long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0);
int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
@@ -262,19 +709,37 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return true;
}
+ /**
+ * @method onResume
+ * @description 在Activity恢复时重新初始化便签的显示
+ */
@Override
protected void onResume() {
super.onResume();
- initNoteScreen();
+ initNoteScreen();//然后调用initNoteScreen方法,该方法会根据mWorkingNote的内容初始化便签的各个UI控件,例如标题栏、编辑区域、图片等。
}
+ //用于初始化笔记屏幕
+ /**
+ * @method initNoteScreen
+ * @description 根据mWorkingNote的内容重新初始化便签的UI,包括文本样式、编辑区域、背景、修改时间等
+ */
private void initNoteScreen() {
mNoteEditor.setTextAppearance(this, TextAppearanceResources
.getTexAppearanceResource(mFontSizeId));
- if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
+ /*
+ * 如果当前便签是“清单”模式,则调用switchToListMode方法将编辑区域切换到“清单”模式,
+ * 并将mWorkingNote中的内容填充到编辑区域。
+ */
+ if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {//首先根据mFontSizeId设置mNoteEditor的文本样式。
switchToListMode(mWorkingNote.getContent());
- } else {
- mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));
+ }
+ /*
+ * 如果当前便签不是“清单”模式,则将mWorkingNote中的内容填充到编辑区域
+ * 并调用getHighlightQueryResult方法将搜索关键字高亮显示。
+ */
+ else {
+ mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));//将所有背景选择器控件隐藏,然后根据mWorkingNote的标题背景和便签背景设置标题栏和编辑区域的背景。
mNoteEditor.setSelection(mNoteEditor.getText().length());
}
for (Integer id : sBgSelectorSelectionMap.keySet()) {
@@ -293,14 +758,20 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* is not ready
*/
showAlertHeader();
+ convertToImage();
}
+ /**
+ * @method showAlertHeader
+ * @description 根据mWorkingNote的提醒设置来显示提醒相关的UI,包括提醒日期文本和提醒图标。
+ * 如果有设置提醒,则根据当前时间判断是否已过期,并显示相应的文本。如果没有设置提醒,则隐藏相关UI。
+ */
private void showAlertHeader() {
- if (mWorkingNote.hasClockAlert()) {
+ if (mWorkingNote.hasClockAlert()) {//首先判断mWorkingNote是否有设置提醒(hasClockAlert)。如果有设置提醒,则执行以下步骤
long time = System.currentTimeMillis();
if (time > mWorkingNote.getAlertDate()) {
- mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired);
- } else {
+ mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired);//判断当前时间是否超过了提醒时间(mWorkingNote.getAlertDate)。如果超过了提醒时间,则将提醒日期文本(tvAlertDate)
+ } else {//如果没有超过提醒时间,则将提醒日期文本设置为相对时间,即距离提醒时间还有多久(使用DateUtils.getRelativeTimeSpanString方法)。
mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString(
mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS));
}
@@ -313,11 +784,18 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
@Override
+ //在Activity已经存在于任务栈中时,再次启动该Activity时的回调方法,可以在其中处理相关的逻辑操作
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
initActivityState(intent);
}
+ /**
+ * @method onSaveInstanceState
+ * @description 在Activity即将被销毁时的回调方法,用于保存当前Activity的状态,
+ * 以便在Activity被恢复时能够正确地加载之前的状态。
+ * @return void
+ */
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -327,28 +805,33 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* is no id which is equivalent to create new note
*/
if (!mWorkingNote.existInDatabase()) {
- saveNote();
+ saveNote();//在创建一个新的标签时,先在数据库中匹配
+ //如果不存在,那么先在数据库中存储
}
outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId());
Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState");
}
@Override
+ //MotionEvent是对屏幕触控的传递机制
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mNoteBgColorSelector.getVisibility() == View.VISIBLE
&& !inRangeOfView(mNoteBgColorSelector, ev)) {
mNoteBgColorSelector.setVisibility(View.GONE);
return true;
- }
+ }//颜色选择器在屏幕上可见
+
+
if (mFontSizeSelector.getVisibility() == View.VISIBLE
&& !inRangeOfView(mFontSizeSelector, ev)) {
mFontSizeSelector.setVisibility(View.GONE);
return true;
- }
+ }//字体大小选择器在屏幕上可见
return super.dispatchTouchEvent(ev);
}
+ //对屏幕触控的坐标进行操作
private boolean inRangeOfView(View view, MotionEvent ev) {
int []location = new int[2];
view.getLocationOnScreen(location);
@@ -358,11 +841,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
|| ev.getX() > (x + view.getWidth())
|| ev.getY() < y
|| ev.getY() > (y + view.getHeight())) {
- return false;
+ return false;//如果触控的位置超出了给定的范围,返回false
}
return true;
}
-
+ //初始化一些资源
private void initResources() {
mHeadViewPanel = findViewById(R.id.note_title);
mNoteHeaderHolder = new HeadViewHolder();
@@ -374,16 +857,24 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mNoteEditor = (EditText) findViewById(R.id.note_edit_view);
mNoteEditorPanel = findViewById(R.id.sv_note_edit);
mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector);
+ editText = (EditText) findViewById(R.id.note_edit_view);
+ textView = (TextView) findViewById(R.id.text_num);
+
+ //这段代码的作用是为sBgSelectorBtnsMap中的所有ImageView对象设置点击事件监听器。
+ // 当某个ImageView被点击时,会触发与当前类关联的onClick()方法。
+ //sBgSelectorBtnsMap是一个Map对象,它存储了一些键值对,其中每个sBgSelectorBtnsMap是一个Map对象,它存储了一些键值对,其中每个键对应一个ImageView对象的id,每个值则未在这段代码中给出。
+ // 这种数据结构通常用于在Android应用中存储和操作UI元素,例如这里的ImageView。
+ // 通过键(即ImageView的id),可以快速找到并操作对应的UI元素。
+ // 具体来说,这段代码遍历了sBgSelectorBtnsMap中的所有键,并为每个键对应的ImageView设置了一个点击事件监听器。
for (int id : sBgSelectorBtnsMap.keySet()) {
ImageView iv = (ImageView) findViewById(id);
iv.setOnClickListener(this);
- }
-
+ }//对标签各项属性内容的初始化
mFontSizeSelector = findViewById(R.id.font_size_selector);
for (int id : sFontSizeBtnsMap.keySet()) {
View view = findViewById(id);
view.setOnClickListener(this);
- };
+ };//对字体大小的选择
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE);
/**
@@ -391,21 +882,163 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* The id may larger than the length of resources, in this case,
* return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
*/
+ //这段代码是用于获取应用程序的字体大小设置
if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) {
mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE;
}
mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list);
+ /*
+ 撤回部分
+ */
+ mNoteEditor.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after)
+ {
+
+ }
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+
+ }
+ @Override
+ public void afterTextChanged(Editable s) {//文本更改后
+ if(!mIsRvoke) {
+ saveMyChanged();
+ }else {
+ mIsRvoke = false;
+ }
+ }
+ });
+
+ //翻译
+ doTranslate();
+ //朗读
+ mTTS = new TextToSpeech(this, new OnInitListener() {
+ @Override
+ public void onInit(int status) {
+ if (status == TextToSpeech.SUCCESS) {
+ mTTS.setLanguage(Locale.ENGLISH);
+ mTTS.setPitch(1.5f);// 设置音调,值越大声音越尖(女生),值越小则变成男声,1.0是常规
+ mTTS.setSpeechRate(0.5f);
+ }
+
+ }
+ });
+ mHeadViewPanel = findViewById(R.id.note_title);
+ }
+
+
+ private void texttoSpeech(){
+ mTTS.speak(mNoteEditor.getText().toString(),TextToSpeech.QUEUE_FLUSH,null,null);
+ }
+ private void doRevoke(){
+ int size = mChanged.size();//获取当前栈大小
+ AlertDialog.Builder dialog = new AlertDialog.Builder(this);//创建一个alertdialog 窗口
+ dialog.setTitle(R.string.tips_of_revoke);//设置 title 信息
+ dialog.setCancelable(true);//设置为可取消
+ dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {//只需要设置一个 OK 键即可
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+ mIsRvoke= true;
+ if(size<=1){//如果栈中元素过少,打印提示信息
+ dialog.setMessage(R.string.have_not_input_anything);//提示用户您还没有输入任何信息
+ dialog.show();//显示当前 alertdialog
+ return;
+ }
+ else {
+ mNoteEditor.setText((CharSequence) mChanged.elementAt(size-2));//在textview 中设置撤销的内容
+ mNoteEditor.setSelection(mNoteEditor.length());
+ mChanged.removeElementAt(size-1);//删除元素
+ if(size==2){
+ dialog.setMessage(R.string.can_not_revoke);//如果只有一次操作,那么提示用户不能再撤销了
+ dialog.show();//显示当前 alertdialog
+ }
+ }
+ }
+ private void saveMyChanged(){
+ SpannableString text = new SpannableString(mNoteEditor.getText());//用 getText方法获取每次编辑的内容
+ if(mChanged.size()>=MAX_TIME_OF_RVOKE_TIME){//如果栈中的数据大于最大撤销次数,就把第一次修改的内容删除
+ mChanged.removeElementAt(0);
+ }
+ mChanged.add(text);//然后把本次修改的内容加入栈中
}
+ public void showSingleAlertDialog(){
+ final String[] items = {"默认-普通","默认-非衬线","默认-衬线","默认-等宽","仿宋","黑体","楷体","隶书","微软雅黑"};
+ AlertDialog.Builder alertBuilder = new AlertDialog.Builder(this);
+ alertBuilder.setTitle("请选择字体");
+ alertBuilder.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ switch (i) {
+ case 0:
+ mNoteEditor.setTypeface(Typeface.DEFAULT);
+ break;
+ case 1:
+ mNoteEditor.setTypeface(Typeface.SANS_SERIF);
+ break;
+ case 2:
+ mNoteEditor.setTypeface(Typeface.SERIF);
+ break;
+ case 3:
+ mNoteEditor.setTypeface(Typeface.MONOSPACE);
+ break;
+ case 4:
+ Typeface typeface0 = Typeface.createFromAsset(getAssets(), "front/simfang.ttf");
+ mNoteEditor.setTypeface(typeface0);
+ break;
+ case 5:
+ Typeface typeface1 = Typeface.createFromAsset(getAssets(), "front/simhei.ttf");
+ mNoteEditor.setTypeface(typeface1);
+
+ break;
+ case 6:
+ Typeface typeface2 = Typeface.createFromAsset(getAssets(), "front/simkai.ttf");
+ mNoteEditor.setTypeface(typeface2);
+
+ break;
+ case 7:
+ Typeface typeface3 = Typeface.createFromAsset(getAssets(), "front/SIMLI.TTF");
+ mNoteEditor.setTypeface(typeface3);
+ break;
+ case 8:
+ Typeface typeface4 = Typeface.createFromAsset(getAssets(), "front/msyh.ttc");
+ mNoteEditor.setTypeface(typeface4);
+ break;
+ }
+ Toast.makeText(NoteEditActivity.this, items[i],Toast.LENGTH_SHORT).show();
+ }
+ });
+ alertBuilder.setPositiveButton("确定",new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ alertDialog2.dismiss();
+ }
+ });
+ alertBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ alertDialog2.dismiss();
+ }
+ });
+ alertDialog2 = alertBuilder.create();
+ alertDialog2.show();
+ }
+
+ //在Activity即将失去焦点并进入后台时的回调方法,用于执行一些与保存数据、清除状态等相关的操作。
@Override
protected void onPause() {
super.onPause();
if(saveNote()) {
Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length());
}
- clearSettingState();
+ clearSettingState();//调用clearSettingState()方法来清除一些设置状态。具体的逻辑需要根据实际需求来实现,可能包括清除临时数据、重置一些标志位等。
}
+ //和桌面小工具的同步
private void updateWidget() {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) {
@@ -421,16 +1054,23 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mWorkingNote.getWidgetId()
});
+ //将当前Note笔记的Widget ID放入Intent的Extra参数中。注意,这里只更新当前Note笔记所绑定的Widget,因此只需要传入一个Widget ID。
sendBroadcast(intent);
setResult(RESULT_OK, intent);
}
-
+ /*
+ 这段代码是一个事件处理函数,用于处理按钮点击事件。根据不同的按钮ID执行不同的操作。
+ */
public void onClick(View v) {
int id = v.getId();
+ //如果按钮ID等于R.id.btn_set_bg_color,则表示用户点击了设置背景颜色的按钮。
+ // 此时,将背景颜色选择器的可见性设置为可见,并显示当前选中的背景颜色对应的控件
if (id == R.id.btn_set_bg_color) {
mNoteBgColorSelector.setVisibility(View.VISIBLE);
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(View.VISIBLE);
} else if (sBgSelectorBtnsMap.containsKey(id)) {
+ //如果按钮ID在sBgSelectorBtnsMap中存在,表示用户点击了某个背景颜色按钮。
+ // 此时,隐藏当前选中的背景颜色对应的控件,将工作笔记的背景颜色设置为该按钮对应的ID,并将背景颜色选择器的可见性设置为不可见。
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.GONE);
mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id));
@@ -444,13 +1084,21 @@ public class NoteEditActivity extends Activity implements OnClickListener,
getWorkingText();
switchToListMode(mWorkingNote.getContent());
} else {
- mNoteEditor.setTextAppearance(this,
- TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
+ mNoteEditor.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
}
+ /*
+ * 如果点击的ID在sFontSizeBtnsMap中存在(即点击的是字体大小选择项的按钮),则将当前字体大小的选择项设置为不可见,
+ * 将字体大小ID更新为对应的值,并将新的字体大小选择项设置为可见。
+ * 同时,根据Note笔记的模式(是否为检查列表模式)进行相应的处理:
+ * 如果是检查列表模式,则切换到列表模式并获取最新的Note内容;
+ * 否则,仅更新文本编辑器的字体样式。
+ */
mFontSizeSelector.setVisibility(View.GONE);
}
}
+ //这段代码重写了Activity的返回按钮操作,
+ // 在返回操作中处理了设置状态的清除和Note笔记的保存。
@Override
public void onBackPressed() {
if(clearSettingState()) {
@@ -461,7 +1109,14 @@ public class NoteEditActivity extends Activity implements OnClickListener,
super.onBackPressed();
}
+ /**
+ * @method clearSettingState
+ * @description 这个方法的作用是在用户按下返回按钮时,检查当前是否处于设置状态(例如正在选择背景颜色或字体大小),
+ * 如果是,则清除设置状态并返回true,否则返回false。
+ * @return true表示成功清除了设置状态 返回false表示当前没有处于设置状态。
+ */
private boolean clearSettingState() {
+ //首先检查背景颜色选择器(mNoteBgColorSelector)和字体大小选择器(mFontSizeSelector)的可见性
if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) {
mNoteBgColorSelector.setVisibility(View.GONE);
return true;
@@ -472,22 +1127,34 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return false;
}
+ /**
+ * @method onBackgroundColorChanged
+ * @description 在背景颜色发生变化时,根据新的背景颜色ID更新选中状态的选择项的可见性,
+ * 并将新的背景颜色资源应用到相关的视图上,以实现界面的背景颜色变更
+ */
public void onBackgroundColorChanged() {
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.VISIBLE);
mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId());
mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId());
+ //获取当前Note笔记的背景颜色资源ID,并将该资源作为背景设置给mNoteEditorPanel和mHeadViewPanel,实现对编辑区域和标题区域的背景颜色的更新。
}
-
+ /**
+ * @method onPrepareOptionsMenu
+ * @description 根据当前Note笔记的状态和属性,动态加载选项菜单的内容,并更新其中的部分选项的名称和可见性。
+ */
+ //该方法的主要作用是根据当前的工作笔记(mWorkingNote)的属性来准备和更新菜单项。
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (isFinishing()) {
return true;
- }
+ }//判断当前Activity是否正在关闭,如果是,则直接返回true,不做任何处理。
clearSettingState();
- menu.clear();
+ menu.clear(); //调用clearSettingState()方法清除当前的设置状态,并使用menu.clear()方法清空选项菜单中的所有选项。
+
+ //工作笔记的文件夹ID
if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) {
- getMenuInflater().inflate(R.menu.call_note_edit, menu);
+ getMenuInflater().inflate(R.menu.call_note_edit, menu);// MenuInflater是用来实例化Menu目录下的Menu布局文件的
} else {
getMenuInflater().inflate(R.menu.note_edit, menu);
}
@@ -496,6 +1163,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} else {
menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode);
}
+ //如果当前Note笔记已经有闹钟提醒,则隐藏“添加提醒”选项,否则隐藏“删除提醒”选项。
if (mWorkingNote.hasClockAlert()) {
menu.findItem(R.id.menu_alert).setVisible(false);
} else {
@@ -504,13 +1172,22 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return true;
}
+ /**
+ * @method onOptionsItemSelected
+ * @description 用于处理选项菜单中的各个选项被点击时的事件响应。
+ * @return boolean 返回true表示已经处理了该选项的点击事件。
+ */
@Override
- //这段代码是一个用于处理菜单项点击事件的方法onOptionsItemSelected(MenuItem item),当用户点击菜单项时,会根据菜单项的ID执行相应的操作。以下是对代码的解释:
public boolean onOptionsItemSelected(MenuItem item) {
- int itemId = item.getItemId();
- if (itemId == R.id.menu_new_note) {
+ int itemId = item.getItemId();//在这个方法中,首先获取被点击的选项的ID,然后根据ID的不同执行相应的操作。
+ if (itemId == R.id.menu_new_note) {//如果被点击的选项是“新建笔记”,则调用createNewNote()方法创建一个新的笔记。
createNewNote();
- } else if (itemId == R.id.menu_delete) {
+ }
+ /*
+ * 如果被点击的选项是“删除”,则弹出一个警告对话框,询问用户是否确认删除当前笔记。
+ * 如果用户确认删除,则调用deleteCurrentNote()方法删除当前笔记,并关闭当前Activity。
+ */
+ else if (itemId == R.id.menu_delete) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.alert_title_delete));
builder.setIcon(android.R.drawable.ic_dialog_alert);
@@ -524,113 +1201,150 @@ public class NoteEditActivity extends Activity implements OnClickListener,
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
- } else if (itemId == R.id.menu_font_size) {//修改字体的大小
- mFontSizeSelector.setVisibility(View.VISIBLE);
+ }
+ //如果被点击的选项是“修改字体大小”,则显示字体大小选择器,以供用户选择字体大小。
+ else if (itemId == R.id.menu_font_size) {
+ mFontSizeSelector.setVisibility (View.VISIBLE);
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE);
- } else if (itemId == R.id.menu_list_mode) {
+
+ }
+ //如果被点击的选项是“切换列表模式”,则切换当前笔记的检查列表模式状态。
+ else if (itemId == R.id.menu_list_mode) {
mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ?
TextNote.MODE_CHECK_LIST : 0);
- } else if (itemId == R.id.menu_share) {
+ }
+ //如果被点击的选项是“分享”,则获取当前笔记的内容并将其发送到其他应用程序。
+ else if (itemId == R.id.menu_share) {
getWorkingText();
sendTo(this, mWorkingNote.getContent());
- } else if (itemId == R.id.menu_send_to_desktop) {
+ }
+ //如果被点击的选项是“发送到桌面”,则将当前笔记发送到桌面。
+ else if (itemId == R.id.menu_send_to_desktop) {
sendToDesktop();
- } else if (itemId == R.id.menu_alert) {
+ }
+ //如果被点击的选项是“添加提醒”,则设置当前笔记的提醒时间
+ else if (itemId == R.id.menu_alert) {
setReminder();
- } else if (itemId == R.id.menu_delete_remind) {
+ }
+ //如果被点击的选项是“删除提醒”,则清除当前笔记的提醒时间
+ else if (itemId == R.id.menu_delete_remind) {
mWorkingNote.setAlertDate(0, false);
+ }else if(itemId == R.id.menu_revoke) {
+ doRevoke();
+ }else if(itemId == R.id.menu_voice_speech){
+ Log.d(TAG,"in");
+ texttoSpeech();
+ }else if(itemId == R.id.menu_font_setting){
+ showSingleAlertDialog();
}
+
+
return true;
}
-//onOptionsItemSelected方法是一个覆盖方法,用于在用户选择某个选项菜单项时被调用。
-//
-//在这段代码中,首先获取选项菜单项的ID,即itemId = item.getItemId()。
-//
-//然后使用if-else语句对不同的菜单项进行处理。
-//
-//若itemId等于R.id.menu_new_note,则调用createNewNote()方法。
-//若itemId等于R.id.menu_delete,则创建一个AlertDialog对话框,设置标题、图标和消息,并添加确定按钮和取消按钮的点击事件监听器,点击确定按钮时调用deleteCurrentNote()方法并结束当前活动。
-//若itemId等于R.id.menu_font_size,则设置字体大小选择器显示,并根据当前选中的字体大小ID找到对应的视图并设置其可见性为可见。
-//若itemId等于R.id.menu_list_mode,则切换工作笔记的清单模式(若当前为0,则切换为检查清单模式,否则切换为普通文本模式)。
-//若itemId等于R.id.menu_share,则获取当前工作笔记的文本内容,并将其发送到指定目标。
-//若itemId等于R.id.menu_send_to_desktop,则发送笔记到桌面。
-//若itemId等于R.id.menu_alert,则设置提醒事项。
-//若itemId等于R.id.menu_delete_remind,则将工作笔记的提醒日期设置为0,表示删除提醒。
-//最后,返回值为true,表示已经处理了选择的菜单项。
+
+
private void setReminder() {
DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis());
d.setOnDateTimeSetListener(new OnDateTimeSetListener() {
+ //首先创建一个DateTimePickerDialog对象,并将当前系统时间作为初始时间传入。
+ // 然后,为该对话框设置一个日期时间选择器监听器。
public void OnDateTimeSet(AlertDialog dialog, long date) {
mWorkingNote.setAlertDate(date , true);
}
});
- d.show();
- }
-//这段代码定义了一个名为setReminder的私有方法,用于设置笔记的提醒时间。
-//
-//在方法内部,首先创建一个DateTimePickerDialog对象d,并将当前时间作为默认时间传递给该对象。
-//
-//接着,为d设置一个OnDateTimeSetListener监听器,当用户设置时间时,会调用该监听器的OnDateTimeSet方法。在该方法中,调用正在编辑的笔记对象mWorkingNote的setAlertDate方法,将用户设置的时间转换成毫秒值,并将其设置为笔记的提醒时间。
-//
-//最后,显示d对话框,让用户选择提醒时间。
-//
-//因此,这段代码用于弹出一个日期时间选择对话框,让用户设置笔记的提醒时间,并将设置的时间保存到正在编辑的笔记对象中。
+ d.show();//最后,显示日期时间选择器对话框。
+ }
+
/**
* Share note to apps that support {@link Intent#ACTION_SEND} action
* and {@text/plain} type
*/
+ /**
+ * @method sendTo
+ * @description 用于在给定的Context上下文环境中,利用系统默认的分享功能将特定的文本信息发送给其他应用程序。
+ */
private void sendTo(Context context, String info) {
- Intent intent = new Intent(Intent.ACTION_SEND);
- intent.putExtra(Intent.EXTRA_TEXT, info);
- intent.setType("text/plain");
- context.startActivity(intent);
- }
-//这段代码是一个私有方法sendTo,用于使用系统默认的分享功能将指定的文本信息发送给其他应用程序。
-//
-//在方法内部,首先创建一个新的Intent对象,并将其动作设置为Intent.ACTION_SEND,表示发送内容。
-//
-//接着,通过putExtra方法将要分享的文本信息info放入Intent中,使用Intent.EXTRA_TEXT作为键。
-//
-//然后,使用setType方法将要分享的内容的MIME类型设置为"text/plain",表示纯文本类型。
-//
-//最后,通过context.startActivity(intent)启动该Intent,将文本信息发送给其他应用程序进行处理。
-//
-//因此,这段代码用于在给定的Context上下文环境中,利用系统默认的分享功能将特定的文本信息发送给其他应用程序。
-
- private void createNewNote() {//新建便签
+ Intent intent = new Intent(Intent.ACTION_SEND);//在方法内部,首先创建一个新的Intent对象,并将其动作设置为Intent.ACTION_SEND,表示发送内容。
+
+ intent.putExtra(Intent.EXTRA_TEXT, info);//接着,通过putExtra方法将要分享的文本信息info放入Intent中,使用Intent.EXTRA_TEXT作为键。
+
+ intent.setType("text/plain"); //然后,使用setType方法将要分享的内容的MIME类型设置为"text/plain",表示纯文本类型。
+
+ context.startActivity(intent);//最后,通过context.startActivity(intent)启动该Intent,将文本信息发送给其他应用程序进行处理。
+ }
+
+ private void count(){//用于实时更新字符数的文本视图
+ mNoteEditor.addTextChangedListener(new TextWatcher() {
+
+ int currentlength = 0;
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ textView.setText("字符数:"+currentlength);
+ }//在beforeTextChanged()方法中,通过获取当前文本的长度并更新textView的文本来显示当前字符数。
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ currentlength = editText.getText().length();
+ }//在onTextChanged()方法中,通过获取编辑框的文本长度并将其赋值给currentLength变量,以便在afterTextChanged()方法中使用。
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ textView.setText("字符数:" + currentlength);
+ }//在afterTextChanged()方法中,再次更新textView的文本以显示最新的字符数
+ });
+ }
+ private void createNewNote() {
// Firstly, save current editing notes
+ //保存当前便签
saveNote();
// For safety, start a new NoteEditActivity
finish();
+ //设置链接器
Intent intent = new Intent(this, NoteEditActivity.class);
+ //将该活动定义为创建或编辑
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
+ //将运行便签的id添加到INTENT_EXTRA_FOLDER_ID标记中
intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId());
+ //开始活动并链接
startActivity(intent);
}
- private void deleteCurrentNote() {//删除便签
+ //删除便签
+ private void deleteCurrentNote() {
+ //假如当前运行的便签内存有数据
if (mWorkingNote.existInDatabase()) {
HashSet ids = new HashSet();
long id = mWorkingNote.getNoteId();
+ //如果不是头文件夹建立一个hash表把便签id存起来
if (id != Notes.ID_ROOT_FOLDER) {
ids.add(id);
} else {
Log.d(TAG, "Wrong note id, should not happen");
}
if (!isSyncMode()) {
+ //在非同步模式情况下
+ //删除操作
if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) {
Log.e(TAG, "Delete Note error");
}
} else {
+ //同步模式
+ //移动至垃圾文件夹的操作
if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) {
Log.e(TAG, "Move notes to trash folder error, should not happens");
}
}
}
+ //将这些标签的删除标记置为true
mWorkingNote.markDeleted(true);
}
+ /**
+ * @method isSyncMode
+ * @description 用于判断是否处于同步模式。
+ * @return 如果此名称的长度大于0,则说明处于同步模式,返回true;否则返回false。
+ */
private boolean isSyncMode() {
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
}
@@ -640,10 +1354,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
* User could set clock to an unsaved note, so before setting the
* alert clock, we should save the note first
*/
- if (!mWorkingNote.existInDatabase()) {
+ if (!mWorkingNote.existInDatabase()) {//首先检查当前工作的便签是否存在于数据库中,如果不存在,则调用saveNote()方法保存便签。
saveNote();
}
- if (mWorkingNote.getNoteId() > 0) {
+ if (mWorkingNote.getNoteId() > 0) {//若当前便签的ID大于0,则创建一个用于触发闹钟的Intent,并设置相应的PendingIntent。
+ // 然后根据参数set来决定是取消闹钟还是设置新的闹钟时间。
Intent intent = new Intent(this, AlarmReceiver.class);
intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId()));
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
@@ -665,10 +1380,15 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
}
+ //更新小部件的显示内容。具体的更新逻辑可能包括重新加载数据、刷新UI等操作,以确保小部件展示的内容和状态是最新的。
public void onWidgetChanged() {
updateWidget();
}
+ /**
+ * @method onEditTextDelete
+ * @description 用于处理删除文本编辑框的操作。
+ */
public void onEditTextDelete(int index, String text) {
int childCount = mEditTextList.getChildCount();
if (childCount == 1) {
@@ -695,17 +1415,21 @@ public class NoteEditActivity extends Activity implements OnClickListener,
edit.setSelection(length);
}
+ /**
+ * @method onEditTextEnter
+ * @description 用于处理插入文本编辑框的操作。
+ */
public void onEditTextEnter(int index, String text) {
/**
* Should not happen, check for debug
*/
if(index > mEditTextList.getChildCount()) {
- Log.e(TAG, "Index out of mEditTextList boundrary, should not happen");
+ Log.e(TAG, "Index out of mEditTextList boundrary, should not happen");//在方法中,首先检查传入的索引位置是否超出了mEditTextList的子视图数量。如果超出了范围,会记录错误日志。
}
- View view = getListItem(text, index);
- mEditTextList.addView(view, index);
- NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
+ View view = getListItem(text, index);//根据传入的文本和索引位置创建一个新的视图view。
+ mEditTextList.addView(view, index);//将创建的视图插入到mEditTextList中的指定索引位置。
+ NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);//获取新插入的文本编辑框,并将其请求获取焦点。同时,将光标定位在文本编辑框的开头位置。
edit.requestFocus();
edit.setSelection(0);
for (int i = index + 1; i < mEditTextList.getChildCount(); i++) {
@@ -714,6 +1438,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
}
+ //用于切换到列表模式
private void switchToListMode(String text) {
mEditTextList.removeAllViews();
String[] items = text.split("\n");
@@ -731,6 +1456,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mEditTextList.setVisibility(View.VISIBLE);
}
+ //用于将匹配到的查询结果进行高亮处理。
private Spannable getHighlightQueryResult(String fullText, String userQuery) {
SpannableString spannable = new SpannableString(fullText == null ? "" : fullText);
if (!TextUtils.isEmpty(userQuery)) {
@@ -748,11 +1474,15 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return spannable;
}
+ /**
+ * @method getListItem
+ * @description 用于根据给定的文本项item和索引index创建一个列表项的视图。
+ */
private View getListItem(String item, int index) {
- View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null);
+ View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null);//首先使用LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null)从布局文件note_edit_list_item中获取一个视图view。
final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
- edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
- CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item));
+ edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));//从view中获取一个NoteEditText编辑框对象edit,并设置其文本外观为当前字体大小mFontSizeId对应的样式。
+ CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); //从view中获取一个CheckBox对象cb,并设置其选中状态改变的监听器,以便在状态改变时修改编辑框的文本外观。
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
@@ -763,6 +1493,11 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
});
+ /*
+ 根据文本项的前缀标记判断当前列表项是否被选中。如果是,则将复选框设置为选中状态,并将编辑框的文本外观设置为带有删除线的样式;
+ 否则,将复选框设置为未选中状态,并将编辑框的文本外观设置为普通样式。
+ 同时,去除前缀标记并去除两端的空格。
+ */
if (item.startsWith(TAG_CHECKED)) {
cb.setChecked(true);
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
@@ -775,38 +1510,61 @@ public class NoteEditActivity extends Activity implements OnClickListener,
edit.setOnTextViewChangeListener(this);
edit.setIndex(index);
- edit.setText(getHighlightQueryResult(item, mUserQuery));
- return view;
+ edit.setText(getHighlightQueryResult(item, mUserQuery));//设置编辑框的值为经过高亮处理的文本项item,并设置编辑框的索引值为传入的索引index,
+ return view;// 最后将edit对象添加到视图view中并返回该视图。
}
+ /**
+ * @method onCheckListModeChanged
+ * @description 用于监听编辑框中文本的改变,并根据是否有文本来控制复选框的可见性。
+ */
public void onTextChange(int index, boolean hasText) {
if (index >= mEditTextList.getChildCount()) {
Log.e(TAG, "Wrong index, should not happen");
return;
+ //判断传入的索引值index是否超出了编辑框列表中子视图的数量范围。
+ //如果超出,则打印错误日志并退出方法。
}
if(hasText) {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE);
} else {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE);
}
+ //根据传入的hasText参数判断当前编辑框是否有文本。如果有文本,则将该编辑框所在的列表项的复选框设置为可见状态;
+ // 否则,将复选框设置为不可见状态。
}
+ /**
+ * @method onCheckListModeChanged
+ * @description 用于监听检查列表模式的改变,并根据新的模式来更新界面显示。
+ */
public void onCheckListModeChanged(int oldMode, int newMode) {
+ //判断新的模式是否为检查列表模式。如果是,则调用switchToListMode()方法,
+ // 并传入当前编辑器中的文本内容,以切换到列表模式。
if (newMode == TextNote.MODE_CHECK_LIST) {
switchToListMode(mNoteEditor.getText().toString());
} else {
+ //调用getWorkingText()方法来获取当前的工作文本。如果获取失败(即没有工作文本),则将工作文本设置为去除了未选中标记的内容。
if (!getWorkingText()) {
mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ",
""));
}
- mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));
- mEditTextList.setVisibility(View.GONE);
- mNoteEditor.setVisibility(View.VISIBLE);
+ mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));//将编辑器的文本设置为经过高亮处理的工作文本内容
+ mEditTextList.setVisibility(View.GONE);//将编辑框列表设置为不可见状态。
+ mNoteEditor.setVisibility(View.VISIBLE);//将编辑器设置为可见状态。
}
}
+ /**
+ * @method getWorkingText
+ * @description 用于获取工作笔记的文本内容,并根据是否为待办事项模式进行相应处理。
+ * @return 该方法返回一个布尔值,表示在待办事项模式下是否有选中的项目。
+ */
private boolean getWorkingText() {
boolean hasChecked = false;
+ //检查当前工作笔记mWorkingNote是否为待办事项模式。如果是,就遍历所有子视图view,其中包含每个待办事项的复选框和文本编辑框。
+ // 对于每个非空的文本编辑框,如果其相应的复选框被选中,则将文本内容作为已选中的待办事项添加到字符串缓冲区sb中,并将标记hasChecked设置为true;
+ // 否则,将文本内容作为未选中的待办事项添加到字符串缓冲区sb中。
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mEditTextList.getChildCount(); i++) {
@@ -817,6 +1575,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n");
hasChecked = true;
} else {
+ //如果不是待办事项模式,则将文本编辑器mNoteEditor中的文本内容设置为工作笔记的文本内容。
sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n");
}
}
@@ -825,20 +1584,16 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} else {
mWorkingNote.setWorkingText(mNoteEditor.getText().toString());
}
- return hasChecked;
- }
-//段代码是一个私有方法getWorkingText,用于获取工作笔记的文本内容,并根据是否为待办事项模式进行相应处理。同时,该方法返回一个布尔值,表示在待办事项模式下是否有选中的项目。
-//
-//在方法内部,首先检查当前工作笔记mWorkingNote是否为待办事项模式。如果是,就遍历所有子视图view,其中包含每个待办事项的复选框和文本编辑框。对于每个非空的文本编辑框,如果其相应的复选框被选中,则将文本内容作为已选中的待办事项添加到字符串缓冲区sb中,并将标记hasChecked设置为true;否则,将文本内容作为未选中的待办事项添加到字符串缓冲区sb中。
-//
-//最后,将字符串缓冲区sb中的内容作为工作笔记的文本内容设置到mWorkingNote对象中。如果不是待办事项模式,则将文本编辑器mNoteEditor中的文本内容设置为工作笔记的文本内容。
-//
-//最终,该方法返回一个布尔值hasChecked,表示在待办事项模式下是否有选中的项目。
-//
-//因此,这段代码用于获取工作笔记的文本内容,并根据是否为待办事项模式进行相应处理并返回结果。
+ return hasChecked;//该方法返回一个布尔值hasChecked,表示在待办事项模式下是否有选中的项目。
+ }
+
+ //用于保存当前正在编辑的笔记。
private boolean saveNote() {
+ //在方法内部,首先调用getWorkingText方法获取当前正在编辑的笔记的文本内容,并将其保存到mWorkingNote对象中。
getWorkingText();
boolean saved = mWorkingNote.saveNote();
+ //如果保存成功,则调用setResult(RESULT_OK)方法,设置当前Activity的返回状态为RESULT_OK。
+ //这个状态用于标识从编辑状态返回到列表视图时,是创建新笔记还是编辑已有笔记。
if (saved) {
/**
* There are two modes from List view to edit view, open one note,
@@ -851,41 +1606,35 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
return saved;
}
-//这段代码是一个私有方法saveNote,用于保存当前正在编辑的笔记。
-//
-//在方法内部,首先调用getWorkingText方法获取当前正在编辑的笔记的文本内容,并将其保存到mWorkingNote对象中。
-//
-//接着,调用mWorkingNote.saveNote()方法将笔记保存到数据库中,并将保存结果保存到saved变量中。
-//
-//如果保存成功,则调用setResult(RESULT_OK)方法,设置当前Activity的返回状态为RESULT_OK。这个状态用于标识从编辑状态返回到列表视图时,是创建新笔记还是编辑已有笔记。
-//
-//最后,返回保存是否成功的布尔值。
-//
-//因此,这段代码用于将当前正在编辑的笔记保存到数据库中,并设置返回状态。
+
+ //用于将笔记发送到桌面。
private void sendToDesktop() {
/**
* Before send message to home, we should make sure that current
* editing note is exists in databases. So, for new note, firstly
* save it
*/
+ //检查当前正在编辑的笔记是否存在于数据库中。如果笔记不存在于数据库中,则调用saveNote()方法保存笔记。
if (!mWorkingNote.existInDatabase()) {
saveNote();
}
if (mWorkingNote.getNoteId() > 0) {
- Intent sender = new Intent();
+ Intent sender = new Intent();//创建一个Intent对象sender用于发送广播。
Intent shortcutIntent = new Intent(this, NoteEditActivity.class);
- shortcutIntent.setAction(Intent.ACTION_VIEW);
- shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId());
+ shortcutIntent.setAction(Intent.ACTION_VIEW);//创建一个Intent对象shortcutIntent,指定其目标为NoteEditActivity类,并设置动作为Intent.ACTION_VIEW
+ shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId());//将正在编辑的笔记ID作为附加数据放入shortcutIntent中。
+ //将笔记内容生成适合作为快捷方式图标标题的字符串,并放入sender中作为附加数据。
sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
sender.putExtra(Intent.EXTRA_SHORTCUT_NAME,
makeShortcutIconTitle(mWorkingNote.getContent()));
sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app));
+ //将应用程序的图标资源作为快捷方式图标放入sender中。
sender.putExtra("duplicate", true);
- sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
- showToast(R.string.info_note_enter_desktop);
- sendBroadcast(sender);
+ sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT");//设置sender的动作为com.android.launcher.action.INSTALL_SHORTCUT,表示要安装快捷方式。
+ showToast(R.string.info_note_enter_desktop);//弹出一个简短的提示消息,提示用户笔记已经进入桌面。
+ sendBroadcast(sender);//发送广播,安装快捷方式。
} else {
/**
* There is the condition that user has input nothing (the note is
@@ -894,46 +1643,26 @@ public class NoteEditActivity extends Activity implements OnClickListener,
*/
Log.e(TAG, "Send to desktop error");
showToast(R.string.error_note_empty_for_send_to_desktop);
+ //如果当前正在编辑的笔记没有有效的笔记ID,则执行以下操作:
+ //输出一个错误日志,表示发送到桌面出错
+ //弹出一个提示消息,提醒用户必须输入一些内容才能发送到桌面。
}
}
-//这段代码定义了一个名为sendToDesktop的私有方法,用于将笔记发送到桌面。
-//
-//在方法内部,首先检查当前正在编辑的笔记是否存在于数据库中。如果笔记不存在于数据库中,则调用saveNote()方法保存笔记。
-//
-//接着,如果当前正在编辑的笔记具有有效的笔记ID(即大于0),则执行以下操作:
-//
-//创建一个Intent对象sender用于发送广播。
-//
-//创建一个Intent对象shortcutIntent,指定其目标为NoteEditActivity类,并设置动作为Intent.ACTION_VIEW。
-//
-//将正在编辑的笔记ID作为附加数据放入shortcutIntent中。
-//
-//将笔记内容生成适合作为快捷方式图标标题的字符串,并放入sender中作为附加数据。
-//
-//将应用程序的图标资源作为快捷方式图标放入sender中。
-//
-//设置sender的动作为com.android.launcher.action.INSTALL_SHORTCUT,表示要安装快捷方式。
-//
-//弹出一个简短的提示消息,提示用户笔记已经进入桌面。
-//
-//发送广播,安装快捷方式。
-//
-//如果当前正在编辑的笔记没有有效的笔记ID,则执行以下操作:
-//
-//输出一个错误日志,表示发送到桌面出错。
-//
-//弹出一个提示消息,提醒用户必须输入一些内容才能发送到桌面。
+
+ //用于生成快捷图标的标题
private String makeShortcutIconTitle(String content) {
- content = content.replace(TAG_CHECKED, "");
+ content = content.replace(TAG_CHECKED, "");//使用replace()方法将文本中的所有TAG_CHECKED和TAG_UNCHECKED替换为空字符串,即去除已选中和未选中标记。
content = content.replace(TAG_UNCHECKED, "");
return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0,
SHORTCUT_ICON_TITLE_MAX_LEN) : content;
}
+ //用于显示一个短时间的 Toast 提示消息
private void showToast(int resId) {
showToast(resId, Toast.LENGTH_SHORT);
}
+ //用于显示一个指定时长的 Toast 提示消息
private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show();
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteEditText.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteEditText.java
index 2afe2a8..ec4c87b 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteEditText.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteEditText.java
@@ -37,7 +37,25 @@ import net.micode.notes.R;
import java.util.HashMap;
import java.util.Map;
-public class NoteEditText extends EditText {
+/**
+ *
+ * @ProjectName: 小米便签代码标注
+ * @Package: net.micode.notes.ui
+ * @ClassName: NoteEditText
+ * @Description:
+ * 处理屏幕被按下的事件,并根据坐标更新光标位置。
+ * 处理用户按下一个键盘按键时会触发的删除事件,并记录光标位置。
+ * 处理用户松开一个键盘按键时会触发的删除和添加新文本事件,并利用OnTextViewChangeListener对文本修改进行监听。
+ * 处理焦点变化的事件,并利用OnTextViewChangeListener对文本修改进行监听。
+ * 生成上下文菜单,根据文本中的URLSpan创建菜单项并跳转到相应链接。
+ * @Author: 作者名 xumingyang
+ * @CreateDate: 2024-01-06 8:13
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2024-01-06 8:13
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
+public class NoteEditText extends EditText {//继承edittext,设置便签设置文本框
private static final String TAG = "NoteEditText";
private int mIndex;
private int mSelectionStartBeforeDelete;
@@ -46,6 +64,7 @@ public class NoteEditText extends EditText {
private static final String SCHEME_HTTP = "http:" ;
private static final String SCHEME_EMAIL = "mailto:" ;
+ //建立一个字符和整数的hash表,用于链接电话,网站,还有邮箱
private static final Map sSchemaActionResMap = new HashMap();
static {
sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel);
@@ -56,18 +75,19 @@ public class NoteEditText extends EditText {
/**
* Call by the {@link NoteEditActivity} to delete or add edit text
*/
+ //在NoteEditActivity中删除或添加文本的操作,可以看做是一个文本是否被变的标记,英文注释已说明的很清楚
public interface OnTextViewChangeListener {
/**
* Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens
* and the text is null
*/
- void onEditTextDelete(int index, String text);
+ void onEditTextDelete(int index, String text);//处理删除按键时的操作
/**
* Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER}
* happen
*/
- void onEditTextEnter(int index, String text);
+ void onEditTextEnter(int index, String text);//处理进入按键时的操作
/**
* Hide or show item option when text change
@@ -77,72 +97,96 @@ public class NoteEditText extends EditText {
private OnTextViewChangeListener mOnTextViewChangeListener;
+ //根据context设置文本
public NoteEditText(Context context) {
- super(context, null);
+ super(context, null);//用super引用父类变量
mIndex = 0;
}
-
+ //设置当前光标
public void setIndex(int index) {
mIndex = index;
}
+ //初始化文本修改标记
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
mOnTextViewChangeListener = listener;
}
+ //AttributeSet 百度了一下是自定义空控件属性,用于维护便签动态变化的属性
+ //初始化便签
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.editTextStyle);
}
+ // 根据defstyle自动初始化
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
+ /**
+ * @method onTouchEvent
+ * @description 在用户触摸屏幕时被调用,实现了根据用户点击的位置更新光标的位置,让用户更加方便地编辑文本。
+ * @param *参数event为手机屏幕触摸事件封装类的对象,其中封装了该事件的所有信息,
+ * 例如触摸的位置、触摸的类型以及触摸的时间等。该对象会在用户触摸手机屏幕时被创建。
+ * @return 返回super.onTouchEvent(event)来处理其他的触摸事件
+ */
@Override
public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
+ switch (event.getAction()) {//重写了需要处理屏幕被按下的事件
case MotionEvent.ACTION_DOWN:
-
+ //更新当前坐标值
int x = (int) event.getX();
int y = (int) event.getY();
x -= getTotalPaddingLeft();
y -= getTotalPaddingTop();
x += getScrollX();
y += getScrollY();
-
+ //用布局控件layout根据x,y的新值设置新的位置
Layout layout = getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
Selection.setSelection(getText(), off);
break;
}
-
+ //更新光标新的位置
return super.onTouchEvent(event);
}
+ /**
+ * @method onKeyDown
+ * @description 处理用户按下一个键盘按键时会触发 的事件
+ * @param
+ * @return 返回super.onKeyDown(keyCode, event)来处理其他的按键事件
+ */
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_ENTER:
- if (mOnTextViewChangeListener != null) {
+ switch (keyCode) {//根据按键的 Unicode 编码值来处理
+ case KeyEvent.KEYCODE_ENTER://“进入”按键
+ if (mOnTextViewChangeListener != null) {//如果设置了则返回false,否则交给父类处理。
return false;
}
break;
- case KeyEvent.KEYCODE_DEL:
- mSelectionStartBeforeDelete = getSelectionStart();
+ case KeyEvent.KEYCODE_DEL://“删除”按键
+ mSelectionStartBeforeDelete = getSelectionStart();//通过getSelectionStart()方法获取当前光标的位置,并记录下来
break;
default:
break;
}
- return super.onKeyDown(keyCode, event);
+ return super.onKeyDown(keyCode, event);//继续执行父类的其他点击事件
}
+ /**
+ * @method onKeyUp
+ * @description 在用户释放一个键盘按键时被调用。它实现了处理删除和回车事件的功能,并触发相应的回调。
+ * @param keyCode 按键码 keyevent 按键对象
+ * @return 需要返回super.onKeyUp(keyCode, event)来处理其他的按键事件。
+ */
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
- switch(keyCode) {
+ switch(keyCode) {//根据按键的 Unicode 编码值来处理,有删除和进入2种操作
case KeyEvent.KEYCODE_DEL:
- if (mOnTextViewChangeListener != null) {
+ if (mOnTextViewChangeListener != null) {//若是被修改过
if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
return true;
@@ -151,7 +195,7 @@ public class NoteEditText extends EditText {
Log.d(TAG, "OnTextViewChangeListener was not seted");
}
break;
- case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_ENTER://同上也是分为监听器是否建立2种情况
if (mOnTextViewChangeListener != null) {
int selectionStart = getSelectionStart();
String text = getText().subSequence(selectionStart, length()).toString();
@@ -168,18 +212,29 @@ public class NoteEditText extends EditText {
}
@Override
+ /**
+ * @method onFocusChanged
+ * @description 在TextView获取或失去焦点时被调用。它实现了当TextView失去焦点且内容为空时,触发onTextChange()回调。
+ * @param * focused表示触发该事件的View是否获得了焦点,当该控件获得焦点时,Focused等于true,否则等于false。
+ * direction表示焦点移动的方向,用数值表示
+ * @return 表示在触发事件的View的坐标系中,前一个获得焦点的矩形区域,即表示焦点是从哪里来的。如果不可用则为null
+ */
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
- if (mOnTextViewChangeListener != null) {
- if (!focused && TextUtils.isEmpty(getText())) {
- mOnTextViewChangeListener.onTextChange(mIndex, false);
+ if (mOnTextViewChangeListener != null) {//若监听器已经建立
+ if (!focused && TextUtils.isEmpty(getText())) {//获取到焦点并且文本不为空
+ mOnTextViewChangeListener.onTextChange(mIndex, false);//mOnTextViewChangeListener子函数,置false隐藏事件选项
} else {
- mOnTextViewChangeListener.onTextChange(mIndex, true);
+ mOnTextViewChangeListener.onTextChange(mIndex, true);//mOnTextViewChangeListener子函数,置true显示事件选项
}
}
- super.onFocusChanged(focused, direction, previouslyFocusedRect);
+ super.onFocusChanged(focused, direction, previouslyFocusedRect); //继续执行父类的其他焦点变化的事件
}
@Override
+ /**
+ * @method onCreateContextMenu
+ * @description 创建上下文菜单(Context Menu)。它实现了在文本中存在URL链接时,在上下文菜单中添加相应的选项,并在点击选项时执行相应的操作。
+ */
protected void onCreateContextMenu(ContextMenu menu) {
if (getText() instanceof Spanned) {
int selStart = getSelectionStart();
@@ -192,13 +247,13 @@ public class NoteEditText extends EditText {
if (urls.length == 1) {
int defaultResId = 0;
for(String schema: sSchemaActionResMap.keySet()) {
- if(urls[0].getURL().indexOf(schema) >= 0) {
+ if(urls[0].getURL().indexOf(schema) >= 0) {//若url可以添加则在添加后将defaultResId置为key所映射的值
defaultResId = sSchemaActionResMap.get(schema);
break;
}
}
- if (defaultResId == 0) {
+ if (defaultResId == 0) {//defaultResId == 0则说明url并没有添加任何东西,所以置为连接其他SchemaActionResMap的值
defaultResId = R.string.note_link_other;
}
@@ -212,6 +267,6 @@ public class NoteEditText extends EditText {
});
}
}
- super.onCreateContextMenu(menu);
+ super.onCreateContextMenu(menu);//继续执行父类的其他菜单创建的事件
}
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteItemData.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteItemData.java
index 0f5a878..15669c7 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteItemData.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NoteItemData.java
@@ -26,6 +26,20 @@ import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.tool.DataUtils;
+/**
+ *
+ * @ProjectName:
+ * @Package: net.micode.notes.ui
+ * @ClassName: NoteItemData
+ * @Description: 这是一个便签应用中的一个数据类,用于存储和管理便签的相关信息。它包含了便签的各种属性和方法,
+ * 例如便签的ID、提醒日期、背景颜色、创建日期、是否有附件等等。
+ * @Author: xumingyang
+ * @CreateDate: 2024-01-06 8:46
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2024-01-06 8:46
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
public class NoteItemData {
static final String [] PROJECTION = new String [] {
NoteColumns.ID,
@@ -42,6 +56,7 @@ public class NoteItemData {
NoteColumns.WIDGET_TYPE,
};
+ //常量标记和数据就不一一标记了,意义翻译基本就知道
private static final int ID_COLUMN = 0;
private static final int ALERTED_DATE_COLUMN = 1;
private static final int BG_COLOR_ID_COLUMN = 2;
@@ -76,7 +91,9 @@ public class NoteItemData {
private boolean mIsOneNoteFollowingFolder;
private boolean mIsMultiNotesFollowingFolder;
+ //初始化NoteItemData,主要利用光标cursor获取的东西
public NoteItemData(Context context, Cursor cursor) {
+ //getxxx为转换格式
mId = cursor.getLong(ID_COLUMN);
mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN);
mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN);
@@ -109,31 +126,35 @@ public class NoteItemData {
checkPostion(cursor);
}
+ //根据鼠标的位置设置标记,和位置
private void checkPostion(Cursor cursor) {
+ //初始化几个标记
mIsLastItem = cursor.isLast() ? true : false;
mIsFirstItem = cursor.isFirst() ? true : false;
mIsOnlyOneItem = (cursor.getCount() == 1);
+ //初始化“多重子文件”“单一子文件”2个标记
mIsMultiNotesFollowingFolder = false;
mIsOneNoteFollowingFolder = false;
- if (mType == Notes.TYPE_NOTE && !mIsFirstItem) {
+ if (mType == Notes.TYPE_NOTE && !mIsFirstItem) {//若是note格式并且不是第一个元素
int position = cursor.getPosition();
- if (cursor.moveToPrevious()) {
+ if (cursor.moveToPrevious()) {//获取光标位置后看上一行
if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER
- || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) {
+ || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) {//若光标满足系统或note格式
if (cursor.getCount() > (position + 1)) {
- mIsMultiNotesFollowingFolder = true;
+ mIsMultiNotesFollowingFolder = true;//若是数据行数大于但前位置+1则设置成正确
} else {
mIsOneNoteFollowingFolder = true;
}
}
- if (!cursor.moveToNext()) {
+ if (!cursor.moveToNext()) {//若不能再往下走则报错
throw new IllegalStateException("cursor move to previous but can't move back");
}
}
}
}
+ //以下都是获取标记
public boolean isOneFollowingFolder() {
return mIsOneNoteFollowingFolder;
}
@@ -214,6 +235,7 @@ public class NoteItemData {
return (mAlertDate > 0);
}
+ //若数据父id为保存至文件夹模式的id且满足电话号码单元不为空,则isCallRecord为true
public boolean isCallRecord() {
return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber));
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListActivity.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListActivity.java
index 766561d..f86b4a9 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListActivity.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListActivity.java
@@ -78,7 +78,26 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
+/**
+ *
+ * @ProjectName:
+ * @Package: net.micode.notes.ui
+ * @ClassName: NotesListActivity
+ * @Description: 显示和管理便签列表的主要界面。
+ * @Author: xumingyang
+ * @CreateDate: 2024-01-09 11:02
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2024-01-09 11:02
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener {
+ /*
+ 用于首页背景切换的控制变量
+ */
+ private int background = -1;
+
+ public static int secret_mode = 0;//初始化为0表示进入隐私模式
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
private static final int FOLDER_LIST_QUERY_TOKEN = 1;
@@ -135,39 +154,68 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
private final static int REQUEST_CODE_OPEN_NODE = 102;
private final static int REQUEST_CODE_NEW_NODE = 103;
+ /**
+ * @method onCreate
+ * @description 用于初始化资源
+ */
@Override
protected void onCreate(Bundle savedInstanceState) {
+ /*
+ 需要是final类型 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。
+ final类不能被继承,没有子类,final类中的方法默认是final的。
+ final方法不能被子类的方法覆盖,但可以被继承。
+ final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
+ final不能用于修饰构造方法。
+ */
super.onCreate(savedInstanceState);
+ // 调用父类的onCreate函数
setContentView(R.layout.note_list);
+ //绑定视图
initResources();
+ //调用初始化函数进行初始化 包括数据和视图的关联
+ getWindow().setBackgroundDrawableResource(R.drawable.picture1);
/**
* Insert an introduction when user firstly use this application
*/
setAppInfoFromRawRes();
}
+
+ /**
+ * @method onActivityResult
+ * @description 返回一些子模块完成的数据交给主Activity处理
+ */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ // 结果值 和 要求值 符合要求
if (resultCode == RESULT_OK
&& (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) {
mNotesListAdapter.changeCursor(null);
} else {
super.onActivityResult(requestCode, resultCode, data);
+ // 调用 Activity 的onActivityResult()
}
}
+ /**
+ * @method setAppInfoFromRawRes
+ * @description 用于从应用的原始资源文件中读取介绍内容,并将其保存为一个便签。
+ */
private void setAppInfoFromRawRes() {
+ // Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) {
StringBuilder sb = new StringBuilder();
InputStream in = null;
try {
+ // 把资源文件放到应用程序的/raw/raw下,那么就可以在应用中使用getResources获取资源后,
+ // 以openRawResource方法(不带后缀的资源文件名)打开这个文件。
in = getResources().openRawResource(R.raw.introduction);
if (in != null) {
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
- char [] buf = new char[1024];
+ char [] buf = new char[1024];// 自行定义的数值,使用者不知道有什么意义
int len = 0;
while ((len = br.read(buf)) > 0) {
sb.append(buf, 0, len);
@@ -189,12 +237,13 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
}
-
+ // 创建空的WorkingNote
WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER,
AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE,
ResourceParser.RED);
note.setWorkingText(sb.toString());
if (note.saveNote()) {
+ // 更新保存note的信息
sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit();
} else {
Log.e(TAG, "Save introduction note error");
@@ -203,17 +252,30 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
+ /**
+ * @method onStart
+ * @description 启动时执行异步查询操作,以获取数据并在 UI 中显示结果。
+ */
@Override
protected void onStart() {
super.onStart();
+ //调用父类的 onStart() 方法
startAsyncNotesListQuery();
}
+ /**
+ * @method initResources
+ * @description 进行资源的初始化
+ */
private void initResources() {
mContentResolver = this.getContentResolver();
+ // 获取应用程序的数据,得到类似数据表的东西
mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver());
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
+
+ // findViewById 是安卓编程的定位函数,主要是引用.R文件里的引用名
mNotesListView = (ListView) findViewById(R.id.notes_list);
+ // 绑定XML中的ListView,作为Item的容器
mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null),
null, false);
mNotesListView.setOnItemClickListener(new OnListItemClickListener());
@@ -221,6 +283,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mNotesListAdapter = new NotesListAdapter(this);
mNotesListView.setAdapter(mNotesListAdapter);
mAddNewNote = (Button) findViewById(R.id.btn_new_note);
+ // 在activity中要获取该按钮
mAddNewNote.setOnClickListener(this);
mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener());
mDispatch = false;
@@ -231,6 +294,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mModeCallBack = new ModeCallback();
}
+ // 继承自ListView.MultiChoiceModeListener 和 OnMenuItemClickListener
private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
private DropdownMenu mDropDownMenu;
private ActionMode mActionMode;
@@ -268,15 +332,24 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
});
return true;
}
+
+ /**
+ * @method updateMenu
+ * @description 新下拉菜单的内容。
+ * 根据已选择的项目数量和选择状态更新下拉菜单的标题和菜单项。它用于在用户选择项目时动态更新菜单的显示内容。
+ */
private void updateMenu() {
int selectedCount = mNotesListAdapter.getSelectedCount();
+ //取已选择的项目数量。
// Update dropdown menu
String format = getResources().getString(R.string.menu_select_title, selectedCount);
- mDropDownMenu.setTitle(format);
+ //获取一个格式化的字符串,其中包含已选择的项目数量。然后,将该字符串设置为下拉菜单的标题
+ mDropDownMenu.setTitle(format);// 更改标题
MenuItem item = mDropDownMenu.findItem(R.id.action_select_all);
if (item != null) {
if (mNotesListAdapter.isAllSelected()) {
+ //检查是否所有项目都被选择。
item.setChecked(true);
item.setTitle(R.string.menu_deselect_all);
} else {
@@ -286,39 +359,76 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
+ /**
+ * @method onPrepareActionMode
+ * @description 进入操作模式时对菜单进行特定的修改或更新
+ * @return 方法直接返回 false,表示不需要进行任何额外的操作或更新。
+ */
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
+
+ /**
+ * @method onActionItemClicked
+ * @description 并用于处理操作模式菜单项的点击事件。
+ * @param mode 和 item 其中,mode 表示当前的操作模式对象,而 item 表示被点击的菜单项对象。
+ * @return 直接返回 false 表示菜单项的点击事件未被处理。 返回 true 表示已经处理了相应的菜单项点击事件。
+ */
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// TODO Auto-generated method stub
return false;
}
+
+ /**
+ * @method onDestroyActionMode
+ * @description 它实现了 ActionMode.Callback 接口中的方法,并用于销毁操作模式。
+ */
public void onDestroyActionMode(ActionMode mode) {
mNotesListAdapter.setChoiceMode(false);
+ //取消列表的选择模式。
mNotesListView.setLongClickable(true);
+ //重新启用列表项的长按事件。
mAddNewNote.setVisibility(View.VISIBLE);
+ //将新建笔记按钮设置为可见状态。
}
+ //用于结束当前的操作模式。
public void finishActionMode() {
mActionMode.finish();
+ //在调用 finish() 方法之前,需要确保当前存在一个有效的操作模式对象 mActionMode。
+ // 如果当前不存在任何操作模式对象,则调用 finish() 方法将抛出异常。
}
+
+ /**
+ * @method onItemCheckedStateChanged
+ * @description 它实现了 ActionMode.Callback 接口中的方法,并用于处理列表项的选中状态变化事件。
+ * @param mode 表示当前的操作模式对象,position 表示列表项的位置,id 表示列表项的唯一标识符,checked 表示列表项的选中状态。
+ */
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
boolean checked) {
mNotesListAdapter.setCheckedItem(position, checked);
+ //将列表项的选中状态传递给列表适配器,在适配器中更新相应的数据。
updateMenu();
+ //根据当前选中的列表项的数量,更新操作模式的菜单项。
}
+ /**
+ * @method onMenuItemClick
+ * @description 它实现了 MenuItem.OnMenuItemClickListener 接口中的方法,并用于处理操作模式菜单项的单击事件。
+ * @param *方法接收一个参数 item,表示被单击的菜单项。
+ */
+
public boolean onMenuItemClick(MenuItem item) {
if (mNotesListAdapter.getSelectedCount() == 0) {
Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none),
Toast.LENGTH_SHORT).show();
return true;
}
-
+ //根据被单击的菜单项 ID,执行不同的操作。
int itemId = item.getItemId();
if (itemId == R.id.delete) {
AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
@@ -339,11 +449,18 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
startQueryDestinationFolders();
} else {
return false;
+ //如果被单击的菜单项不是删除或移动菜单项,则返回 false
}
return true;
+ //如果成功处理了菜单项,则返回 true。
}
}
+ /**
+ * @method
+ * @description 实现了OnTouchListener接口。主要功能是处理触摸。
+ */
+
private class NewNoteOnTouchListener implements OnTouchListener {
public boolean onTouch(View v, MotionEvent event) {
@@ -354,6 +471,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
int newNoteViewHeight = mAddNewNote.getHeight();
int start = screenHeight - newNoteViewHeight;
int eventY = start + (int) event.getY();
+ //首先获取屏幕高度和新笔记视图的高度,并计算出起始位置。如果当前状态是子文件夹状态,则还需减去标题栏的高度。
/**
* Minus TitleBar's height
*/
@@ -371,6 +489,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
* also change. This is very bad, just for the UI designer's strong requirement.
*/
if (event.getY() < (event.getX() * (-0.12) + 94)) {
+ //通过判断触摸点的坐标是否在"New Note"按钮的透明部分上方,来决定是否将事件转发给位于按钮后面的列表视图。
View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1
- mNotesListView.getFooterViewsCount());
if (view != null && view.getBottom() > start
@@ -389,6 +508,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mDispatchY += (int) event.getY() - mOriginY;
event.setLocation(event.getX(), mDispatchY);
return mNotesListView.dispatchTouchEvent(event);
+ //当动作为ACTION_MOVE(移动)时,如果之前已经开始转发事件,则更新转发的Y坐标,并将事件重新定位后转发给列表视图。
}
break;
}
@@ -397,6 +517,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
event.setLocation(event.getX(), mDispatchY);
mDispatch = false;
return mNotesListView.dispatchTouchEvent(event);
+ //如果没有进行事件转发,则返回false,表示本类未处理该事件。
}
break;
}
@@ -406,31 +527,77 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
};
+ /**
+ * @method startAsyncNotesListQuery
+ * @description 它通过异步查询数据库,获取指定文件夹下的笔记列表,并将结果显示在UI上。
+ * @param
+ * *FOLDER_NOTE_LIST_QUERY_TOKEN是一个常量值,用于标识该次查询(可以理解为查询ID)。
+ * 第二个参数为null,表示不需要传递额外的数据。
+ * 第三个参数是查询的URI,即Notes.CONTENT_NOTE_URI,表示查询笔记内容的URI。
+ * 第四个参数是查询需要返回的列名数组(NoteItemData.PROJECTION),用于指定查询结果中需要包含哪些列。
+ * 第五个参数是selection,表示查询时要使用的筛选条件。
+ * 最后一个参数是一个字符串数组,表示用于替换查询语句中占位符的值。
+ */
private void startAsyncNotesListQuery() {
String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION
: NORMAL_SELECTION;
- mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null,
- Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[] {
- String.valueOf(mCurrentFolderId)
- }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
+ String str1 = "123456789";
+ String[] PROJECTION = new String[]{ //定义一个新的PROJECTION数组,只换掉SNIPPET
+ NoteColumns.ID,
+ NoteColumns.ALERTED_DATE,
+ NoteColumns.BG_COLOR_ID,
+ NoteColumns.CREATED_DATE,
+ NoteColumns.HAS_ATTACHMENT,
+ NoteColumns.MODIFIED_DATE,
+ NoteColumns.NOTES_COUNT,
+ NoteColumns.PARENT_ID,
+ //NoteColumns.SNIPPET,
+ str1,
+ NoteColumns.TYPE,
+ NoteColumns.WIDGET_ID,
+ NoteColumns.WIDGET_TYPE,
+ };
+ if(secret_mode == 0) {
+ mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null,
+ Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[]{
+ String.valueOf(mCurrentFolderId)
+ }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
+ }
+ else {
+ mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null,
+ Notes.CONTENT_NOTE_URI, PROJECTION, selection, new String[]{
+ String.valueOf(mCurrentFolderId)
+ }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
+ }
}
private final class BackgroundQueryHandler extends AsyncQueryHandler {
public BackgroundQueryHandler(ContentResolver contentResolver) {
super(contentResolver);
}
-
+
+
+ /**
+ * @method onQueryComplete
+ * @description 用于处理异步查询完成后的回调。
+ * @param token 参数来判断当前是哪个查询完成了。根据不同的查询标识(token),执行相应的操作。
+ */
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
switch (token) {
case FOLDER_NOTE_LIST_QUERY_TOKEN:
+ //表示文件夹笔记列表查询完成。
mNotesListAdapter.changeCursor(cursor);
+ //更新笔记列表的显示内容。
break;
case FOLDER_LIST_QUERY_TOKEN:
+ //表示文件夹列表查询完成。
if (cursor != null && cursor.getCount() > 0) {
showFolderListMenu(cursor);
+ //调用showFolderListMenu(cursor)方法,显示文件夹列表菜单。
} else {
Log.e(TAG, "Query folder failed");
+ //在日志中记录查询文件夹失败的错误信息。
}
break;
default:
@@ -439,32 +606,51 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
}
+
+ /**
+ * @method showFolderListMenu
+ * @description 用于显示文件夹列表菜单。
+ */
private void showFolderListMenu(Cursor cursor) {
AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
builder.setTitle(R.string.menu_title_select_folder);
final FoldersListAdapter adapter = new FoldersListAdapter(this, cursor);
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
+ //设置对话框的列表项和点击事件监听器。
+ //将适配器设置为对话框的列表项,并在点击列表项时执行相应的操作。
public void onClick(DialogInterface dialog, int which) {
DataUtils.batchMoveToFolder(mContentResolver,
mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which));
Toast.makeText(
+ //显示一条消息,内容为移动的笔记数量和所选文件夹的名称。
NotesListActivity.this,
getString(R.string.format_move_notes_to_folder,
mNotesListAdapter.getSelectedCount(),
adapter.getFolderName(NotesListActivity.this, which)),
Toast.LENGTH_SHORT).show();
mModeCallBack.finishActionMode();
+ //结束动作模式(Action Mode),即退出多选模式。
}
});
builder.show();
+ //显示文件夹列表菜单对话框
}
+
+ /**
+ * @method createNewNote
+ * @description 用于创建新的笔记
+ * @param * intent 来启动一个名为NoteEditActivity的活动,
+ * ACTION_INSERT_OR_EDIT表示要执行插入或编辑操作
+ * Notes.INTENT_EXTRA_FOLDER_ID则是传递当前文件夹的ID
+ */
private void createNewNote() {
Intent intent = new Intent(this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId);
this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE);
+ //通过startActivityForResult方法启动活动,并传递了一个请求码(REQUEST_CODE_NEW_NOTE),以便在活动返回结果时进行区分。
}
private void batchDelete() {
@@ -504,20 +690,30 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}.execute();
}
+
+ /**
+ * @method deleteFolder
+ * @description 避免意外情况下删除根文件夹
+ * @date: 2024-01-09 14:54
+ * @author: 作者名
+ * @param folderId,表示要删除的文件夹的ID
+ * @return
+ */
+
private void deleteFolder(long folderId) {
if (folderId == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Wrong folder id, should not happen " + folderId);
return;
+ //在方法内部,首先通过条件判断检查folderId是否等于Notes.ID_ROOT_FOLDER(根文件夹的ID)。
+ // 如果是根文件夹的ID,则记录错误日志并返回,不执行删除操作。
}
-//该方法接收一个参数folderId,表示要删除的文件夹的ID。
-//
-//在方法内部,首先通过条件判断检查folderId是否等于Notes.ID_ROOT_FOLDER(根文件夹的ID)。如果是根文件夹的ID,则记录错误日志并返回,不执行删除操作。
-//
-//这段代码的作用是避免意外情况下删除根文件夹,因为根文件夹通常是系统的关键文件夹,不应该被删除。如果传入的folderId等于根文件夹的ID,会输出错误日志并直接返回,避免继续执行删除根文件夹的操作。
+
HashSet ids = new HashSet();
ids.add(folderId);
+ //创建一个HashSet对象,并将folderId添加到该集合中
HashSet widgets = DataUtils.getFolderNoteWidget(mContentResolver,
folderId);
+ //调用DataUtils.getFolderNoteWidget()方法获取与该文件夹相关联的小部件。将结果保存在widgets变量中。
if (!isSyncMode()) {
// if not synced, delete folder directly
DataUtils.batchDeleteNotes(mContentResolver, ids);
@@ -530,11 +726,17 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) {
updateWidget(widget.widgetId, widget.widgetType);
+ //遍历widgets集合中的每个小部件,并根据小部件的ID和类型调用updateWidget()方法进行小部件的更新操作。
}
}
}
}
+
+ /**
+ * @method openNode
+ * @description 用于打开笔记。
+ */
private void openNode(NoteItemData data) {
Intent intent = new Intent(this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_VIEW);
@@ -542,64 +744,75 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE);
}
+ /**
+ * @method openFolder
+ * @description 打开指定的文件夹
+ * @param data,表示要打开的文件夹
+ * @return
+ */
private void openFolder(NoteItemData data) {
mCurrentFolderId = data.getId();
+ //将当前文件夹的ID设置为参数data的ID,并调用startAsyncNotesListQuery()方法开始异步查询当前文件夹下的笔记列表。
startAsyncNotesListQuery();
+ //根据文件夹的ID判断当前状态:
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
mState = ListEditState.CALL_RECORD_FOLDER;
mAddNewNote.setVisibility(View.GONE);
+ //如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER,则将状态设置为ListEditState.CALL_RECORD_FOLDER,并隐藏添加新笔记按钮;
} else {
mState = ListEditState.SUB_FOLDER;
+ //将状态设置为ListEditState.SUB_FOLDER。
}
+ //根据文件夹的ID设置标题栏的文本:
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
mTitleBar.setText(R.string.call_record_folder_name);
+ //如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER,则设置标题栏的文本为字符串资源R.string.call_record_folder_name;
} else {
mTitleBar.setText(data.getSnippet());
+ //否则,设置标题栏的文本为文件夹的名称(通过调用data.getSnippet()方法获取)
}
mTitleBar.setVisibility(View.VISIBLE);
+ //将标题栏设置为可见状态。
}
-//该方法接收一个参数data,表示要打开的文件夹。
-//
-//首先,将当前文件夹的ID设置为参数data的ID,并调用startAsyncNotesListQuery()方法开始异步查询当前文件夹下的笔记列表。
-//
-//接下来,根据文件夹的ID判断当前状态:
-//
-//如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER,则将状态设置为ListEditState.CALL_RECORD_FOLDER,并隐藏添加新笔记按钮;
-//否则,将状态设置为ListEditState.SUB_FOLDER。
-//然后,根据文件夹的ID设置标题栏的文本:
-//
-//如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER,则设置标题栏的文本为字符串资源R.string.call_record_folder_name;
-//否则,设置标题栏的文本为文件夹的名称(通过调用data.getSnippet()方法获取)。
-//最后,将标题栏设置为可见状态。
-//
-//总之,这段代码实现了打开文件夹的功能,根据文件夹的ID设置不同的状态和标题,并更新UI显示。
+ //当按钮控件的 id 为 btn_new_note 的按钮被点击时,该方法会调用 createNewNote() 方法。
public void onClick(View v) {
if (v.getId() == R.id.btn_new_note) {
createNewNote();
}
}
+ //显示软键盘
private void showSoftInput() {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputMethodManager != null) {
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
}
-
+ //隐藏软键盘
private void hideSoftInput(View view) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
+ /**
+ * @method showCreateOrModifyFolderDialog
+ * @description 用于创建或者是修改文件夹
+ * @param *接收一个参数create,用于指示是创建文件夹还是修改文件夹。
+ */
private void showCreateOrModifyFolderDialog(final boolean create) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
+ //在方法内部,首先创建一个AlertDialog.Builder对象,并通过LayoutInflater从XML布局文件中实例化一个视图。
final EditText etName = (EditText) view.findViewById(R.id.et_foler_name);
showSoftInput();
+ //获取EditText对象用于输入文件夹名称,并调用showSoftInput()方法显示软键盘。
+
+ //根据create参数的值,判断是创建文件夹还是修改文件夹。如果是修改文件夹,
if (!create) {
if (mFocusNoteDataItem != null) {
etName.setText(mFocusNoteDataItem.getSnippet());
+ // 从mFocusNoteDataItem中获取文件夹名称,并设置对话框的标题为对应的修改文件夹名称;
builder.setTitle(getString(R.string.menu_folder_change_name));
} else {
Log.e(TAG, "The long click data item is null");
@@ -608,6 +821,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} else {
etName.setText("");
builder.setTitle(this.getString(R.string.menu_create_folder));
+ // 如果是创建文件夹,则将EditText的文本设置为空,并设置对话框的标题为创建文件夹。
}
builder.setPositiveButton(android.R.string.ok, null);
@@ -637,7 +851,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
values.put(NoteColumns.LOCAL_MODIFIED, 1);
mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID
+ "=?", new String[] {
- String.valueOf(mFocusNoteDataItem.getId())//获取文件夹名称,并设置对话框的标题为对应的修改文件夹名称;
+ String.valueOf(mFocusNoteDataItem.getId())
});
}
} else if (!TextUtils.isEmpty(name)) {
@@ -650,6 +864,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
});
+
if (TextUtils.isEmpty(etName.getText())) {
positive.setEnabled(false);
}
@@ -676,23 +891,29 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
});
}
-//该方法接收一个参数create,用于指示是创建文件夹还是修改文件夹。
-//
-//在方法内部,首先创建一个AlertDialog.Builder对象,并通过LayoutInflater从XML布局文件中实例化一个视图。
-// 获取EditText对象用于输入文件夹名称,并调用showSoftInput()方法显示软键盘。
-//
-//根据create参数的值,判断是创建文件夹还是修改文件夹。如果是修改文件夹,
-// 则从mFocusNoteDataItem中获取文件夹名称,并设置对话框的标题为对应的修改文件夹名称;
-// 如果是创建文件夹,则将EditText的文本设置为空,并设置对话框的标题为创建文件夹。
+
+ /**
+ * @method onBackPressed
+ * @description 用于处理用户按下返回按钮的操作
+ */
+
@Override
public void onBackPressed() {
switch (mState) {
+ //通过switch语句检查当前的状态(mState)
case SUB_FOLDER:
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
mState = ListEditState.NOTE_LIST;
startAsyncNotesListQuery();
mTitleBar.setVisibility(View.GONE);
break;
+ /*
+ 如果当前状态为SUB_FOLDER(子文件夹),
+ 则将mCurrentFolderId设置为根文件夹的ID(Notes.ID_ROOT_FOLDER),
+ 将状态设置为笔记列表状态(ListEditState.NOTE_LIST),
+ 并调用startAsyncNotesListQuery()方法开始异步查询笔记列表。
+ 同时,隐藏标题栏(mTitleBar.setVisibility(View.GONE))
+ */
case CALL_RECORD_FOLDER:
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
mState = ListEditState.NOTE_LIST;
@@ -700,27 +921,43 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
mTitleBar.setVisibility(View.GONE);
startAsyncNotesListQuery();
break;
+ /*
+ 如果当前状态为CALL_RECORD_FOLDER(通话记录文件夹),
+ 则同样将mCurrentFolderId设置为根文件夹的ID,
+ 将状态设置为笔记列表状态,显示添加新笔记按钮(mAddNewNote.setVisibility(View.VISIBLE)),
+ 隐藏标题栏,并调用startAsyncNotesListQuery()方法开始异步查询笔记列表。
+ */
case NOTE_LIST:
super.onBackPressed();
+ //调用父类的onBackPressed()方法,执行默认的返回操作。
break;
default:
break;
}
}
+
+ /**
+ * @method updateWidget
+ * @description 用于更新小部件(widget)
+ */
private void updateWidget(int appWidgetId, int appWidgetType) {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ //根据appWidgetType的不同值,设置不同的NoteWidgetProvider类作为接收广播的目标。
if (appWidgetType == Notes.TYPE_WIDGET_2X) {
intent.setClass(this, NoteWidgetProvider_2x.class);
+ //设置NoteWidgetProvider_2x类作为目标;
} else if (appWidgetType == Notes.TYPE_WIDGET_4X) {
intent.setClass(this, NoteWidgetProvider_4x.class);
+ //则设置NoteWidgetProvider_4x类作为目标
} else {
Log.e(TAG, "Unspported widget type");
+ //不匹配任何已知的类型,则记录一个错误日志并返回
return;
}
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {
- appWidgetId
+ appWidgetId//将appWidgetId作为额外参数放入意图中,并通过sendBroadcast方法发送广播。
});
sendBroadcast(intent);
@@ -738,17 +975,31 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
};
+
+ /**
+ * @method onContextMenuClosed
+ * @description 在上下文菜单关闭时调用的方法
+ */
@Override
public void onContextMenuClosed(Menu menu) {
if (mNotesListView != null) {
mNotesListView.setOnCreateContextMenuListener(null);
+ //然后通过调用 setOnCreateContextMenuListener(null) 方法将上下文菜单的创建监听器设置为 null,即移除了上下文菜单的创建监听器。
}
super.onContextMenuClosed(menu);
+ //调用 super.onContextMenuClosed(menu) 方法来执行父类的相应操作。
}
+
+ /**
+ * @method onContextItemSelected
+ * @description 用于处理上下文菜单项的选择操作
+ * @return 返回true表示操作已经成功处理 如果为空,则记录错误日志并返回false
+ */
@Override
public boolean onContextItemSelected(MenuItem item) {
if (mFocusNoteDataItem == null) {
+ //通过检查mFocusNoteDataItem是否为空来确保当前长按操作的数据项不为空
Log.e(TAG, "The long click data item is null");
return false;
}
@@ -756,6 +1007,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
case MENU_FOLDER_VIEW:
openFolder(mFocusNoteDataItem);
break;
+ //如果用户选择了“查看文件夹”菜单项,则调用openFolder()方法打开该文件夹。
case MENU_FOLDER_DELETE:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.alert_title_delete));
@@ -770,9 +1022,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
break;
+ //如果用户选择了“删除文件夹”菜单项,则弹出一个提示对话框,
+ // 并在用户确认删除操作后调用deleteFolder()方法执行相应的数据库操作。
case MENU_FOLDER_CHANGE_NAME:
showCreateOrModifyFolderDialog(false);
break;
+ //如果用户选择了“重命名文件夹”菜单项,则调用showCreateOrModifyFolderDialog()方法显示创建或修改文件夹的对话框。
default:
break;
}
@@ -780,9 +1035,19 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
return true;
}
+
+ /**
+ * @method onPrepareOptionsMenu
+ * @description 用于在菜单准备显示时进行处理的。
+ * 它会根据当前的状态(mState)来加载不同的菜单布局,并设置相应的标题。
+ * @return 方法返回true,表示菜单已经被处理完毕。
+ */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.clear();
+ //通过调用menu.clear()方法清除菜单中的所有项。
+ //根据mState的不同值,使用getMenuInflater().inflate()方法加载对应的菜单布局文件。
+
if (mState == ListEditState.NOTE_LIST) {
getMenuInflater().inflate(R.menu.note_list, menu);
// set sync or sync_cancel
@@ -795,11 +1060,58 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
} else {
Log.e(TAG, "Wrong state:" + mState);
}
+
+ if (background == -1)
+ {
+ menu.findItem(R.id.menu_switch_to_picture3).setVisible(false);
+ }else if (background == 0){
+ menu.findItem(R.id.menu_switch_to_picture2).setVisible(false);
+ }else if (background == 1){
+ menu.findItem(R.id.menu_switch_to_picture3).setVisible(false);
+ }
+ if(secret_mode ==1){
+ menu.findItem(R.id.menu_secret).setVisible(false);
+ }
+ else{
+ menu.findItem(R.id.menu_quit_secret).setVisible(false);
+ }
return true;
}
+ private void change_password() {
+ Intent intent=new Intent(NotesListActivity.this,ChangePassword.class);
+ startActivity(intent);
+ finish();
+ }
+
+ private void delete_password() {
+ Intent intent=new Intent(NotesListActivity.this, DeletePassword.class);
+ startActivity(intent);
+ finish();
+ }
+
+ private void set_login_password() {
+ Intent intent=new Intent(NotesListActivity.this, CreatePassword.class);
+ startActivity(intent);
+ finish();
+ }
+
+ /**
+ * @method onOptionsItemSelected
+ * @description 每当用户选择菜单项时,Android 系统会调用该方法,并传入被选中的菜单项(MenuItem)。
+ */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ int login_mode=-1;
+ SharedPreferences pref=getSharedPreferences("user management",MODE_PRIVATE);
+ boolean User_boolean = pref.getBoolean("user",false);
+ if(User_boolean==true){
+ login_mode=1;
+ }
+ else{
+ login_mode=0;
+ }
+ //该方法首先获取被选中菜单项的ID,然后根据不同的ID执行相应的操作。
int itemId = item.getItemId();
if (itemId == R.id.menu_new_folder) {
showCreateOrModifyFolderDialog(true);
@@ -821,34 +1133,90 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
createNewNote();
} else if (itemId == R.id.menu_search) {
onSearchRequested();
+ }else if (itemId == R.id.menu_switch_to_picture3) {
+ background = 1;
+ getWindow().setBackgroundDrawableResource(R.drawable.picture1);
+ }else if (itemId == R.id.menu_switch_to_picture2) {
+ background = 0;
+ getWindow().setBackgroundDrawableResource(R.drawable.picture2);
+ }else if (itemId == R.id.menu_switch_to_picture1) {
+ background = -1;
+ getWindow().setBackgroundDrawableResource(R.drawable.picture3);
+ }
+
+ else if (itemId == R.id.menu_createlogin) { //设置登录密码功能
+ if(login_mode == 0) {//没有设置密码
+ set_login_password();
+ }
+ else{
+ Toast.makeText(NotesListActivity.this,"您已经设置了密码",Toast.LENGTH_SHORT).show();
+ }
+ }
+ else if (itemId == R.id.menu_deletelogin){
+ if(login_mode==1) {
+ delete_password();
+ }
+ else {
+ Toast.makeText(NotesListActivity.this, "您还没有设置密码", Toast.LENGTH_SHORT).show();
+ }
+ }
+ else if (itemId ==R.id.menu_changelogin) {
+ if (login_mode == 1) {
+ change_password();
+ }
+ else{
+ Toast.makeText(NotesListActivity.this,"您还没有设置密码",Toast.LENGTH_SHORT).show();
+ }
+ }
+ else if (itemId == R.id.menu_secret){
+ secret_mode = 1;
+ startAsyncNotesListQuery();
+ Toast.makeText(this,"您已进入隐私模式",Toast.LENGTH_SHORT).show();
+ }
+ else if (itemId == R.id.menu_quit_secret){
+ secret_mode = 0;
+ AlertDialog.Builder dialog = new AlertDialog.Builder(NotesListActivity.this);
+ dialog.setTitle("提醒");
+ dialog.setMessage("您确认退出隐私模式吗?");
+ dialog.setCancelable(false);
+ dialog.setPositiveButton("确认", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ startAsyncNotesListQuery();
+ Toast.makeText(NotesListActivity.this,"您已退出隐私模式",Toast.LENGTH_SHORT).show();
+ }
+ });
+ dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which){}
+ });
+ dialog.show();
}
return true;
+ /*
+ * 如果选中的菜单项是R.id.menu_new_folder,则调用showCreateOrModifyFolderDialog(true)方法,显示创建或修改文件夹的对话框。
+ * 如果选中的菜单项是R.id.menu_export_text,则调用exportNoteToText()方法,将笔记导出为文本。
+ * 如果选中的菜单项是R.id.menu_sync,则根据当前是否处于同步模式(isSyncMode())分别启动或取消同步服务(GTaskSyncService)或打开设置活动(startPreferenceActivity)。
+ * 如果选中的菜单项是R.id.menu_setting,则打开设置活动(startPreferenceActivity)。
+ * 如果选中的菜单项是R.id.menu_new_note,则创建新的笔记(createNewNote)。
+ * 如果选中的菜单项是R.id.menu_search,则执行搜索请求(onSearchRequested)。
+ */
}
-//每当用户选择菜单项时,Android 系统会调用该方法,并传入被选中的菜单项(MenuItem)。该方法首先获取被选中菜单项的ID,然后根据不同的ID执行相应的操作。
-//
-//具体来说:
-//
-//如果选中的菜单项是R.id.menu_new_folder,则调用showCreateOrModifyFolderDialog(true)方法,显示创建或修改文件夹的对话框。
-//如果选中的菜单项是R.id.menu_export_text,则调用exportNoteToText()方法,将笔记导出为文本。
-//如果选中的菜单项是R.id.menu_sync,则根据当前是否处于同步模式(isSyncMode())分别启动或取消同步服务(GTaskSyncService)或打开设置活动(startPreferenceActivity)。
-//如果选中的菜单项是R.id.menu_setting,则打开设置活动(startPreferenceActivity)。
-//如果选中的菜单项是R.id.menu_new_note,则创建新的笔记(createNewNote)。
-//如果选中的菜单项是R.id.menu_search,则执行搜索请求(onSearchRequested)。
-//最后,该方法返回true,表示菜单项的选择事件已经得到处理。
-//
-//总之,该方法根据用户选择的菜单项执行不同的操作,包括创建新文件夹、导出笔记、同步服务控制、打开设置活动、创建新笔记和执行搜索请求等。
+
+ /**
+ * @method onSearchRequested
+ * @description nSearchRequested方法是一个覆盖方法,用于在用户点击搜索按钮或者执行搜索手势时被调用。
+ * @param *搜索关键字(null表示没有指定关键字),
+ * 是否全局搜索(false表示只搜索当前应用程序),
+ * 应用程序数据(null表示没有额外的应用程序数据),
+ * 以及是否由用户触发的搜索(false表示不是由用户触发)。
+ */
@Override
public boolean onSearchRequested() {
startSearch(null, false, null /* appData */, false);
return true;
}
-//nSearchRequested方法是一个覆盖方法,用于在用户点击搜索按钮或者执行搜索手势时被调用。
-//
-//在这段代码中,首先调用了startSearch方法来启动搜索功能。startSearch方法接受四个参数:搜索关键字(null表示没有指定关键字),是否全局搜索(false表示只搜索当前应用程序),应用程序数据(null表示没有额外的应用程序数据),以及是否由用户触发的搜索(false表示不是由用户触发)。
-//
-//然后,返回值为true,表示该方法已经处理了搜索请求,并不需要其他的默认处理。
-//
-//总之,该代码片段实现了在搜索请求时调用startSearch方法,并返回true表示已经处理了该搜索请求。
+
private void exportNoteToText() {
final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this);
new AsyncTask() {
@@ -890,25 +1258,23 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}.execute();
}
-//首先,定义了一个名为exportNoteToText的私有方法,没有任何参数。
-//
-//在该方法中,首先通过BackupUtils.getInstance(NotesListActivity.this)获取一个备份工具类的实例。然后创建一个异步任务(AsyncTask)来执行导出操作。
-//
-//在异步任务的doInBackground方法中,调用backup.exportToText()方法来执行导出操作,并返回一个结果值。
-//
-//在异步任务的onPostExecute方法中,根据导出的结果值进行不同的处理:
-//
-//如果结果值等于BackupUtils.STATE_SD_CARD_UNMOUONTED,表示SD卡未挂载,弹出一个对话框提示导出失败和SD卡未挂载的错误信息。
-//如果结果值等于BackupUtils.STATE_SUCCESS,表示导出成功,弹出一个对话框提示导出成功和导出文件的位置信息。
-//如果结果值等于BackupUtils.STATE_SYSTEM_ERROR,表示导出失败,弹出一个对话框提示导出失败的错误信息。
-//在最后,通过调用execute方法来执行异步任务。
+ //用于检查是否处于同步模式
private boolean isSyncMode() {
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
}
+
+ /**
+ * @method startPreferenceActivity
+ * @description 用于启动应用程序的“偏好设置”屏幕
+ * @param
+ * @return
+ */
private void startPreferenceActivity() {
Activity from = getParent() != null ? getParent() : this;
+ //通过检查父活动是否存在来确定从哪个活动中启动偏好设置屏幕。
Intent intent = new Intent(from, NotesPreferenceActivity.class);
+ //创建一个新的意图(Intent)对象,并将其目标设置为NotesPreferenceActivity类。
from.startActivityIfNeeded(intent, -1);
}
@@ -953,6 +1319,18 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
}
+ /**
+ * @method startQueryDestinationFolders
+ * @description 用于开始查询目标文件夹列表。
+ * @param
+ * *FOLDER_LIST_QUERY_TOKEN:查询令牌,用于标识此次查询。
+ * null:附加到查询令牌的对象,这里为null。
+ * Notes.CONTENT_NOTE_URI:要查询的URI,表示笔记内容。
+ * FoldersListAdapter.PROJECTION:要返回的数据列数组。
+ * selection:查询的条件字符串。
+ * new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER), String.valueOf(mCurrentFolderId) }:查询条件中的参数值。
+ * NoteColumns.MODIFIED_DATE + " DESC":查询结果按照修改日期降序排列。
+ */
private void startQueryDestinationFolders() {
String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?";
selection = (mState == ListEditState.NOTE_LIST) ? selection:
@@ -970,21 +1348,30 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
},
NoteColumns.MODIFIED_DATE + " DESC");
}
-
+ /**
+ * @method onItemLongClick
+ * @description 用于处理列表项的长按事件
+ * @return 返回false表示事件未被消耗,以便继续处理其他可能的事件。
+ */
public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) {
if (view instanceof NotesListItem) {
+ //通过检查view是否是NotesListItem的实例来确定长按的列表项类型。
mFocusNoteDataItem = ((NotesListItem) view).getItemData();
if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) {
if (mNotesListView.startActionMode(mModeCallBack) != null) {
mModeCallBack.onItemCheckedStateChanged(null, position, id, true);
- mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ //调用mModeCallBack.onItemCheckedStateChanged()方法更新选择状态。
+ mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ //调用mNotesListView.performHapticFeedback()方法进行触觉反馈,表示长按操作已触发。
} else {
Log.e(TAG, "startActionMode fails");
}
} else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) {
mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener);
- }
+ //如果数据项的类型为文件夹类型(Notes.TYPE_FOLDER),则设置列表视图的上下文菜单创建监听器(mFolderOnCreateContextMenuListener)。
+ }
}
return false;
+ //返回false表示事件未被消耗,以便继续处理其他可能的事件。
}
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java
index 51c9cb9..a7c847f 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java
@@ -31,56 +31,104 @@ import java.util.HashSet;
import java.util.Iterator;
+/**
+ *
+ * @ProjectName:
+ * @Package: net.micode.notes.ui
+ * @ClassName: NotesListAdapter
+ * @Description: 扩展了CursorAdapter类,用于显示笔记列表。
+ * 该适配器具有选择模式,允许用户选择多个项目,并处理所选项目的响应。
+ * 它还提供了一些实用方法,例如获取所选项目的ID和小部件属性等。
+ * @Author: xumingyang
+ * @CreateDate: 2024-01-07 23:46
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2024-01-07 23:46
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
public class NotesListAdapter extends CursorAdapter {
private static final String TAG = "NotesListAdapter";
private Context mContext;
private HashMap mSelectedIndex;
- private int mNotesCount;
- private boolean mChoiceMode;
+ private int mNotesCount;//便签数
+ private boolean mChoiceMode;//选择模式标记
+ //桌面widget的属性,包括编号和类型
public static class AppWidgetAttribute {
public int widgetId;
public int widgetType;
};
+ /**
+ * @method NotesListAdapter
+ * @description 初始化便签链接器
+ */
public NotesListAdapter(Context context) {
- super(context, null);
- mSelectedIndex = new HashMap();
+ super(context, null);//父类对象置空
+ mSelectedIndex = new HashMap();//新建选项下标的hash表
mContext = context;
mNotesCount = 0;
}
+ /**
+ * @method newView
+ * @description 新建一个视图来存储光标所指向的数据
+ * return 返回一个新的项目选项
+ */
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new NotesListItem(context);
}
+ /**
+ * @method bindView
+ * @description 将已经存在的视图和鼠标指向的数据进行捆绑
+ */
@Override
public void bindView(View view, Context context, Cursor cursor) {
- if (view instanceof NotesListItem) {
+ if (view instanceof NotesListItem) {//若view是NotesListItem的一个实例
+ //则新建一个项目选项并且用bind跟将view和鼠标,内容,便签数据捆绑在一起
NoteItemData itemData = new NoteItemData(context, cursor);
((NotesListItem) view).bind(context, itemData, mChoiceMode,
isSelectedItem(cursor.getPosition()));
}
}
+ /**
+ * @method setCheckedItem
+ * @description 设置勾选框
+ */
public void setCheckedItem(final int position, final boolean checked) {
- mSelectedIndex.put(position, checked);
- notifyDataSetChanged();
+ mSelectedIndex.put(position, checked);//根据定位和是否勾选设置下标
+ notifyDataSetChanged();//在修改后刷新activity
}
+ //判断单选按钮是否勾选
public boolean isInChoiceMode() {
return mChoiceMode;
}
+ /**
+ * @method setChoiceMode
+ * @description 设置单项选项框
+ */
public void setChoiceMode(boolean mode) {
- mSelectedIndex.clear();
+ mSelectedIndex.clear();//重置下标并且根据参数mode设置选项
mChoiceMode = mode;
}
+ /*
+ * 函数功能:选择全部选项
+ * 函数实现:如下注释
+ */
+ /**
+ * @method selectAll
+ * @description 选择全部选项
+ * @param *cursor游标对象
+ */
public void selectAll(boolean checked) {
- Cursor cursor = getCursor();
- for (int i = 0; i < getCount(); i++) {
+ Cursor cursor = getCursor();//获取光标位置
+ for (int i = 0; i < getCount(); i++) {//遍历所有光标可用的位置在判断为便签类型之后勾选单项框
if (cursor.moveToPosition(i)) {
if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) {
setCheckedItem(i, checked);
@@ -89,14 +137,20 @@ public class NotesListAdapter extends CursorAdapter {
}
}
+ /**
+ * @method getSelectedItemIds
+ * @description 建立选择项的下标列表
+ * @param *hashset hash表
+ * @return 返回一个itemSet 下标列表
+ */
public HashSet getSelectedItemIds() {
- HashSet itemSet = new HashSet();
- for (Integer position : mSelectedIndex.keySet()) {
- if (mSelectedIndex.get(position) == true) {
+ HashSet itemSet = new HashSet();//建立hash表
+ for (Integer position : mSelectedIndex.keySet()) {//遍历所有的关键
+ if (mSelectedIndex.get(position) == true) {//若光标位置可用
Long id = getItemId(position);
- if (id == Notes.ID_ROOT_FOLDER) {
+ if (id == Notes.ID_ROOT_FOLDER) {//原文件不需要添加
Log.d(TAG, "Wrong item id, should not happen");
- } else {
+ } else { //则将id该下标假如选项集合中
itemSet.add(id);
}
}
@@ -105,12 +159,18 @@ public class NotesListAdapter extends CursorAdapter {
return itemSet;
}
+ /**
+ * @method getSelectedWidget
+ * @description 建立桌面Widget的选项表
+ * @param *hashset hash表
+ * @return 返回一个itemSet 桌面Widget选项表
+ */
public HashSet getSelectedWidget() {
HashSet itemSet = new HashSet();
for (Integer position : mSelectedIndex.keySet()) {
if (mSelectedIndex.get(position) == true) {
Cursor c = (Cursor) getItem(position);
- if (c != null) {
+ if (c != null) {//光标位置可用的话就建立新的Widget属性并编辑下标和类型,最后添加到选项集中
AppWidgetAttribute widget = new AppWidgetAttribute();
NoteItemData item = new NoteItemData(mContext, c);
widget.widgetId = item.getWidgetId();
@@ -128,12 +188,17 @@ public class NotesListAdapter extends CursorAdapter {
return itemSet;
}
+ /**
+ * @method getSelectedCount
+ * @description 统计选项的个数
+ * @return 返回count 表示选项的个数
+ */
public int getSelectedCount() {
- Collection values = mSelectedIndex.values();
+ Collection values = mSelectedIndex.values();//首先获取选项下标的值
if (null == values) {
return 0;
}
- Iterator iter = values.iterator();
+ Iterator iter = values.iterator();//初始化叠加器
int count = 0;
while (iter.hasNext()) {
if (true == iter.next()) {
@@ -143,37 +208,44 @@ public class NotesListAdapter extends CursorAdapter {
return count;
}
+ //函数功能:判断是否全部选中
public boolean isAllSelected() {
int checkedCount = getSelectedCount();
return (checkedCount != 0 && checkedCount == mNotesCount);
+ //获取选项数看是否等于便签的个数
}
+ //函数功能:判断是否为选项表
public boolean isSelectedItem(final int position) {
if (null == mSelectedIndex.get(position)) {
return false;
}
return mSelectedIndex.get(position);
+ //通过传递的下标来确定
}
+ //函数功能:在activity内容发生局部变动的时候回调该函数计算便签的数量
@Override
protected void onContentChanged() {
- super.onContentChanged();
+ super.onContentChanged();//执行基类函数
calcNotesCount();
}
+ //函数功能:在activity光标发生局部变动的时候回调该函数计算便签的数量
@Override
public void changeCursor(Cursor cursor) {
super.changeCursor(cursor);
calcNotesCount();
}
+ //函数功能:计算便签数量
private void calcNotesCount() {
mNotesCount = 0;
for (int i = 0; i < getCount(); i++) {
Cursor c = (Cursor) getItem(i);
if (c != null) {
if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) {
- mNotesCount++;
+ mNotesCount++;//若该位置不为空并且文本类型为便签就+1
}
} else {
Log.e(TAG, "Invalid cursor");
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListItem.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListItem.java
index 1221e80..77ef8ce 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListItem.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesListItem.java
@@ -29,18 +29,21 @@ import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.ResourceParser.NoteItemBgResources;
-
+//创建便签列表项目选项
public class NotesListItem extends LinearLayout {
- private ImageView mAlert;
- private TextView mTitle;
- private TextView mTime;
+ private ImageView mAlert;//闹钟图片
+ private TextView mTitle;//标题
+ private TextView mTime;//时间
private TextView mCallName;
- private NoteItemData mItemData;
- private CheckBox mCheckBox;
+ private NoteItemData mItemData;//标签数据
+ private CheckBox mCheckBox;//打钩框
+ /*初始化基本信息*/
public NotesListItem(Context context) {
- super(context);
+ super(context);//super()它的主要作用是调整调用父类构造函数的顺序
inflate(context, R.layout.note_item, this);
+ //Inflate可用于将一个xml中定义的布局控件找出来,这里的xml是r。layout
+ //findViewById用于从contentView中查找指定ID的View,转换出来的形式根据需要而定;
mAlert = (ImageView) findViewById(R.id.iv_alert_icon);
mTitle = (TextView) findViewById(R.id.tv_title);
mTime = (TextView) findViewById(R.id.tv_time);
@@ -48,6 +51,7 @@ public class NotesListItem extends LinearLayout {
mCheckBox = (CheckBox) findViewById(android.R.id.checkbox);
}
+ //根据data的属性对各个控件的属性的控制,主要是可见性Visibility,内容setText,格式setTextAppearance
public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) {
if (choiceMode && data.getType() == Notes.TYPE_NOTE) {
mCheckBox.setVisibility(View.VISIBLE);
@@ -57,6 +61,7 @@ public class NotesListItem extends LinearLayout {
}
mItemData = data;
+ //设置控件属性,一共三种情况,由data的id和父id是否与保存到文件夹的id一致来决定
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
mCallName.setVisibility(View.GONE);
mAlert.setVisibility(View.VISIBLE);
@@ -94,13 +99,15 @@ public class NotesListItem extends LinearLayout {
}
}
}
- mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate()));
+ mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate()));//设置内容,获取相关时间,从data里编辑的日期中获取
setBackground(data);
}
+ //根据data的文件属性来设置背景
private void setBackground(NoteItemData data) {
int id = data.getBgColorId();
+ //若是note型文件,则4种情况,对于4种不同情况的背景来源
if (data.getType() == Notes.TYPE_NOTE) {
if (data.isSingle() || data.isOneFollowingFolder()) {
setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id));
@@ -111,7 +118,9 @@ public class NotesListItem extends LinearLayout {
} else {
setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id));
}
- } else {
+ }
+ //若不是note直接调用文件夹的背景来源
+ else {
setBackgroundResource(NoteItemBgResources.getFolderBgRes());
}
}
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java
index 07c5f7e..0d8db59 100644
--- a/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/NotesPreferenceActivity.java
@@ -48,53 +48,78 @@ import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.remote.GTaskSyncService;
+/**
+ *
+ * @ProjectName:
+ * @Package: net.micode.notes.ui
+ * @ClassName: NotesPreferenceActivity
+ * @Description: 它提供了一些选项供用户选择,例如设置字体大小、颜色、排序方式、备份/恢复等。
+ * 用户可以通过这个界面来调整应用程序的行为和外观,以更好地适应其需求和喜好。
+ * NotesPreferenceActivity,在小米便签中主要实现的是对背景颜色和字体大小的数据储存。
+ * 继承了PreferenceActivity主要功能为对系统信息和配置进行自动保存的Activity
+ * @Author: xumingyang
+ * @CreateDate: 2024-01-08 18:03
+ * @UpdateUser: 更新者:
+ * @UpdateDate: 2024-01-08 18:03
+ * @UpdateRemark: 更新说明:
+ * @Version: 1.0
+ */
public class NotesPreferenceActivity extends PreferenceActivity {
- public static final String PREFERENCE_NAME = "notes_preferences";
+ public static final String PREFERENCE_NAME = "notes_preferences";//优先名
- public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name";
+ public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name";//同步账号
- public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time";
+ public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time";//同步时间
public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear";
- private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key";
+ private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key"; //同步密码
- private static final String AUTHORITIES_FILTER_KEY = "authorities";
+ private static final String AUTHORITIES_FILTER_KEY = "authorities";//本地密码
- private PreferenceCategory mAccountCategory;
+ private PreferenceCategory mAccountCategory; //账户分组
- private GTaskReceiver mReceiver;
+ private GTaskReceiver mReceiver;//同步任务接收器
- private Account[] mOriAccounts;
+ private Account[] mOriAccounts;//账户
- private boolean mHasAddedAccount;
+ private boolean mHasAddedAccount;//账户的HASH标记
+ /**
+ * @method onCreate
+ * @description 创建一个activity,在函数里要完成所有的正常静态设置
+ * @param *Bundle icicle:存放了 activity 当前的状态
+ */
@Override
protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
+ super.onCreate(icicle);//先执行父类的创建函数
/* using the app icon for navigation */
- getActionBar().setDisplayHomeAsUpEnabled(true);
+ getActionBar().setDisplayHomeAsUpEnabled(true);//给左上角图标的左边加上一个返回的图标
- addPreferencesFromResource(R.xml.preferences);
- mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);
+ addPreferencesFromResource(R.xml.preferences);//添加xml来源并显示 xml
+ mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);//根据同步账户关键码来初始化分组
mReceiver = new GTaskReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME);
- registerReceiver(mReceiver, filter);
+ registerReceiver(mReceiver, filter);//初始化同步组件
mOriAccounts = null;
- View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null);
- getListView().addHeaderView(header, null, true);
+ View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null);//获取listvivew,ListView的作用:用于列出所有选择
+ getListView().addHeaderView(header, null, true); //在listview组件上方添加其他组件
}
@Override
+ /**
+ * @method onResume
+ * @description activity交互功能的实现,用于接受用户的输入
+ */
protected void onResume() {
- super.onResume();
+ super.onResume();//先执行父类 的交互实现
// need to set sync account automatically if user has added a new
// account
- if (mHasAddedAccount) {
+ if (mHasAddedAccount) {//若用户新加了账户则自动设置同步账户
Account[] accounts = getGoogleAccounts();
if (mOriAccounts != null && accounts.length > mOriAccounts.length) {
for (Account accountNew : accounts) {
@@ -116,6 +141,10 @@ public class NotesPreferenceActivity extends PreferenceActivity {
refreshUI();
}
+ /**
+ * @method onDestroy
+ * @description 销毁一个activity
+ */
@Override
protected void onDestroy() {
if (mReceiver != null) {
@@ -124,48 +153,66 @@ public class NotesPreferenceActivity extends PreferenceActivity {
super.onDestroy();
}
+ /**
+ * @method loadAccountPreference
+ * @description 重新设置账户信息
+ */
private void loadAccountPreference() {
mAccountCategory.removeAll();
-
+ //销毁所有的分组
Preference accountPref = new Preference(this);
+ //建立首选项
final String defaultAccount = getSyncAccountName(this);
accountPref.setTitle(getString(R.string.preferences_account_title));
accountPref.setSummary(getString(R.string.preferences_account_summary));
+ //设置首选项的大标题和小标题
accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
+ //建立监听器
if (!GTaskSyncService.isSyncing()) {
if (TextUtils.isEmpty(defaultAccount)) {
// the first time to set account
+ //若是第一次建立账户显示选择账户提示对话框
showSelectAccountAlertDialog();
} else {
// if the account has already been set, we need to promp
// user about the risk
+ //若是已经建立则显示修改对话框并进行修改操作
showChangeAccountConfirmAlertDialog();
}
} else {
+ //若在没有同步的情况下,则在toast中显示不能修改
Toast.makeText(NotesPreferenceActivity.this,
- R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT)
+ R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT)
.show();
}
return true;
}
});
+ //根据新建首选项编辑新的账户分组
mAccountCategory.addPreference(accountPref);
}
+ /**
+ * @method loadSyncButton
+ * @description 设置按键的状态和最后同步的时间
+ */
private void loadSyncButton() {
Button syncButton = (Button) findViewById(R.id.preference_sync_button);
TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
-
+ //获取同步按钮控件和最终同步时间的的窗口
// set button state
+ //设置按钮的状态
if (GTaskSyncService.isSyncing()) {
+ //若是在同步状态下
syncButton.setText(getString(R.string.preferences_button_sync_cancel));
syncButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
GTaskSyncService.cancelSync(NotesPreferenceActivity.this);
}
});
+ //设置按钮显示的文本为“取消同步”以及监听器
} else {
syncButton.setText(getString(R.string.preferences_button_sync_immediately));
syncButton.setOnClickListener(new View.OnClickListener() {
@@ -173,50 +220,68 @@ public class NotesPreferenceActivity extends PreferenceActivity {
GTaskSyncService.startSync(NotesPreferenceActivity.this);
}
});
+ //若是不同步则设置按钮显示的文本为“立即同步”以及对应监听器
}
syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this)));
+ //设置按键可用还是不可用
// set last sync time
+ // 设置最终同步时间
if (GTaskSyncService.isSyncing()) {
+ //若是在同步的情况下
lastSyncTimeView.setText(GTaskSyncService.getProgressString());
lastSyncTimeView.setVisibility(View.VISIBLE);
+ // 根据当前同步服务器设置时间显示框的文本以及可见性
} else {
+ //若是非同步情况
long lastSyncTime = getLastSyncTime(this);
if (lastSyncTime != 0) {
lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time,
DateFormat.format(getString(R.string.preferences_last_sync_time_format),
lastSyncTime)));
lastSyncTimeView.setVisibility(View.VISIBLE);
+ //则根据最后同步时间的信息来编辑时间显示框的文本内容和可见性
} else {
+ //若时间为空直接设置为不可见状态
lastSyncTimeView.setVisibility(View.GONE);
}
}
}
+ /**
+ * @method refreshUI
+ * @description 刷新标签界面
+ */
private void refreshUI() {
loadAccountPreference();
loadSyncButton();
+ //调用上文设置账号和设置按键两个函数来实现
}
-
+ /**
+ * @method showSelectAccountAlertDialog
+ * @description 函数功能:显示账户选择的对话框并进行账户的设置
+ */
private void showSelectAccountAlertDialog() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
+ //创建一个新的对话框
View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
titleTextView.setText(getString(R.string.preferences_dialog_select_account_title));
TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips));
-
+ //设置标题以及子标题的内容
dialogBuilder.setCustomTitle(titleView);
dialogBuilder.setPositiveButton(null, null);
-
+ //设置对话框的自定义标题,建立一个YES的按钮
Account[] accounts = getGoogleAccounts();
String defAccount = getSyncAccountName(this);
-
+ //获取同步账户信息
mOriAccounts = accounts;
mHasAddedAccount = false;
if (accounts.length > 0) {
+ //若账户不为空
CharSequence[] items = new CharSequence[accounts.length];
final CharSequence[] itemMapping = items;
int checkedItem = -1;
@@ -224,83 +289,119 @@ public class NotesPreferenceActivity extends PreferenceActivity {
for (Account account : accounts) {
if (TextUtils.equals(account.name, defAccount)) {
checkedItem = index;
+ //在账户列表中查询到所需账户
}
items[index++] = account.name;
}
dialogBuilder.setSingleChoiceItems(items, checkedItem,
+ //在对话框建立一个单选的复选框
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
setSyncAccount(itemMapping[which].toString());
dialog.dismiss();
+ //取消对话框
refreshUI();
}
+ //设置点击后执行的事件,包括检录新同步账户和刷新标签界面
});
+ //建立对话框网络版的监听器
}
View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null);
dialogBuilder.setView(addAccountView);
+ //给新加账户对话框设置自定义样式
final AlertDialog dialog = dialogBuilder.show();
+ //显示对话框
addAccountView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mHasAddedAccount = true;
+ //将新加账户的hash置true
Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
+ //建立网络建立组件
intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] {
- "gmail-ls"
+ "gmail-ls"
});
startActivityForResult(intent, -1);
+ //跳回上一个选项
dialog.dismiss();
}
});
+ //建立新加账户对话框的监听器
}
+ /**
+ * @method showChangeAccountConfirmAlertDialog
+ * @description 显示账户选择对话框和相关账户操作
+ */
private void showChangeAccountConfirmAlertDialog() {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
-
+ //创建一个新的对话框
View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
titleTextView.setText(getString(R.string.preferences_dialog_change_account_title,
getSyncAccountName(this)));
TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg));
+ //根据同步修改的账户信息设置标题以及子标题的内容
dialogBuilder.setCustomTitle(titleView);
-
+ //设置对话框的自定义标题
CharSequence[] menuItemArray = new CharSequence[] {
getString(R.string.preferences_menu_change_account),
getString(R.string.preferences_menu_remove_account),
getString(R.string.preferences_menu_cancel)
};
+ //定义一些标记字符串
dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() {
+ //设置对话框要显示的一个list,用于显示几个命令时,即change,remove,cancel
public void onClick(DialogInterface dialog, int which) {
+ //按键功能,由which来决定
if (which == 0) {
+ //进入账户选择对话框
showSelectAccountAlertDialog();
} else if (which == 1) {
+ //删除账户并且跟新便签界面
removeSyncAccount();
refreshUI();
}
}
});
dialogBuilder.show();
+ //显示对话框
}
+ /**
+ * @method getGoogleAccounts
+ * @description 获取谷歌账户
+ */
private Account[] getGoogleAccounts() {
AccountManager accountManager = AccountManager.get(this);
return accountManager.getAccountsByType("com.google");
+ //通过账户管理器直接获取
}
+ /**
+ * @method setSyncAccount
+ * @description 设置同步账户
+ */
private void setSyncAccount(String account) {
if (!getSyncAccountName(this).equals(account)) {
+ //假如该账号不在同步账号列表中
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
+ //编辑共享的首选项
if (account != null) {
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account);
} else {
editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
}
+ //将该账号加入到首选项中
+
editor.commit();
+ //提交修改的数据
- // clean up last sync time
setLastSyncTime(this, 0);
+ //将最后同步时间清零
// clean up local gtask related info
new Thread(new Runnable() {
@@ -311,23 +412,34 @@ public class NotesPreferenceActivity extends PreferenceActivity {
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
}
}).start();
+ //重置当地同步任务的信息
Toast.makeText(NotesPreferenceActivity.this,
getString(R.string.preferences_toast_success_set_accout, account),
Toast.LENGTH_SHORT).show();
+ //将toast的文本信息置为“设置账户成功”并显示出来
}
}
+ /**
+ * @method removeSyncAccount
+ * @description 删除同步账户
+ */
private void removeSyncAccount() {
SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
+ //设置共享首选项
+
if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) {
editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME);
+ //假如当前首选项中有账户就删除
}
if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) {
editor.remove(PREFERENCE_LAST_SYNC_TIME);
+ //删除当前首选项中有账户时间
}
editor.commit();
+ //提交更新后的数据
// clean up local gtask related info
new Thread(new Runnable() {
@@ -338,51 +450,82 @@ public class NotesPreferenceActivity extends PreferenceActivity {
getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
}
}).start();
+ //重置当地同步任务的信息
}
+
+ /**
+ * @method getSyncAccountName
+ * @description 获取同步账户名称
+ */
public static String getSyncAccountName(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
+ //通过共享的首选项里的信息直接获取
return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
}
+
+ /**
+ * @method setLastSyncTime
+ * @description 设置最终同步的时间
+ */
public static void setLastSyncTime(Context context, long time) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
+ // 从共享首选项中找到相关账户并获取其编辑器
editor.putLong(PREFERENCE_LAST_SYNC_TIME, time);
editor.commit();
+ //编辑最终同步时间并提交更新
}
+ /**
+ * @method getLastSyncTime
+ * @description 获取最终同步时间
+ */
public static long getLastSyncTime(Context context) {
SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
Context.MODE_PRIVATE);
+ //通过共享的首选项里的信息直接获取
return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0);
}
+ /**
+ * @method
+ * @description 接受同步信息
+ */
private class GTaskReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
refreshUI();
if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) {
+ //获取随广播而来的Intent中的同步服务的数据
TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
syncStatus.setText(intent
.getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG));
+ //通过获取的数据在设置系统的状态
}
}
}
-
+ /**
+ * @method onOptionsItemSelected
+ * @description 处理菜单的选项
+ * @param *MenuItem菜单选项
+ */
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
+ //根据选项的id选择,这里只有一个主页
case android.R.id.home:
Intent intent = new Intent(this, NotesListActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
+ //在主页情况下在创建连接组件intent,发出清空的信号并开始一个相应的activity
default:
return false;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/ui/SplashActivity.java b/src/xiaomi/Notes-master/src/net/micode/notes/ui/SplashActivity.java
new file mode 100644
index 0000000..a0753b0
--- /dev/null
+++ b/src/xiaomi/Notes-master/src/net/micode/notes/ui/SplashActivity.java
@@ -0,0 +1,36 @@
+package net.micode.notes.ui;
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowInsets;
+
+import net.micode.notes.databinding.ActivitySplashBinding;
+import net.micode.notes.R;
+
+public class SplashActivity extends AppCompatActivity {
+ Handler mHandler=new Handler();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState); //加载启动界面
+ setContentView(R.layout.activity_splash); //加载启动图片
+
+ // 当计时结束时,跳转至NotesListActivity
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ Intent intent=new Intent();
+ intent.setClass(SplashActivity.this, LoginActivity.class);
+ startActivity(intent);
+ finish(); //销毁欢迎页面
+ }
+ }, 2000); // 2 秒后跳转
+ }
+}
\ No newline at end of file