third commit

unknown 9 months ago
parent 642cdcb7a1
commit 158abe7b14

@ -26,267 +26,345 @@ import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
/**
* 便
*
* 便
*
* 便便
*/
public class NotesDatabaseHelper extends SQLiteOpenHelper {
// 数据库名称
private static final String DB_NAME = "note.db";
// 数据库版本号
private static final int DB_VERSION = 4;
/**
*
*
*/
public interface TABLE {
// 便签表,存储便签基本信息
public static final String NOTE = "note";
// 数据表,存储便签内容数据
public static final String DATA = "data";
}
private static final String TAG = "NotesDatabaseHelper";
// 单例实例
private static NotesDatabaseHelper mInstance;
/**
* 便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" +
NoteColumns.ID + " INTEGER PRIMARY KEY," + // 便签ID主键
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 父级ID文件夹ID
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + // 提醒日期
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + // 背景颜色ID
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," + // 小部件ID
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + // 小部件类型
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + // 同步ID
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + // 本地修改标记
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 原始父级ID
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + // Google任务ID
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + // 版本号
")";
/**
* SQL
* 便
*/
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," +
DataColumns.MIME_TYPE + " TEXT NOT NULL," +
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA1 + " INTEGER," +
DataColumns.DATA2 + " INTEGER," +
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
DataColumns.ID + " INTEGER PRIMARY KEY," + // 数据ID主键
DataColumns.MIME_TYPE + " TEXT NOT NULL," + // 数据MIME类型
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + // 关联的便签ID
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," + // 通用数据字段1整型
DataColumns.DATA2 + " INTEGER," + // 通用数据字段2整型
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + // 通用数据字段3文本
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + // 通用数据字段4文本
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + // 通用数据字段5文本
")";
/**
* NOTE_IDSQL
* 便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 + ");";
/**
* Increase folder's note count when move note to the folder
* 便便
* 便PARENT_ID便
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_update "+
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + // 增加新文件夹的便签计数
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
/**
* Decrease folder's note count when move note from folder
* 便便
* 便PARENT_ID便
*/
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" +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + // 减少原文件夹的便签计数
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + // 确保计数不会为负
" END";
/**
* 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" +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + // 增加文件夹的便签计数
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
/**
* 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" +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + // 减少文件夹的便签计数
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0;" +
" AND " + NoteColumns.NOTES_COUNT + ">0;" + // 确保计数不会为负
" END";
/**
* Update note's content when insert data with type {@link DataConstants#NOTE}
* 便便
* 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 + "'" +
" WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + // 当数据类型为NOTE时
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + // 用新内容更新便签摘要
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has changed
* 便便
* NOTE便
*/
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 + "'" +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + // 当原数据类型为NOTE时
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + // 用新内容更新便签摘要
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has deleted
* 便便
* NOTE便
*/
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 + "'" +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + // 当删除的数据类型为NOTE时
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=''" +
" SET " + NoteColumns.SNIPPET + "=''" + // 清空便签摘要
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
" END";
/**
* 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 +
" DELETE FROM " + TABLE.DATA + // 删除便签相关的所有数据
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* 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 +
" DELETE FROM " + TABLE.NOTE + // 删除文件夹中的所有便签
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* 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 +
" WHEN (old." + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + ")" + // 当文件夹被移入回收站时
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
" SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + "," + // 将包含的便签也移入回收站
" " + NoteColumns.ORIGIN_PARENT_ID + "=old." + NoteColumns.PARENT_ID + // 保存便签原始的父ID
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
*
*
* @param context
*/
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
/**
* 便
* 便
*
* @param db
*/
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
createSystemFolder(db);
Log.d(TAG, "note table has been created");
db.execSQL(CREATE_NOTE_TABLE_SQL); // 创建便签表
reCreateNoteTableTriggers(db); // 创建便签表相关的触发器
}
/**
* 便
*
*
* @param db
*/
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 increase_folder_count_on_insert");
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_INCREASE_FOLDER_COUNT_ON_INSERT_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);
}
/**
*
* 便
*
* @param db
*/
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
/**
* call record foler for call notes
*/
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
// 创建根文件夹
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
values.put(NoteColumns.CREATED_DATE, System.currentTimeMillis());
values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
db.insert(TABLE.NOTE, null, values);
/**
* root folder which is default folder
*/
// 创建临时文件夹
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
values.put(NoteColumns.CREATED_DATE, System.currentTimeMillis());
values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
db.insert(TABLE.NOTE, null, values);
/**
* temporary folder which is used for moving note
*/
// 创建通话记录文件夹
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
values.put(NoteColumns.CREATED_DATE, System.currentTimeMillis());
values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
db.insert(TABLE.NOTE, null, values);
/**
* create trash folder
*/
// 创建回收站文件夹
values.clear();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
values.put(NoteColumns.CREATED_DATE, System.currentTimeMillis());
values.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
db.insert(TABLE.NOTE, null, values);
}
/**
*
*
*
* @param db
*/
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");
db.execSQL(CREATE_DATA_TABLE_SQL); // 创建数据表
reCreateDataTableTriggers(db); // 创建数据表相关的触发器
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); // 创建数据表NOTE_ID索引
}
/**
*
*
*
* @param db
*/
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);
}
/**
*
*
* @param context
* @return
*/
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
@ -294,26 +372,44 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
return mInstance;
}
/**
*
*
*
* @param db
*/
@Override
public void onCreate(SQLiteDatabase db) {
createNoteTable(db);
createDataTable(db);
createNoteTable(db); // 创建便签表
createDataTable(db); // 创建数据表
createSystemFolder(db); // 创建系统文件夹
}
/**
*
*
*
* @param db
* @param oldVersion
* @param newVersion
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false;
boolean skipV2 = false;
// 根据旧版本执行相应的升级操作
if (oldVersion < 1) {
createNoteTable(db);
createDataTable(db);
createSystemFolder(db);
return;
}
if (oldVersion == 1) {
upgradeToV2(db);
skipV2 = true; // this upgrade including the upgrade from v2 to v3
oldVersion++;
}
if (oldVersion == 2 && !skipV2) {
if (oldVersion == 2) {
upgradeToV3(db);
reCreateTriggers = true;
oldVersion++;
}
@ -321,42 +417,44 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
upgradeToV4(db);
oldVersion++;
}
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
reCreateDataTableTriggers(db);
}
if (oldVersion != newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails");
}
}
/**
* 2
* GTASK_ID
*
* @param db
*/
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);
}
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
// 在便签表中添加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);
// 重新创建便签表触发器
reCreateNoteTableTriggers(db);
}
private void upgradeToV4(SQLiteDatabase db) {
/**
* 3
* VERSION
*
* @param db
*/
private void upgradeToV3(SQLiteDatabase db) {
// 在便签表中添加VERSION字段
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
/**
* 4
*
*
* @param db
*/
private void upgradeToV4(SQLiteDatabase db) {
// 删除可能存在的旧触发器
db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash");
// 创建新触发器
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}
}

@ -31,37 +31,47 @@ import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.tool.ResourceParser.NoteBgResources;
/**
* 便
*
* 便
* 便便
* WorkingNote便便
*/
public class WorkingNote {
// Note for the working note
// 底层Note对象用于数据操作
private Note mNote;
// Note Id
// 便签ID
private long mNoteId;
// Note content
// 便签内容
private String mContent;
// Note mode
// 便签模式(普通模式或清单模式)
private int mMode;
// 提醒日期
private long mAlertDate;
// 修改日期
private long mModifiedDate;
// 背景颜色ID
private int mBgColorId;
// 小部件ID
private int mWidgetId;
// 小部件类型
private int mWidgetType;
// 所属文件夹ID
private long mFolderId;
// 应用上下文
private Context mContext;
private static final String TAG = "WorkingNote";
// 是否已删除标记
private boolean mIsDeleted;
// 便签设置变更监听器
private NoteSettingChangedListener mNoteSettingStatusListener;
/**
*
* 便
*/
public static final String[] DATA_PROJECTION = new String[] {
DataColumns.ID,
DataColumns.CONTENT,
@ -72,6 +82,10 @@ public class WorkingNote {
DataColumns.DATA4,
};
/**
* 便
* 便
*/
public static final String[] NOTE_PROJECTION = new String[] {
NoteColumns.PARENT_ID,
NoteColumns.ALERTED_DATE,
@ -81,31 +95,30 @@ public class WorkingNote {
NoteColumns.MODIFIED_DATE
};
// 数据表列索引常量
private static final int DATA_ID_COLUMN = 0;
private static final int DATA_CONTENT_COLUMN = 1;
private static final int DATA_MIME_TYPE_COLUMN = 2;
private static final int DATA_MODE_COLUMN = 3;
// 便签表列索引常量
private static final int NOTE_PARENT_ID_COLUMN = 0;
private static final int NOTE_ALERTED_DATE_COLUMN = 1;
private static final int NOTE_BG_COLOR_ID_COLUMN = 2;
private static final int NOTE_WIDGET_ID_COLUMN = 3;
private static final int NOTE_WIDGET_TYPE_COLUMN = 4;
private static final int NOTE_MODIFIED_DATE_COLUMN = 5;
// New note construct
/**
* 便
*
* @param context
* @param folderId ID
*/
private WorkingNote(Context context, long folderId) {
mContext = context;
mAlertDate = 0;
mModifiedDate = System.currentTimeMillis();
mModifiedDate = System.currentTimeMillis(); // 设置当前时间为修改时间
mFolderId = folderId;
mNote = new Note();
mNoteId = 0;
@ -114,23 +127,35 @@ public class WorkingNote {
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
}
// Existing note construct
/**
* 便
*
* @param context
* @param noteId 便ID
* @param folderId ID
*/
private WorkingNote(Context context, long noteId, long folderId) {
mContext = context;
mNoteId = noteId;
mFolderId = folderId;
mIsDeleted = false;
mNote = new Note();
loadNote();
loadNote(); // 加载便签数据
}
/**
* 便
* 便
*/
private void loadNote() {
// 查询便签基本信息
Cursor cursor = mContext.getContentResolver().query(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
// 从查询结果中提取便签属性
mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN);
mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN);
mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN);
@ -143,10 +168,17 @@ public class WorkingNote {
Log.e(TAG, "No note with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note with id " + mNoteId);
}
// 加载便签内容数据
loadNoteData();
}
/**
* 便
* 便
*/
private void loadNoteData() {
// 查询便签内容数据
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] {
String.valueOf(mNoteId)
@ -155,12 +187,15 @@ public class WorkingNote {
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
// 根据MIME类型处理不同类型的数据
String type = cursor.getString(DATA_MIME_TYPE_COLUMN);
if (DataConstants.NOTE.equals(type)) {
// 文本便签数据
mContent = cursor.getString(DATA_CONTENT_COLUMN);
mMode = cursor.getInt(DATA_MODE_COLUMN);
mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN));
} else if (DataConstants.CALL_NOTE.equals(type)) {
// 通话记录便签数据
mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN));
} else {
Log.d(TAG, "Wrong note type with type:" + type);
@ -174,21 +209,46 @@ public class WorkingNote {
}
}
/**
* 便
* WorkingNote
*
* @param context
* @param folderId ID
* @param widgetId ID
* @param widgetType
* @param defaultBgColorId ID
* @return WorkingNote
*/
public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId);
note.setBgColorId(defaultBgColorId);
note.setWidgetId(widgetId);
note.setWidgetType(widgetType);
note.setBgColorId(defaultBgColorId); // 设置背景颜色
note.setWidgetId(widgetId); // 设置小部件ID
note.setWidgetType(widgetType); // 设置小部件类型
return note;
}
/**
* 便
* ID便
*
* @param context
* @param id 便ID
* @return WorkingNote
*/
public static WorkingNote load(Context context, long id) {
return new WorkingNote(context, id, 0);
}
/**
* 便
*
* @return
*/
public synchronized boolean saveNote() {
if (isWorthSaving()) {
// 如果便签不存在于数据库,创建新便签
if (!existInDatabase()) {
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
Log.e(TAG, "Create new note fail with id:" + mNoteId);
@ -196,172 +256,305 @@ public class WorkingNote {
}
}
// 同步便签数据到数据库
mNote.syncNote(mContext, mNoteId);
/**
* Update widget content if there exist any widget of this note
*/
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE
&& mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
// 设置便签内容
if (TextUtils.isEmpty(mContent)) {
mContent = "";
}
mNote.setTextData(DataColumns.CONTENT, mContent);
// 设置便签类型为文本便签
mNote.setTextData(DataColumns.MIME_TYPE, DataConstants.NOTE);
// 设置便签模式(普通或清单)
mNote.setTextData(DataColumns.DATA1, String.valueOf(mMode));
// 设置小部件ID和类型
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
// 设置背景颜色
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(mBgColorId));
// 设置提醒日期
mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate));
// 设置所属文件夹
mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(mFolderId));
return true;
} else {
return false;
}
return false;
}
/**
* 便
*
* @return 便
*/
public boolean existInDatabase() {
return mNoteId > 0;
}
/**
* 便
* 便
*
* @return 便
*/
private boolean isWorthSaving() {
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) {
if (mIsDeleted) {
return false;
} else if (!existInDatabase() && TextUtils.isEmpty(mContent)
&& mWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID && mAlertDate == 0) {
return false;
} else {
return true;
}
return true;
}
/**
* 便
*
* @param l
*/
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l;
}
/**
*
*
* @param date
* @param set
*/
public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) {
mAlertDate = date;
mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate));
}
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onClockAlertChanged(date, set);
// 触发监听器回调
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onClockAlertChanged(date, set);
}
}
}
/**
* 便
*
* @param mark
*/
public void markDeleted(boolean mark) {
mIsDeleted = mark;
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
}
}
/**
* ID
*
* @param id ID
*/
public void setBgColorId(int id) {
if (id != mBgColorId) {
mBgColorId = id;
// 触发监听器回调
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onBackgroundColorChanged();
}
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
}
}
/**
* 便
*
* @param mode 便
*/
public void setCheckListMode(int mode) {
if (mMode != mode) {
int oldMode = mMode;
mMode = mode;
// 触发监听器回调
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode);
mNoteSettingStatusListener.onCheckListModeChanged(oldMode, mode);
}
mMode = mode;
mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
}
}
/**
*
*
* @param type
*/
public void setWidgetType(int type) {
if (type != mWidgetType) {
mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
}
mWidgetType = type;
}
/**
* ID
*
* @param id ID
*/
public void setWidgetId(int id) {
if (id != mWidgetId) {
mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
}
mWidgetId = id;
}
/**
* 便
*
* @param text 便
*/
public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) {
mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent);
}
}
/**
* 便便
*
* @param phoneNumber
* @param callDate
*/
public void convertToCallNote(String phoneNumber, long callDate) {
mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate));
mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber);
mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER));
}
/**
* 便
*
* @return
*/
public boolean hasClockAlert() {
return (mAlertDate > 0 ? true : false);
return (mAlertDate > 0);
}
/**
* 便
*
* @return 便
*/
public String getContent() {
return mContent;
}
/**
*
*
* @return
*/
public long getAlertDate() {
return mAlertDate;
}
/**
*
*
* @return
*/
public long getModifiedDate() {
return mModifiedDate;
}
/**
* ID
*
* @return ID
*/
public int getBgColorResId() {
return NoteBgResources.getNoteBgResource(mBgColorId);
}
/**
* ID
*
* @return ID
*/
public int getBgColorId() {
return mBgColorId;
}
/**
* ID
*
* @return ID
*/
public int getTitleBgResId() {
return NoteBgResources.getNoteTitleBgResource(mBgColorId);
}
/**
* 便
*
* @return 便
*/
public int getCheckListMode() {
return mMode;
}
/**
* 便ID
*
* @return 便ID
*/
public long getNoteId() {
return mNoteId;
}
/**
* ID
*
* @return ID
*/
public long getFolderId() {
return mFolderId;
}
/**
* ID
*
* @return ID
*/
public int getWidgetId() {
return mWidgetId;
}
/**
*
*
* @return
*/
public int getWidgetType() {
return mWidgetType;
}
/**
* 便
* 便
*/
public interface NoteSettingChangedListener {
/**
* Called when the background color of current note has just changed
* 便
*/
void onBackgroundColorChanged();
/**
* Called when user set clock
*
*
* @param date
* @param set
*/
void onClockAlertChanged(long date, boolean set);
/**
* Call when user create note from widget
* 便
*/
void onWidgetChanged();
/**
* Call when switch between check list mode and normal mode
* @param oldMode is previous mode before change
* @param newMode is new mode
*
*
* @param oldMode
* @param newMode
*/
void onCheckListModeChanged(int oldMode, int newMode);
}

@ -18,10 +18,13 @@ package net.micode.notes.ui;
import android.content.Context;
import android.graphics.Rect;
import android.text.Editable;
import android.text.Layout;
import android.text.Selection;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.TextAppearanceSpan;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.util.Log;
@ -31,12 +34,20 @@ import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.MotionEvent;
import android.widget.EditText;
import android.widget.TextView;
import net.micode.notes.R;
import java.util.HashMap;
import java.util.Map;
/**
* 便
*
* EditText便
*
* 便UI便
*/
public class NoteEditText extends EditText {
private static final String TAG = "NoteEditText";
private int mIndex;
@ -54,49 +65,150 @@ public class NoteEditText extends EditText {
}
/**
* Call by the {@link NoteEditActivity} to delete or add edit text
*
* 便
*/
public interface OnTextViewChangeListener {
/**
* Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens
* and the text is null
*
*
* @param index
* @param text
*/
void onEditTextDelete(int index, String text);
/**
* Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER}
* happen
*
*
* @param index
* @param text
*/
void onEditTextEnter(int index, String text);
/**
* Hide or show item option when text change
*
*
* @param index
* @param hasText
*/
void onTextChange(int index, boolean hasText);
}
// 编辑框变化监听器
private OnTextViewChangeListener mOnTextViewChangeListener;
// 监听状态标志
private boolean mEnableTextChange;
/**
*
*
* @param context
*/
public NoteEditText(Context context) {
super(context, null);
super(context);
init();
}
/**
*
*
* @param context
* @param attrs
*/
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
/**
*
*
* @param context
* @param attrs
* @param defStyle
*/
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
/**
*
*
*/
private void init() {
mIndex = 0;
mEnableTextChange = true;
// 添加文本变化监听器
addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
// 启用文本变化监听时执行回调
if (mEnableTextChange && mOnTextViewChangeListener != null) {
mOnTextViewChangeListener.onTextChange(mIndex, !TextUtils.isEmpty(s));
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// 当删除所有文本且启用了监听时
if (mEnableTextChange && count > 0 && after == 0 && start == 0) {
// 如果删除的是所有文本,触发删除回调
if (mOnTextViewChangeListener != null) {
mOnTextViewChangeListener.onEditTextDelete(mIndex, s.toString());
}
}
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// 当按下回车键且启用了监听时
if (mEnableTextChange && count > 0 && before == 0 &&
s.charAt(start) == '\n' && start == 0) {
// 如果是在开始位置按下回车,触发回车回调
if (mOnTextViewChangeListener != null) {
mOnTextViewChangeListener.onEditTextEnter(mIndex, s.toString());
}
}
}
});
}
/**
*
*
* @param index
*/
public void setIndex(int index) {
mIndex = index;
}
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
mOnTextViewChangeListener = listener;
/**
*
*
* @return
*/
public int getIndex() {
return mIndex;
}
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.editTextStyle);
/**
*
*
* @param listener
*/
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
mOnTextViewChangeListener = listener;
}
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
/**
*
*
* @param enable
*/
public void setTextChangeEnable(boolean enable) {
mEnableTextChange = enable;
}
@Override
@ -167,16 +279,20 @@ public class NoteEditText extends EditText {
return super.onKeyUp(keyCode, event);
}
/**
* onFocusChanged
*
*/
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (mOnTextViewChangeListener != null) {
if (!focused && TextUtils.isEmpty(getText())) {
mOnTextViewChangeListener.onTextChange(mIndex, false);
} else {
mOnTextViewChangeListener.onTextChange(mIndex, true);
}
}
// 调用父类方法
super.onFocusChanged(focused, direction, previouslyFocusedRect);
// 当获得焦点且文本不为空时,设置光标位置
if (focused && !TextUtils.isEmpty(getText())) {
// 设置光标位置为文本末尾
Selection.setSelection(getText(), getText().length());
}
}
@Override
@ -214,4 +330,126 @@ public class NoteEditText extends EditText {
}
super.onCreateContextMenu(menu);
}
/**
* onTextContextMenuItem
*
*/
@Override
public boolean onTextContextMenuItem(int id) {
// 保存当前选择
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
// 执行上下文菜单操作
boolean result = super.onTextContextMenuItem(id);
// 根据操作ID处理选中文本的文本外观
switch (id) {
case android.R.id.cut:
// 剪切操作
break;
case android.R.id.paste:
case android.R.id.pasteAsPlainText:
// 粘贴操作,根据新文本长度设置选择区域
if (result) {
int newSelStart = getSelectionStart();
int newSelEnd = getSelectionEnd();
// 选中从选择开始到当前光标位置的文本
Selection.setSelection(getEditableText(), selStart, newSelEnd);
// 应用选定文本的外观
setSelectedTextAppearance(R.style.TextAppearanceNormal);
}
break;
case android.R.id.copyUrl:
case android.R.id.copy:
// 复制操作
break;
case android.R.id.selectAll:
// 全选操作,选中所有文本
if (result) {
setSelectedTextAppearance(R.style.TextAppearanceNormal);
}
break;
}
return result;
}
/**
*
*
* @param appearance ID
*/
private void setSelectedTextAppearance(int appearance) {
// 获取当前选择的开始和结束位置
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
// 如果有选中文本
if (selStart != selEnd) {
// 创建文本外观样式并应用到选中文本
Editable editable = getEditableText();
TextAppearanceSpan tas = new TextAppearanceSpan(getContext(), appearance);
editable.setSpan(tas, selStart, selEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
/**
*
*
* @return
*/
public String getCurrentLineText() {
int selStart = getSelectionStart();
Layout layout = getLayout();
if (layout != null) {
// 获取光标所在行
int line = layout.getLineForOffset(selStart);
// 获取行开始和结束位置
int lineStart = layout.getLineStart(line);
int lineEnd = layout.getLineEnd(line);
// 返回当前行文本
return getText().toString().substring(lineStart, lineEnd);
}
return "";
}
/**
*
*
* @return
*/
public String getTextBeforeLine() {
int selStart = getSelectionStart();
Layout layout = getLayout();
if (layout != null) {
// 获取光标所在行
int line = layout.getLineForOffset(selStart);
// 获取行开始位置
int lineStart = layout.getLineStart(line);
// 返回当前行之前的所有文本
return getText().toString().substring(0, lineStart);
}
return "";
}
/**
*
*
* @return
*/
public String getTextAfterLine() {
int selStart = getSelectionStart();
Layout layout = getLayout();
if (layout != null) {
// 获取光标所在行
int line = layout.getLineForOffset(selStart);
// 获取行结束位置
int lineEnd = layout.getLineEnd(line);
// 返回当前行之后的所有文本
return getText().toString().substring(lineEnd);
}
return "";
}
}

Loading…
Cancel
Save