Compare commits

..

1 Commits

Author SHA1 Message Date
gxh 7f8c3473fa micode
1 week 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"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
<bytecodeTargetLevel target="17" />
</component>
</project>

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

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<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" />
</component>
<component name="ProjectType">

@ -5,13 +5,6 @@ plugins {
android {
namespace = "net.micode.notes"
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 {
applicationId = "net.micode.notes"
@ -33,8 +26,15 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_1_8
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.activity)
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:\\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-osgi-4.5.14.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)
androidTestImplementation(libs.ext.junit)
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;
public class Contact {//联系人
public class Contact {
private static HashMap<String, String> sContactCache;
//sContactCache一个静态的 HashMap用于缓存电话号码到联系人姓名的映射以避免重复查询数据库。
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
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN "
+ "(SELECT raw_contact_id "
+ " FROM phone_lookup"
+ " WHERE min_match = '+')";
//getContact(Context context, String phoneNumber):这是一个静态方法,接收一个 Context 对象和一个电话号码字符串作为参数,
// 返回与该电话号码匹配的联系人姓名。如果找到匹配的联系人,则将该电话号码和姓名添加到 sContactCache 中,以便未来快速查询。
public static String getContact(Context context, String phoneNumber) {
if(sContactCache == null) {
sContactCache = new HashMap<String, String>();
}
// 查找HashMap中是否已有phoneNumber信息
if(sContactCache.containsKey(phoneNumber)) {
return sContactCache.get(phoneNumber);
}
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
// 查找数据库中phoneNumber的信息
Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME },
selection,
new String[] { phoneNumber },
null);
// 判定查询结果
// moveToFirst()返回第一条
if (cursor != null && cursor.moveToFirst()) {
try {
String name = cursor.getString(0);

@ -14,20 +14,23 @@
* limitations under the License.
*/
package net.micode.notes.data;
import android.net.Uri;
// Notes 类中定义了很多常量这些常量大多是int型和string型
public class Notes {
public static final String AUTHORITY = "micode_notes";
public static final String TAG = "Notes";
//以下三个常量对NoteColumns.TYPE的值进行设置时会用到
public static final int TYPE_NOTE = 0;
public static final int TYPE_FOLDER = 1;
public static final int TYPE_SYSTEM = 2;
//权限字符串AUTHORITY用于内容提供者Content Provider的权限控制确保数据的安全访问。
//日志标签TAG用于日志记录便于开发者在日志输出中快速定位与笔记应用相关的日志信息。
//数据项类型:
//TYPE_NOTE表示普通笔记项。
//TYPE_FOLDER表示用于组织笔记的文件夹项。
//TYPE_SYSTEM表示系统级数据项如应用设置或用户信息。
/**
* Following IDs are system folders' identifiers
* {@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_CALL_RECORD_FOLDER = -2;
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_BACKGROUND_ID = "net.micode.notes.background_color_id";
public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id";
public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type";
public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id";
public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date";
//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_2X = 0;
public static final int TYPE_WIDGET_4X = 1;
//小部件类型常量:
//TYPE_WIDGET_INVALID无效的小部件类型值为-1。可能用于表示小部件类型未设置或错误。
public static class DataConstants {
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
//NOTE普通文本笔记的内容类型
// CALL_NOTE通话记录笔记的内容类型
}
/**
* Uri to query all notes and folders
*/
public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note");
//CONTENT_NOTE_URI用于访问笔记内容的URI。
/**
* Uri to query 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 {
/**
* The unique ID for a row
@ -170,7 +188,8 @@ public class Notes {
*/
public static final String VERSION = "version";
}
//定义了一系列与数据项相关的列名如ID、MIME类型、所属笔记ID、创建日期、修改日期和内容等。
//还包含了泛型数据列DATA1至DATA5这些列的具体含义取决于MIME类型。
public interface DataColumns {
/**
* The unique ID for a row
@ -244,7 +263,9 @@ public class Notes {
*/
public static final String DATA5 = "data5";
}
//实现了DataColumns接口表示文本笔记。
//定义了检查列表模式MODE和相关的常量。
//提供了文本笔记的内容类型和URI。
public static final class TextNote implements DataColumns {
/**
* 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");
}
//同样实现了DataColumns接口表示通话记录笔记。
//定义了通话日期CALL_DATE和电话号码PHONE_NUMBER等字段。
//提供了通话记录笔记的内容类型和URI。
public static final class CallNote implements DataColumns {
/**
* Call date for this record

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

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

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

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

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

@ -61,7 +61,7 @@ public class WorkingNote {
private boolean mIsDeleted;
private NoteSettingChangedListener mNoteSettingStatusListener;
// 声明 DATA_PROJECTION字符串数组
public static final String[] DATA_PROJECTION = new String[] {
DataColumns.ID,
DataColumns.CONTENT,
@ -71,7 +71,7 @@ public class WorkingNote {
DataColumns.DATA3,
DataColumns.DATA4,
};
// 声明 NOTE_PROJECTION字符串数组
public static final String[] NOTE_PROJECTION = new String[] {
NoteColumns.PARENT_ID,
NoteColumns.ALERTED_DATE,
@ -113,7 +113,7 @@ public class WorkingNote {
mMode = 0;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
}
// WorkingNote的构造函数
// Existing note construct
private WorkingNote(Context context, long noteId, long folderId) {
mContext = context;
@ -123,12 +123,14 @@ public class WorkingNote {
mNote = new Note();
loadNote();
}
// 加载Note
// 通过数据库调用query函数找到第一个条目
private void loadNote() {
Cursor cursor = mContext.getContentResolver().query(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
null, null);
// 若存在,储存相应信息
if (cursor != null) {
if (cursor.moveToFirst()) {
mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN);
@ -139,6 +141,8 @@ public class WorkingNote {
mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN);
}
cursor.close();
// 若不存在,报错
} else {
Log.e(TAG, "No note with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note with id " + mNoteId);
@ -146,6 +150,7 @@ public class WorkingNote {
loadNoteData();
}
// 加载NoteData
private void loadNoteData() {
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] {
@ -153,7 +158,8 @@ public class WorkingNote {
}, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
// 查到信息不为空
if (cursor.moveToFirst()) {// 查看第一项是否存在
do {
String type = cursor.getString(DATA_MIME_TYPE_COLUMN);
if (DataConstants.NOTE.equals(type)) {
@ -173,7 +179,8 @@ public class WorkingNote {
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,
int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId);
@ -186,7 +193,7 @@ public class WorkingNote {
public static WorkingNote load(Context context, long id) {
return new WorkingNote(context, id, 0);
}
// 保存Note
public synchronized boolean saveNote() {
if (isWorthSaving()) {
if (!existInDatabase()) {
@ -211,12 +218,13 @@ public class WorkingNote {
return false;
}
}
// 是否在数据库中存在
public boolean existInDatabase() {
return mNoteId > 0;
}
// 是否值得保存
private boolean isWorthSaving() {
// 被删除,或(不在数据库中 内容为空),或 本地已保存过
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) {
return false;
@ -224,11 +232,12 @@ public class WorkingNote {
return true;
}
}
// 设置mNoteSettingStatusListener
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l;
}
// 设置AlertDate
// 若 mAlertDate与data不同则更改mAlertDate并设定NoteValue
public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) {
mAlertDate = date;
@ -238,15 +247,18 @@ public class WorkingNote {
mNoteSettingStatusListener.onClockAlertChanged(date, set);
}
}
// 设定删除标记
public void markDeleted(boolean mark) {
// 设定标记
mIsDeleted = mark;
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
// 调用mNoteSettingStatusListener的 onWidgetChanged方法
}
}
// 设定背景颜色
public void setBgColorId(int id) {
if (id != mBgColorId) {
mBgColorId = id;
@ -256,7 +268,8 @@ public class WorkingNote {
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
}
}
// 设定检查列表模式
// 参数mode
public void setCheckListMode(int mode) {
if (mMode != mode) {
if (mNoteSettingStatusListener != null) {
@ -266,28 +279,32 @@ public class WorkingNote {
mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
}
}
// 设定WidgetType
// 参数type
public void setWidgetType(int type) {
if (type != mWidgetType) {
mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
}
}
// 设定WidgetId
// 参数id
public void setWidgetId(int id) {
if (id != mWidgetId) {
mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
}
}
// 设定WorkingTex
// 参数更改的text
public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) {
mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent);
}
}
// 转变mNote的CallData及CallNote信息
// 参数String phoneNumber, long callDate
public void convertToCallNote(String phoneNumber, long callDate) {
mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate));
mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber);
@ -341,7 +358,9 @@ public class WorkingNote {
public int getWidgetType() {
return mWidgetType;
}
// 创建接口 NoteSettingChangedListener,便签更新监视
// 为NoteEditActivity提供接口
// 提供函数有
public interface NoteSettingChangedListener {
/**
* 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.PrintStream;
// 定义一个名为BackupUtils的工具类
public class BackupUtils {
// 用于日志记录
private static final String TAG = "BackupUtils";
// Singleton stuff
// 单例模式相关变量
// 用于保存BackupUtils类的唯一实例
private static BackupUtils sInstance;
// 用于获取BackupUtils类的唯一实例
// 确保多线程环境下的线程安全
public static synchronized BackupUtils getInstance(Context context) {
// 如果sInstance为空则创建一个新的实例并赋值给sInstance
if (sInstance == null) {
sInstance = new BackupUtils(context);
}
// 返回BackupUtils类的唯一实例
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;
// 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;
// TextExport类型的私有变量mTextExport用于导出文本
private TextExport mTextExport;
// 防止外部直接创建BackupUtils类的实例
// 该构造方法接收一个Context类型的参数用于初始化TextExport对象
private BackupUtils(Context context) {
mTextExport = new TextExport(context);
}
/**
* Following states are signs to represents backup or restore
* status
*/
private static boolean externalStorageAvailable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
@ -92,13 +104,13 @@ public class BackupUtils {
NoteColumns.SNIPPET,
NoteColumns.TYPE
};
// 用于标识NOTE_PROJECTION数组中各列的索引
private static final int NOTE_COLUMN_ID = 0;
private static final int NOTE_COLUMN_MODIFIED_DATE = 1;
private static final int NOTE_COLUMN_SNIPPET = 2;
// 用于查询数据时的投影
private static final String[] DATA_PROJECTION = {
DataColumns.CONTENT,
DataColumns.MIME_TYPE,
@ -145,7 +157,7 @@ public class BackupUtils {
NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] {
folderId
}, null);
// 如果notesCursor不为空则遍历查询结果
if (notesCursor != null) {
if (notesCursor.moveToFirst()) {
do {

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