Compare commits

..

No commits in common. 'djx_branch' and 'main' have entirely different histories.

@ -1,100 +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.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;
// Contact类用于处理联系人相关的操作主要功能是根据电话号码查询对应的联系人姓名并使用缓存机制来提高查询效率避免重复查询相同号码的联系人信息。
public class Contact {
// 用于缓存已经查询过的电话号码及其对应的联系人姓名,以提高查询效率,避免重复查询相同号码的联系人信息,减少对数据库等资源的频繁访问。
private static HashMap<String, String> sContactCache;
// 用于日志输出的标签方便在Logcat中识别该类相关的日志信息便于调试和查看运行情况。
private static final String TAG = "Contact";
// 定义一个用于查询联系人的筛选条件字符串,用于在联系人数据中查找与给定电话号码匹配的联系人记录。
// 该条件使用了数据库函数PHONE_NUMBERS_EQUAL来比较电话号码是否相等同时限定了数据的MIME类型为电话号码类型Phone.CONTENT_ITEM_TYPE
// 并且要求对应的原始联系人ID在特定的查询结果集中通过子查询查找符合最小匹配条件的原始联系人ID
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 = '+')";
/**
* ContextphoneNumber
* sContactCache
* ContentResolver便使
*
* @param context ContentResolver便
* @param phoneNumber
* @return null
*/
public static String getContact(Context context, String phoneNumber) {
// 如果联系人缓存为空即第一次使用该功能或者缓存被清空等情况则创建一个新的HashMap实例作为缓存容器。
if (sContactCache == null) {
sContactCache = new HashMap<String, String>();
}
// 检查缓存中是否已经存在给定电话号码对应的联系人姓名,如果存在则直接从缓存中获取并返回,避免重复查询数据库。
if (sContactCache.containsKey(phoneNumber)) {
return sContactCache.get(phoneNumber);
}
// 替换查询条件中的占位符(“+”为电话号码的最小匹配格式通过PhoneNumberUtils工具类的toCallerIDMinMatch方法进行转换
// 以适应不同格式的电话号码匹配需求,使查询条件更准确地匹配联系人数据库中的记录。
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
// 通过上下文的ContentResolver发起查询操作查询联系人数据的统一资源标识符Data.CONTENT_URI
// 指定只查询联系人的显示名称Phone.DISPLAY_NAME这一列数据传入处理后的查询条件selection以及要查询的电话号码参数phoneNumber
// 排序规则设置为null表示使用默认排序方式这里暂未关注排序情况
Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI,
new String[]{Phone.DISPLAY_NAME},
selection,
new String[]{phoneNumber},
null);
// 如果查询结果游标Cursor不为空且游标可以移动到第一条记录表示查询到了至少一条匹配的联系人记录则进行以下操作。
if (cursor != null && cursor.moveToFirst()) {
try {
// 从游标中获取第一列索引为0的数据即联系人的显示名称这里假设查询结果中只返回了显示名称这一列数据。
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;
}
}
}

@ -1,86 +0,0 @@
package net.micode.notes.gtask.data;
import android.database.Cursor;
import android.util.Log;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
// MetaData类继承自Task类用于处理任务相关的元数据信息
public class MetaData extends Task {
// 定义一个私有静态常量TAG用于在日志输出时标识当前类其值为类的简单名称
private final static String TAG = MetaData.class.getSimpleName();
// 用于存储相关任务的标识符初始值设为null
private String mRelatedGid = null;
// 设置元数据的方法接收任务标识符gid和一个JSONObject类型的metaInfo对象
public void setMeta(String gid, JSONObject metaInfo) {
try {
// 尝试将任务标识符gid添加到metaInfo这个JSON对象中键由GTaskStringUtils.META_HEAD_GTASK_ID指定
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
} catch (JSONException e) {
// 如果添加过程中出现JSONException异常通过Log.e记录错误日志提示添加相关标识符失败
Log.e(TAG, "failed to put related gid");
}
// 将更新后的metaInfo对象转换为字符串并通过调用继承自Task类的setNotes方法进行设置
setNotes(metaInfo.toString());
// 设置名称为GTaskStringUtils.META_NOTE_NAME所代表的值该值应该是一个预定义的用于标识名称的字符串常量
setName(GTaskStringUtils.META_NOTE_NAME);
}
// 获取相关任务标识符的方法返回mRelatedGid的值
public String getRelatedGid() {
return mRelatedGid;
}
// 重写isWorthSaving方法判断当前MetaData对象是否值得保存
// 逻辑是只要通过getNotes方法推测来自Task类用于获取备注信息相关内容获取到的值不为null就返回true
@Override
public boolean isWorthSaving() {
return getNotes()!= null;
}
// 重写用于根据远程获取的JSON对象来设置内容的方法
@Override
public void setContentByRemoteJSON(JSONObject js) {
// 首先调用父类Task类的setContentByRemoteJSON方法进行一些通用的或者继承体系中已有的设置操作
super.setContentByRemoteJSON(js);
if (getNotes()!= null) {
try {
// 对通过getNotes获取到的内容先进行trim操作去除首尾空白字符然后解析为JSONObject
JSONObject metaInfo = new JSONObject(getNotes().trim());
// 从解析出的JSONObject中获取以GTaskStringUtils.META_HEAD_GTASK_ID为键对应的字符串值并赋值给mRelatedGid
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
} catch (JSONException e) {
// 如果在获取过程中出现JSONException异常通过Log.w记录警告日志并将mRelatedGid设为null
Log.w(TAG, "failed to get related gid");
mRelatedGid = null;
}
}
}
// 重写用于根据本地JSON对象设置内容的方法此方法在当前类的设计中不应该被调用
// 直接抛出IllegalAccessError异常并给出相应提示信息
@Override
public void setContentByLocalJSON(JSONObject js) {
// this function should not be called
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
}
// 重写获取本地JSON对象的方法此方法在当前类的设计中不应该被调用
// 直接抛出IllegalAccessError异常并给出相应提示信息
@Override
public JSONObject getLocalJSONFromContent() {
throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");
}
// 重写获取同步操作相关的方法,此方法在当前类的设计中不应该被调用
// 直接抛出IllegalAccessError异常并给出相应提示信息
@Override
public int getSyncAction(Cursor c) {
throw new IllegalAccessError("MetaData:getSyncAction should not be called");
}
}

@ -1,313 +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.
*/
// 包声明表明该类属于net.micode.notes.data包用于存放笔记相关的数据结构和常量定义等内容
package net.micode.notes.data;
import android.net.Uri;
// Notes类主要用于定义笔记应用中的各种常量、数据列接口以及特定类型笔记相关的内部类等起到统一管理和规范数据相关定义的作用
public class Notes {
// 用于定义内容提供器Content Provider的授权Authority字符串用于标识该应用的数据来源在使用Content Provider进行数据共享和访问时会用到
public static final String AUTHORITY = "micode_notes";
// 用于日志输出等场景的标签字符串,方便在代码中标记与笔记相关操作的日志信息,便于调试和查看运行情况
public static final String TAG = "Notes";
// 定义笔记的不同类型常量,方便区分不同性质的笔记或文件夹,例如普通笔记、文件夹以及系统相关特殊类型等
public static final int TYPE_NOTE = 0;
public static final int TYPE_FOLDER = 1;
public static final int TYPE_SYSTEM = 2;
/**
* 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;
public static final int ID_TEMPARAY_FOLDER = -1;
public static final int ID_CALL_RECORD_FOLDER = -2;
public static final int ID_TRASH_FOLER = -3;
// 用于在不同组件间传递数据的Intent额外数据的键Key比如在启动某个与笔记相关的Activity或者Service时可以通过这些键传递特定的参数此处是与提醒日期相关的键
public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date";
// 与笔记背景颜色ID相关的Intent额外数据的键用于传递或获取笔记背景颜色相关设置信息
public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id";
// 与笔记对应的桌面小部件ID相关的Intent额外数据的键可用于在不同组件间传递小部件相关的标识信息
public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id";
// 与笔记对应的桌面小部件类型相关的Intent额外数据的键例如可能区分不同尺寸、样式的小部件类型
public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type";
// 与文件夹ID相关的Intent额外数据的键用于传递文件夹相关的标识信息方便进行文件夹相关操作的参数传递
public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id";
// 与通话日期相关的Intent额外数据的键针对通话记录笔记等场景传递通话发生的日期信息
public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date";
// 定义无效的桌面小部件类型常量,用于表示不符合规范或者未初始化等情况下的小部件类型
public static final int TYPE_WIDGET_INVALIDE = -1;
// 定义一种桌面小部件类型常量可能表示2倍尺寸等特定样式的小部件具体含义需根据应用实际布局和设计确定
public static final int TYPE_WIDGET_2X = 0;
// 定义另一种桌面小部件类型常量可能表示4倍尺寸等特定样式的小部件同样具体样式和用途取决于应用本身的设定
public static final int TYPE_WIDGET_4X = 1;
// DataConstants内部类用于定义数据相关的常量比如不同类型笔记对应的MIME类型等方便统一管理和识别不同类型的数据内容
public static class DataConstants {
// 表示普通文本笔记对应的MIME类型其具体值来源于TextNote内部类中定义的CONTENT_ITEM_TYPE用于标识文本笔记类型的数据
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
// 表示通话记录笔记对应的MIME类型其值来自CallNote内部类中定义的CONTENT_ITEM_TYPE用于区分通话记录这种特殊类型的数据
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
}
/**
* Uri
* "content://" AUTHORITY"/note"
* 使Content Provider
*/
public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note");
/**
* Uri
* "content://" "/data"
* 访Content Provider使
*/
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data");
// NoteColumns接口用于定义笔记表note表中各个数据列的名称常量方便在数据库操作以及数据处理过程中统一引用保证列名的准确性和一致性
public interface NoteColumns {
/**
* ID
* <P> INTEGER </P>
*/
public static final String ID = "_id";
/**
* ID
* <P> INTEGER </P>
*/
public static final String PARENT_ID = "parent_id";
/**
* 便
* <P> INTEGER </P>
*/
public static final String CREATED_DATE = "created_date";
/**
*
* <P> INTEGER </P>
*/
public static final String MODIFIED_DATE = "modified_date";
/**
*
* <P> INTEGER </P>
*/
public static final String ALERTED_DATE = "alert_date";
/**
* 便
* <P> TEXT </P>
*/
public static final String SNIPPET = "snippet";
/**
* ID便
* <P> INTEGER </P>
*/
public static final String WIDGET_ID = "widget_id";
/**
* 2X4X
* <P> INTEGER </P>
*/
public static final String WIDGET_TYPE = "widget_type";
/**
* ID便
* <P> INTEGER </P>
*/
public static final String BG_COLOR_ID = "bg_color_id";
/**
* 01
* <P> INTEGER </P>
*/
public static final String HAS_ATTACHMENT = "has_attachment";
/**
* 便
* <P> INTEGER </P>
*/
public static final String NOTES_COUNT = "notes_count";
/**
* TYPE_NOTETYPE_FOLDERTYPE_SYSTEM
* <P> INTEGER </P>
*/
public static final String TYPE = "type";
/**
* ID便
* <P> INTEGER </P>
*/
public static final String SYNC_ID = "sync_id";
/**
* 便
* <P> INTEGER </P>
*/
public static final String LOCAL_MODIFIED = "local_modified";
/**
* ID
* <P> : INTEGER </P>
*/
public static final String ORIGIN_PARENT_ID = "origin_parent_id";
/**
* gtask IDGoogle Tasks
* <P> : TEXT </P>
*/
public static final String GTASK_ID = "gtask_id";
/**
*
* <P> : INTEGER </P>
*/
public static final String VERSION = "version";
}
// DataColumns接口用于定义存放笔记相关数据如附件、详细内容等的数据表data表中各数据列的名称常量与NoteColumns类似保证在数据库操作中对列名的准确引用
public interface DataColumns {
/**
* ID
* <P> INTEGER </P>
*/
public static final String ID = "_id";
/**
* MIMEMIME
* <P> Text </P>
*/
public static final String MIME_TYPE = "mime_type";
/**
* ID
* <P> INTEGER </P>
*/
public static final String NOTE_ID = "note_id";
/**
* NoteColumnsCREATED_DATE
* <P> INTEGER </P>
*/
public static final String CREATED_DATE = "created_date";
/**
* NoteColumnsMODIFIED_DATE便
* <P> INTEGER </P>
*/
public static final String MODIFIED_DATE = "modified_date";
/**
* MIME
* <P> TEXT </P>
*/
public static final String CONTENT = "content";
/**
* {@link #MIMETYPE}MIME
* <P> INTEGER </P>
*/
public static final String DATA1 = "data1";
/**
* MIME
* <P> INTEGER </P>
*/
public static final String DATA2 = "data2";
/**
* MIME
* <P> TEXT </P>
*/
public static final String DATA3 = "data3";
/**
* MIME
* <P> TEXT </P>
*/
public static final String DATA4 = "data3";
/**
* MIME使
* <P> TEXT </P>
*/
public static final String DATA5 = "data5";
}
// TextNote内部类继承自DataColumns接口主要用于定义文本笔记相关的特定数据列或常量进一步细化文本笔记的数据结构和相关操作属性
public static final class TextNote implements DataColumns {
/**
* 使10
* <P> Integer10 </P>
*/
public static final String MODE = DATA1;
public static final int MODE_CHECK_LIST = 1;
// 文本笔记对应的内容类型的MIME字符串用于标识一组文本笔记内容的类型通常在Content Provider相关操作中用于匹配查询等情况。
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note";
// 单个文本笔记项对应的内容类型的MIME字符串用于精确标识一条文本笔记内容的类型方便更细致的Content Provider操作如获取单条文本笔记数据等。
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note";
// 用于查询文本笔记相关数据的统一资源标识符Uri按照标准的Content Provider的Uri构建方式通过授权字符串和特定资源路径"/text_note")组成,作为访问文本笔记数据的入口。
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note");
}
// CallNote内部类它实现了DataColumns接口意味着它遵循该接口定义的数据列规范
// 主要用于定义通话记录笔记相关的特定数据属性、MIME类型以及对应的内容访问Uri等
// 方便在整个笔记应用的数据体系中对通话记录笔记这种特定类型进行专门的处理和操作。
public static final class CallNote implements DataColumns {
/**
*
* DataColumnsDATA1
* <P> INTEGER便 </P>
*/
public static final String CALL_DATE = DATA1;
/**
*
* 使DataColumnsDATA3
* <P> TEXT </P>
*/
public static final String PHONE_NUMBER = DATA3;
// 定义通话记录笔记对应的内容类型的MIME字符串用于标识一组通话记录笔记内容的类型。
// 在Content Provider相关操作中当需要查询、匹配一组通话记录笔记时可通过该MIME类型进行筛选判断
// 表明这是一种代表多个通话记录笔记的目录类型(通常对应数据库中的多条记录集合)。
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note";
// 定义单个通话记录笔记项对应的内容类型的MIME字符串用于精确标识一条通话记录笔记内容的类型。
// 相比于CONTENT_TYPE用于表示一组记录它更侧重于精准定位到单条通话记录笔记方便在Content Provider操作中进行获取单条数据等更细致的操作。
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note";
// 定义用于查询通话记录笔记相关数据的统一资源标识符Uri
// 按照安卓中Content Provider标准的Uri构建方式通过指定 "content://" 协议、应用的授权字符串AUTHORITY在外部类Notes中定义以及特定资源路径"/call_note")组成,
// 这个Uri作为访问通话记录笔记数据的入口地址在使用ContentResolver等进行数据查询、插入、更新、删除等操作时会用到以定位到通话记录笔记相关的数据资源。
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note");
}
}

@ -1,470 +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.
*/
// 包声明该类位于net.micode.notes.data包下用于处理笔记相关的数据库操作
package net.micode.notes.data;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
// NotesDatabaseHelper类继承自SQLiteOpenHelper用于管理和操作笔记应用的数据库
// 包括数据库的创建、升级以及相关表结构、触发器等的维护
public class NotesDatabaseHelper extends SQLiteOpenHelper {
// 数据库名称
private static final String DB_NAME = "note.db";
// 数据库版本号,用于数据库升级时的版本判断
private static final int DB_VERSION = 4;
// 定义内部接口TABLE用于存放数据库中表的名称常量方便统一管理和引用
public interface TABLE {
// 存放笔记基本信息的表名
public static final String NOTE = "note";
// 存放笔记相关数据(如附件等内容)的表名
public static final String DATA = "data";
}
// 用于日志输出的标签方便在Logcat中识别该类相关的日志信息
private static final String TAG = "NotesDatabaseHelper";
// 采用单例模式,保存该类的唯一实例
private static NotesDatabaseHelper mInstance;
// 创建note表的SQL语句定义了表的结构包括各个列名、数据类型、默认值以及主键等信息
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" +
")";
// 创建data表的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 ''" +
")";
// 创建基于note_id的索引的SQL语句用于提高在DATA表中根据note_id查询数据的效率
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
"CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
/**
* SQL
* notePARENT_IDID
*/
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
* notePARENT_IDID
* 0
*/
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
* noteID
*/
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
* noteID
* 0
*/
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";
/**
* {@link DataConstants#NOTE}SQL
* DATA
* SNIPPETCONTENT
*/
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";
/**
* {@link DataConstants#NOTE}SQL
* DATA
* SNIPPETCONTENT
*/
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";
/**
* {@link DataConstants#NOTE}SQL
* DATA
* SNIPPET
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
"CREATE TRIGGER update_note_content_on_delete " +
" AFTER delete ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=''" +
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
" END";
/**
* SQL
* noteDATANOTE_ID
*/
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
"CREATE TRIGGER delete_data_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.DATA +
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* SQL
* notenote
*/
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
* notePARENT_IDIDID
* IDID
*/
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";
// 构造函数调用父类SQLiteOpenHelper的构造函数来初始化数据库相关信息传入上下文、数据库名称、游标工厂此处为null以及数据库版本号
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
// 在数据库中创建note表的方法执行创建表的SQL语句重新创建note表相关的触发器并创建系统文件夹
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
createSystemFolder(db);
Log.d(TAG, "note table has been created");
}
// 重新创建note表相关触发器的方法先删除已存在的同名触发器如果有再重新创建所有定义的note表相关触发器
private void reCreateNoteTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update");
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);
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER);
db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER);
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER);
db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER);
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}
// 创建系统文件夹的方法向note表中插入不同类型的系统文件夹记录如通话记录文件夹、根文件夹、临时文件夹、回收站文件夹等
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
// 通话记录文件夹设置相关字段值并插入到note表
/**
* call record foler for call notes
*/
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
// 根文件夹清空ContentValues后重新设置字段值并插入到note表根文件夹是默认文件夹
/**
* root folder which is default folder
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
// 临时文件夹用于临时移动笔记等操作同样设置字段值后插入到note表
/**
* temporary folder which is used for moving note
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* note
* ID
* ContentValues
*/
/**
* root folder which is default folder
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* note
* ContentValuesID
*/
/**
* temporary folder which is used for moving note
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* note
* ContentValuesIDnote
*/
/**
* create trash folder
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}
/**
* data
* dataSQLdata
* note_iddata
*/
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
Log.d(TAG, "data table has been created");
}
/**
* data
*
* SQLdatanote
*/
private void reCreateDataTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete");
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
}
/**
* NotesDatabaseHelper
* mInstanceNotesDatabaseHelpermInstance
* 便
*
*/
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
}
return mInstance;
}
/**
* SQLiteOpenHelperonCreate
* notedata
* 使
*/
@Override
public void onCreate(SQLiteDatabase db) {
createNoteTable(db);
createDataTable(db);
}
/**
* SQLiteOpenHelperonUpgrade
*
*
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false;
boolean skipV2 = false;
// 如果旧版本号是1执行升级到版本2的操作并标记跳过单独的从版本2到版本3的升级步骤因为此次升级可能包含了后续版本升级的部分内容然后将旧版本号加1。
if (oldVersion == 1) {
upgradeToV2(db);
skipV2 = true; // this upgrade including the upgrade from v2 to v3
oldVersion++;
}
// 如果旧版本号是2且没有跳过版本2升级的标记执行升级到版本3的操作并设置需要重新创建触发器的标记为true之后将旧版本号加1。
if (oldVersion == 2 &&!skipV2) {
upgradeToV3(db);
reCreateTriggers = true;
oldVersion++;
}
// 如果旧版本号是3执行升级到版本4的操作然后将旧版本号加1。
if (oldVersion == 3) {
upgradeToV4(db);
oldVersion++;
}
// 如果需要重新创建触发器分别调用重新创建note表和data表相关触发器的方法确保触发器逻辑与升级后的数据库结构相匹配。
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
reCreateDataTableTriggers(db);
}
// 如果最终旧版本号与新版本号不相等,说明升级过程出现问题,抛出异常表示数据库升级失败。
if (oldVersion!= newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails");
}
}
/**
* 12
* notedata
* 12
*/
private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
createNoteTable(db);
createDataTable(db);
}
/**
* 23
* 使
* notegtask_idIDnote
* 23
*/
private void upgradeToV3(SQLiteDatabase db) {
// 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 ''");
// add a trash system folder
ContentValues values = new ContentValues();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}
/**
* 34
* ALTER TABLEnoteversion0
* 34
*/
private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Loading…
Cancel
Save