();
}
@@ -74,11 +67,11 @@ public class Contact {
return sContactCache.get(phoneNumber);
}
- //构造匹配串,提取数字核心部分
+ //构造匹配串,提取电话号码数字核心部分
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
- //cursor是数据库游标,初始位置是-1;query把SQL拼装好后交给系统联系人Provider
+ //getcontentresolver.query()方法查询数据库,根据URI和电话号码匹配
Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME },
@@ -86,16 +79,17 @@ public class Contact {
new String[] { phoneNumber },
null);
- //指针移到第一行,成功返回true
+ //利用cursor获取联系人姓名
if (cursor != null && cursor.moveToFirst()) {
try {
String name = cursor.getString(0);
sContactCache.put(phoneNumber, name); //将号码-姓名键值对放进内存缓存
return name;
- } catch (IndexOutOfBoundsException e) { //捕获异常,索引超出列范围的情况,返回错误日志
+ } catch (IndexOutOfBoundsException e) {
+ //捕获索引越界异常
Log.e(TAG, " Cursor get string error " + e.toString());
return null;
- } finally { //无论是否发生异常都必须释放cursor。
+ } finally {
cursor.close();
}
} else { //查询失败,输出日志信息
diff --git a/src/notes/data/Notes.java b/src/notes/data/Notes.java
index 414c31f..34c26dd 100644
--- a/src/notes/data/Notes.java
+++ b/src/notes/data/Notes.java
@@ -25,14 +25,14 @@ package net.micode.notes.data;
import android.net.Uri;
/**
-*Notes是便签数据库类
-* 定义了URI常量、便签/文件夹类型常量、Intent扩展字段名、数据库接口、两种与业务实体
-* 本类所有字段均用static final修饰,说明字段不会变,可以直接用
+* Notes是便签数据库类
+* 定义了URI常量、便签/文件夹类型常量、Intent扩展字段名、数据库接口、两种业务实体
+* 所有字段均用static final修饰,静态变量,静态常量,静态方法,静态内部类。
*/
public class Notes {
public static final String AUTHORITY = "micode_notes"; //拼接URI的前缀
- public static final String TAG = "Notes"; //日志显示Notes
+ public static final String TAG = "Notes"; //日志显示的标记
/**
* 定义便签/文件夹/系统文件夹类型常量
@@ -55,7 +55,6 @@ public class Notes {
/**
* Intent实现各个组件(界面)之间数据的传递
- *
*/
public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; //提醒时间戳
public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; //便签背景颜色
@@ -65,7 +64,7 @@ public class Notes {
public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; //通话记录时间戳
/**
- * 定义桌面小部件类型常量
+ * 定义桌面小部件类型常量
*/
public static final int TYPE_WIDGET_INVALIDE = -1;
public static final int TYPE_WIDGET_2X = 0;
@@ -94,7 +93,7 @@ public class Notes {
/**
* NoteColumns是便签数据库列名接口
- * 声明便签信息列名,包括便签ID,父文件夹ID,创建日期,修改日期,提醒日期等。
+ * 声明便签信息列名,包括便签ID,父文件夹ID,创建日期,修改日期,提醒日期等
*/
public interface NoteColumns {
/**
@@ -247,7 +246,7 @@ public class Notes {
/**
- * 数据库列名接口,声明与便签内容相关的字段
+ * 数据库列名接口,声明与便签具体内容相关的字段
*/
public interface DataColumns {
/**
@@ -345,27 +344,27 @@ public class Notes {
* Mode to indicate the text in check list mode or not
* Type: Integer 1:check list mode 0: normal mode
*/
- public static final String MODE = DATA1; //清单模式or普通文本模式?
+ public static final String MODE = DATA1; //存储文本的清单模式或普通文本模式
public static final int MODE_CHECK_LIST = 1;
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; //MIME类型为集合(多条)
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; //MIME类型为批量笔记
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; //MIME类型为单条
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; //MIME类型为单条笔记
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note");
}
/**
* CallNote是通话记录便签实体常量类
- * 实现了DataColumns接口,与TextNote一起,体现了接口的多实现特性。
+ * TextNote和Callote实现DataColumns接口,体现接口的多实现特性
*/
public static final class CallNote implements DataColumns {
/**
* Call date for this record
* Type: INTEGER (long)
*/
- public static final String CALL_DATE = DATA1; //DATA1是数据库中的真实列名,将通话的时间戳存入DATA1列中
+ public static final String CALL_DATE = DATA1; //DATA1存储通话的时间戳
/**
* Phone number for this record
@@ -382,6 +381,7 @@ public class Notes {
/**
* 图片数据实体常量类
+ * 增加原因是新增了便签插入图片功能
*/
public static final class ImageData implements DataColumns {
/**
diff --git a/src/notes/data/NotesDatabaseHelper.java b/src/notes/data/NotesDatabaseHelper.java
index ee7df8c..1445fd7 100644
--- a/src/notes/data/NotesDatabaseHelper.java
+++ b/src/notes/data/NotesDatabaseHelper.java
@@ -32,32 +32,29 @@ import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
/**
-*便签数据库辅助类
-
- *负责以下功能:
+*便签数据库辅助类:
*
- * - 创建/升级 note 与 data 表
- * - 建立触发器维护文件夹便签数量、便签摘要
- * - 插入系统文件夹(根、临时、通话、回收站)
- * - 提供单例实例
+ * - 版本:7
+ * - 数据库名:note.db
+ * - 创建/升级note与data表
+ * - 建立更新和删除触发器维护文件夹便签数量和内容
+ * - 插入系统文件夹(根、临时、通话、回收站)
+ * - 提供单例实例
*
-
*
* @author 蒙程
- * @version {@link #DB_VERSION} 4
- * @since 2010-2011
+ * @version 1.0
+ * @since 2025-12-13
*/
public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
- *一、数据库基础常量
+ *一、声明数据库基础常量
*/
private static final String DB_NAME = "note.db";
private static final int DB_VERSION = 7;
-
- /**表明常量接口*/
public interface TABLE {
public static final String NOTE = "note";
@@ -66,16 +63,17 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "NotesDatabaseHelper";
- //类加载时不创建NotesDatabaseHelper实例(mInstance),真正需要使用数据库时才调用getInstance初始化,节省应用启动时的内存和资源开销。
+ //类加载时不创建实例单例,真正需要使用时才调用getInstance初始化,节省应用启动时的内存和资源开销。
private static NotesDatabaseHelper mInstance;
-
- //二、建表SQL,初始化note和data表,同时添加note_id_index索引列
/**
- * 结合在Notes中定义的NoteColumns初始化
- * 在Notes类里定义了NoteColumns,是便签数据库列名接口,ID、PARENT_ID等都是列名,表示把Notes数据库里声明的列名拿来用
- * NOT NULL约束强制列不接受NULL值,DEFAULT 0 表示默认值为0,如果字段设定NOT NULL,没有输入值时,DEFAULT后跟的默认值来填充
- * 这里的strftime是SQLite内置的时间、日期格式化函数,参数为输出格式(%s表示秒级Unix时间戳)、时间源(‘now'表示现在)
+ * 二、初始化Note和Data表中各列
+ * NoteColumns是 Notes类便签数据库列名接口,ID、PARENT_ID等都是列名
+ *
+ * NOT NULL约束强制列不接受NULL值,DEFAULT 0 表示默认值为0,
+ * 如果字段设定 NOT NULL,没有输入值时,用DEFAULT后的默认值填充。
+ *
+ * strftime是 SQLite内置的时间、日期格式化函数,参数为输出格式(%s表示秒级Unix时间戳)、时间源(‘now'表示现在)
*/
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" + //开始建表,表名是TABLE.NOTE(note)
@@ -105,8 +103,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* 创建 Data 表 SQL,结合在Notes中定义的DataColumns初始化
*
- * 外键:{@link DataColumns#NOTE_ID} 指向 note.id
- * 通用列 data1~data5 含义由 {@link DataColumns#MIME_TYPE} 决定。
+ * 外键:{@link DataColumns#NOTE_ID} 指向 note.id
+ * 通用列 data1~data5 含义由 {@link DataColumns#MIME_TYPE} 决定。
*
*/
private static final String CREATE_DATA_TABLE_SQL =
@@ -127,20 +125,19 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
")";
/**
- *在data(NOTE_ID)这一列上创建名为note_id_index的索引(如果该索引不存在)
- * 便于执行SELECT * FROM data WHERE note_id=?之类的查询语句
+ * 在data表中如果不存在 note_id索引列,则创建
+ * 便于执行"SELECT * FROM data WHERE 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 + ");";
-
- //三、创建Note表触发器,在文件夹下便签数量变化时自动增减便签数量(notes_count)的值
/**
+ * 三、创建 Note表触发器,文件夹下便签数量变化时自动增减便签数量的值
* Increase folder's note count when move note to the folder
- * 创建触发器,名字叫increase_folder_count_on_update
- * 在note表的parent_id列更新后
- * 执行触发器体,更新Note表,设置notes_count=notes_count+1,在id=new.parent_id的地方
+ * 创建触发器 increase_folder_count_on_update
+ * 在 note表的 parent_id列更新后
+ * 执行触发器体,更新 Note表,设置 notes_count=notes_count+1,在 id=new.parent_id的地方
* 此处用于自动更新父文件夹下的便签数量
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
@@ -190,11 +187,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" AND " + NoteColumns.NOTES_COUNT + ">0;" +
" END";
- //四、Data 表触发器:自动同步便签摘要(snippet)
/**
+ * 四、Data 表触发器:自动同步便签摘要(snippet)
* Update note's content when insert data with type {@link DataConstants#NOTE}
- * 仅当新插入的DATA记录的mime_type字段值为note(笔记)类型时,触发器才会执行后续逻辑,若插入的是其他数据类型,比如图片,则不触发
- * 执行触发器,将note表里的snippet列值更新为新纪录的content值,且仅更新note表里主键id=新纪录note_id的行
+ * 启动触发器:新插入的记录 mime_type字段值为note类型(其他数据类型,比如图片,则不触发)
+ * 执行触发器:根据 note_id将 Note表里相应的snippet列值更新为 DataColumn表中的content列值
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
"CREATE TRIGGER update_note_content_on_insert " +
@@ -234,8 +231,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Delete data belong to note which has been deleted
- * 当从note表删除一条笔记记录后,通过data表的note_id与note表的id关联
- * 自动删除data表中所有与这条被删笔记关联的记录,笔记-笔记内容
+ * 当从 note表删除一条笔记记录后,通过 note表的id与 data表的 note_id关联
+ * 自动删除data表中所有与这条被删笔记关联的记录
*/
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
"CREATE TRIGGER delete_data_on_delete " +
@@ -247,7 +244,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* Delete notes belong to folder which has been deleted
- * 当从note表里删除一条记录后,自动级联删除note表中所有parent_id等于被删记录id的子记录
+ * 从note表里删除一条笔记,自动级联删除note表中所有parent_id为该记录id的子记录
+ * 比如:删除一个文件夹,该文件夹下的所有笔记都会被删除
*/
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
"CREATE TRIGGER folder_delete_notes_on_delete " +
@@ -271,7 +269,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
" END";
/**
- * Android开发中自定义的数据库辅助类的构造方法,作用是初始化,指定要创建/管理的数据库名称、版本号等核心参数
+ * Android开发中自定义的数据库辅助类的构造方法,作用是初始化要创建/管理的数据库名称、版本号等核心参数
* @param context 上下文,提供应用运行的环境信息,如访问资源、数据库文件路径、系统服务等。
*/
public NotesDatabaseHelper(Context context) {
@@ -279,13 +277,15 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/** super是调用的父类(SQLiteOpenHelper)构造方法
* @param context 父类通过context确定数据库文件的存储位置
* @param DB_NAME 数据库文件名
- * @param null 创建数据库查询的游标(cursor),传null表示默认
- * @param DB_VERSION自定义常量,数据库版本号
+ * @param null 创建数据库查询的游标(cursor),null表示默认(默认值为 1,表示只读)
+ * @param DB_VERSION 自定义常量,数据库版本号
*/
super(context, DB_NAME, null, DB_VERSION);
}
- //完成note表的全量初始化
+ /**
+ * 创建Note表
+ */
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL); //执行SQL语句创建note表
reCreateNoteTableTriggers(db); //重建该表关联的触发器
@@ -293,7 +293,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
Log.d(TAG, "note table has been created"); //打印日志,确认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");
@@ -312,7 +314,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}
- //向note表插入四个系统默认文件夹:通话记录、根、临时、回收站。保证应用首次启动时有基础的文件夹结构。
+ /**
+ * 创建系统文件夹
+ * 向note表插入四个系统默认文件夹:通话记录、根、临时、回收站.保证应用首次启动时有基础的文件夹结构
+ * @param db
+ */
private void createSystemFolder(SQLiteDatabase db) {
//ContentValues类用于存储键值对
ContentValues values = new ContentValues();
@@ -349,6 +355,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.insert(TABLE.NOTE, null, values);
}
+ /**
+ * 创建 Data 表
+ */
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
@@ -367,10 +376,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
}
/**
- * synchronized同步关键字,保证多线程安全,避免多个线程同时调用该方法时,进入if分支,创建多个实例
- * getInstance函数用于获取唯一实例
+ * synchronized同步关键字,保证多线程安全,避免多个线程同时调用该方法时创建多个实例
+ * getInstance方法用于获取唯一实例
*/
-
static synchronized NotesDatabaseHelper getInstance(Context context) {
//首次调用该方法时,才创建实例;若已创建,则直接复用
if (mInstance == null) {
@@ -379,13 +387,24 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
return mInstance;
}
- //@override是Java中的一种注解,用于明确表示子类的方法是对父类方法的重写,实现多态性
+ /**
+ * onCreate方法在数据库第一次创建时调用
+ * "@override"表示子类重写父类方法,实现多态性
+ */
@Override
public void onCreate(SQLiteDatabase db) {
- createNoteTable(db); //初始化笔记表
- createDataTable(db); //初始化数据表
+ createNoteTable(db); //初始化笔记表Note
+ createDataTable(db); //初始化数据表Data
}
+ /**
+ * onUpgrade方法在数据库升级时调用
+ *
+ * 什么时候需要更新数据库版本?
+ *
数据库结构发生改变,比如添加字段 rich_text_format
+ * 数据库结构没有改变,但数据结构发生改变, 比如增加了富文本样式
+ *
+ */
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false;
@@ -408,25 +427,25 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
oldVersion++;
}
- if (oldVersion == 4) {
- upgradeToV5(db);
- oldVersion++;
- }
+ if (oldVersion == 4) {
+ upgradeToV5(db);
+ oldVersion++;
+ }
- if (oldVersion == 5) {
- upgradeToV6(db);
- oldVersion++;
- }
+ if (oldVersion == 5) {
+ upgradeToV6(db);
+ oldVersion++;
+ }
- if (oldVersion == 6) {
- upgradeToV7(db);
- oldVersion++;
- }
+ if (oldVersion == 6) {
+ upgradeToV7(db);
+ oldVersion++;
+ }
- if (oldVersion == 7) {
- upgradeToV8(db);
- oldVersion++;
- }
+ if (oldVersion == 7) {
+ upgradeToV8(db);
+ oldVersion++;
+ }
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
@@ -439,7 +458,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
}
}
- //v1到v2的升级,删除旧的note data表,清空所有用户数据,重建新的
+ /**
+ * v1到v2的升级,删除旧的note data表,清空所有用户数据,重建新的
+ */
private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); //执行具体的SQL语句,删除旧的note表
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); //删除旧的data表
@@ -447,7 +468,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
createDataTable(db);
}
- //v2到v3的升级,清除无用触发器,新增gtask_id列,新增回收站文件夹
+ /**
+ * v2到v3的升级,清除无用触发器,Note表新增 gtask_id列,新增回收站文件夹
+ */
private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
@@ -463,37 +486,49 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.insert(TABLE.NOTE, null, values);
}
- //v3到v4的升级,为note表新增version列,且约束非空,默认为0
+ /**
+ *v3到 v4的升级,为 note表新增 version列,且约束非空,默认为0
+ */
private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
- //v4到v5的升级,为data表新增rich_text_format列,用于存储富文本格式信息
+ /**
+ * v4到v5的升级,为 data表新增 rich_text_format列,用于存储富文本格式信息
+ */
private void upgradeToV5(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.DATA + " ADD COLUMN rich_text_format TEXT NOT NULL DEFAULT ''");
}
- //v5到v6的升级,为data表新增用于存储图片路径的列
+ /**
+ * v5到v6的升级,为 data表新增用于存储图片路径的列
+ */
private void upgradeToV6(SQLiteDatabase db) {
- // 为data表添加一个专门存储图片路径的列
db.execSQL("ALTER TABLE " + TABLE.DATA + " ADD COLUMN image_path TEXT NOT NULL DEFAULT ''");
}
-
- //v6到v7的升级,为note表新增位置提醒相关的列
+
+ /**
+ * v6到v7的升级,为 note表新增位置提醒相关的列
+ */
private void upgradeToV7(SQLiteDatabase db) {
- // 为note表添加位置提醒相关的列
- db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LATITUDE + " REAL NOT NULL DEFAULT 0");
- db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LONGITUDE + " REAL NOT NULL DEFAULT 0");
- db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_RADIUS + " REAL NOT NULL DEFAULT 0");
- db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LOCATION_NAME + " TEXT NOT NULL DEFAULT ''");
+ db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LATITUDE + " REAL NOT NULL DEFAULT 0"); //纬度
+ db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LONGITUDE + " REAL NOT NULL DEFAULT 0"); //经度
+ db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_RADIUS + " REAL NOT NULL DEFAULT 0"); //半径
+ db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ALERT_LOCATION_NAME + " TEXT NOT NULL DEFAULT ''"); //地点名称
}
-
- //v7到v8的升级,为note表新增隐私锁相关的列
+
+ /**
+ * v7到v8的升级,为 note表新增隐私锁相关的列
+ */
private void upgradeToV8(SQLiteDatabase db) {
- // 为note表添加隐私锁相关列
- db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.LOCKED + " INTEGER NOT NULL DEFAULT 0"); // 锁定状态:0-未锁定,1-已锁定
- db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.LOCK_TYPE + " INTEGER NOT NULL DEFAULT 0"); // 锁类型:0-无锁,1-密码锁,2-手势锁
- db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ENCRYPTED_PASSWORD + " TEXT NOT NULL DEFAULT ''"); // 加密后的密码
+ // 锁定状态:0-未锁定,1-已锁定
+ db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.LOCKED + " INTEGER NOT NULL DEFAULT 0");
+
+ // 锁类型:0-无锁,1-密码锁,2-手势锁
+ db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.LOCK_TYPE + " INTEGER NOT NULL DEFAULT 0");
+
+ // 加密后的密码
+ db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.ENCRYPTED_PASSWORD + " TEXT NOT NULL DEFAULT ''");
}
-}
+}
\ No newline at end of file
diff --git a/src/notes/ui/LoginRegisterActivity.java b/src/notes/ui/LoginRegisterActivity.java
index b2ac984..d797bd8 100644
--- a/src/notes/ui/LoginRegisterActivity.java
+++ b/src/notes/ui/LoginRegisterActivity.java
@@ -3,7 +3,6 @@ package net.micode.notes.ui;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
-
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
@@ -47,6 +46,8 @@ public class LoginRegisterActivity extends AppCompatActivity {
// 密码可见性状态
private boolean isPasswordVisible = false;
+
+ private static final int ROOT_AUTH_REQUEST_CODE = 1001;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -130,7 +131,8 @@ public class LoginRegisterActivity extends AppCompatActivity {
if (isLoginMode) {
performLogin();
} else {
- performRegister();
+ // 注册前需要验证根用户权限
+ showRootAuthDialog();
}
}
});
@@ -144,6 +146,15 @@ public class LoginRegisterActivity extends AppCompatActivity {
});
}
+ /**
+ * 显示根用户权限验证对话框
+ */
+ private void showRootAuthDialog() {
+ Intent intent = new Intent(this, SplashActivity.class);
+ intent.putExtra("SHOW_ROOT_AUTH_DIALOG", true);
+ startActivityForResult(intent, ROOT_AUTH_REQUEST_CODE);
+ }
+
/**
* 更新UI以适应当前模式(登录或注册)
*/
@@ -323,6 +334,24 @@ public class LoginRegisterActivity extends AppCompatActivity {
})
.show();
}
-
-
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (requestCode == ROOT_AUTH_REQUEST_CODE) {
+ if (resultCode == RESULT_OK && data != null) {
+ boolean authResult = data.getBooleanExtra("ROOT_AUTH_RESULT", false);
+ if (authResult) {
+ // 根用户验证成功,执行注册
+ performRegister();
+ } else {
+ Toast.makeText(this, "根用户验证失败,无法注册新用户", Toast.LENGTH_SHORT).show();
+ }
+ } else if (resultCode == RESULT_CANCELED) {
+ // 用户取消了验证
+ Toast.makeText(this, "已取消根用户验证", Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/notes/ui/SplashActivity.java b/src/notes/ui/SplashActivity.java
index 14938cf..9b72136 100644
--- a/src/notes/ui/SplashActivity.java
+++ b/src/notes/ui/SplashActivity.java
@@ -3,24 +3,16 @@ package net.micode.notes.ui;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import net.micode.notes.R;
+import net.micode.notes.tool.UserManager;
public class SplashActivity extends AppCompatActivity {
private static final int SPLASH_DURATION = 3000; // 3秒
- private static final int TEXT_FADE_IN_DELAY = 2000; // 2秒后文字淡入
-
- // 动画完成回调接口
- public interface OnSplashCompleteListener {
- void onSplashComplete();
- }
// 启动页创建,初始化动画界面和跳转逻辑
@Override
@@ -28,37 +20,29 @@ public class SplashActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
- ImageView logo = findViewById(R.id.splash_logo);
TextView text = findViewById(R.id.splash_text);
- // 加载文字滑动动画
- Animation slideUpAnimation = AnimationUtils.loadAnimation(this, R.anim.text_slide_up);
-
- // 2秒后显示文字动画
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- text.setVisibility(android.view.View.VISIBLE);
- text.startAnimation(slideUpAnimation);
- }
- }, TEXT_FADE_IN_DELAY);
-
- // 3秒后跳转到登录界面
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- onSplashComplete();
+ // 开始淡入动画
+ WaveAnimation.applyFadeInAnimation(text);
+
+ // 3秒后根据登录状态跳转
+ new Handler().postDelayed(() -> {
+ UserManager userManager = UserManager.getInstance(this);
+ boolean isLoggedIn = userManager.isLoggedIn();
+
+ if (isLoggedIn) {
+ // 已登录,直接进入主界面
+ Intent intent = new Intent(SplashActivity.this, NotesListActivity.class);
+ startActivity(intent);
+ } else {
+ // 未登录,跳转到注册登录界面
+ Intent intent = new Intent(SplashActivity.this, LoginRegisterActivity.class);
+ startActivity(intent);
}
+ finish();
+ overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}, SPLASH_DURATION);
}
-
- // 动画完成回调方法
- private void onSplashComplete() {
- Intent intent = new Intent(SplashActivity.this, LoginRegisterActivity.class);
- startActivity(intent);
- finish(); // 结束启动页,防止用户返回到此页面
- overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
- }
// 处理屏幕旋转等配置变更
@Override
diff --git a/src/notes/ui/WaveAnimation.java b/src/notes/ui/WaveAnimation.java
new file mode 100644
index 0000000..3963599
--- /dev/null
+++ b/src/notes/ui/WaveAnimation.java
@@ -0,0 +1,76 @@
+package net.micode.notes.ui;
+
+import android.animation.ValueAnimator;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.TextView;
+
+public class WaveAnimation {
+
+ // 整行文字从左到右淡入显示动画
+ public static void applyFadeInAnimation(TextView textView) {
+ // 设置初始状态为完全透明
+ textView.setAlpha(0f);
+ textView.setVisibility(android.view.View.VISIBLE);
+
+ // 创建透明度渐变动画
+ ValueAnimator fadeInAnimator = ValueAnimator.ofFloat(0f, 1f);
+ fadeInAnimator.setDuration(2000); // 2秒淡入效果
+ fadeInAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ fadeInAnimator.addUpdateListener(animation -> {
+ float alpha = (float) animation.getAnimatedValue();
+ textView.setAlpha(alpha);
+ });
+
+ // 创建从左到右的滑入效果
+ ValueAnimator slideInAnimator = ValueAnimator.ofFloat(-100f, 0f);
+ slideInAnimator.setDuration(1500); // 1.5秒滑入
+ slideInAnimator.setInterpolator(new android.view.animation.OvershootInterpolator());
+
+ slideInAnimator.addUpdateListener(animation -> {
+ float translationX = (float) animation.getAnimatedValue();
+ textView.setTranslationX(translationX);
+ });
+
+ // 同时启动两个动画
+ fadeInAnimator.start();
+ slideInAnimator.start();
+ }
+
+ // 从左到右逐字淡入效果(如果需要的话)
+ public static void applyCharByCharFadeIn(TextView textView) {
+ String text = textView.getText().toString();
+ int length = text.length();
+
+ // 设置初始状态
+ textView.setAlpha(0f);
+ textView.setVisibility(android.view.View.VISIBLE);
+
+ // 为整行文字创建统一的淡入动画
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ animator.setDuration(2500); // 总时长2.5秒
+ animator.setInterpolator(new android.view.animation.DecelerateInterpolator());
+
+ animator.addUpdateListener(animation -> {
+ float progress = (float) animation.getAnimatedValue();
+ textView.setAlpha(progress);
+
+ // 添加轻微的缩放效果
+ float scale = 0.8f + (progress * 0.2f); // 从0.8倍放大到1倍
+ textView.setScaleX(scale);
+ textView.setScaleY(scale);
+ });
+
+ animator.start();
+ }
+
+ // 兼容旧版本的方法名 - 使用新的淡入效果
+ public static void applyComplexWaveAnimation(TextView textView) {
+ applyFadeInAnimation(textView);
+ }
+
+ // 兼容旧版本的另一个方法名
+ public static void applyCharWaveAnimation(TextView textView) {
+ applyCharByCharFadeIn(textView);
+ }
+}
\ No newline at end of file