Compare commits

..

1 Commits

Author SHA1 Message Date
gxh 7f8c3473fa micode
5 days ago

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" /> <bytecodeTargetLevel target="17" />
</component> </component>
</project> </project>

@ -4,7 +4,6 @@
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" /> <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules"> <option name="modules">

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

@ -5,13 +5,6 @@ plugins {
android { android {
namespace = "net.micode.notes" namespace = "net.micode.notes"
compileSdk = 34 compileSdk = 34
packaging {
resources.excludes.add("META-INF/DEPENDENCIES");
resources.excludes.add("META-INF/NOTICE");
resources.excludes.add("META-INF/LICENSE");
resources.excludes.add("META-INF/LICENSE.txt");
resources.excludes.add("META-INF/NOTICE.txt");
}
defaultConfig { defaultConfig {
applicationId = "net.micode.notes" applicationId = "net.micode.notes"
@ -33,8 +26,15 @@ android {
} }
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_1_8
}
packaging {
resources.excludes.add("META-INF/DEPENDENCIES");
resources.excludes.add("META-INF/NOTICE");
resources.excludes.add("META-INF/LICENSE");
resources.excludes.add("META-INF/LICENSE.txt");
resources.excludes.add("META-INF/NOTICE.txt");
} }
} }
@ -44,9 +44,10 @@ dependencies {
implementation(libs.material) implementation(libs.material)
implementation(libs.activity) implementation(libs.activity)
implementation(libs.constraintlayout) implementation(libs.constraintlayout)
implementation(files("D:\\Z\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-osgi-4.5.14.jar"))
implementation(files("D:\\Z\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-win-4.5.14.jar")) implementation(files("D:\\Code\\AndroidCode\\Notesmaster\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-osgi-4.5.14.jar"))
implementation(files("D:\\Z\\httpcomponents-client-4.5.14-bin\\lib\\httpcore-4.4.16.jar")) implementation(files("D:\\Code\\AndroidCode\\Notesmaster\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-win-4.5.14.jar"))
implementation(files("D:\\Code\\AndroidCode\\Notesmaster\\httpcomponents-client-4.5.14-bin\\lib\\httpcore-4.4.16.jar"))
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core) androidTestImplementation(libs.espresso.core)

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Notesmaster"
tools:targetApi="31">
<activity
android:name=".ui.NotesListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustPan"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.INSERT_OR_EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/text_note" />
<data android:mimeType="vnd.android.cursor.item/call_note" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<provider
android:name="net.micode.notes.data.NotesProvider"
android:authorities="micode_notes"
android:multiprocess="true" />
<receiver
android:name=".widget.NoteWidgetProvider_2x"
android:label="@string/app_widget2x2"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_2x_info" />
</receiver>
<receiver
android:name=".widget.NoteWidgetProvider_4x"
android:label="@string/app_widget4x4"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_4x_info" />
</receiver>
<receiver android:name=".ui.AlarmInitReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name="net.micode.notes.ui.AlarmReceiver"
android:process=":remote" >
</receiver>
<activity
android:name=".ui.AlarmAlertActivity"
android:label="@string/app_name"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" >
</activity>
<activity
android:name="net.micode.notes.ui.NotesPreferenceActivity"
android:label="@string/preferences_title"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Holo.Light" >
</activity>
<service
android:name="net.micode.notes.gtask.remote.GTaskSyncService"
android:exported="false" >
</service>
<meta-data
android:name="android.app.default_searchable"
android:value=".ui.NoteEditActivity" />
<!-- <activity-->
<!-- android:name=".MainActivity"-->
<!-- android:exported="true">-->
<!-- <intent-filter>-->
<!-- <action android:name="android.intent.action.MAIN" />-->
<!-- <category android:name="android.intent.category.LAUNCHER" />-->
<!-- </intent-filter>-->
<!-- </activity>-->
</application>
</manifest>

@ -25,37 +25,41 @@ import android.util.Log;
import java.util.HashMap; import java.util.HashMap;
public class Contact {//联系人
public class Contact {
private static HashMap<String, String> sContactCache; private static HashMap<String, String> sContactCache;
//sContactCache一个静态的 HashMap用于缓存电话号码到联系人姓名的映射以避免重复查询数据库。
private static final String TAG = "Contact"; private static final String TAG = "Contact";
// 定义字符串CALLER_ID_SELECTION //TAG一个用于日志输出的标签。
//CALLER_ID_SELECTION一个 SQL 查询的选择条件字符串,用于筛选与给定电话号码匹配的联系人。
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN " + " AND " + Data.RAW_CONTACT_ID + " IN "
+ "(SELECT raw_contact_id " + "(SELECT raw_contact_id "
+ " FROM phone_lookup" + " FROM phone_lookup"
+ " WHERE min_match = '+')"; + " WHERE min_match = '+')";
//getContact(Context context, String phoneNumber):这是一个静态方法,接收一个 Context 对象和一个电话号码字符串作为参数,
// 返回与该电话号码匹配的联系人姓名。如果找到匹配的联系人,则将该电话号码和姓名添加到 sContactCache 中,以便未来快速查询。
public static String getContact(Context context, String phoneNumber) { public static String getContact(Context context, String phoneNumber) {
if(sContactCache == null) { if(sContactCache == null) {
sContactCache = new HashMap<String, String>(); sContactCache = new HashMap<String, String>();
} }
// 查找HashMap中是否已有phoneNumber信息
if(sContactCache.containsKey(phoneNumber)) { if(sContactCache.containsKey(phoneNumber)) {
return sContactCache.get(phoneNumber); return sContactCache.get(phoneNumber);
} }
String selection = CALLER_ID_SELECTION.replace("+", String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
// 查找数据库中phoneNumber的信息
Cursor cursor = context.getContentResolver().query( Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI, Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME }, new String [] { Phone.DISPLAY_NAME },
selection, selection,
new String[] { phoneNumber }, new String[] { phoneNumber },
null); null);
// 判定查询结果
// moveToFirst()返回第一条
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
try { try {
String name = cursor.getString(0); String name = cursor.getString(0);

@ -14,20 +14,23 @@
* limitations under the License. * limitations under the License.
*/ */
package net.micode.notes.data; package net.micode.notes.data;
import android.net.Uri; import android.net.Uri;
// Notes 类中定义了很多常量这些常量大多是int型和string型
public class Notes { public class Notes {
public static final String AUTHORITY = "micode_notes"; public static final String AUTHORITY = "micode_notes";
public static final String TAG = "Notes"; public static final String TAG = "Notes";
//以下三个常量对NoteColumns.TYPE的值进行设置时会用到
public static final int TYPE_NOTE = 0; public static final int TYPE_NOTE = 0;
public static final int TYPE_FOLDER = 1; public static final int TYPE_FOLDER = 1;
public static final int TYPE_SYSTEM = 2; public static final int TYPE_SYSTEM = 2;
//权限字符串AUTHORITY用于内容提供者Content Provider的权限控制确保数据的安全访问。
//日志标签TAG用于日志记录便于开发者在日志输出中快速定位与笔记应用相关的日志信息。
//数据项类型:
//TYPE_NOTE表示普通笔记项。
//TYPE_FOLDER表示用于组织笔记的文件夹项。
//TYPE_SYSTEM表示系统级数据项如应用设置或用户信息。
/** /**
* Following IDs are system folders' identifiers * Following IDs are system folders' identifiers
* {@link Notes#ID_ROOT_FOLDER } is default folder * {@link Notes#ID_ROOT_FOLDER } is default folder
@ -38,33 +41,48 @@ public class Notes {
public static final int ID_TEMPARAY_FOLDER = -1; public static final int ID_TEMPARAY_FOLDER = -1;
public static final int ID_CALL_RECORD_FOLDER = -2; public static final int ID_CALL_RECORD_FOLDER = -2;
public static final int ID_TRASH_FOLER = -3; public static final int ID_TRASH_FOLER = -3;
//ID_ROOT_FOLDER根文件夹的ID值为0。
//ID_TEMPORARY_FOLDER临时文件夹的ID值为-1。这个文件夹可能用于存储临时笔记或草稿。
//ID_CALL_RECORD_FOLDER通话记录文件夹的ID值为-2。这个文件夹可能专门用于存储与电话通话相关的笔记。
//ID_TRASH_FOLDER垃圾箱文件夹的ID值为-3。用于存储被用户删除的笔记可能提供恢复功能
public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date";
public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id";
public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id";
public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type";
public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id";
public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date";
//INTENT_EXTRA_ALERT_DATE用于指定提醒日期的键。
//INTENT_EXTRA_BACKGROUND_ID用于指定背景颜色ID的键。
//INTENT_EXTRA_WIDGET_ID用于指定小部件ID的键。
//INTENT_EXTRA_WIDGET_TYPE用于指定小部件类型的键。
//INTENT_EXTRA_FOLDER_ID用于指定文件夹ID的键。
//INTENT_EXTRA_CALL_DATE用于指定通话日期的键。
public static final int TYPE_WIDGET_INVALIDE = -1; public static final int TYPE_WIDGET_INVALIDE = -1;
public static final int TYPE_WIDGET_2X = 0; public static final int TYPE_WIDGET_2X = 0;
public static final int TYPE_WIDGET_4X = 1; public static final int TYPE_WIDGET_4X = 1;
//小部件类型常量:
//TYPE_WIDGET_INVALID无效的小部件类型值为-1。可能用于表示小部件类型未设置或错误。
public static class DataConstants { public static class DataConstants {
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
//NOTE普通文本笔记的内容类型
// CALL_NOTE通话记录笔记的内容类型
} }
/** /**
* Uri to query all notes and folders * Uri to query all notes and folders
*/ */
public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note");
//CONTENT_NOTE_URI用于访问笔记内容的URI。
/** /**
* Uri to query data * Uri to query data
*/ */
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data");
//CONTENT_DATA_URI用于查询数据的URI。
//定义了一系列与笔记和文件夹相关的列名字段名如ID、父ID、创建日期、修改日期、提醒日期、摘要、小部件ID、小部件类型、背景颜色ID等。
//还包括了是否包含附件、笔记计数、类型、同步ID、本地修改标志、原始父ID、GTask ID和版本等字段。
public interface NoteColumns { public interface NoteColumns {
/** /**
* The unique ID for a row * The unique ID for a row
@ -170,7 +188,8 @@ public class Notes {
*/ */
public static final String VERSION = "version"; public static final String VERSION = "version";
} }
//定义了一系列与数据项相关的列名如ID、MIME类型、所属笔记ID、创建日期、修改日期和内容等。
//还包含了泛型数据列DATA1至DATA5这些列的具体含义取决于MIME类型。
public interface DataColumns { public interface DataColumns {
/** /**
* The unique ID for a row * The unique ID for a row
@ -244,7 +263,9 @@ public class Notes {
*/ */
public static final String DATA5 = "data5"; public static final String DATA5 = "data5";
} }
//实现了DataColumns接口表示文本笔记。
//定义了检查列表模式MODE和相关的常量。
//提供了文本笔记的内容类型和URI。
public static final class TextNote implements DataColumns { public static final class TextNote implements DataColumns {
/** /**
* Mode to indicate the text in check list mode or not * Mode to indicate the text in check list mode or not
@ -260,7 +281,9 @@ public class Notes {
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note");
} }
//同样实现了DataColumns接口表示通话记录笔记。
//定义了通话日期CALL_DATE和电话号码PHONE_NUMBER等字段。
//提供了通话记录笔记的内容类型和URI。
public static final class CallNote implements DataColumns { public static final class CallNote implements DataColumns {
/** /**
* Call date for this record * Call date for this record

@ -92,7 +92,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" UPDATE " + TABLE.NOTE + " UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";//在文件夹中移入一个Note之后需要更改的数据的表格 " END";//在文件夹中移入一个Note之后需要更改的数据的表格
/** /**
* Decrease folder's note count when move note from folder * Decrease folder's note count when move note from folder
@ -105,7 +105,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
" END";//在文件夹中移出一个Note之后需要更改的数据的表格 " END";//在文件夹中移出一个Note之后需要更改的数据的表格
/** /**
* Increase folder's note count when insert new note to the folder * Increase folder's note count when insert new note to the folder
@ -145,7 +145,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";//在文件夹中对一个Note导入新的数据之后需要更改的数据的表格。 " END";//在文件夹中对一个Note导入新的数据之后需要更改的数据的表格。
/** /**
* Update note's content when data with {@link DataConstants#NOTE} type has changed * Update note's content when data with {@link DataConstants#NOTE} type has changed
*/ */
@ -157,7 +156,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" UPDATE " + TABLE.NOTE + " UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";//Note数据被修改后需要更改的数据的表格 " END";//Note数据被修改后需要更改的数据的表格
/** /**
* Update note's content when data with {@link DataConstants#NOTE} type has deleted * Update note's content when data with {@link DataConstants#NOTE} type has deleted
@ -170,7 +169,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" UPDATE " + TABLE.NOTE + " UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=''" + " SET " + NoteColumns.SNIPPET + "=''" +
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
" END";//Note数据被删除后需要更改的数据的表格 " END";//Note数据被删除后需要更改的数据的表格
/** /**
* Delete datas belong to note which has been deleted * Delete datas belong to note which has been deleted
@ -192,7 +191,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" BEGIN" + " BEGIN" +
" DELETE FROM " + TABLE.NOTE + " DELETE FROM " + TABLE.NOTE +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";//删除已删除的文件夹的便签后需要更改的数据的表格 " END";//删除已删除的文件夹的便签后需要更改的数据的表格
/** /**
* Move notes belong to folder which has been moved to trash folder * Move notes belong to folder which has been moved to trash folder
@ -209,7 +208,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
public NotesDatabaseHelper(Context context) { public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION); super(context, DB_NAME, null, DB_VERSION);
} }//构造函数,传入数据库的名称和版本
public void createNoteTable(SQLiteDatabase db) { public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL); db.execSQL(CREATE_NOTE_TABLE_SQL);
@ -237,7 +236,6 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
}//execSQL是数据库操作的API主要是更改行为的SQL语句。 }//execSQL是数据库操作的API主要是更改行为的SQL语句。
//在这里主要是用来重新创建上述定义的表格用的,先删除原来有的数据库的触发器再重新创建新的数据库 //在这里主要是用来重新创建上述定义的表格用的,先删除原来有的数据库的触发器再重新创建新的数据库
private void createSystemFolder(SQLiteDatabase db) { private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
@ -288,7 +286,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
} }//同上面的execSQL
static synchronized NotesDatabaseHelper getInstance(Context context) { static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) { if (mInstance == null) {
@ -336,7 +334,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
throw new IllegalStateException("Upgrade notes database to version " + newVersion throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails"); + "fails");
} }
}//数据库版本的更新(数据库内容的更改 }//数据库版本的更新(数据库内容的更改
private void upgradeToV2(SQLiteDatabase db) { private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
@ -363,5 +361,5 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
private void upgradeToV4(SQLiteDatabase db) { private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0"); + " INTEGER NOT NULL DEFAULT 0");
} }//更新到V4版本,但是不知道V2、V3、V4是什么意思
} }

@ -16,7 +16,6 @@
package net.micode.notes.data; package net.micode.notes.data;
import android.app.SearchManager; import android.app.SearchManager;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentUris; import android.content.ContentUris;
@ -33,7 +32,6 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE; import net.micode.notes.data.NotesDatabaseHelper.TABLE;
//为存储和获取数据提供接口。可以在不同的应用程序之间共享数据 //为存储和获取数据提供接口。可以在不同的应用程序之间共享数据
//ContentProvider提供的方法 //ContentProvider提供的方法
//query查询 //query查询
@ -74,6 +72,7 @@ public class NotesProvider extends ContentProvider {
* x'0A' represents the '\n' character in sqlite. For title and content in the search result, * 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. * we will trim '\n' and white space in order to show more information.
*/ */
// 声明 NOTES_SEARCH_PROJECTION
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," + 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_1 + ","
@ -81,7 +80,7 @@ public class NotesProvider extends ContentProvider {
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA;
// 声明NOTES_SNIPPET_SEARCH_QUERY
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
+ " FROM " + TABLE.NOTE + " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?" + " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
@ -104,6 +103,7 @@ public class NotesProvider extends ContentProvider {
// 获取可读数据库 // 获取可读数据库
SQLiteDatabase db = mHelper.getReadableDatabase(); SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null; String id = null;
// 匹配查找uri
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
// 对于不同的匹配值,在数据库中查找相应的条目 // 对于不同的匹配值,在数据库中查找相应的条目
case URI_NOTE: case URI_NOTE:
@ -135,6 +135,8 @@ public class NotesProvider extends ContentProvider {
String searchString = null; String searchString = null;
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
if (uri.getPathSegments().size() > 1) { if (uri.getPathSegments().size() > 1) {
// getPathSegments()方法得到一个String的List
// 在uri.getPathSegments().get(1)为第2个元素
searchString = uri.getPathSegments().get(1); searchString = uri.getPathSegments().get(1);
} }
} else { } else {
@ -187,6 +189,7 @@ public class NotesProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
// Notify the note uri // Notify the note uri
// notifyChange获得一个ContextResolver对象并且更新里面的内容
if (noteId > 0) { if (noteId > 0) {
getContext().getContentResolver().notifyChange( getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
@ -206,9 +209,9 @@ public class NotesProvider extends ContentProvider {
// 删除一个uri // 删除一个uri
public int delete(Uri uri, String selection, String[] selectionArgs) { public int delete(Uri uri, String selection, String[] selectionArgs) {
//Uri代表要操作的数据Android上可用的每种资源 -包括 图像、视频片段、音频资源等都可以用Uri来表示。 //Uri代表要操作的数据Android上可用的每种资源 -包括 图像、视频片段、音频资源等都可以用Uri来表示。
int count = 0; int count = 0;
String id = null; String id = null;
// 获得可写的数据库
SQLiteDatabase db = mHelper.getWritableDatabase(); SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false; boolean deleteData = false;
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {

@ -24,31 +24,39 @@ import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
// MetaData类继承自Task类用于处理任务的元数据
public class MetaData extends Task { public class MetaData extends Task {
// 定义日志标签,用于日志输出
private final static String TAG = MetaData.class.getSimpleName(); private final static String TAG = MetaData.class.getSimpleName();
// 与当前元数据相关的GIDGroup ID或其他标识初始化为null
private String mRelatedGid = null; private String mRelatedGid = null;
// 设置元数据的方法接收GID和JSON格式的元数据信息
public void setMeta(String gid, JSONObject metaInfo) { public void setMeta(String gid, JSONObject metaInfo) {
try { try {
// 将GID添加到metaInfo JSON对象中
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
} catch (JSONException e) { } catch (JSONException e) {
// 如果添加GID失败则记录错误日志
Log.e(TAG, "failed to put related gid"); Log.e(TAG, "failed to put related gid");
} }
// 将metaInfo转换为字符串并设置为任务的笔记内容
setNotes(metaInfo.toString()); setNotes(metaInfo.toString());
// 设置任务的名称为一个特定的元数据名称
setName(GTaskStringUtils.META_NOTE_NAME); setName(GTaskStringUtils.META_NOTE_NAME);
} }
// 获取与当前元数据相关的GID
public String getRelatedGid() { public String getRelatedGid() {
return mRelatedGid; return mRelatedGid;
} }
// 判断当前元数据是否值得保存(即是否有笔记内容)
@Override @Override
public boolean isWorthSaving() { public boolean isWorthSaving() {
return getNotes() != null; return getNotes() != null;
} }
// 根据远程JSON对象设置元数据内容
@Override @Override
public void setContentByRemoteJSON(JSONObject js) { public void setContentByRemoteJSON(JSONObject js) {
super.setContentByRemoteJSON(js); super.setContentByRemoteJSON(js);
@ -57,23 +65,24 @@ public class MetaData extends Task {
JSONObject metaInfo = new JSONObject(getNotes().trim()); JSONObject metaInfo = new JSONObject(getNotes().trim());
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
} catch (JSONException e) { } catch (JSONException e) {
// 如果解析失败则记录警告日志并将GID设置为null
Log.w(TAG, "failed to get related gid"); Log.w(TAG, "failed to get related gid");
mRelatedGid = null; mRelatedGid = null;
} }
} }
} }
// 根据本地JSON对象设置元数据内容
@Override @Override
public void setContentByLocalJSON(JSONObject js) { public void setContentByLocalJSON(JSONObject js) {
// this function should not be called // this function should not be called
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
} }
// 从内容中获取本地JSON对象
@Override @Override
public JSONObject getLocalJSONFromContent() { public JSONObject getLocalJSONFromContent() {
throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");
} }
//根据Cursor对象获取同步动作
@Override @Override
public int getSyncAction(Cursor c) { public int getSyncAction(Cursor c) {
throw new IllegalAccessError("MetaData:getSyncAction should not be called"); throw new IllegalAccessError("MetaData:getSyncAction should not be called");

@ -19,8 +19,9 @@ package net.micode.notes.gtask.data;
import android.database.Cursor; import android.database.Cursor;
import org.json.JSONObject; import org.json.JSONObject;
// Node抽象类定义了节点的基本属性和同步操作
public abstract class Node { 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;
@ -38,24 +39,24 @@ public abstract class Node {
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; private String mGid;
private String mName; private String mName;
private long mLastModified; private long mLastModified;
private boolean mDeleted; private boolean mDeleted;// 是否已删除
// 无参构造函数,初始化节点属性
public Node() { public Node() {
mGid = null; mGid = null;
mName = ""; mName = "";
mLastModified = 0; mLastModified = 0;
mDeleted = false; mDeleted = false;
} }
// 用于获取创建节点的操作JSON对象
public abstract JSONObject getCreateAction(int actionId); public abstract JSONObject getCreateAction(int actionId);
// 用于获取更新节点的操作JSON对象
public abstract JSONObject getUpdateAction(int actionId); public abstract JSONObject getUpdateAction(int actionId);
public abstract void setContentByRemoteJSON(JSONObject js); public abstract void setContentByRemoteJSON(JSONObject js);
@ -89,11 +90,11 @@ public abstract class Node {
public String getName() { public String getName() {
return this.mName; return this.mName;
} }
// 用于获取节点的最后修改时间戳
public long getLastModified() { public long getLastModified() {
return this.mLastModified; return this.mLastModified;
} }
// 用于获取节点的删除状态
public boolean getDeleted() { public boolean getDeleted() {
return this.mDeleted; return this.mDeleted;
} }

@ -15,15 +15,15 @@
*/ */
package net.micode.notes.model; package net.micode.notes.model;
import android.content.ContentProviderOperation; import android.content.ContentProviderOperation;//批量的更新、插入、删除数据
import android.content.ContentProviderResult; import android.content.ContentProviderResult;//操作的结果
import android.content.ContentUris; import android.content.ContentUris;//用于添加和获取Uri后面的ID
import android.content.ContentValues; import android.content.ContentValues;//一种用来存储基本数据类型数据的存储机制
import android.content.Context; import android.content.Context;//需要用该类来弄清楚调用者的实例
import android.content.OperationApplicationException; import android.content.OperationApplicationException;//操作应用程序容错
import android.net.Uri; import android.net.Uri;//表示待操作的数据
import android.os.RemoteException; import android.os.RemoteException;//远程容错
import android.util.Log; import android.util.Log;//输出日志,比如说出错、警告等
import net.micode.notes.data.Notes; import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote; import net.micode.notes.data.Notes.CallNote;
@ -34,6 +34,8 @@ import net.micode.notes.data.Notes.TextNote;
import java.util.ArrayList; import java.util.ArrayList;
public class Note { public class Note {
private ContentValues mNoteDiffValues; private ContentValues mNoteDiffValues;
private NoteData mNoteData; private NoteData mNoteData;
@ -51,7 +53,8 @@ public class Note {
values.put(NoteColumns.LOCAL_MODIFIED, 1); values.put(NoteColumns.LOCAL_MODIFIED, 1);
values.put(NoteColumns.PARENT_ID, folderId); values.put(NoteColumns.PARENT_ID, folderId);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
//ContentResolver()主要是实现外部应用对ContentProvider中的数据
//进行添加、删除、修改和查询操作
long noteId = 0; long noteId = 0;
try { try {
noteId = Long.valueOf(uri.getPathSegments().get(1)); noteId = Long.valueOf(uri.getPathSegments().get(1));
@ -68,37 +71,38 @@ public class Note {
public Note() { public Note() {
mNoteDiffValues = new ContentValues(); mNoteDiffValues = new ContentValues();
mNoteData = new NoteData(); mNoteData = new NoteData();
} }//定义两个变量用来存储便签的数据,一个是存储便签属性、一个是存储便签内容
public void setNoteValue(String key, String value) { public void setNoteValue(String key, String value) {
mNoteDiffValues.put(key, value); mNoteDiffValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
} }//设置数据库表格的标签属性数据
public void setTextData(String key, String value) { public void setTextData(String key, String value) {
mNoteData.setTextData(key, value); mNoteData.setTextData(key, value);
} }//设置数据库表格的标签文本内容的数据
public void setTextDataId(long id) { public void setTextDataId(long id) {
mNoteData.setTextDataId(id); mNoteData.setTextDataId(id);
} }//设置文本数据的ID
public long getTextDataId() { public long getTextDataId() {
return mNoteData.mTextDataId; return mNoteData.mTextDataId;
} }//得到文本数据的ID
public void setCallDataId(long id) { public void setCallDataId(long id) {
mNoteData.setCallDataId(id); mNoteData.setCallDataId(id);
} }//设置电话号码数据的ID
public void setCallData(String key, String value) { public void setCallData(String key, String value) {
mNoteData.setCallData(key, value); mNoteData.setCallData(key, value);
} }//得到电话号码数据的ID
public boolean isLocalModified() { public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
} }//判断是否是本地修改
public boolean syncNote(Context context, long noteId) { public boolean syncNote(Context context, long noteId) {
if (noteId <= 0) { if (noteId <= 0) {
@ -128,16 +132,16 @@ public class Note {
} }
return true; return true;
} }//判断数据是否同步
private class NoteData { private class NoteData {//定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据
private long mTextDataId; private long mTextDataId;
private ContentValues mTextDataValues; private ContentValues mTextDataValues;//文本数据
private long mCallDataId; private long mCallDataId;
private ContentValues mCallDataValues; private ContentValues mCallDataValues;//电话号码数据
private static final String TAG = "NoteData"; private static final String TAG = "NoteData";
@ -184,7 +188,7 @@ public class Note {
*/ */
if (noteId <= 0) { if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId); throw new IllegalArgumentException("Wrong note id:" + noteId);
} }//判断数据是否合法
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = null; ContentProviderOperation.Builder builder = null;
@ -209,7 +213,7 @@ public class Note {
operationList.add(builder.build()); operationList.add(builder.build());
} }
mTextDataValues.clear(); mTextDataValues.clear();
} }//把文本数据存入DataColumns
if(mCallDataValues.size() > 0) { if(mCallDataValues.size() > 0) {
mCallDataValues.put(DataColumns.NOTE_ID, noteId); mCallDataValues.put(DataColumns.NOTE_ID, noteId);
@ -223,7 +227,7 @@ public class Note {
Log.e(TAG, "Insert new call data fail with noteId" + noteId); Log.e(TAG, "Insert new call data fail with noteId" + noteId);
mCallDataValues.clear(); mCallDataValues.clear();
return null; return null;
} }//存储过程中的异常处理
} else { } else {
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId)); Notes.CONTENT_DATA_URI, mCallDataId));
@ -232,11 +236,16 @@ public class Note {
} }
mCallDataValues.clear(); mCallDataValues.clear();
} }
// 检查操作列表是否不为空
if (operationList.size() > 0) { if (operationList.size() > 0) {
try { try {
// 使用内容解析器批量应用操作列表中的操作
// Notes.AUTHORITY 是内容提供者的权威名称operationList 是要执行的操作列表
ContentProviderResult[] results = context.getContentResolver().applyBatch( ContentProviderResult[] results = context.getContentResolver().applyBatch(
Notes.AUTHORITY, operationList); Notes.AUTHORITY, operationList);
// 检查返回的结果集
// 如果结果为空、长度为0或第一个结果为空则返回null
// 否则使用返回的noteId与Notes.CONTENT_NOTE_URI结合构造并返回指向特定笔记的URI
return (results == null || results.length == 0 || results[0] == null) ? null return (results == null || results.length == 0 || results[0] == null) ? null
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId); : ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
} catch (RemoteException e) { } catch (RemoteException e) {

@ -61,7 +61,7 @@ public class WorkingNote {
private boolean mIsDeleted; private boolean mIsDeleted;
private NoteSettingChangedListener mNoteSettingStatusListener; private NoteSettingChangedListener mNoteSettingStatusListener;
// 声明 DATA_PROJECTION字符串数组
public static final String[] DATA_PROJECTION = new String[] { public static final String[] DATA_PROJECTION = new String[] {
DataColumns.ID, DataColumns.ID,
DataColumns.CONTENT, DataColumns.CONTENT,
@ -71,7 +71,7 @@ public class WorkingNote {
DataColumns.DATA3, DataColumns.DATA3,
DataColumns.DATA4, DataColumns.DATA4,
}; };
// 声明 NOTE_PROJECTION字符串数组
public static final String[] NOTE_PROJECTION = new String[] { public static final String[] NOTE_PROJECTION = new String[] {
NoteColumns.PARENT_ID, NoteColumns.PARENT_ID,
NoteColumns.ALERTED_DATE, NoteColumns.ALERTED_DATE,
@ -113,7 +113,7 @@ public class WorkingNote {
mMode = 0; mMode = 0;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE; mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
} }
// WorkingNote的构造函数
// Existing note construct // Existing note construct
private WorkingNote(Context context, long noteId, long folderId) { private WorkingNote(Context context, long noteId, long folderId) {
mContext = context; mContext = context;
@ -123,12 +123,14 @@ public class WorkingNote {
mNote = new Note(); mNote = new Note();
loadNote(); loadNote();
} }
// 加载Note
// 通过数据库调用query函数找到第一个条目
private void loadNote() { private void loadNote() {
Cursor cursor = mContext.getContentResolver().query( Cursor cursor = mContext.getContentResolver().query(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
null, null); null, null);
// 若存在,储存相应信息
if (cursor != null) { if (cursor != null) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN);
@ -139,6 +141,8 @@ public class WorkingNote {
mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN);
} }
cursor.close(); cursor.close();
// 若不存在,报错
} else { } else {
Log.e(TAG, "No note with id:" + mNoteId); Log.e(TAG, "No note with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note with id " + mNoteId); throw new IllegalArgumentException("Unable to find note with id " + mNoteId);
@ -146,6 +150,7 @@ public class WorkingNote {
loadNoteData(); loadNoteData();
} }
// 加载NoteData
private void loadNoteData() { private void loadNoteData() {
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] { DataColumns.NOTE_ID + "=?", new String[] {
@ -153,7 +158,8 @@ public class WorkingNote {
}, null); }, null);
if (cursor != null) { if (cursor != null) {
if (cursor.moveToFirst()) { // 查到信息不为空
if (cursor.moveToFirst()) {// 查看第一项是否存在
do { do {
String type = cursor.getString(DATA_MIME_TYPE_COLUMN); String type = cursor.getString(DATA_MIME_TYPE_COLUMN);
if (DataConstants.NOTE.equals(type)) { if (DataConstants.NOTE.equals(type)) {
@ -173,7 +179,8 @@ public class WorkingNote {
throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId);
} }
} }
// 创建空的Note
// 传参context文件夹idwidget背景颜色
public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
int widgetType, int defaultBgColorId) { int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId); WorkingNote note = new WorkingNote(context, folderId);
@ -186,7 +193,7 @@ public class WorkingNote {
public static WorkingNote load(Context context, long id) { public static WorkingNote load(Context context, long id) {
return new WorkingNote(context, id, 0); return new WorkingNote(context, id, 0);
} }
// 保存Note
public synchronized boolean saveNote() { public synchronized boolean saveNote() {
if (isWorthSaving()) { if (isWorthSaving()) {
if (!existInDatabase()) { if (!existInDatabase()) {
@ -211,12 +218,13 @@ public class WorkingNote {
return false; return false;
} }
} }
// 是否在数据库中存在
public boolean existInDatabase() { public boolean existInDatabase() {
return mNoteId > 0; return mNoteId > 0;
} }
// 是否值得保存
private boolean isWorthSaving() { private boolean isWorthSaving() {
// 被删除,或(不在数据库中 内容为空),或 本地已保存过
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) { || (existInDatabase() && !mNote.isLocalModified())) {
return false; return false;
@ -224,11 +232,12 @@ public class WorkingNote {
return true; return true;
} }
} }
// 设置mNoteSettingStatusListener
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l; mNoteSettingStatusListener = l;
} }
// 设置AlertDate
// 若 mAlertDate与data不同则更改mAlertDate并设定NoteValue
public void setAlertDate(long date, boolean set) { public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) { if (date != mAlertDate) {
mAlertDate = date; mAlertDate = date;
@ -238,15 +247,18 @@ public class WorkingNote {
mNoteSettingStatusListener.onClockAlertChanged(date, set); mNoteSettingStatusListener.onClockAlertChanged(date, set);
} }
} }
// 设定删除标记
public void markDeleted(boolean mark) { public void markDeleted(boolean mark) {
// 设定标记
mIsDeleted = mark; mIsDeleted = mark;
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged(); mNoteSettingStatusListener.onWidgetChanged();
// 调用mNoteSettingStatusListener的 onWidgetChanged方法
} }
} }
// 设定背景颜色
public void setBgColorId(int id) { public void setBgColorId(int id) {
if (id != mBgColorId) { if (id != mBgColorId) {
mBgColorId = id; mBgColorId = id;
@ -256,7 +268,8 @@ public class WorkingNote {
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
} }
} }
// 设定检查列表模式
// 参数mode
public void setCheckListMode(int mode) { public void setCheckListMode(int mode) {
if (mMode != mode) { if (mMode != mode) {
if (mNoteSettingStatusListener != null) { if (mNoteSettingStatusListener != null) {
@ -266,28 +279,32 @@ public class WorkingNote {
mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
} }
} }
// 设定WidgetType
// 参数type
public void setWidgetType(int type) { public void setWidgetType(int type) {
if (type != mWidgetType) { if (type != mWidgetType) {
mWidgetType = type; mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
} }
} }
// 设定WidgetId
// 参数id
public void setWidgetId(int id) { public void setWidgetId(int id) {
if (id != mWidgetId) { if (id != mWidgetId) {
mWidgetId = id; mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
} }
} }
// 设定WorkingTex
// 参数更改的text
public void setWorkingText(String text) { public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) { if (!TextUtils.equals(mContent, text)) {
mContent = text; mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent); mNote.setTextData(DataColumns.CONTENT, mContent);
} }
} }
// 转变mNote的CallData及CallNote信息
// 参数String phoneNumber, long callDate
public void convertToCallNote(String phoneNumber, long callDate) { public void convertToCallNote(String phoneNumber, long callDate) {
mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate));
mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber);
@ -341,7 +358,9 @@ public class WorkingNote {
public int getWidgetType() { public int getWidgetType() {
return mWidgetType; return mWidgetType;
} }
// 创建接口 NoteSettingChangedListener,便签更新监视
// 为NoteEditActivity提供接口
// 提供函数有
public interface NoteSettingChangedListener { public interface NoteSettingChangedListener {
/** /**
* Called when the background color of current note has just changed * Called when the background color of current note has just changed

@ -35,40 +35,52 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
// 定义一个名为BackupUtils的工具类
public class BackupUtils { public class BackupUtils {
// 用于日志记录
private static final String TAG = "BackupUtils"; private static final String TAG = "BackupUtils";
// Singleton stuff
// 单例模式相关变量
// 用于保存BackupUtils类的唯一实例
private static BackupUtils sInstance; private static BackupUtils sInstance;
// 用于获取BackupUtils类的唯一实例
// 确保多线程环境下的线程安全
public static synchronized BackupUtils getInstance(Context context) { public static synchronized BackupUtils getInstance(Context context) {
// 如果sInstance为空则创建一个新的实例并赋值给sInstance
if (sInstance == null) { if (sInstance == null) {
sInstance = new BackupUtils(context); sInstance = new BackupUtils(context);
} }
// 返回BackupUtils类的唯一实例
return sInstance; return sInstance;
} }
// 用于表示备份或恢复的状态
/**
* Following states are signs to represents backup or restore
* status
*/
// Currently, the sdcard is not mounted
public static final int STATE_SD_CARD_UNMOUONTED = 0; public static final int STATE_SD_CARD_UNMOUONTED = 0;
// The backup file not exist
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
// The data is not well formated, may be changed by other programs
public static final int STATE_DATA_DESTROIED = 2; public 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; public static final int STATE_SYSTEM_ERROR = 3;
// Backup or restore success // 备份或恢复成功
public static final int STATE_SUCCESS = 4; public static final int STATE_SUCCESS = 4;
// TextExport类型的私有变量mTextExport用于导出文本
private TextExport mTextExport; private TextExport mTextExport;
// 防止外部直接创建BackupUtils类的实例
// 该构造方法接收一个Context类型的参数用于初始化TextExport对象
private BackupUtils(Context context) { private BackupUtils(Context context) {
mTextExport = new TextExport(context); mTextExport = new TextExport(context);
} }
/**
* Following states are signs to represents backup or restore
* status
*/
private static boolean externalStorageAvailable() { private static boolean externalStorageAvailable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
} }
@ -92,13 +104,13 @@ public class BackupUtils {
NoteColumns.SNIPPET, NoteColumns.SNIPPET,
NoteColumns.TYPE NoteColumns.TYPE
}; };
// 用于标识NOTE_PROJECTION数组中各列的索引
private static final int NOTE_COLUMN_ID = 0; private static final int NOTE_COLUMN_ID = 0;
private static final int NOTE_COLUMN_MODIFIED_DATE = 1; private static final int NOTE_COLUMN_MODIFIED_DATE = 1;
private static final int NOTE_COLUMN_SNIPPET = 2; private static final int NOTE_COLUMN_SNIPPET = 2;
// 用于查询数据时的投影
private static final String[] DATA_PROJECTION = { private static final String[] DATA_PROJECTION = {
DataColumns.CONTENT, DataColumns.CONTENT,
DataColumns.MIME_TYPE, DataColumns.MIME_TYPE,
@ -145,7 +157,7 @@ public class BackupUtils {
NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] {
folderId folderId
}, null); }, null);
// 如果notesCursor不为空则遍历查询结果
if (notesCursor != null) { if (notesCursor != null) {
if (notesCursor.moveToFirst()) { if (notesCursor.moveToFirst()) {
do { do {

@ -55,7 +55,7 @@ public class ResourceParser {
R.drawable.edit_title_green, R.drawable.edit_title_green,
R.drawable.edit_title_red R.drawable.edit_title_red
}; };
//直接获取默认的背景颜色。
public static int getNoteBgResource(int id) { public static int getNoteBgResource(int id) {
return BG_EDIT_RESOURCES[id]; return BG_EDIT_RESOURCES[id];
} }
@ -148,7 +148,7 @@ public class ResourceParser {
R.drawable.widget_4x_green, R.drawable.widget_4x_green,
R.drawable.widget_4x_red R.drawable.widget_4x_red
}; };
//防止输入的id大于资源总量若如此则自动返回默认的设置结果
public static int getWidget4xBgResource(int id) { public static int getWidget4xBgResource(int id) {
return BG_4X_RESOURCES[id]; return BG_4X_RESOURCES[id];
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save