From eb6413252f394b9405aaedea7577ea43c7e9ebea Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Sat, 28 Sep 2024 08:46:44 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Contact.java | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/Contact.java diff --git a/src/Contact.java b/src/Contact.java new file mode 100644 index 0000000..24e8fc3 --- /dev/null +++ b/src/Contact.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +// 这是一个多行注释,用来说明这个文件的版权信息和许可协议。它指出这个文件是由MiCode开源社区版权所有,并在Apache License 2.0下授权。它还提供了获取许可证的链接,并说明了许可证的条款和条件。 + +package net.micode.notes.data; + +// 声明这个类属于哪个包。在这个例子中,它属于`net.micode.notes.data`包。 + +import android.content.Context; +import android.database.Cursor; +import android.provider.ContactsContract.CommonDataKinds.Phone; +import android.provider.ContactsContract.Data; +import android.telephony.PhoneNumberUtils; +import android.util.Log; + +import java.util.HashMap; + +// 导入所需的Android类和接口。 + +public class Contact { + private static HashMap sContactCache; + private static final String TAG = "Contact"; + + // 定义一个静态的HashMap,用来缓存电话号码和对应的联系人名称。定义一个静态常量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 " + + "(SELECT raw_contact_id " + + " FROM phone_lookup" + + " WHERE min_match = '+')"; + + // 定义一个SQL查询语句模板,用于查询电话号码。这个查询语句使用了Android Contacts Provider的内容URI和一些过滤条件。 + + public static String getContact(Context context, String phoneNumber) { + if(sContactCache == null) { + sContactCache = new HashMap(); + } + + // 如果缓存不存在,则初始化一个空的HashMap作为缓存。 + + if(sContactCache.containsKey(phoneNumber)) { + return sContactCache.get(phoneNumber); + } + + // 如果电话号码已经在缓存中,则直接返回缓存中的联系人名称,避免重复查询。 + + String selection = CALLER_ID_SELECTION.replace("+", + PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); + Cursor cursor = context.getContentResolver().query( + Data.CONTENT_URI, + new String [] { Phone.DISPLAY_NAME }, + selection, + new String[] { phoneNumber }, + null); + + // 将查询语句中的"+"替换为电话号码的最小匹配模式,然后使用设备的ContentResolver执行查询。查询的目标是获取联系人的显示名称。 + + if (cursor != null && cursor.moveToFirst()) { + try { + String name = cursor.getString(0); + sContactCache.put(phoneNumber, name); + return name; + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, " Cursor get string error " + e.toString()); + return null; + } finally { + cursor.close(); + } + } else { + Log.d(TAG, "No contact matched with number:" + phoneNumber); + return null; + } + } + // 定义一个静态方法`getContact`,它接受一个`Context`对象和一个电话号码作为参数。这个方法首先检查缓存,如果没有缓存则执行查询,并将结果存入缓存。如果查询成功,返回联系人名称;如果失败,则记录错误日志并返回null。 + +} \ No newline at end of file -- 2.34.1 From f3b685e67bfeed824e0bc9285c7ebd25aa61bb43 Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Tue, 8 Oct 2024 12:58:39 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E6=8A=A5=E5=91=8A=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/xiaomi | 1 + 1 file changed, 1 insertion(+) create mode 160000 doc/xiaomi diff --git a/doc/xiaomi b/doc/xiaomi new file mode 160000 index 0000000..03616c0 --- /dev/null +++ b/doc/xiaomi @@ -0,0 +1 @@ +Subproject commit 03616c09cee159b75c295eff7c61f5b387d09250 -- 2.34.1 From 4d0c358930841d353ca5f53ff1434a15fcf1190c Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Tue, 8 Oct 2024 13:05:26 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E6=8A=A5=E5=91=8A=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/xiaomi | 1 - 1 file changed, 1 deletion(-) delete mode 160000 doc/xiaomi diff --git a/doc/xiaomi b/doc/xiaomi deleted file mode 160000 index 03616c0..0000000 --- a/doc/xiaomi +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 03616c09cee159b75c295eff7c61f5b387d09250 -- 2.34.1 From 73d505101d93fd51e9472f318c8b6a80e80f4b9b Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Tue, 8 Oct 2024 13:32:36 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ActionFailureException.java | 39 -------------- src/Contact.java | 91 --------------------------------- 2 files changed, 130 deletions(-) delete mode 100644 src/ActionFailureException.java delete mode 100644 src/Contact.java diff --git a/src/ActionFailureException.java b/src/ActionFailureException.java deleted file mode 100644 index ed5de58..0000000 --- a/src/ActionFailureException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.gtask.exception; -//这行代码声明了这个类所在的包名是net.micode.notes.gtask.exception,表明这个类是用于处理特定软件模块中与任务相关的 -//异常情况。 -public class ActionFailureException extends RuntimeException { -//这行代码定义了一个名为ActionFailureException的公共类,它继承自RuntimeException,意味着它是一种运行时异常,可以 -//在程序运行过程中被抛出而不需要在方法签名中进行声明。 - private static final long serialVersionUID = 4425249765923293627L; -//这是一个用于序列化和反序列化的版本号标识,确保在类的结构发生变化时,序列化和反序列化的兼容性。 - public ActionFailureException() { - super(); - } -//这是一个无参构造方法,它调用了父类RuntimeException的无参构造方法,创建一个没有特定错误消息的异常对象。 - public ActionFailureException(String paramString) { - super(paramString); - } -//这是一个带一个字符串参数的构造方法,它接受一个错误消息,并将其传递给父类RuntimeException的构造方法,创建一个带 -//有特定错误消息的异常对象。 - public ActionFailureException(String paramString, Throwable paramThrowable) { - super(paramString, paramThrowable); - } -} -//这是一个带两个参数的构造方法,第一个参数是错误消息,第二个参数是一个Throwable类型的对象,代表导致这个异常的原 -//因。它将这两个参数传递给父类RuntimeException的构造方法,创建一个带有特定错误消息和原因的异常对象。 \ No newline at end of file diff --git a/src/Contact.java b/src/Contact.java deleted file mode 100644 index 24e8fc3..0000000 --- a/src/Contact.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - */ - -// 这是一个多行注释,用来说明这个文件的版权信息和许可协议。它指出这个文件是由MiCode开源社区版权所有,并在Apache License 2.0下授权。它还提供了获取许可证的链接,并说明了许可证的条款和条件。 - -package net.micode.notes.data; - -// 声明这个类属于哪个包。在这个例子中,它属于`net.micode.notes.data`包。 - -import android.content.Context; -import android.database.Cursor; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.Data; -import android.telephony.PhoneNumberUtils; -import android.util.Log; - -import java.util.HashMap; - -// 导入所需的Android类和接口。 - -public class Contact { - private static HashMap sContactCache; - private static final String TAG = "Contact"; - - // 定义一个静态的HashMap,用来缓存电话号码和对应的联系人名称。定义一个静态常量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 " - + "(SELECT raw_contact_id " - + " FROM phone_lookup" - + " WHERE min_match = '+')"; - - // 定义一个SQL查询语句模板,用于查询电话号码。这个查询语句使用了Android Contacts Provider的内容URI和一些过滤条件。 - - public static String getContact(Context context, String phoneNumber) { - if(sContactCache == null) { - sContactCache = new HashMap(); - } - - // 如果缓存不存在,则初始化一个空的HashMap作为缓存。 - - if(sContactCache.containsKey(phoneNumber)) { - return sContactCache.get(phoneNumber); - } - - // 如果电话号码已经在缓存中,则直接返回缓存中的联系人名称,避免重复查询。 - - String selection = CALLER_ID_SELECTION.replace("+", - PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); - Cursor cursor = context.getContentResolver().query( - Data.CONTENT_URI, - new String [] { Phone.DISPLAY_NAME }, - selection, - new String[] { phoneNumber }, - null); - - // 将查询语句中的"+"替换为电话号码的最小匹配模式,然后使用设备的ContentResolver执行查询。查询的目标是获取联系人的显示名称。 - - if (cursor != null && cursor.moveToFirst()) { - try { - String name = cursor.getString(0); - sContactCache.put(phoneNumber, name); - return name; - } catch (IndexOutOfBoundsException e) { - Log.e(TAG, " Cursor get string error " + e.toString()); - return null; - } finally { - cursor.close(); - } - } else { - Log.d(TAG, "No contact matched with number:" + phoneNumber); - return null; - } - } - // 定义一个静态方法`getContact`,它接受一个`Context`对象和一个电话号码作为参数。这个方法首先检查缓存,如果没有缓存则执行查询,并将结果存入缓存。如果查询成功,返回联系人名称;如果失败,则记录错误日志并返回null。 - -} \ No newline at end of file -- 2.34.1 From 5a3467ca8ef6a1038126fcb23eda86b14b5b7f3a Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Tue, 8 Oct 2024 13:52:44 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/NotesProvider.java | 468 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 468 insertions(+) create mode 100644 src/NotesProvider.java diff --git a/src/NotesProvider.java b/src/NotesProvider.java new file mode 100644 index 0000000..6f16cba --- /dev/null +++ b/src/NotesProvider.java @@ -0,0 +1,468 @@ +/* + * 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. + */ + +// 版权声明:2010 - 2011 年,MiCode 开源社区(www.micode.net)。 +// 在 Apache License 2.0 协议下授权;你不得在不符合该协议的情况下使用此文件。你可以在以下地址获取该协议的副本:http://www.apache.org/licenses/LICENSE-2.0。 +// 除非适用法律要求或书面同意,否则根据本许可证分发的软件是基于“按原样”基础提供的,不附带任何明示或暗示的保证或条件。请参阅许可证以了解管理权限和限制的特定语言。 + +package net.micode.notes.data; + +import android.app.SearchManager; +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Intent; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +import net.micode.notes.R; +import net.micode.notes.data.Notes.DataColumns; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.data.NotesDatabaseHelper.TABLE; + +// 导入相关的包和类。 + +public class NotesProvider extends ContentProvider { +// 定义公共类 NotesProvider,继承自 ContentProvider。 + + private static final UriMatcher mMatcher; + // 定义静态的 UriMatcher 对象 mMatcher。 + + private NotesDatabaseHelper mHelper; + // 定义 NotesDatabaseHelper 对象 mHelper。 + + private static final String TAG = "NotesProvider"; + // 定义静态常量 TAG,值为“NotesProvider”。 + + private static final int URI_NOTE = 1; + // 定义常量 URI_NOTE,值为 1。 + + private static final int URI_NOTE_ITEM = 2; + // 定义常量 URI_NOTE_ITEM,值为 2。 + + private static final int URI_DATA = 3; + // 定义常量 URI_DATA,值为 3。 + + private static final int URI_DATA_ITEM = 4; + // 定义常量 URI_DATA_ITEM,值为 4。 + + private static final int URI_SEARCH = 5; + // 定义常量 URI_SEARCH,值为 5。 + + private static final int URI_SEARCH_SUGGEST = 6; + // 定义常量 URI_SEARCH_SUGGEST,值为 6。 + + static { + // 静态初始化块。 + + mMatcher = new UriMatcher(UriMatcher.NO_MATCH); + // 创建一个新的 UriMatcher 对象,并设置初始匹配结果为 UriMatcher.NO_MATCH。 + + mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); + // 将 Uri “content://micode_notes/note” 与常量 URI_NOTE 关联。 + + mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); + // 将 Uri “content://micode_notes/note/[ID]” 与常量 URI_NOTE_ITEM 关联。 + + mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); + // 将 Uri “content://micode_notes/data” 与常量 URI_DATA 关联。 + + mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); + // 将 Uri “content://micode_notes/data/[ID]” 与常量 URI_DATA_ITEM 关联。 + + mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); + // 将 Uri “content://micode_notes/search” 与常量 URI_SEARCH 关联。 + + mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); + // 将 Uri “content://micode_notes/search_query”(根据 SearchManager.SUGGEST_URI_PATH_QUERY)与常量 URI_SEARCH_SUGGEST 关联。 + + mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); + // 将 Uri “content://micode_notes/search_query/[SEARCH_STRING]”(根据 SearchManager.SUGGEST_URI_PATH_QUERY 和通配符)与常量 URI_SEARCH_SUGGEST 关联。 + + } + + /** + * 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; + // 定义常量 NOTES_SEARCH_PROJECTION,用于搜索结果中的投影列。 + + private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION + + " FROM " + TABLE.NOTE + + " WHERE " + NoteColumns.SNIPPET + " LIKE?" + + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + // 定义常量 NOTES_SNIPPET_SEARCH_QUERY,用于搜索笔记片段的查询语句。 + + @Override + public boolean onCreate() { + // 重写 onCreate 方法。 + + mHelper = NotesDatabaseHelper.getInstance(getContext()); + // 获取 NotesDatabaseHelper 的实例。 + + return true; + // 返回 true,表示创建成功。 + + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + // 重写 query 方法,用于查询数据。 + + Cursor c = null; + // 定义游标对象 c,并初始化为 null。 + + SQLiteDatabase db = mHelper.getReadableDatabase(); + // 获取可读的 SQLiteDatabase 对象。 + + String id = null; + // 定义字符串 id,初始化为 null。 + + switch (mMatcher.match(uri)) { + // 根据 Uri 匹配结果进行分支处理。 + + case URI_NOTE: + c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, + sortOrder); + // 查询所有笔记。 + + break; + case URI_NOTE_ITEM: + id = uri.getPathSegments().get(1); + // 获取笔记的 ID。 + + c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id + + parseSelection(selection), selectionArgs, null, null, sortOrder); + // 根据 ID 查询单个笔记。 + + break; + case URI_DATA: + c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, + sortOrder); + // 查询所有数据。 + + break; + case URI_DATA_ITEM: + id = uri.getPathSegments().get(1); + // 获取数据的 ID。 + + c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id + + parseSelection(selection), selectionArgs, null, null, sortOrder); + // 根据 ID 查询单个数据。 + + break; + 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"); + } + + String searchString = null; + // 定义字符串 searchString,初始化为 null。 + + if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { + // 如果是搜索建议的 Uri。 + + if (uri.getPathSegments().size() > 1) { + // 如果路径段数量大于 1。 + + searchString = uri.getPathSegments().get(1); + // 获取搜索字符串。 + + } + } else { + // 否则是普通搜索的 Uri。 + + searchString = uri.getQueryParameter("pattern"); + // 从查询参数中获取搜索字符串。 + + } + + if (TextUtils.isEmpty(searchString)) { + // 如果搜索字符串为空。 + + return null; + // 返回 null。 + + } + + try { + // 尝试执行查询。 + + searchString = String.format("%%%s%%", searchString); + // 格式化搜索字符串。 + + c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, + new String[]{searchString}); + // 执行查询。 + + } catch (IllegalStateException ex) { + // 捕获异常。 + + Log.e(TAG, "got exception: " + ex.toString()); + // 记录错误日志。 + + } + break; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + // 如果 Uri 不匹配任何已知的情况,抛出异常。 + + } + if (c!= null) { + // 如果游标不为 null。 + + c.setNotificationUri(getContext().getContentResolver(), uri); + // 设置通知 Uri。 + + } + return c; + // 返回游标。 + + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + // 重写 insert 方法,用于插入数据。 + + SQLiteDatabase db = mHelper.getWritableDatabase(); + // 获取可写的 SQLiteDatabase 对象。 + + long dataId = 0, noteId = 0, insertedId = 0; + // 定义长整型变量 dataId、noteId 和 insertedId,并初始化为 0。 + + switch (mMatcher.match(uri)) { + // 根据 Uri 匹配结果进行分支处理。 + + case URI_NOTE: + insertedId = noteId = db.insert(TABLE.NOTE, null, values); + // 插入笔记。 + + break; + case URI_DATA: + if (values.containsKey(DataColumns.NOTE_ID)) { + // 如果 ContentValues 中包含 NOTE_ID。 + + noteId = values.getAsLong(DataColumns.NOTE_ID); + // 获取笔记 ID。 + + } else { + // 否则。 + + Log.d(TAG, "Wrong data format without note id:" + values.toString()); + // 记录错误日志。 + + } + insertedId = dataId = db.insert(TABLE.DATA, null, values); + // 插入数据。 + + break; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + // 如果 Uri 不匹配任何已知的情况,抛出异常。 + + } + // Notify the note uri + if (noteId > 0) { + // 如果笔记 ID 大于 0。 + + getContext().getContentResolver().notifyChange( + ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); + // 通知笔记 Uri 的更改。 + + } + + // Notify the data uri + if (dataId > 0) { + // 如果数据 ID 大于 0。 + + getContext().getContentResolver().notifyChange( + ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); + // 通知数据 Uri 的更改。 + + } + + return ContentUris.withAppendedId(uri, insertedId); + // 返回插入后的 Uri。 + + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + // 重写 delete 方法,用于删除数据。 + + int count = 0; + // 定义整型变量 count,初始化为 0。 + + String id = null; + // 定义字符串 id,初始化为 null。 + + SQLiteDatabase db = mHelper.getWritableDatabase(); + // 获取可写的 SQLiteDatabase 对象。 + + boolean deleteData = false; + // 定义布尔变量 deleteData,初始化为 false。 + + switch (mMatcher.match(uri)) { + // 根据 Uri 匹配结果进行分支处理。 + + case URI_NOTE: + selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; + count = db.delete(TABLE.NOTE, selection, selectionArgs); + // 删除笔记,添加条件 ID 大于 0。 + + break; + case URI_NOTE_ITEM: + id = uri.getPathSegments().get(1); + // 获取笔记的 ID。 + + /** + * ID that smaller than 0 is system folder which is not allowed to + * trash + */ + // 注释说明小于 0 的 ID 是系统文件夹,不允许删除。 + + long noteId = Long.valueOf(id); + // 将 ID 转换为长整型。 + + if (noteId <= 0) { + // 如果笔记 ID 小于等于 0。 + + break; + // 跳出循环。 + + } + count = db.delete(TABLE.NOTE, + NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); + // 删除单个笔记。 + + break; + case URI_DATA: + count = db.delete(TABLE.DATA, selection, selectionArgs); + deleteData = true; + // 删除数据,设置 deleteData 为 true。 + + break; + case URI_DATA_ITEM: + id = uri.getPathSegments().get(1); + // 获取数据的 ID。 + + count = db.delete(TABLE.DATA, + DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); + deleteData = true; + // 删除单个数据,设置 deleteData 为 true。 + + break; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + // 如果 Uri 不匹配任何已知的情况,抛出异常。 + + } + if (count > 0) { + // 如果删除的数量大于 0。 + + if (deleteData) { + // 如果删除的是数据。 + + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); + // 通知笔记 Uri 的更改。 + + } + getContext().getContentResolver().notifyChange(uri, null); + // 通知当前 Uri 的更改。 + + } + return count; + // 返回删除的数量。 + + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + // 重写 update 方法,用于更新数据。 + + int count = 0; + // 定义整型变量 count,初始化为 0。 + + String id = null; + // 定义字符串 id,初始化为 null。 + + SQLiteDatabase db = mHelper.getWritableDatabase(); + // 获取可写的 SQLiteDatabase 对象。 + + boolean updateData = false; + // 定义布尔变量 updateData,初始化为 false。 + + switch (mMatcher.match(uri)) { + // 根据 Uri 匹配结果进行分支处理。 + + case URI_NOTE: + increaseNoteVersion(-1, selection, selectionArgs); + // 更新所有笔记的版本号。 + + count = db.update(TABLE.NOTE, values, selection, selectionArgs); + // 更新笔记。 + + break; + case URI_NOTE_ITEM: + id = uri.getPathSegments().get(1); + // 获取笔记的 ID。 + + increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); + // 更新指定笔记的版本号。 + + count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id + + parseSelection(selection), selectionArgs); + // 更新单个笔记。 + + break; + case URI_DATA: + count = db.update(TABLE.DATA, values, selection, selectionArgs); + updateData = true; + // 更新数据,设置 updateData 为 true。 + + break; + case URI_DATA_ITEM: + id = uri.getPathSegments().get(1); + // 获取数据的 ID。 + + count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id + + parseSelection(selection), selectionArgs); + updateData = true; + // 更新单个数据,设置 updateData 为 true。 + + break; + default: + throw new IllegalArgumentException("Unknown URI " + uri); + // 如果 Uri 不匹配任何已知的情况,抛出 \ No newline at end of file -- 2.34.1 From 96679d032e3fc660b33b564e7f1576221a267f89 Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Tue, 8 Oct 2024 13:53:31 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Notes.java | 373 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 src/Notes.java diff --git a/src/Notes.java b/src/Notes.java new file mode 100644 index 0000000..e366776 --- /dev/null +++ b/src/Notes.java @@ -0,0 +1,373 @@ +/* + * 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. + */ + +// 版权声明:2010 - 2011 年,MiCode 开源社区(www.micode.net)。 +// 在 Apache License 2.0 协议下授权;你不得在不符合该协议的情况下使用此文件。你可以在以下地址获取该协议的副本:http://www.apache.org/licenses/LICENSE-2.0。 +// 除非适用法律要求或书面同意,否则根据本许可证分发的软件是基于“按原样”基础提供的,不附带任何明示或暗示的保证或条件。请参阅许可证以了解管理权限和限制的特定语言。 + +package net.micode.notes.data; +// 包名为 net.micode.notes.data。 + +import android.net.Uri; +// 导入安卓网络包中的 Uri 类。 + +public class Notes { +// 定义公共类 Notes。 + + public static final String AUTHORITY = "micode_notes"; + // 定义静态常量 AUTHORITY,值为“micode_notes”。 + + public static final String TAG = "Notes"; + // 定义静态常量 TAG,值为“Notes”。 + + public static final int TYPE_NOTE = 0; + // 定义静态常量 TYPE_NOTE,值为 0。 + + public static final int TYPE_FOLDER = 1; + // 定义静态常量 TYPE_FOLDER,值为 1。 + + public static final int TYPE_SYSTEM = 2; + // 定义静态常量 TYPE_SYSTEM,值为 2。 + + /** + * 以下 ID 是系统文件夹的标识符。 + * {@link Notes#ID_ROOT_FOLDER} 是默认文件夹。 + * {@link Notes#ID_TEMPARAY_FOLDER} 用于不属于任何文件夹的笔记。 + * {@link Notes#ID_CALL_RECORD_FOLDER} 用于存储通话记录。 + */ + // 注释解释了后续常量的用途。 + + public static final int ID_ROOT_FOLDER = 0; + // 定义静态常量 ID_ROOT_FOLDER,值为 0。 + + public static final int ID_TEMPARAY_FOLDER = -1; + // 定义静态常量 ID_TEMPARAY_FOLDER,值为 -1。 + + public static final int ID_CALL_RECORD_FOLDER = -2; + // 定义静态常量 ID_CALL_RECORD_FOLDER,值为 -2。 + + public static final int ID_TRASH_FOLER = -3; + // 定义静态常量 ID_TRASH_FOLER,值为 -3。 + + public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; + // 定义静态常量 INTENT_EXTRA_ALERT_DATE,值为“net.micode.notes.alert_date”。 + + public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; + // 定义静态常量 INTENT_EXTRA_BACKGROUND_ID,值为“net.micode.notes.background_color_id”。 + + public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; + // 定义静态常量 INTENT_EXTRA_WIDGET_ID,值为“net.micode.notes.widget_id”。 + + public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; + // 定义静态常量 INTENT_EXTRA_WIDGET_TYPE,值为“net.micode.notes.widget_type”。 + + public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; + // 定义静态常量 INTENT_EXTRA_FOLDER_ID,值为“net.micode.notes.folder_id”。 + + public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; + // 定义静态常量 INTENT_EXTRA_CALL_DATE,值为“net.micode.notes.call_date”。 + + public static final int TYPE_WIDGET_INVALIDE = -1; + // 定义静态常量 TYPE_WIDGET_INVALIDE,值为 -1。 + + public static final int TYPE_WIDGET_2X = 0; + // 定义静态常量 TYPE_WIDGET_2X,值为 0。 + + public static final int TYPE_WIDGET_4X = 1; + // 定义静态常量 TYPE_WIDGET_4X,值为 1。 + + public static class DataConstants { + // 定义静态内部类 DataConstants。 + + public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; + // 定义静态常量 NOTE,值为 TextNote 类中的 CONTENT_ITEM_TYPE。 + + public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; + // 定义静态常量 CALL_NOTE,值为 CallNote 类中的 CONTENT_ITEM_TYPE。 + + } + + /** + * 用于查询所有笔记和文件夹的 Uri。 + */ + + public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); + // 定义静态常量 CONTENT_NOTE_URI,通过解析字符串“content://micode_notes/note”得到 Uri 对象。 + + /** + * 用于查询数据的 Uri。 + */ + public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); + // 定义静态常量 CONTENT_DATA_URI,通过解析字符串“content://micode_notes/data”得到 Uri 对象。 + + public interface NoteColumns { + // 定义公共接口 NoteColumns。 + + /** + * 一行的唯一 ID。类型:整数(长整型)。 + */ + + public static final String ID = "_id"; + // 定义静态常量 ID,值为“_id”。 + + /** + * 笔记或文件夹的父级 ID。类型:整数(长整型)。 + */ + + public static final String PARENT_ID = "parent_id"; + // 定义静态常量 PARENT_ID,值为“parent_id”。 + + /** + * 笔记或文件夹的创建日期。类型:整数(长整型)。 + */ + + public static final String CREATED_DATE = "created_date"; + // 定义静态常量 CREATED_DATE,值为“created_date”。 + + /** + * 最新修改日期。类型:整数(长整型)。 + */ + + public static final String MODIFIED_DATE = "modified_date"; + // 定义静态常量 MODIFIED_DATE,值为“modified_date”。 + + /** + * 提醒日期。类型:整数(长整型)。 + */ + + public static final String ALERTED_DATE = "alert_date"; + // 定义静态常量 ALERTED_DATE,值为“alert_date”。 + + /** + * 文件夹的名称或笔记的文本内容。类型:文本。 + */ + + public static final String SNIPPET = "snippet"; + // 定义静态常量 SNIPPET,值为“snippet”。 + + /** + * 笔记的小部件 ID。类型:整数(长整型)。 + */ + + public static final String WIDGET_ID = "widget_id"; + // 定义静态常量 WIDGET_ID,值为“widget_id”。 + + /** + * 笔记的小部件类型。类型:整数(长整型)。 + */ + + public static final String WIDGET_TYPE = "widget_type"; + // 定义静态常量 WIDGET_TYPE,值为“widget_type”。 + + /** + * 笔记的背景颜色 ID。类型:整数(长整型)。 + */ + + public static final String BG_COLOR_ID = "bg_color_id"; + // 定义静态常量 BG_COLOR_ID,值为“bg_color_id”。 + + /** + * 对于文本笔记,它没有附件;对于多媒体笔记,它至少有一个附件。类型:整数。 + */ + + public static final String HAS_ATTACHMENT = "has_attachment"; + // 定义静态常量 HAS_ATTACHMENT,值为“has_attachment”。 + + /** + * 文件夹中的笔记数量。类型:整数(长整型)。 + */ + + public static final String NOTES_COUNT = "notes_count"; + // 定义静态常量 NOTES_COUNT,值为“notes_count”。 + + /** + * 文件类型:文件夹或笔记。类型:整数。 + */ + + public static final String TYPE = "type"; + // 定义静态常量 TYPE,值为“type”。 + + /** + * 最后一次同步的 ID。类型:整数(长整型)。 + */ + + public static final String SYNC_ID = "sync_id"; + // 定义静态常量 SYNC_ID,值为“sync_id”。 + + /** + * 表示本地是否已修改的标志。类型:整数。 + */ + + public static final String LOCAL_MODIFIED = "local_modified"; + // 定义静态常量 LOCAL_MODIFIED,值为“local_modified”。 + + /** + * 移动到临时文件夹之前的原始父级 ID。类型:整数。 + */ + + public static final String ORIGIN_PARENT_ID = "origin_parent_id"; + // 定义静态常量 ORIGIN_PARENT_ID,值为“origin_parent_id”。 + + /** + * gtask 的 ID。类型:文本。 + */ + + public static final String GTASK_ID = "gtask_id"; + // 定义静态常量 GTASK_ID,值为“gtask_id”。 + + /** + * 版本代码。类型:整数(长整型)。 + */ + + public static final String VERSION = "version"; + // 定义静态常量 VERSION,值为“version”。 + + } + + public interface DataColumns { + // 定义公共接口 DataColumns。 + + /** + * 一行的唯一 ID。类型:整数(长整型)。 + */ + + public static final String ID = "_id"; + // 定义静态常量 ID,值为“_id”。 + + /** + * 这一行所代表的项目的 MIME 类型。类型:文本。 + */ + + public static final String MIME_TYPE = "mime_type"; + // 定义静态常量 MIME_TYPE,值为“mime_type”。 + + /** + * 此数据所属笔记的引用 ID。类型:整数(长整型)。 + */ + + public static final String NOTE_ID = "note_id"; + // 定义静态常量 NOTE_ID,值为“note_id”。 + + /** + * 笔记或文件夹的创建日期。类型:整数(长整型)。 + */ + + public static final String CREATED_DATE = "created_date"; + // 定义静态常量 CREATED_DATE,值为“created_date”。 + + /** + * 最新修改日期。类型:整数(长整型)。 + */ + + public static final String MODIFIED_DATE = "modified_date"; + // 定义静态常量 MODIFIED_DATE,值为“modified_date”。 + + /** + * 数据的内容。类型:文本。 + */ + + public static final String CONTENT = "content"; + // 定义静态常量 CONTENT,值为“content”。 + + /** + * 通用数据列,其含义特定于{@link #MIMETYPE},用于整数数据类型。类型:整数。 + */ + + public static final String DATA1 = "data1"; + // 定义静态常量 DATA1,值为“data1”。 + + /** + * 通用数据列,其含义特定于{@link #MIMETYPE},用于整数数据类型。类型:整数。 + */ + + public static final String DATA2 = "data2"; + // 定义静态常量 DATA2,值为“data2”。 + + /** + * 通用数据列,其含义特定于{@link #MIMETYPE},用于文本数据类型。类型:文本。 + */ + + public static final String DATA3 = "data3"; + // 定义静态常量 DATA3,值为“data3”。 + + /** + * 通用数据列,其含义特定于{@link #MIMETYPE},用于文本数据类型。类型:文本。 + */ + + public static final String DATA4 = "data4"; + // 定义静态常量 DATA4,值为“data4”。 + + /** + * 通用数据列,其含义特定于{@link #MIMETYPE},用于文本数据类型。类型:文本。 + */ + + public static final String DATA5 = "data5"; + // 定义静态常量 DATA5,值为“data5”。 + + } + + public static final class TextNote implements DataColumns { + // 定义静态内部类 TextNote,实现 DataColumns 接口。 + + /** + * 模式,用于指示文本是否处于清单模式。类型:整数,1 表示清单模式,0 表示正常模式。 + */ + + public static final String MODE = DATA1; + // 定义静态常量 MODE,值为 DATA1。 + + public static final int MODE_CHECK_LIST = 1; + // 定义静态常量 MODE_CHECK_LIST,值为 1。 + + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; + // 定义静态常量 CONTENT_TYPE,值为“vnd.android.cursor.dir/text_note”。 + + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; + // 定义静态常量 CONTENT_ITEM_TYPE,值为“vnd.android.cursor.item/text_note”。 + + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); + // 定义静态常量 CONTENT_URI,通过解析字符串“content://micode_notes/text_note”得到 Uri 对象。 + + } + + public static final class CallNote implements DataColumns { + // 定义静态内部类 CallNote,实现 DataColumns 接口。 + + /** + * 此记录的通话日期。类型:整数(长整型)。 + */ + + public static final String CALL_DATE = DATA1; + // 定义静态常量 CALL_DATE,值为 DATA1。 + + /** + * 此记录的电话号码。类型:文本。 + */ + + public static final String PHONE_NUMBER = DATA3; + // 定义静态常量 PHONE_NUMBER,值为 DATA3。 + + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; + // 定义静态常量 CONTENT_TYPE,值为“vnd.android.cursor.dir/call_note”。 + + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; + // 定义静态常量 CONTENT_ITEM_TYPE,值为“vnd.android.cursor.item/call_note”。 + + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); + // 定义静态常量 CONTENT_URI,通过解析字符串“content://micode_notes/call_note”得到 Uri 对象。 + + } +} \ No newline at end of file -- 2.34.1 From ffc3dcd734763ebd4f6dee88f255c37b83e4c7d1 Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Tue, 8 Oct 2024 13:58:25 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Contact.java | 98 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/Contact.java diff --git a/src/Contact.java b/src/Contact.java new file mode 100644 index 0000000..79c0018 --- /dev/null +++ b/src/Contact.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +// 这是一个多行注释,用来说明这个文件的版权信息和许可协议。它指出这个文件是由 MiCode 开源社区版权所有,并在 Apache License 2.0 下授权。它还提供了获取许可证的链接,并说明了许可证的条款和条件。 + +package net.micode.notes.data; + +// 声明这个类属于哪个包。在这个例子中,它属于`net.micode.notes.data`包。 + +import android.content.Context; +// 导入 Android 的 Context 类,用于获取应用上下文。 +import android.database.Cursor; +// 导入 Cursor 类,用于在数据库查询结果中进行遍历。 +import android.provider.ContactsContract.CommonDataKinds.Phone; +// 导入 Android Contacts Provider 中与电话号码相关的常量类。 +import android.provider.ContactsContract.Data; +// 导入 Android Contacts Provider 的数据访问类。 +import android.telephony.PhoneNumberUtils; +// 导入用于处理电话号码的工具类。 +import android.util.Log; +// 导入 Android 的日志工具类。 + +import java.util.HashMap; +// 导入 Java 的 HashMap 类,用于存储电话号码和联系人名称的映射关系。 + +public class Contact { + // 定义一个静态的 HashMap,用来缓存电话号码和对应的联系人名称。 + private static HashMap sContactCache; + // 定义一个静态常量 TAG,用于日志输出时标记来源。 + private static final String TAG = "Contact"; + + // 定义一个 SQL 查询语句模板,用于查询电话号码。 + // 这个查询语句使用了 Android Contacts Provider 的内容 URI 和一些过滤条件。 + 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 对象和一个电话号码作为参数。 + // 这个方法主要用于根据电话号码查询对应的联系人名称。 + public static String getContact(Context context, String phoneNumber) { + // 如果缓存不存在,则初始化一个空的 HashMap 作为缓存。 + if(sContactCache == null) { + sContactCache = new HashMap(); + } + // 如果电话号码已经在缓存中,则直接返回缓存中的联系人名称,避免重复查询。 + if(sContactCache.containsKey(phoneNumber)) { + return sContactCache.get(phoneNumber); + } + // 将查询语句中的"+"替换为电话号码的最小匹配模式。 + String selection = CALLER_ID_SELECTION.replace("+", + PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); + // 使用设备的 ContentResolver 执行查询,查询目标是获取联系人的显示名称。 + Cursor cursor = context.getContentResolver().query( + Data.CONTENT_URI, + new String [] { Phone.DISPLAY_NAME }, + selection, + new String[] { phoneNumber }, + null); + // 如果查询结果不为空并且可以移动到第一条记录。 + if (cursor!= null && cursor.moveToFirst()) { + try { + // 获取查询结果中的联系人名称。 + String name = cursor.getString(0); + // 将电话号码和联系人名称存入缓存。 + sContactCache.put(phoneNumber, name); + // 返回联系人名称。 + return name; + } catch (IndexOutOfBoundsException e) { + // 如果发生索引越界异常,记录错误日志并返回 null。 + Log.e(TAG, " Cursor get string error " + e.toString()); + return null; + } finally { + // 无论是否发生异常,都关闭游标。 + cursor.close(); + } + } else { + // 如果查询结果为空,记录日志并返回 null。 + Log.d(TAG, "No contact matched with number:" + phoneNumber); + return null; + } + } +} \ No newline at end of file -- 2.34.1 From 9b5201288f58967a6da575ea5df7cdb41b6500c1 Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Tue, 8 Oct 2024 17:12:18 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E8=A1=A5=E5=85=85=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/NotesProvider.java | 81 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/src/NotesProvider.java b/src/NotesProvider.java index 6f16cba..d587c7f 100644 --- a/src/NotesProvider.java +++ b/src/NotesProvider.java @@ -465,4 +465,83 @@ public class NotesProvider extends ContentProvider { break; default: throw new IllegalArgumentException("Unknown URI " + uri); - // 如果 Uri 不匹配任何已知的情况,抛出 \ No newline at end of file + // 如果 Uri 不匹配任何已知的情况,抛出 +} + if (count > 0) { +// 如果更新操作影响的记录数大于 0。 + if (updateData) { +// 如果更新了数据记录。 + // 如果更新了数据记录,则通知监听器。 + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); +// 获取上下文环境,通过内容解析器通知与笔记内容相关的监听器(Notes.CONTENT_NOTE_URI)数据发生了变化,第二个参数为 null 表示没有额外的通知数据。 + } + // 通知监听器指定的 URI 发生了变化。 + getContext().getContentResolver().notifyChange(uri, null); +// 获取上下文环境,通过内容解析器通知本次更新操作对应的 URI(uri)的数据发生了变化,第二个参数为 null 表示没有额外的通知数据。 + } + return count; +// 返回更新操作所影响的记录数。 + + } + +// 解析选择条件的方法。 +private String parseSelection(String selection) { +// 定义一个私有方法,接收一个选择条件字符串参数。 + return (!TextUtils.isEmpty(selection)? " AND (" + selection + ')' : ""); +// 如果选择条件字符串不为空,返回在其前后加上“ AND (”和“)”的字符串;如果为空,返回空字符串。 +} + +// 增加笔记版本号的方法。 +private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { +// 定义一个私有方法,接收笔记的 ID、选择条件字符串和选择条件参数数组。 + StringBuilder sql = new StringBuilder(120); +// 创建一个 StringBuilder 对象,用于构建 SQL 语句,初始容量为 120。 + sql.append("UPDATE "); +// 在 StringBuilder 中添加“UPDATE ”。 + sql.append(TABLE.NOTE); +// 添加表名 TABLE.NOTE。 + sql.append(" SET "); +// 添加“ SET ”。 + sql.append(NoteColumns.VERSION); +// 添加版本号列名 NoteColumns.VERSION。 + sql.append("=" + NoteColumns.VERSION + "+1 "); +// 添加版本号设置的 SQL 片段,将版本号设置为当前版本号加 1。 + + if (id > 0 ||!TextUtils.isEmpty(selection)) { +// 如果传入的 ID 大于 0 或者选择条件字符串不为空。 + sql.append(" WHERE "); +// 在 StringBuilder 中添加“ WHERE ”。 + } + if (id > 0) { +// 如果传入的 ID 大于 0。 + sql.append(NoteColumns.ID + "=" + String.valueOf(id)); +// 添加笔记 ID 的条件到 StringBuilder 中。 + } + if (!TextUtils.isEmpty(selection)) { +// 如果选择条件字符串不为空。 + String selectString = id > 0? parseSelection(selection) : selection; +// 如果 ID 大于 0,调用 parseSelection 方法处理选择条件字符串;否则直接使用选择条件字符串。 + for (String args : selectionArgs) { +// 遍历选择条件参数数组。 + selectString = selectString.replaceFirst("\\?", args); +// 将选择条件字符串中的第一个占位符替换为当前参数值。 + } + sql.append(selectString); +// 将处理后的选择条件字符串添加到 StringBuilder 中。 + } + + mHelper.getWritableDatabase().execSQL(sql.toString()); +// 使用数据库帮助类 mHelper 的可写数据库执行构建好的 SQL 语句。 + +} + +// 内容提供器的 getType 方法,用于返回指定 URI 的 MIME 类型。 +@Override +public String getType(Uri uri) { +// 重写内容提供器的 getType 方法,接收一个 URI 参数。 + // TODO Auto-generated method stub +// 这里是一个待实现的方法注释。 + return null; +// 返回 null,表示当前未实现该方法。 +} +} \ No newline at end of file -- 2.34.1 From 6d27ec553946b1574952d8f02cabb25b119da220 Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Tue, 8 Oct 2024 17:20:12 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/NotesDatabaseHelper.java | 492 +++++++++++++++++++++++++++++++++++ 1 file changed, 492 insertions(+) create mode 100644 src/NotesDatabaseHelper.java diff --git a/src/NotesDatabaseHelper.java b/src/NotesDatabaseHelper.java new file mode 100644 index 0000000..e520bcd --- /dev/null +++ b/src/NotesDatabaseHelper.java @@ -0,0 +1,492 @@ +/* + * 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. + */ + +// 版权声明:2010 - 2011 年,MiCode 开源社区(www.micode.net)。 +// 遵循 Apache License 2.0 许可协议,若不遵守该协议则不可使用此文件。可在以下地址获取许可证副本:http://www.apache.org/licenses/LICENSE-2.0。 +// 除非法律要求或书面同意,否则在该许可证下发布的软件基于“现状”发布,不提供任何形式的保证和条件。 +// 许可证具体条款规定了权限和限制。 + +package net.micode.notes.data; + +// 包声明:这个类属于 net.micode.notes.data 包。 + +import android.content.ContentValues; +// 导入用于存储键值对的数据容器类,通常用于向数据库中插入或更新数据。 +import android.content.Context; +// 导入用于获取应用上下文的类。 +import android.database.sqlite.SQLiteDatabase; +// 导入用于操作 SQLite 数据库的类。 +import android.database.sqlite.SQLiteOpenHelper; +// 导入用于创建和管理 SQLite 数据库的帮助类,继承此类可以方便地创建和升级数据库。 +import android.util.Log; +// 导入 Android 的日志工具类,用于在开发过程中输出调试信息和错误信息。 + +import net.micode.notes.data.Notes.DataColumns; +// 导入 Notes 类中的 DataColumns 内部类,可能包含与数据相关的常量或方法。 +import net.micode.notes.data.Notes.DataConstants; +// 导入 Notes 类中的 DataConstants 内部类,可能包含一些常量定义。 +import net.micode.notes.data.Notes.NoteColumns; +// 导入 Notes 类中的 NoteColumns 内部类,可能包含与笔记相关的常量或方法。 + + +public class NotesDatabaseHelper extends SQLiteOpenHelper { +// 定义一个名为 NotesDatabaseHelper 的类,继承自 SQLiteOpenHelper,用于创建和管理笔记数据库。 + + private static final String DB_NAME = "note.db"; +// 定义数据库名称为“note.db”。 + + private static final int DB_VERSION = 4; +// 定义数据库版本号为 4。 + + public interface TABLE { +// 定义一个内部接口 TABLE,用于表示数据库中的表名。 + public static final String NOTE = "note"; +// 定义名为“note”的表名常量。 + + public static final String DATA = "data"; +// 定义名为“data”的表名常量。 + } + + private static final String TAG = "NotesDatabaseHelper"; +// 用于日志输出的标记。 + + 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" + + ")"; +// 创建“note”表的 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 ''" + + ")"; +// 创建“data”表的 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 + ");"; +// 创建“data”表中“note_id”索引的 SQL 语句。 + + /** + * Increase folder's note count when move note to the folder + */ + 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"; +// 当将笔记移动到文件夹时增加文件夹的笔记数量的触发器 SQL。 + + /** + * Decrease folder's note count when move note from folder + */ + private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = + "CREATE TRIGGER decrease_folder_count_on_update " + + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + + " END"; +// 当从文件夹中移动笔记时减少文件夹的笔记数量的触发器 SQL。 + + /** + * Increase folder's note count when insert new note to the folder + */ + private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = + "CREATE TRIGGER increase_folder_count_on_insert " + + " AFTER INSERT ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + + " END"; +// 当向文件夹中插入新笔记时增加文件夹的笔记数量的触发器 SQL。 + + /** + * Decrease folder's note count when delete note from the folder + */ + private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = + "CREATE TRIGGER decrease_folder_count_on_delete " + + " AFTER DELETE ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + + " AND " + NoteColumns.NOTES_COUNT + ">0;" + + " END"; +// 当从文件夹中删除笔记时减少文件夹的笔记数量的触发器 SQL。 + + /** + * Update note's content when insert data with type {@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"; +// 当插入数据类型为 DataConstants.NOTE 的数据时更新笔记内容的触发器 SQL。 + + /** + * 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"; +// 当数据类型为 DataConstants.NOTE 的数据发生变化时更新笔记内容的触发器 SQL。 + + /** + * 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"; +// 当数据类型为 DataConstants.NOTE 的数据被删除时更新笔记内容为空的触发器 SQL。 + + /** + * Delete datas belong to note which has been deleted + */ + 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"; +// 当笔记被删除时删除属于该笔记的数据的触发器 SQL。 + + /** + * Delete notes belong to folder which has been deleted + */ + 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"; +// 当文件夹被删除时删除属于该文件夹的笔记的触发器 SQL。 + + /** + * Move notes belong to folder which has been moved to trash folder + */ + 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"; +// 当文件夹被移动到垃圾桶时,将属于该文件夹的笔记也移动到垃圾桶的触发器 SQL。 + + public NotesDatabaseHelper(Context context) { +// 构造函数,传入上下文对象。 + super(context, DB_NAME, null, DB_VERSION); +// 调用父类构造函数,传入数据库名称、游标工厂和版本号。 + } + + public void createNoteTable(SQLiteDatabase db) { +// 创建“note”表的方法。 + db.execSQL(CREATE_NOTE_TABLE_SQL); +// 执行创建“note”表的 SQL 语句。 + reCreateNoteTableTriggers(db); +// 重新创建“note”表的触发器。 + createSystemFolder(db); +// 创建系统文件夹。 + Log.d(TAG, "note table has been created"); +// 输出日志,表明“note”表已创建。 + } + + private void reCreateNoteTableTriggers(SQLiteDatabase db) { +// 重新创建“note”表触发器的方法。 + db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); +// 删除可能已存在的特定触发器。 + db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); +// 删除可能已存在的特定触发器。 + db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); +// 删除可能已存在的特定触发器。 + db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete"); +// 删除可能已存在的特定触发器。 + db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert"); +// 删除可能已存在的特定触发器。 + db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); +// 删除可能已存在的特定触发器。 + db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); +// 删除可能已存在的特定触发器。 + + db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + } + + private void createSystemFolder(SQLiteDatabase db) { +// 创建系统文件夹的方法。 + ContentValues values = new ContentValues(); +// 创建一个 ContentValues 对象,用于存储要插入数据库的值。 + + /** + * call record foler for call notes + */ + values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); +// 将特定值放入 ContentValues 中,用于插入记录文件夹。 + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); +// 将特定值放入 ContentValues 中,用于插入记录文件夹。 + db.insert(TABLE.NOTE, null, values); +// 将数据插入“note”表。 + + /** + * root folder which is default folder + */ + values.clear(); +// 清空 ContentValues。 + values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); +// 将特定值放入 ContentValues 中,用于插入根文件夹。 + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); +// 将特定值放入 ContentValues 中,用于插入根文件夹。 + db.insert(TABLE.NOTE, null, values); +// 将数据插入“note”表。 + + /** + * temporary folder which is used for moving note + */ + values.clear(); +// 清空 ContentValues。 + values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); +// 将特定值放入 ContentValues 中,用于插入临时文件夹。 + values.put values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); +// 将特定值放入 ContentValues 中,用于插入临时文件夹的类型为系统类型。 + db.insert(TABLE.NOTE, null, values); +// 将数据插入“note”表。 + + /** + * create trash folder + */ + values.clear(); +// 清空 ContentValues。 + values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); +// 将特定值放入 ContentValues 中,用于插入垃圾桶文件夹的 ID。 + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); +// 将特定值放入 ContentValues 中,用于插入垃圾桶文件夹的类型为系统类型。 + db.insert(TABLE.NOTE, null, values); +// 将数据插入“note”表。 + } + + public void createDataTable(SQLiteDatabase db) { +// 创建“data”表的方法。 + db.execSQL(CREATE_DATA_TABLE_SQL); +// 执行创建“data”表的 SQL 语句。 + reCreateDataTableTriggers(db); +// 重新创建“data”表的触发器。 + db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); +// 创建“data”表中“note_id”索引。 + Log.d(TAG, "data table has been created"); +// 输出日志,表明“data”表已创建。 + } + + private void reCreateDataTableTriggers(SQLiteDatabase db) { +// 重新创建“data”表触发器的方法。 + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); +// 删除可能已存在的特定触发器。 + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); +// 删除可能已存在的特定触发器。 + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); +// 删除可能已存在的特定触发器。 + + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); +// 执行创建新的触发器的 SQL 语句。 + } + + static synchronized NotesDatabaseHelper getInstance(Context context) { +// 获取单例实例的静态方法。 + if (mInstance == null) { +// 如果单例实例为空。 + mInstance = new NotesDatabaseHelper(context); +// 创建一个新的 NotesDatabaseHelper 实例并赋值给单例实例。 + } + return mInstance; +// 返回单例实例。 + } + + @Override + public void onCreate(SQLiteDatabase db) { +// 重写 onCreate 方法,在数据库首次创建时被调用。 + createNoteTable(db); +// 创建“note”表。 + createDataTable(db); +// 创建“data”表。 + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { +// 重写 onUpgrade 方法,在数据库版本升级时被调用。 + boolean reCreateTriggers = false; +// 标记是否需要重新创建触发器。 + boolean skipV2 = false; +// 标记是否跳过版本 2 的升级步骤。 + + if (oldVersion == 1) { +// 如果当前数据库版本为 1。 + upgradeToV2(db); +// 执行升级到版本 2 的方法。 + skipV2 = true; // this upgrade including the upgrade from v2 to v3 +// 设置跳过版本 2 的标记为 true,表示这个升级包含了从版本 2 到版本 3 的升级步骤。 + oldVersion++; +// 将旧版本号加 1。 + } + + if (oldVersion == 2 &&!skipV2) { +// 如果当前数据库版本为 2 且没有跳过版本 2 的升级步骤。 + upgradeToV3(db); +// 执行升级到版本 3 的方法。 + reCreateTriggers = true; +// 设置需要重新创建触发器的标记为 true。 + oldVersion++; +// 将旧版本号加 1。 + } + + if (oldVersion == 3) { +// 如果当前数据库版本为 3。 + upgradeToV4(db); +// 执行升级到版本 4 的方法。 + oldVersion++; +// 将旧版本号加 1。 + } + + if (reCreateTriggers) { +// 如果需要重新创建触发器。 + reCreateNoteTableTriggers(db); +// 重新创建“note”表的触发器。 + reCreateDataTableTriggers(db); +// 重新创建“data”表的触发器。 + } + + if (oldVersion!= newVersion) { +// 如果旧版本号与新版本号不相等。 + throw new IllegalStateException("Upgrade notes database to version " + newVersion + + "fails"); +// 抛出异常,表示数据库升级失败。 + } + } + + private void upgradeToV2(SQLiteDatabase db) { +// 升级到版本 2 的方法。 + db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); +// 如果存在“note”表,则删除它。 + db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); +// 如果存在“data”表,则删除它。 + createNoteTable(db); +// 创建“note”表。 + createDataTable(db); +// 创建“data”表。 + } + + private void upgradeToV3(SQLiteDatabase db) { +// 升级到版本 3 的方法。 + // drop unused triggers + db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); +// 删除未使用的触发器(如果存在)。 + db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete"); +// 删除未使用的触发器(如果存在)。 + db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update"); +// 删除未使用的触发器(如果存在)。 + // add a column for gtask id + db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID + + " TEXT NOT NULL DEFAULT ''"); +// 在“note”表中添加一个用于存储 gtask id 的列。 + // add a trash system folder + ContentValues values = new ContentValues(); +// 创建一个 ContentValues 对象,用于存储要插入数据库的值。 + values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); +// 将垃圾桶文件夹的 ID 放入 ContentValues 中。 + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); +// 将垃圾桶文件夹的类型为系统类型放入 ContentValues 中。 + db.insert(TABLE.NOTE, null, values); +// 将数据插入“note”表。 + } + + private void upgradeToV4(SQLiteDatabase db) { +// 升级到版本 4 的方法。 + db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + + " INTEGER NOT NULL DEFAULT 0"); +// 在“note”表中添加一个版本号列。 + } +} \ No newline at end of file -- 2.34.1 From 396a207a9b57c1ff188d0e7cc94f3534ef91e772 Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Sun, 13 Oct 2024 12:47:00 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MetaData.java | 127 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/MetaData.java diff --git a/src/MetaData.java b/src/MetaData.java new file mode 100644 index 0000000..ebead02 --- /dev/null +++ b/src/MetaData.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2010 - 2011, The MiCode Open Source Community (www.micode.net) + * (版权所有(c)2010 - 2011,MiCode 开源社区(www.micode.net)) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * (根据 Apache License 2.0 版(“许可证”)获得许可;) + * 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 + * (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.gtask.data; +// 包 net.micode.notes.gtask.data;(包名为 net.micode.notes.gtask.data;) + +import android.database.Cursor; +// 导入 android.database.Cursor;(导入 Android 的数据库游标类;) +import android.util.Log; +// 导入 android.util.Log;(导入 Android 的日志工具类;) + +import net.micode.notes.tool.GTaskStringUtils; +// 导入 net.micode.notes.tool.GTaskStringUtils;(导入来自 net.micode.notes.tool 的 GTaskStringUtils 类;) + +import org.json.JSONException; +// 导入 org.json.JSONException;(导入 JSON 处理的异常类;) +import org.json.JSONObject; +// 导入 org.json.JSONObject;(导入 JSON 对象类;) + + +public class MetaData extends Task { +// 公共类 MetaData 继承自 Task;(定义一个名为 MetaData 的公共类,它继承自 Task 类;) + private final static String TAG = MetaData.class.getSimpleName(); +// 私有最终静态字符串变量 TAG,赋值为 MetaData 类的简单名称;(定义一个私有最终静态的字符串变量 TAG,值为 MetaData 类的简单名称;) + + private String mRelatedGid = null; +// 私有字符串变量 mRelatedGid,初始值为 null;(定义一个私有字符串变量 mRelatedGid,初始值为 null;) + + public void setMeta(String gid, JSONObject metaInfo) { +// 公共方法 setMeta,接收字符串 gid 和 JSON 对象 metaInfo;(定义一个名为 setMeta 的公共方法,接收一个字符串 gid 和一个 JSONObject 对象 metaInfo;) + try { +// 尝试执行以下代码块;(开始 try 代码块;) + metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); +// 将 gid 放入 metaInfo 的特定键中;(尝试将 gid 放入 metaInfo 对象中,键为 GTaskStringUtils.META_HEAD_GTASK_ID;) + } catch (JSONException e) { +// 如果发生 JSON 异常,进入此代码块;(捕获 JSONException 异常;) + Log.e(TAG, "failed to put related gid"); +// 输出错误日志;(打印错误日志,提示“failed to put related gid”;) + } + setNotes(metaInfo.toString()); +// 设置 notes 属性;(设置当前对象的 notes 属性为 metaInfo 的字符串表示形式;) + setName(GTaskStringUtils.META_NOTE_NAME); +// 设置 name 属性;(设置当前对象的 name 属性为 GTaskStringUtils.META_NOTE_NAME;) + } + + public String getRelatedGid() { +// 公共方法 getRelatedGid;(定义一个名为 getRelatedGid 的公共方法;) + return mRelatedGid; +// 返回 mRelatedGid;(返回 mRelatedGid 的值;) + } + + @Override + public boolean isWorthSaving() { +// 重写方法 isWorthSaving;(重写父类的 isWorthSaving 方法;) + return getNotes()!= null; +// 返回 notes 属性不为 null 的判断结果;(返回当前对象的 notes 属性不为 null 的判断结果;) + } + + @Override + public void setContentByRemoteJSON(JSONObject js) { +// 重写方法 setContentByRemoteJSON;(重写父类的 setContentByRemoteJSON 方法;) + super.setContentByRemoteJSON(js); +// 调用父类的同名方法;(先调用父类的 setContentByRemoteJSON 方法;) + if (getNotes()!= null) { +// 如果 notes 属性不为 null;(如果当前对象的 notes 属性不为 null;) + try { +// 尝试执行以下代码块;(开始 try 代码块;) + JSONObject metaInfo = new JSONObject(getNotes().trim()); +// 创建一个新的 JSON 对象,从 notes 属性的字符串表示形式中获取;(从当前对象的 notes 属性的字符串表示形式中创建一个新的 JSONObject 对象;) + mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); +// 获取相关的 gid;(从新创建的 JSONObject 对象中获取特定键的值,并赋值给 mRelatedGid;) + } catch (JSONException e) { +// 如果发生 JSON 异常,进入此代码块;(捕获 JSONException 异常;) + Log.w(TAG, "failed to get related gid"); +// 输出警告日志;(打印警告日志,提示“failed to get related gid”;) + mRelatedGid = null; +// 将 mRelatedGid 设为 null;(将 mRelatedGid 设为 null;) + } + } + } + + @Override + public void setContentByLocalJSON(JSONObject js) { +// 重写方法 setContentByLocalJSON;(重写父类的 setContentByLocalJSON 方法;) + // this function should not be called +// 此函数不应被调用;(注释说明这个函数不应该被调用;) + throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); +// 抛出非法访问错误;(抛出 IllegalAccessError 异常,提示“MetaData:setContentByLocalJSON should not be called”;) + } + + @Override + public JSONObject getLocalJSONFromContent() { +// 重写方法 getLocalJSONFromContent;(重写父类的 getLocalJSONFromContent 方法;) + throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); +// 抛出非法访问错误;(抛出 IllegalAccessError 异常,提示“MetaData:getLocalJSONFromContent should not be called”;) + } + + @Override + public int getSyncAction(Cursor c) { +// 重写方法 getSyncAction;(重写父类的 getSyncAction 方法;) + throw new IllegalAccessError("MetaData:getSyncAction should not be called"); +// 抛出非法访问错误;(抛出 IllegalAccessError 异常,提示“MetaData:getSyncAction should not be called”;) + } + +} \ No newline at end of file -- 2.34.1 From b27086c8e020a49c63b67b2048ccc92328a34694 Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Sun, 13 Oct 2024 12:48:28 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Node.java | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/Node.java diff --git a/src/Node.java b/src/Node.java new file mode 100644 index 0000000..42b7d09 --- /dev/null +++ b/src/Node.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2010 - 2011, The MiCode Open Source Community (www.micode.net) + * (版权所有(c)2010 - 2011,MiCode 开源社区(www.micode.net)) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * (根据 Apache License 2.0 版(“许可证”)获得许可;) + * 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 + * (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.gtask.data; +// 包 net.micode.notes.gtask.data;(包名为 net.micode.notes.gtask.data;) + +import android.database.Cursor; +// 导入 android.database.Cursor;(导入 Android 的数据库游标类;) + +import org.json.JSONObject; +// 导入 org.json.JSONObject;(导入 JSON 对象类;) + +public abstract class Node { +// 公共抽象类 Node;(定义一个名为 Node 的公共抽象类;) + public static final int SYNC_ACTION_NONE = 0; +// 公共静态最终整型变量 SYNC_ACTION_NONE,赋值为 0;(定义一个公共静态最终的整型变量 SYNC_ACTION_NONE,值为 0;) + + public static final int SYNC_ACTION_ADD_REMOTE = 1; +// 公共静态最终整型变量 SYNC_ACTION_ADD_REMOTE,赋值为 1;(定义一个公共静态最终的整型变量 SYNC_ACTION_ADD_REMOTE,值为 1;) + + public static final int SYNC_ACTION_ADD_LOCAL = 2; +// 公共静态最终整型变量 SYNC_ACTION_ADD_LOCAL,赋值为 2;(定义一个公共静态最终的整型变量 SYNC_ACTION_ADD_LOCAL,值为 2;) + + public static final int SYNC_ACTION_DEL_REMOTE = 3; +// 公共静态最终整型变量 SYNC_ACTION_DEL_REMOTE,赋值为 3;(定义一个公共静态最终的整型变量 SYNC_ACTION_DEL_REMOTE,值为 3;) + + public static final int SYNC_ACTION_DEL_LOCAL = 4; +// 公共静态最终整型变量 SYNC_ACTION_DEL_LOCAL,赋值为 4;(定义一个公共静态最终的整型变量 SYNC_ACTION_DEL_LOCAL,值为 4;) + + public static final int SYNC_ACTION_UPDATE_REMOTE = 5; +// 公共静态最终整型变量 SYNC_ACTION_UPDATE_REMOTE,赋值为 5;(定义一个公共静态最终的整型变量 SYNC_ACTION_UPDATE_REMOTE,值为 5;) + + public static final int SYNC_ACTION_UPDATE_LOCAL = 6; +// 公共静态最终整型变量 SYNC_ACTION_UPDATE_LOCAL,赋值为 6;(定义一个公共静态最终的整型变量 SYNC_ACTION_UPDATE_LOCAL,值为 6;) + + public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; +// 公共静态最终整型变量 SYNC_ACTION_UPDATE_CONFLICT,赋值为 7;(定义一个公共静态最终的整型变量 SYNC_ACTION_UPDATE_CONFLICT,值为 7;) + + public static final int SYNC_ACTION_ERROR = 8; +// 公共静态最终整型变量 SYNC_ACTION_ERROR,赋值为 8;(定义一个公共静态最终的整型变量 SYNC_ACTION_ERROR,值为 8;) + + private String mGid; +// 私有字符串变量 mGid;(定义一个私有字符串变量 mGid;) + + private String mName; +// 私有字符串变量 mName;(定义一个私有字符串变量 mName;) + + private long mLastModified; +// 私有长整型变量 mLastModified;(定义一个私有长整型变量 mLastModified;) + + private boolean mDeleted; +// 私有布尔型变量 mDeleted;(定义一个私有布尔型变量 mDeleted;) + + public Node() { +// 公共构造函数;(定义一个公共的构造函数;) + mGid = null; +// 初始化 mGid 为 null;(将 mGid 初始化为 null;) + mName = ""; +// 初始化 mName 为空字符串;(将 mName 初始化为空字符串;) + mLastModified = 0; +// 初始化 mLastModified 为 0;(将 mLastModified 初始化为 0;) + mDeleted = false; +// 初始化 mDeleted 为 false;(将 mDeleted 初始化为 false;) + } + + public abstract JSONObject getCreateAction(int actionId); +// 公共抽象方法 getCreateAction,接收整型参数 actionId;(定义一个公共抽象方法 getCreateAction,接收一个整型参数 actionId,返回一个 JSONObject 对象;) + + public abstract JSONObject getUpdateAction(int actionId); +// 公共抽象方法 getUpdateAction,接收整型参数 actionId;(定义一个公共抽象方法 getUpdateAction,接收一个整型参数 actionId,返回一个 JSONObject 对象;) + + public abstract void setContentByRemoteJSON(JSONObject js); +// 公共抽象方法 setContentByRemoteJSON,接收 JSONObject 参数 js;(定义一个公共抽象方法 setContentByRemoteJSON,接收一个 JSONObject 参数 js;) + + public abstract void setContentByLocalJSON(JSONObject js); +// 公共抽象方法 setContentByLocalJSON,接收 JSONObject 参数 js;(定义一个公共抽象方法 setContentByLocalJSON,接收一个 JSONObject 参数 js;) + + public abstract JSONObject getLocalJSONFromContent(); +// 公共抽象方法 getLocalJSONFromContent;(定义一个公共抽象方法 getLocalJSONFromContent,返回一个 JSONObject 对象;) + + public abstract int getSyncAction(Cursor c); +// 公共抽象方法 getSyncAction,接收 Cursor 参数 c;(定义一个公共抽象方法 getSyncAction,接收一个 Cursor 参数 c,返回一个整型值;) + + public void setGid(String gid) { +// 公共方法 setGid,接收字符串参数 gid;(定义一个名为 setGid 的公共方法,接收一个字符串参数 gid;) + this.mGid = gid; +// 设置 mGid 的值;(将 this.mGid 赋值为 gid;) + } + + public void setName(String name) { +// 公共方法 setName,接收字符串参数 name;(定义一个名为 setName 的公共方法,接收一个字符串参数 name;) + this.mName = name; +// 设置 mName 的值;(将 this.mName 赋值为 name;) + } + + public void setLastModified(long lastModified) { +// 公共方法 setLastModified,接收长整型参数 lastModified;(定义一个名为 setLastModified 的公共方法,接收一个长整型参数 lastModified;) + this.mLastModified = lastModified; +// 设置 mLastModified 的值;(将 this.mLastModified 赋值为 lastModified;) + } + + public void setDeleted(boolean deleted) { +// 公共方法 setDeleted,接收布尔型参数 deleted;(定义一个名为 setDeleted 的公共方法,接收一个布尔型参数 deleted;) + this.mDeleted = deleted; +// 设置 mDeleted 的值;(将 this.mDeleted 赋值为 deleted;) + } + + public String getGid() { +// 公共方法 getGid;(定义一个名为 getGid 的公共方法;) + return this.mGid; +// 返回 mGid 的值;(返回 this.mGid 的值;) + } + + public String getName() { +// 公共方法 getName;(定义一个名为 getName 的公共方法;) + return this.mName; +// 返回 mName 的值;(返回 this.mName 的值;) + } + + public long getLastModified() { +// 公共方法 getLastModified;(定义一个名为 getLastModified 的公共方法;) + return this.mLastModified; +// 返回 mLastModified 的值;(返回 this.mLastModified 的值;) + } + + public boolean getDeleted() { +// 公共方法 getDeleted;(定义一个名为 getDeleted 的公共方法;) + return this.mDeleted; +// 返回 mDeleted 的值;(返回 this.mDeleted 的值;) + } + +} \ No newline at end of file -- 2.34.1 From f112ea0fb28d35c1d516fc3727c4736a5d56419b Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Sun, 13 Oct 2024 12:56:39 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/SqlData.java | 304 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 src/SqlData.java diff --git a/src/SqlData.java b/src/SqlData.java new file mode 100644 index 0000000..48e6514 --- /dev/null +++ b/src/SqlData.java @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2010 - 2011, The MiCode Open Source Community (www.micode.net) + * (版权所有(c)2010 - 2011,MiCode 开源社区(www.micode.net)。) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * (根据 Apache License 2.0 版(“许可证”)获得许可;) + * 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 + * (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.gtask.data; +// 包 net.micode.notes.gtask.data;(这个包的名字是 net.micode.notes.gtask.data。) + +import android.content.ContentResolver; +// 导入 android.content.ContentResolver;(导入 Android 的内容解析器类。) +import android.content.ContentUris; +// 导入 android.content.ContentUris;(导入 Android 的内容 URI 工具类。) +import android.content.ContentValues; +// 导入 android.content.ContentValues;(导入 Android 的内容值类。) +import android.content.Context; +// 导入 android.content.Context;(导入 Android 的上下文类。) +import android.database.Cursor; +// 导入 android.database.Cursor;(导入 Android 的数据库游标类。) +import android.net.Uri; +// 导入 android.net.Uri;(导入 Android 的统一资源标识符类。) +import android.util.Log; +// 导入 android.util.Log;(导入 Android 的日志工具类。) + +import net.micode.notes.data.Notes; +// 导入 net.micode.notes.data.Notes;(导入来自 net.micode.notes.data 的 Notes 类。) +import net.micode.notes.data.Notes.DataColumns; +// 导入 net.micode.notes.data.Notes.DataColumns;(导入 Notes 类中的数据列类。) +import net.micode.notes.data.Notes.DataConstants; +// 导入 net.micode.notes.data.Notes.DataConstants;(导入 Notes 类中的数据常量类。) +import net.micode.notes.data.Notes.NoteColumns; +// 导入 net.micode.notes.data.Notes.NoteColumns;(导入 Notes 类中的笔记列类。) +import net.micode.notes.data.NotesDatabaseHelper.TABLE; +// 导入 net.micode.notes.data.NotesDatabaseHelper.TABLE;(导入 Notes 数据库助手类中的表枚举。) +import net.micode.notes.gtask.exception.ActionFailureException; +// 导入 net.micode.notes.gtask.exception.ActionFailureException;(导入特定的异常类。) + +import org.json.JSONException; +// 导入 org.json.JSONException;(导入 JSON 处理的异常类。) +import org.json.JSONObject; +// 导入 org.json.JSONObject;(导入 JSON 对象类。) + + +public class SqlData { +// 公共类 SqlData;(定义一个名为 SqlData 的公共类。) + private static final String TAG = SqlData.class.getSimpleName(); +// 私有静态最终字符串变量 TAG,赋值为 SqlData 类的简单名称;(定义一个私有静态最终的字符串变量 TAG,值为 SqlData 类的简单名称。) + + private static final int INVALID_ID = -99999; +// 私有静态最终整型变量 INVALID_ID,赋值为 -99999;(定义一个私有静态最终的整型变量 INVALID_ID,值为 -99999。) + + public static final String[] PROJECTION_DATA = new String[] { + DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, + DataColumns.DATA3 + }; +// 公共静态最终字符串数组变量 PROJECTION_DATA;(定义一个公共静态最终的字符串数组变量 PROJECTION_DATA,包含特定的数据列名称。) + + public static final int DATA_ID_COLUMN = 0; +// 公共静态最终整型变量 DATA_ID_COLUMN,赋值为 0;(定义一个公共静态最终的整型变量 DATA_ID_COLUMN,值为 0。) + + public static final int DATA_MIME_TYPE_COLUMN = 1; +// 公共静态最终整型变量 DATA_MIME_TYPE_COLUMN,赋值为 1;(定义一个公共静态最终的整型变量 DATA_MIME_TYPE_COLUMN,值为 1。) + + public static final int DATA_CONTENT_COLUMN = 2; +// 公共静态最终整型变量 DATA_CONTENT_COLUMN,赋值为 2;(定义一个公共静态最终的整型变量 DATA_CONTENT_COLUMN,值为 2。) + + public static final int DATA_CONTENT_DATA_1_COLUMN = 3; +// 公共静态最终整型变量 DATA_CONTENT_DATA_1_COLUMN,赋值为 3;(定义一个公共静态最终的整型变量 DATA_CONTENT_DATA_1_COLUMN,值为 3。) + + public static final int DATA_CONTENT_DATA_3_COLUMN = 4; +// 公共静态最终整型变量 DATA_CONTENT_DATA_3_COLUMN,赋值为 4;(定义一个公共静态最终的整型变量 DATA_CONTENT_DATA_3_COLUMN,值为 4。) + + private ContentResolver mContentResolver; +// 私有 ContentResolver 变量 mContentResolver;(定义一个私有变量 mContentResolver,类型为 ContentResolver。) + + private boolean mIsCreate; +// 私有布尔型变量 mIsCreate;(定义一个私有布尔型变量 mIsCreate。) + + private long mDataId; +// 私有长整型变量 mDataId;(定义一个私有长整型变量 mDataId。) + + private String mDataMimeType; +// 私有字符串变量 mDataMimeType;(定义一个私有字符串变量 mDataMimeType。) + + private String mDataContent; +// 私有字符串变量 mDataContent;(定义一个私有字符串变量 mDataContent。) + + private long mDataContentData1; +// 私有长整型变量 mDataContentData1;(定义一个私有长整型变量 mDataContentData1。) + + private String mDataContentData3; +// 私有字符串变量 mDataContentData3;(定义一个私有字符串变量 mDataContentData3。) + + private ContentValues mDiffDataValues; +// 私有 ContentValues 变量 mDiffDataValues;(定义一个私有变量 mDiffDataValues,类型为 ContentValues。) + + public SqlData(Context context) { +// 公共构造函数,接收 Context 参数;(定义一个公共构造函数,接收一个 Context 参数。) + mContentResolver = context.getContentResolver(); +// 获取内容解析器;(将 context 的内容解析器赋值给 mContentResolver。) + mIsCreate = true; +// 设置创建标志;(将 mIsCreate 设置为 true。) + mDataId = INVALID_ID; +// 初始化数据 ID;(将 mDataId 初始化为 INVALID_ID。) + mDataMimeType = DataConstants.NOTE; +// 初始化数据 MIME 类型;(将 mDataMimeType 初始化为 DataConstants.NOTE。) + mDataContent = ""; +// 初始化数据内容;(将 mDataContent 初始化为空字符串。) + mDataContentData1 = 0; +// 初始化数据内容数据 1;(将 mDataContentData1 初始化为 0。) + mDataContentData3 = ""; +// 初始化数据内容数据 3;(将 mDataContentData3 初始化为空字符串。) + mDiffDataValues = new ContentValues(); +// 创建新的 ContentValues 对象;(创建一个新的 ContentValues 对象并赋值给 mDiffDataValues。) + } + + public SqlData(Context context, Cursor c) { +// 公共构造函数,接收 Context 和 Cursor 参数;(定义一个公共构造函数,接收一个 Context 参数和一个 Cursor 参数。) + mContentResolver = context.getContentResolver(); +// 获取内容解析器;(将 context 的内容解析器赋值给 mContentResolver。) + mIsCreate = false; +// 设置创建标志;(将 mIsCreate 设置为 false。) + loadFromCursor(c); +// 从游标加载数据;(调用 loadFromCursor 方法,从传入的游标中加载数据。) + mDiffDataValues = new ContentValues(); +// 创建新的 ContentValues 对象;(创建一个新的 ContentValues 对象并赋值给 mDiffDataValues。) + } + + private void loadFromCursor(Cursor c) { +// 私有方法 loadFromCursor,接收 Cursor 参数;(定义一个私有方法 loadFromCursor,接收一个 Cursor 参数。) + mDataId = c.getLong(DATA_ID_COLUMN); +// 获取数据 ID;(从游标中获取指定列的数据 ID,并赋值给 mDataId。) + mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); +// 获取数据 MIME 类型;(从游标中获取指定列的数据 MIME 类型,并赋值给 mDataMimeType。) + mDataContent = c.getString(DATA_CONTENT_COLUMN); +// 获取数据内容;(从游标中获取指定列的数据内容,并赋值给 mDataContent。) + mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); +// 获取数据内容数据 1;(从游标中获取指定列的数据内容数据 1,并赋值给 mDataContentData1。) + mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); +// 获取数据内容数据 3;(从游标中获取指定列的数据内容数据 3,并赋值给 mDataContentData3。) + } + + public void setContent(JSONObject js) throws JSONException { +// 公共方法 setContent,接收 JSONObject 参数;(定义一个公共方法 setContent,接收一个 JSONObject 参数。) + long dataId = js.has(DataColumns.ID)? js.getLong(DataColumns.ID) : INVALID_ID; +// 获取数据 ID;(如果 JSONObject 中包含指定键,则获取对应的值作为数据 ID,否则设置为 INVALID_ID。) + if (mIsCreate || mDataId!= dataId) { +// 判断是否创建或数据 ID 不一致;(如果正在创建或者当前数据 ID 与新的数据 ID 不一致。) + mDiffDataValues.put(DataColumns.ID, dataId); +// 更新差异数据值;(将新的数据 ID 放入差异数据值的对应键中。) + } + mDataId = dataId; +// 更新数据 ID;(将 dataId 赋值给 mDataId。) + + String dataMimeType = js.has(DataColumns.MIME_TYPE)? js.getString(DataColumns.MIME_TYPE) + : DataConstants.NOTE; +// 获取数据 MIME 类型;(如果 JSONObject 中包含指定键,则获取对应的值作为数据 MIME 类型,否则设置为 DataConstants.NOTE。) + if (mIsCreate ||!mDataMimeType.equals(dataMimeType)) { +// 判断是否创建或数据 MIME 类型不一致;(如果正在创建或者当前数据 MIME 类型与新的数据 MIME 类型不一致。) + mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType); +// 更新差异数据值;(将新的数据 MIME 类型放入差异数据值的对应键中。) + } + mDataMimeType = dataMimeType; +// 更新数据 MIME 类型;(将 dataMimeType 赋值给 mDataMimeType。) + + String dataContent = js.has(DataColumns.CONTENT)? js.getString(DataColumns.CONTENT) : ""; +// 获取数据内容;(如果 JSONObject 中包含指定键,则获取对应的值作为数据内容,否则设置为空字符串。) + if (mIsCreate ||!mDataContent.equals(dataContent)) { +// 判断是否创建或数据内容不一致;(如果正在创建或者当前数据内容与新的数据内容不一致。) + mDiffDataValues.put(DataColumns.CONTENT, dataContent); +// 更新差异数据值;(将新的数据内容放入差异数据值的对应键中。) + } + mDataContent = dataContent; +// 更新数据内容;(将 dataContent 赋值给 mDataContent。) + + long dataContentData1 = js.has(DataColumns.DATA1)? js.getLong(DataColumns.DATA1) : 0; +// 获取数据内容数据 1;(如果 JSONObject 中包含指定键,则获取对应的值作为数据内容数据 1,否则设置为 0。) + if (mIsCreate || mDataContentData1!= dataContentData1) { +// 判断是否创建或数据内容数据 1 不一致;(如果正在创建或者当前数据内容数据 1 与新的数据内容数据 1 不一致。) + mDiffDataValues.put(DataColumns.DATA1, dataContentData1); +// 更新差异数据值;(将新的数据内容数据 1 放入差异数据值的对应键中。) + } + mDataContentData1 = dataContentData1; +// 更新数据内容数据 1;(将 dataContentData1 赋值给 mDataContentData1。) + + String dataContentData3 = js.has(DataColumns.DATA3)? js.getString(DataColumns.DATA3) : ""; +// 获取数据内容数据 3;(如果 JSONObject 中包含指定键,则获取对应的值作为数据内容数据 3,否则设置为空字符串。) + if (mIsCreate ||!mDataContentData3.equals(dataContentData3)) { +// 判断是否创建或数据内容数据 3 不一致;(如果正在创建或者当前数据内容数据 3 与新的数据内容数据 3 不一致。) + mDiffDataValues.put(DataColumns.DATA3, dataContentData3); +// 更新差异数据值;(将新的数据内容数据 3 放入差异数据值的对应键中。) + } + mDataContentData3 = dataContentData3; +// 更新数据内容数据 3;(将 dataContentData3 赋值给 mDataContentData3。) + } + + public JSONObject getContent() throws JSONException { +// 公共方法 getContent;(定义一个公共方法 getContent。) + if (mIsCreate) { +// 判断是否正在创建;(如果正在创建。) + Log.e(TAG, "it seems that we haven't created this in database yet"); +// 输出错误日志;(打印错误日志,提示“看起来我们还没有在数据库中创建这个。”) + return null; +// 返回 null;(返回 null。) + } + JSONObject js = new JSONObject(); +// 创建新的 JSONObject 对象;(创建一个新的 JSONObject 对象。) + js.put(DataColumns.ID, mDataId); +// 设置数据 ID;(将 mDataId 放入 JSONObject 的对应键中。) + js.put(DataColumns.MIME_TYPE, mDataMimeType); +// 设置数据 MIME 类型;(将 mDataMimeType 放入 JSONObject 的对应键中。) + js.put(DataColumns.CONTENT, mDataContent); +// 设置数据内容;(将 mDataContent 放入 JSONObject 的对应键中。) + js.put(DataColumns.DATA1, mDataContentData1); +// 设置数据内容数据 1;(将 mDataContentData1 放入 JSONObject 的对应键中。) + js.put(DataColumns.DATA3, mDataContentData3); +// 设置数据内容数据 3;(将 mDataContentData3 放入 JSONObject 的对应键中。) + return js; +// 返回 JSONObject 对象;(返回创建好的 JSONObject 对象。) + } + + public void commit(long noteId, boolean validateVersion, long version) { +// 公共方法 commit,接收长整型、布尔型和长整型参数;(定义一个公共方法 commit,接收一个长整型 noteId、一个布尔型 validateVersion 和一个长整型 version 参数。) + + if (mIsCreate) { +// 判断是否正在创建;(如果正在创建。) + if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { +// 判断数据 ID 是否无效且差异数据值包含特定键;(如果数据 ID 无效且差异数据值中包含指定键。) + mDiffDataValues.remove(DataColumns.ID); +// 移除该键值对;(从差异数据值中移除该键值对。) + } + + mDiffDataValues.put(DataColumns.NOTE_ID, noteId); +// 设置笔记 ID;(将 noteId 放入差异数据值的对应键中。) + Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); +// 插入数据;(向 Notes 的内容数据 URI 中插入差异数据值,获取返回的 URI。) + try { +// 尝试执行以下代码块;(开始 try 代码块。) + mDataId = Long.valueOf(uri.getPathSegments().get(1)); +// 获取数据 ID;(从返回的 URI 中获取数据 ID,并赋值给 mDataId。) + } catch (NumberFormatException e) { +// 如果发生数字格式异常,进入此代码块;(捕获 NumberFormatException 异常。) + Log.e(TAG, "Get note id error :" + e.toString()); +// 输出错误日志;(打印错误日志,提示“获取笔记 ID 错误:”加上异常信息。) + throw new ActionFailureException("create note failed"); +// 抛出异常 + } else { +// 如果不是正在创建;(如果不是正在创建的状态。) + if (mDiffDataValues.size() > 0) { +// 如果差异数据值不为空;(如果差异数据值有内容。) + int result = 0; +// 初始化结果变量;(先把结果设为 0。) + if (!validateVersion) { +// 如果不验证版本;(如果不需要验证版本。) + result = mContentResolver.update(ContentUris.withAppendedId( + Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); +// 更新数据;(用内容解析器更新数据,不考虑版本验证。) + } else { +// 如果要验证版本;(如果需要验证版本。) + result = mContentResolver.update(ContentUris.withAppendedId( + Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, + "? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE + + " WHERE " + NoteColumns.VERSION + "=?)", new String[]{ + String.valueOf(noteId), String.valueOf(version) + }); +// 更新数据并验证版本;(用内容解析器更新数据,同时验证版本。) + } + if (result == 0) { +// 如果更新结果为 0;(如果更新没有效果。) + Log.w(TAG, "there is no update. maybe user updates note when syncing"); +// 输出警告日志;(打印警告日志,提示可能是用户在同步时更新了笔记。) + } + } + } + + mDiffDataValues.clear(); +// 清空差异数据值;(把差异数据值清空。) + mIsCreate = false; +// 设置不是创建状态;(设置当前不是创建新数据的状态。) + + public long getId() { +// 获取 ID 的方法;(定义一个获取数据 ID 的方法。) + return mDataId; +// 返回数据 ID;(返回当前的数据 ID。) + } \ No newline at end of file -- 2.34.1 From 7de23f11f6f93eb1421a652ae4d5111d667d49f4 Mon Sep 17 00:00:00 2001 From: lwh <3324016427@qq.com> Date: Tue, 15 Oct 2024 15:59:26 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/SqlNote.java | 711 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 711 insertions(+) create mode 100644 src/SqlNote.java diff --git a/src/SqlNote.java b/src/SqlNote.java new file mode 100644 index 0000000..8572cf4 --- /dev/null +++ b/src/SqlNote.java @@ -0,0 +1,711 @@ +/* + * 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.gtask.data; +// 包声明:net.micode.notes.gtask.data + +import android.appwidget.AppWidgetManager; +// 导入安卓小部件管理器类 +import android.content.ContentResolver; +// 导入内容解析器类 +import android.content.ContentValues; +// 导入内容值类 +import android.content.Context; +// 导入上下文类 +import android.database.Cursor; +// 导入游标类 +import android.net.Uri; +// 导入统一资源标识符类 +import android.util.Log; +// 导入日志类 + +import net.micode.notes.data.Notes; +// 导入笔记数据类 +import net.micode.notes.data.Notes.DataColumns; +// 导入笔记数据列类 +import net.micode.notes.data.Notes.NoteColumns; +// 导入笔记列类 +import net.micode.notes.gtask.exception.ActionFailureException; +// 导入操作失败异常类 +import net.micode.notes.tool.GTaskStringUtils; +// 导入工具类中的字符串工具类 +import net.micode.notes.tool.ResourceParser; +// 导入资源解析器类 + +import org.json.JSONArray; +// 导入 JSON 数组类 +import org.json.JSONException; +// 导入 JSON 异常类 +import org.json.JSONObject; +// 导入 JSON 对象类 + +import java.util.ArrayList; +// 导入 ArrayList 类 + +public class SqlNote { + // SQL 笔记类定义 + + private static final String TAG = SqlNote.class.getSimpleName(); + // 定义静态常量 TAG,为当前类名的简写 + + private static final int INVALID_ID = -99999; + // 定义无效 ID 的常量值 + + public static final String[] PROJECTION_NOTE = new String[]{ + 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, NoteColumns.TYPE, + NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.SYNC_ID, + NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID, + NoteColumns.VERSION + }; + // 定义笔记投影数组,包含各种列名 + + public static final int ID_COLUMN = 0; + // ID 列的索引常量 + + public static final int ALERTED_DATE_COLUMN = 1; + // 提醒日期列的索引常量 + + public static final int BG_COLOR_ID_COLUMN = 2; + // 背景颜色 ID 列的索引常量 + + public static final int CREATED_DATE_COLUMN = 3; + // 创建日期列的索引常量 + + public static final int HAS_ATTACHMENT_COLUMN = 4; + // 是否有附件列的索引常量 + + public static final int MODIFIED_DATE_COLUMN = 5; + // 修改日期列的索引常量 + + public static final int NOTES_COUNT_COLUMN = 6; + // 笔记数量列的索引常量 + + public static final int PARENT_ID_COLUMN = 7; + // 父 ID 列的索引常量 + + public static final int SNIPPET_COLUMN = 8; + // 摘要列的索引常量 + + public static final int TYPE_COLUMN = 9; + // 类型列的索引常量 + + public static final int WIDGET_ID_COLUMN = 10; + // 小部件 ID 列的索引常量 + + public static final int WIDGET_TYPE_COLUMN = 11; + // 小部件类型列的索引常量 + + public static final int SYNC_ID_COLUMN = 12; + // 同步 ID 列的索引常量 + + public static final int LOCAL_MODIFIED_COLUMN = 13; + // 本地修改列的索引常量 + + public static final int ORIGIN_PARENT_ID_COLUMN = 14; + // 原始父 ID 列的索引常量 + + public static final int GTASK_ID_COLUMN = 15; + // GTask ID 列的索引常量 + + public static final int VERSION_COLUMN = 16; + // 版本列的索引常量 + + private Context mContext; + // 定义上下文变量 + + private ContentResolver mContentResolver; + // 定义内容解析器变量 + + private boolean mIsCreate; + // 定义是否为创建状态的变量 + + private long mId; + // 定义 ID 变量 + + private long mAlertDate; + // 定义提醒日期变量 + + private int mBgColorId; + // 定义背景颜色 ID 变量 + + private long mCreatedDate; + // 定义创建日期变量 + + private int mHasAttachment; + // 定义是否有附件变量 + + private long mModifiedDate; + // 定义修改日期变量 + + private long mParentId; + // 定义父 ID 变量 + + private String mSnippet; + // 定义摘要变量 + + private int mType; + // 定义类型变量 + + private int mWidgetId; + // 定义小部件 ID 变量 + + private int mWidgetType; + // 定义小部件类型变量 + + private long mOriginParent; + // 定义原始父 ID 变量 + + private long mVersion; + // 定义版本变量 + + private ContentValues mDiffNoteValues; + // 定义差异笔记值变量 + + private ArrayList mDataList; + // 定义 SQL 数据列表变量 + + public SqlNote(Context context) { + // 无参构造函数,接受上下文参数 + mContext = context; + // 将传入的上下文赋值给成员变量 + mContentResolver = context.getContentResolver(); + // 获取上下文的内容解析器并赋值给成员变量 + mIsCreate = true; + // 设置为创建状态 + mId = INVALID_ID; + // 设置 ID 为无效值 + mAlertDate = 0; + // 设置提醒日期为 0 + mBgColorId = ResourceParser.getDefaultBgId(context); + // 设置背景颜色 ID 为资源解析器获取的默认背景颜色 ID + mCreatedDate = System.currentTimeMillis(); + // 设置创建日期为当前时间戳 + mHasAttachment = 0; + // 设置是否有附件为 0 + mModifiedDate = System.currentTimeMillis(); + // 设置修改日期为当前时间戳 + mParentId = 0; + // 设置父 ID 为 0 + mSnippet = ""; + // 设置摘要为空字符串 + mType = Notes.TYPE_NOTE; + // 设置类型为笔记类型 + mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; + // 设置小部件 ID 为无效值 + mWidgetType = Notes.TYPE_WIDGET_INVALIDE; + // 设置小部件类型为无效值 + mOriginParent = 0; + // 设置原始父 ID 为 0 + mVersion = 0; + // 设置版本为 0 + mDiffNoteValues = new ContentValues(); + // 创建新的内容值对象并赋值给差异笔记值变量 + mDataList = new ArrayList(); + // 创建新的 SQL 数据列表 + } + + public SqlNote(Context context, Cursor c) { + // 接受上下文和游标参数的构造函数 + mContext = context; + // 将传入的上下文赋值给成员变量 + mContentResolver = context.getContentResolver(); + // 获取上下文的内容解析器并赋值给成员变量 + mIsCreate = false; + // 设置为非创建状态 + loadFromCursor(c); + // 从游标加载数据 + mDataList = new ArrayList(); + // 创建新的 SQL 数据列表 + if (mType == Notes.TYPE_NOTE) + loadDataContent(); + // 如果类型为笔记类型,加载数据内容 + mDiffNoteValues = new ContentValues(); + // 创建新的内容值对象并赋值给差异笔记值变量 + } + + public SqlNote(Context context, long id) { + // 接受上下文和 ID 参数的构造函数 + mContext = context; + // 将传入的上下文赋值给成员变量 + mContentResolver = context.getContentResolver(); + // 获取上下文的内容解析器并赋值给成员变量 + mIsCreate = false; + // 设置为非创建状态 + loadFromCursor(id); + // 从 ID 加载数据 + mDataList = new ArrayList(); + // 创建新的 SQL 数据列表 + if (mType == Notes.TYPE_NOTE) + loadDataContent(); + // 如果类型为笔记类型,加载数据内容 + mDiffNoteValues = new ContentValues(); + // 创建新的内容值对象并赋值给差异笔记值变量 + } + + private void loadFromCursor(long id) { + // 从 ID 加载游标数据的私有方法 + Cursor c = null; + // 初始化游标为 null + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", + new String[]{ + String.valueOf(id) + }, null); + // 查询内容解析器,获取指定 ID 的笔记数据游标 + if (c!= null) { + c.moveToNext(); + loadFromCursor(c); + // 如果游标不为 null,移动到下一行并从游标加载数据 + } else { + Log.w(TAG, "loadFromCursor: cursor = null"); + // 如果游标为 null,记录日志警告 + } + } finally { + if (c!= null) + c.close(); + // 最终,如果游标不为 null,关闭游标 + } + } + + private void loadFromCursor(Cursor c) { + // 从游标加载数据的私有方法 + mId = c.getLong(ID_COLUMN); + // 获取游标中 ID 列的值并赋值给成员变量 + mAlertDate = c.getLong(ALERTED_DATE_COLUMN); + // 获取游标中提醒日期列的值并赋值给成员变量 + mBgColorId = c.getInt(BG_COLOR_ID_COLUMN); + // 获取游标中背景颜色 ID 列的值并赋值给成员变量 + mCreatedDate = c.getLong(CREATED_DATE_COLUMN); + // 获取游标中创建日期列的值并赋值给成员变量 + mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN); + // 获取游标中是否有附件列的值并赋值给成员变量 + mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN); + // 获取游标中修改日期列的值并赋值给成员变量 + mParentId = c.getLong(PARENT_ID_COLUMN); + // 获取游标中父 ID 列的值并赋值给成员变量 + mSnippet = c.getString(SNIPPET_COLUMN); + // 获取游标中摘要列的值并赋值给成员变量 + mType = c.getInt(TYPE_COLUMN); + // 获取游标中类型列的值并赋值给成员变量 + mWidgetId = c.getInt(WIDGET_ID_COLUMN); + // 获取游标中小部件 ID 列的值并赋值给成员变量 + mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); + // 获取游标中小部件类型列的值并赋值给成员变量 + mVersion = c.getLong(VERSION_COLUMN); + // 获取游标中版本列的值并赋值给成员变量 + } + + private void loadDataContent() { + // 加载数据内容的私有方法 + Cursor c = null; + // 初始化游标为 null + mDataList.clear(); + // 清空数据列表 + try { + c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, + "(note_id=?)", new String[]{ + String.valueOf(mId) + }, null); + // 查询内容解析器,获取指定笔记 ID 的数据游标 + if (c!= null) { + if (c.getCount() == 0) { + Log.w(TAG, "it seems that the note has not data"); + // 如果游标计数为 0,记录日志警告 + return; + } + while (c.moveToNext()) { + SqlData data = new SqlData(mContext, c); + mDataList.add(data); + // 如果游标不为 null,遍历游标并创建 SQL 数据对象添加到数据列表 + } + } else { + Log.w(TAG, "loadDataContent: cursor = null"); + // 如果游标为 null,记录日志警告 + } + } finally { + if (c!= null) + c.close(); + // 最终,如果游标不为 null,关闭游标 + } + } + + public boolean setContent(JSONObject js) { + // 设置内容的方法,接受 JSON 对象参数,返回布尔值 + try { + JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + // 从传入的 JSON 对象中获取名为 GTaskStringUtils.META_HEAD_NOTE 的 JSON 对象 + if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { + Log.w(TAG, "cannot set system folder"); + // 如果类型为系统文件夹类型,记录日志警告并返回 false + return false; + } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { + // 如果类型为文件夹类型 + // for folder we can only update the snnipet and type + String snippet = note.has(NoteColumns.SNIPPET)? note + .getString(NoteColumns.SNIPPET) : ""; + // 获取摘要,如果存在则获取,否则为空字符串 + if (mIsCreate ||!mSnippet.equals(snippet)) { + mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); + } + // 如果为创建状态或摘要与当前不同,将摘要添加到差异笔记值中 + mSnippet = snippet; + // 更新摘要变量 + + int type = note.has(NoteColumns.TYPE)? note.getInt(NoteColumns.TYPE) + : Notes.TYPE_NOTE; + // 获取类型,如果存在则获取,否则为笔记类型 + if (mIsCreate || mType!= type) { + mDiffNoteValues.put(NoteColumns.TYPE, type); + } + // 如果为创建状态或类型与当前不同,将类型添加到差异笔记值中 + mType = type; + // 更新类型变量 + } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { + // 如果类型为笔记类型 + JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + // 获取数据数组 + long id = note.has(NoteColumns.ID)? note.getLong(NoteColumns.ID) : INVALID_ID; + // 获取 ID,如果存在则获取,否则为无效值 + if (mIsCreate || mId!= id) { + mDiffNoteValues.put(NoteColumns.ID, id); + } + // 如果为创建状态或 ID 与当前不同,将 ID 添加到差异笔记值中 + mId = id; + // 更新 ID 变量 + + long alertDate = note.has(NoteColumns.ALERTED_DATE)? note + .getLong(NoteColumns.ALERTED_DATE) : 0; + // 获取提醒日期,如果存在则获取,否则为 0 + if (mIsCreate || mAlertDate!= alertDate) { + mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate); + } + // 如果为创建状态或提醒日期与当前不同,将提醒日期添加到差异笔记值中 + mAlertDate = alertDate; + // 更新提醒日期变量 + + int bgColorId = note.has(NoteColumns.BG_COLOR_ID)? note + .getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext); + // 获取背景颜色 ID,如果存在则获取,否则为默认背景颜色 ID + if (mIsCreate || mBgColorId!= bgColorId) { + mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId); + } + // 如果为创建状态或背景颜色 ID 与当前不同,将背景颜色 ID 添加到差异笔记值中 + mBgColorId = bgColorId; + // 更新背景颜色 ID 变量 + + long createDate = note.has(NoteColumns.CREATED_DATE)? note + .getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis(); + // 获取创建日期,如果存在则获取,否则为当前时间戳 + if (mIsCreate || mCreatedDate!= createDate) { + mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate); + } + // 如果为创建状态或创建日期与当前不同,将创建日期添加到差异笔记值中 + mCreatedDate = createDate; + // 更新创建日期变量 +int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT)? note + .getInt(NoteColumns.HAS_ATTACHMENT) : 0; +// 判断 JSON 对象 note 中是否存在 HAS_ATTACHMENT 字段,如果有则获取其整数值,否则将 hasAttachment 初始化为 0。 + +if (mIsCreate || mHasAttachment!= hasAttachment) { + mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment); +} +// 如果当前处于创建状态或者当前的 hasAttachment 值与新获取的值不同,则将新的 hasAttachment 值放入差异笔记值的 HAS_ATTACHMENT 字段中。 + +mHasAttachment = hasAttachment; +// 更新当前对象的 hasAttachment 变量。 + +long modifiedDate = note.has(NoteColumns.MODIFIED_DATE)? note + .getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis(); +// 判断 JSON 对象 note 中是否存在 MODIFIED_DATE 字段,如果有则获取其长整数值,否则将 modifiedDate 初始化为当前时间戳。 + +if (mIsCreate || mModifiedDate!= modifiedDate) { + mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate); +} +// 如果当前处于创建状态或者当前的 modifiedDate 值与新获取的值不同,则将新的 modifiedDate 值放入差异笔记值的 MODIFIED_DATE 字段中。 + +mModifiedDate = modifiedDate; +// 更新当前对象的 modifiedDate 变量。 + +long parentId = note.has(NoteColumns.PARENT_ID)? note + .getLong(NoteColumns.PARENT_ID) : 0; +// 判断 JSON 对象 note 中是否存在 PARENT_ID 字段,如果有则获取其长整数值,否则将 parentId 初始化为 0。 + +if (mIsCreate || mParentId!= parentId) { + mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId); +} +// 如果当前处于创建状态或者当前的 parentId 值与新获取的值不同,则将新的 parentId 值放入差异笔记值的 PARENT_ID 字段中。 + +mParentId = parentId; +// 更新当前对象的 parentId 变量。 + +String snippet = note.has(NoteColumns.SNIPPET)? note + .getString(NoteColumns.SNIPPET) : ""; +// 判断 JSON 对象 note 中是否存在 SNIPPET 字段,如果有则获取其字符串值,否则将 snippet 初始化为空字符串。 + +if (mIsCreate ||!mSnippet.equals(snippet)) { + mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); +} +// 如果当前处于创建状态或者当前的 snippet 值与新获取的值不同,则将新的 snippet 值放入差异笔记值的 SNIPPET 字段中。 + +mSnippet = snippet; +// 更新当前对象的 snippet 变量。 + +int type = note.has(NoteColumns.TYPE)? note.getInt(NoteColumns.TYPE) + : Notes.TYPE_NOTE; +// 判断 JSON 对象 note 中是否存在 TYPE 字段,如果有则获取其整数值,否则将 type 初始化为笔记类型。 + +if (mIsCreate || mType!= type) { + mDiffNoteValues.put(NoteColumns.TYPE, type); +} +// 如果当前处于创建状态或者当前的 type 值与新获取的值不同,则将新的 type 值放入差异笔记值的 TYPE 字段中。 + +mType = type; +// 更新当前对象的 type 变量。 + +int widgetId = note.has(NoteColumns.WIDGET_ID)? note.getInt(NoteColumns.WIDGET_ID) + : AppWidgetManager.INVALID_APPWIDGET_ID; +// 判断 JSON 对象 note 中是否存在 WIDGET_ID 字段,如果有则获取其整数值,否则将 widgetId 初始化为无效小部件 ID。 + +if (mIsCreate || mWidgetId!= widgetId) { + mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId); +} +// 如果当前处于创建状态或者当前的 widgetId 值与新获取的值不同,则将新的 widgetId 值放入差异笔记值的 WIDGET_ID 字段中。 + +mWidgetId = widgetId; +// 更新当前对象的 widgetId 变量。 + +int widgetType = note.has(NoteColumns.WIDGET_TYPE)? note + .getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE; +// 判断 JSON 对象 note 中是否存在 WIDGET_TYPE 字段,如果有则获取其整数值,否则将 widgetType 初始化为无效小部件类型。 + +if (mIsCreate || mWidgetType!= widgetType) { + mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType); +} +// 如果当前处于创建状态或者当前的 widgetType 值与新获取的值不同,则将新的 widgetType 值放入差异笔记值的 WIDGET_TYPE 字段中。 + +mWidgetType = widgetType; +// 更新当前对象的 widgetType 变量。 + +long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID)? note + .getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; +// 判断 JSON 对象 note 中是否存在 ORIGIN_PARENT_ID 字段,如果有则获取其长整数值,否则将 originParent 初始化为 0。 + +if (mIsCreate || mOriginParent!= originParent) { + mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent); +} +// 如果当前处于创建状态或者当前的 originParent 值与新获取的值不同,则将新的 originParent 值放入差异笔记值的 ORIGIN_PARENT_ID 字段中。 + +mOriginParent = originParent; +// 更新当前对象的 originParent 变量。 + +for (int i = 0; i < dataArray.length(); i++) { + JSONObject data = dataArray.getJSONObject(i); + // 从 JSON 数组 dataArray 中获取第 i 个元素,即一个 JSON 对象,并赋值给 data。 + SqlData sqlData = null; + // 初始化一个 SqlData 对象为 null。 + if (data.has(DataColumns.ID)) { + long dataId = data.getLong(DataColumns.ID); + // 如果 data 中包含 ID 字段,则获取其长整数值并赋值给 dataId。 + for (SqlData temp : mDataList) { + if (dataId == temp.getId()) { + sqlData = temp; + } + } + // 在当前对象的 mDataList 中遍历每个 SqlData 对象 temp,如果 dataId 与 temp 的 ID 相等,则将 temp 赋值给 sqlData。 + } + + if (sqlData == null) { + sqlData = new SqlData(mContext); + mDataList.add(sqlData); + } + // 如果 sqlData 为 null,即没有找到匹配的 SqlData 对象,则创建一个新的 SqlData 对象并添加到 mDataList 中。 + + sqlData.setContent(data); + // 调用 sqlData 的 setContent 方法,将当前的 data 对象作为参数传入。 +} +java +复制 +public JSONObject getContent() { + try { + JSONObject js = new JSONObject(); + // 创建一个新的 JSON 对象 js。 + if (mIsCreate) { + Log.e(TAG, "it seems that we haven't created this in database yet"); + return null; + } + // 如果当前处于创建状态,则记录日志并返回 null。 + + JSONObject note = new JSONObject(); + // 创建一个新的 JSON 对象 note。 + if (mType == Notes.TYPE_NOTE) { + note.put(NoteColumns.ID, mId); + note.put(NoteColumns.ALERTED_DATE, mAlertDate); + note.put(NoteColumns.BG_COLOR_ID, mBgColorId); + note.put(NoteColumns.CREATED_DATE, mCreatedDate); + note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment); + note.put(NoteColumns.MODIFIED_DATE, mModifiedDate); + note.put(NoteColumns.PARENT_ID, mParentId); + note.put(NoteColumns.SNIPPET, mSnippet); + note.put(NoteColumns.TYPE, mType); + note.put(NoteColumns.WIDGET_ID, mWidgetId); + note.put(NoteColumns.WIDGET_TYPE, mWidgetType); + note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent); + js.put(GTaskStringUtils.META_HEAD_NOTE, note); + // 如果当前对象的类型是笔记类型,则将各种属性放入 note 中,并将 note 放入 js 的特定键下。 + + JSONArray dataArray = new JSONArray(); + for (SqlData sqlData : mDataList) { + JSONObject data = sqlData.getContent(); + if (data!= null) { + dataArray.put(data); + } + } + js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); + // 创建一个新的 JSON 数组 dataArray,遍历数据列表获取每个 SqlData 的内容放入 JSON 数组中,再将 dataArray 放入 js 的特定键下。 + } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { + note.put(NoteColumns.ID, mId); + note.put(NoteColumns.TYPE, mType); + note.put(NoteColumns.SNIPPET, mSnippet); + js.put(GTaskStringUtils.META_HEAD_NOTE, note); + } + // 如果当前对象的类型是文件夹类型或系统类型,则只将 ID、类型和摘要放入 note 中,再将 note 放入 js 的特定键下。 + + return js; + } catch (JSONException e) { + Log.e(TAG, e.toString()); + e.printStackTrace(); + } + return null; +} +java +复制 +public void setParentId(long id) { + mParentId = id; + // 更新当前对象的父 ID 变量。 + mDiffNoteValues.put(NoteColumns.PARENT_ID, id); + // 将新的父 ID 放入差异笔记值的 PARENT_ID 字段中。 +} + +public void setGtaskId(String gid) { + mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); + // 将新的 GTask ID 放入差异笔记值的 GTASK_ID 字段中。 +} + +public void setSyncId(long syncId) { + mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); + // 将新的同步 ID 放入差异笔记值的 SYNC_ID 字段中。 +} + +public void resetLocalModified() { + mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); + // 将本地修改状态设置为 0,并放入差异笔记值的 LOCAL_MODIFIED 字段中。 +} + +public long getId() { + return mId; + // 返回当前对象的 ID。 +} + +public long getParentId() { + return mParentId; + // 返回当前对象的父 ID。 +} + +public String getSnippet() { + return mSnippet; + // 返回当前对象的摘要。 +} + +public boolean isNoteType() { + return mType == Notes.TYPE_NOTE; + // 判断是否是笔记类型的方法。如果当前对象的类型等于笔记类型,则返回 true,否则返回 false。 +} + +public void commit(boolean validateVersion) { + if (mIsCreate) { + if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { + mDiffNoteValues.remove(NoteColumns.ID); + } + // 如果当前处于创建状态且 ID 为无效值且差异笔记值中包含 ID 字段,则移除该 ID 字段。 + + Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues); + try { + mId = Long.valueOf(uri.getPathSegments().get(1)); + } catch (NumberFormatException e) { + Log.e(TAG, "Get note id error :" + e.toString()); + throw new ActionFailureException("create note failed"); + } + // 插入新的笔记数据到内容解析器中,并获取新插入的笔记 ID。如果插入失败则抛出异常。 + + if (mId == 0) { + throw new IllegalStateException("Create thread id failed"); + } + // 如果当前 ID 为 0,则抛出非法状态异常。 + + if (mType == Notes.TYPE_NOTE) { + for (SqlData sqlData : mDataList) { + sqlData.commit(mId, false, -1); + } + } + // 如果类型是笔记类型,则对数据列表中的每个 SqlData 对象调用提交方法。 + } else { + if (mId <= 0 && mId!= Notes.ID_ROOT_FOLDER && mId!= Notes.ID_CALL_RECORD_FOLDER) { + Log.e(TAG, "No such note"); + throw new IllegalStateException("Try to update note with invalid id"); + } + // 如果不是创建状态且 ID 无效(不等于根文件夹 ID 和通话记录文件夹 ID),则抛出异常。 + + if (mDiffNoteValues.size() > 0) { + mVersion++; + int result = 0; + if (!validateVersion) { + result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" + + NoteColumns.ID + "=?)", new String[]{ + String.valueOf(mId) + }); + } else { + result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" + + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", + new String[]{ + String.valueOf(mId), String.valueOf(mVersion) + }); + } + if (result == 0) { + Log.w(TAG, "there is no update. maybe user updates note when syncing"); + } + } + // 如果差异笔记值不为空,则更新版本号,并根据 validateVersion 的值选择不同的更新方式。如果更新结果为 0,则记录日志警告。 + + if (mType == Notes.TYPE_NOTE) { + for (SqlData sqlData : mDataList) { + sqlData.commit(mId, validateVersion, mVersion); + } + } + // 如果类型是笔记类型,则对数据列表中的每个 SqlData 对象调用提交方法。 + } + + // refresh local info + loadFromCursor(mId); + if (mType == Notes.TYPE_NOTE) + loadDataContent(); + // 刷新本地信息,根据 ID 重新加载当前对象的数据,如果类型是笔记类型,则加载数据内容。 + + mDiffNoteValues.clear(); + mIsCreate = false; + // 清空差异笔记值,并设置为非创建状态。 +} \ No newline at end of file -- 2.34.1