Compare commits

...

4 Commits

Author SHA1 Message Date
xxxx 48e03e4daf 注释代码
2 months ago
xxxx f03bf9a43d 注释代码
2 months ago
xxxx be3e994de6 注释代码
2 months ago
xxxx 4c99398b86 注释代码
2 months ago

@ -0,0 +1,313 @@
/*
* 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.
*/
// 导入所需的Android和Java类
package net.micode.notes.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.view.Window;
import android.view.WindowManager;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import java.io.IOException;
// 声明AlarmAlertActivity类继承自Activity并实现OnClickListener和OnDismissListener接口
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
// 声明成员变量
private long mNoteId; // 笔记ID
private String mSnippet; // 笔记摘要
private static final int SNIPPET_PREW_MAX_LEN = 60; // 摘要最大长度
MediaPlayer mPlayer; // 媒体播放器,用于播放闹钟声音
// onCreate方法Activity创建时调用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); // 请求无标题窗口
final Window win = getWindow(); // 获取当前窗口
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); // 允许在锁屏时显示
// 如果屏幕未点亮,则添加一系列标志以点亮屏幕并保持其开启
if (!isScreenOn()) {
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
}
Intent intent = getIntent(); // 获取启动此Activity的Intent
try {
// 从Intent中提取笔记ID
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1));
// 从数据库中获取笔记摘要
mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId);
// 如果摘要长度超过最大长度,则截断并添加省略号
mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info)
: mSnippet;
} catch (IllegalArgumentException e) {
e.printStackTrace(); // 捕获异常并打印堆栈跟踪
return; // 如果发生异常,则退出方法
}
mPlayer = new MediaPlayer(); // 初始化媒体播放器
// 检查笔记是否在数据库中且类型为普通笔记
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
showActionDialog(); // 显示操作对话框
playAlarmSound(); // 播放闹钟声音
} else {
finish(); // 如果笔记不存在则结束Activity
}
}
// 检查屏幕是否点亮
private boolean isScreenOn() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn();
}
// 播放闹钟声音
private void playAlarmSound() {
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); // 获取默认的闹钟铃声URI
// 获取静音模式下受影响的音频流类型
int silentModeStreams = Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
// 根据静音模式设置音频流类型
if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) {
mPlayer.setAudioStreamType(silentModeStreams);
} else {
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
}
try {
// 设置媒体播放器的数据源并开始播放
mPlayer.setDataSource(this, url);
mPlayer.prepare();
mPlayer.setLooping(true);
mPlayer.start();
} catch (IllegalArgumentException | SecurityException | IllegalStateException | IOException e) {
e.printStackTrace(); // 捕获并打印各种异常
}
}
// 显示操作对话框
private void showActionDialog() {
AlertDialog.Builder dialog = new AlertDialog.Builder(this); // 创建对话框构建器
dialog.setTitle(R.string.app_name); // 设置对话框标题
dialog.setMessage(mSnippet); // 设置对话框消息
dialog.setPositiveButton(R.string.notealert_ok, this); // 设置正面按钮及其点击事件监听器
if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this); // 如果屏幕点亮,则设置负面按钮及其点击事件监听器
}
dialog.show().setOnDismissListener(this); // 显示对话框并设置其关闭事件监听器
}
// 点击对话框按钮时调用
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_NEGATIVE: // 如果点击的是负面按钮
Intent intent = new Intent(this, NoteEditActivity.class); // 创建跳转到NoteEditActivity的Intent
intent.setAction(Intent.ACTION_VIEW); // 设置Intent动作为查看
intent.putExtra(Intent.EXTRA_UID, mNoteId); // 将笔记ID作为额外数据添加到Intent中
startActivity(intent); // 启动NoteEditActivity
break;
default:
break;
}
}
// 对话框关闭时调用
public void onDismiss(DialogInterface dialog) {
stopAlarmSound(); // 停止播放闹钟声音
finish(); // 结束Activity
}
// 停止播放闹钟声音
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop(); // 停止媒体播放器
mPlayer.release(); // 释放媒体播放器资源
mPlayer = null; // 将媒体播放器引用置为空
}
}
}

@ -0,0 +1,131 @@
/*
* 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.
*/
// 导入所需的Android和应用程序特定的包
package net.micode.notes.ui;
import android.app.AlarmManager; // 导入AlarmManager类用于设置闹钟
import android.app.PendingIntent; // 导入PendingIntent类用于表示一个将要执行的操作
import android.content.BroadcastReceiver; // 导入BroadcastReceiver类用于接收广播消息
import android.content.ContentUris; // 导入ContentUris类用于生成内容URI
import android.content.Context; // 导入Context类表示应用程序环境的全局信息
import android.content.Intent; // 导入Intent类用于不同组件之间的通信
import android.database.Cursor; // 导入Cursor类用于遍历查询结果
import net.micode.notes.data.Notes; // 导入Notes类包含NoteProvider的相关常量
import net.micode.notes.data.Notes.NoteColumns; // 导入NoteColumns接口包含Note表的列名
// 定义一个继承自BroadcastReceiver的类用于初始化闹钟
public class AlarmInitReceiver extends BroadcastReceiver {
// 定义要从Note表中查询的列
private static final String [] PROJECTION = new String [] {
NoteColumns.ID, // Note的ID
NoteColumns.ALERTED_DATE // Note的提醒日期
};
// 定义查询结果集中列的索引
private static final int COLUMN_ID = 0; // ID列的索引
private static final int COLUMN_ALERTED_DATE = 1; // 提醒日期列的索引
// 当接收到广播时调用的方法
@Override
public void onReceive(Context context, Intent intent) {
long currentDate = System.currentTimeMillis(); // 获取当前时间(毫秒)
// 从Note表中查询提醒日期大于当前时间且类型为Note的记录
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE,
new String[] { String.valueOf(currentDate) }, // 替换查询语句中的?为当前时间的字符串表示
null); // 不对结果进行排序
if (c != null) { // 如果查询结果不为空
if (c.moveToFirst()) { // 移动到查询结果的第一条记录
do {
long alertDate = c.getLong(COLUMN_ALERTED_DATE); // 获取当前记录的提醒日期
Intent sender = new Intent(context, AlarmReceiver.class); // 创建一个Intent指向AlarmReceiver
// 设置Intent的数据为Note的URI并附加Note的ID
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID)));
// 创建一个PendingIntent表示在指定时间执行的操作
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0);
// 获取AlarmManager实例用于设置闹钟
AlarmManager alermManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
// 设置一个闹钟在指定的提醒日期alertDate触发AlarmReceiver
alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext()); // 移动到下一条记录,直到遍历完所有结果
}
c.close(); // 关闭Cursor释放资源
}
}
}

@ -0,0 +1,65 @@
/*
* 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.
*/
// 导入必要的Android框架类
package net.micode.notes.ui; // 指定这个类所在的包名
import android.content.BroadcastReceiver; // 导入BroadcastReceiver类用于接收广播
import android.content.Context; // 导入Context类代表应用的当前状态包括资源和类以及调用应用级操作
import android.content.Intent; // 导入Intent类用于不同组件之间的通信
// 定义一个名为AlarmReceiver的类它继承自BroadcastReceiver
public class AlarmReceiver extends BroadcastReceiver {
// 重写onReceive方法这是BroadcastReceiver的核心方法用于接收广播
@Override
public void onReceive(Context context, Intent intent) {
// 设置Intent的目标Activity为AlarmAlertActivity这意味着当广播被接收时将启动这个Activity
intent.setClass(context, AlarmAlertActivity.class);
// 添加一个标志指定这个Activity应该在一个新的任务中启动
// 这对于从非Activity的上下文中启动Activity如BroadcastReceiver是必要的
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 使用上下文context启动Intent指定的Activity
// 这将导致AlarmAlertActivity被创建并显示在屏幕上
context.startActivity(intent);
}
}

@ -0,0 +1,822 @@
/*
* 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.tool;
import android.content.Context; // 引入Context类它是Android应用的全局信息的接口
import android.database.Cursor; // 引入Cursor类用于遍历数据库查询结果
import android.os.Environment; // 引入Environment类提供有关Android设备环境的访问
import android.text.TextUtils; // 引入TextUtils类包含一些静态方法用于处理字符串
import android.text.format.DateFormat; // 引入DateFormat类用于格式化日期和时间
import android.util.Log; // 引入Log类用于记录日志信息
import net.micode.notes.R; // 引入R类它是一个包含应用资源引用的类
import net.micode.notes.data.Notes; // 引入Notes类它可能是一个包含数据库访问逻辑的类
import net.micode.notes.data.Notes.DataColumns; // 引入DataColumns接口定义了数据表列名
import net.micode.notes.data.Notes.DataConstants; // 引入DataConstants类可能包含一些数据相关的常量
import net.micode.notes.data.Notes.NoteColumns; // 引入NoteColumns接口定义了笔记表列名
import java.io.File; // 引入File类表示文件和目录路径名的抽象表示形式
import java.io.FileNotFoundException; // 引入FileNotFoundException类当文件未找到时抛出
import java.io.FileOutputStream; // 引入FileOutputStream类用于写入文件数据
import java.io.IOException; // 引入IOException类是输入输出异常的超类
import java.io.PrintStream; // 引入PrintStream类用于表示打印流的抽象类
// BackupUtils类用于实现备份工具的功能
public class BackupUtils {
private static final String TAG = "BackupUtils"; // 定义日志标签,用于日志输出
// Singleton stuff单例模式相关代码
private static BackupUtils sInstance; // 定义单例实例变量
// 获取BackupUtils类的实例使用单例模式确保全局只有一个实例
public static synchronized BackupUtils getInstance(Context context) {
if (sInstance == null) {
sInstance = new BackupUtils(context);
}
return sInstance;
}
// 定义一些常量来表示备份或恢复的状态
public static final int STATE_SD_CARD_UNMOUONTED = 0; // SD卡未挂载
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; // 备份文件不存在
public static final int STATE_DATA_DESTROIED = 2; // 数据被破坏
public static final int STATE_SYSTEM_ERROR = 3; // 系统错误
public static final int STATE_SUCCESS = 4; // 成功
private TextExport mTextExport; // TextExport类的实例变量用于导出文本
// 私有构造方法,防止外部直接创建实例,配合单例模式使用
private BackupUtils(Context context) {
mTextExport = new TextExport(context);
}
// 检查外部存储是否可用的方法
private static boolean externalStorageAvailable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
// 导出数据到文本文件的方法
public int exportToText() {
return mTextExport.exportToText();
}
// 获取导出的文本文件名的方法
public String getExportedTextFileName() {
return mTextExport.mFileName;
}
// 获取导出的文本文件目录的方法
public String getExportedTextFileDir() {
return mTextExport.mFileDirectory;
}
// TextExport内部类用于实现将数据导出到文本文件的功能
private static class TextExport {
// 定义从Note表中查询数据的列名数组
private static final String[] NOTE_PROJECTION = {
NoteColumns.ID,
NoteColumns.MODIFIED_DATE,
NoteColumns.SNIPPET,
NoteColumns.TYPE
};
// 定义Note表中各列在NOTE_PROJECTION数组中的索引
private static final int NOTE_COLUMN_ID = 0;
private static final int NOTE_COLUMN_MODIFIED_DATE = 1;
private static final int NOTE_COLUMN_SNIPPET = 2;
// 定义从Data表中查询数据的列名数组
private static final String[] DATA_PROJECTION = {
DataColumns.CONTENT,
DataColumns.MIME_TYPE,
DataColumns.DATA1,
DataColumns.DATA2,
DataColumns.DATA3,
DataColumns.DATA4,
};
// 定义Data表中各列在DATA_PROJECTION数组中的索引
// 注意这里有一个错误应该是DATA_COLUMN_DATA3而不是DATA_COLUMN_CALL_DATE
private static final int DATA_COLUMN_CONTENT = 0;
private static final int DATA_COLUMN_MIME_TYPE = 1;
private static final int DATA_COLUMN_CALL_DATE = 2; // 错误应为DATA_COLUMN_DATA1或其他正确的索引
private static final int DATA_COLUMN_PHONE_NUMBER = 4; // 错误索引与DATA_PROJECTION不匹配
// 从资源文件中获取文本格式的数组
private final String [] TEXT_FORMAT;
// 定义TEXT_FORMAT数组中各个格式的索引
private static final int FORMAT_FOLDER_NAME = 0;
private static final int FORMAT_NOTE_DATE = 1;
private static final int FORMAT_NOTE_CONTENT = 2;
// Context实例变量用于访问应用的资源和类
private Context mContext;
// 导出的文本文件名
private String mFileName;
// 导出的文本文件目录
private String mFileDirectory;
// TextExport类的构造方法
public TextExport(Context context) {
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note);
mContext = context;
mFileName = "";
mFileDirectory = "";
}
// 根据索引获取TEXT_FORMAT数组中对应格式的方法
private String getFormat(int id) {
return TEXT_FORMAT[id];
}
/**
* Export the folder identified by folder id to text
*/
private void exportFolderToText(String folderId, PrintStream ps) {
// 使用内容解析器查询属于指定文件夹的笔记
Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] {
folderId
}, null);
// 检查返回的Cursor是否为null
if (notesCursor != null) {
// 移动Cursor到第一行如果Cursor不为空且至少有一行数据
if (notesCursor.moveToFirst()) {
do {
// 打印笔记的最后修改日期
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// 获取当前笔记的ID
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
// 调用方法导出指定ID的笔记到文本
exportNoteToText(noteId, ps);
} while (notesCursor.moveToNext()); // 循环直到所有笔记都被处理
}
// 关闭Cursor
notesCursor.close();
}
}
/**
* Export note identified by id to a print stream
*/
private void exportNoteToText(String noteId, PrintStream ps) {
// 使用内容解析器查询指定笔记的数据
Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI,
DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] {
noteId
}, null);
// 检查返回的Cursor是否为null
if (dataCursor != null) {
// 移动Cursor到第一行如果Cursor不为空且至少有一行数据
if (dataCursor.moveToFirst()) {
do {
// 获取当前数据的MIME类型
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
// 如果MIME类型表示这是一个电话笔记
if (DataConstants.CALL_NOTE.equals(mimeType)) {
// 打印电话号码
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER);
long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE);
String location = dataCursor.getString(DATA_COLUMN_CONTENT);
// 如果电话号码不为空,则打印电话号码
if (!TextUtils.isEmpty(phoneNumber)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
phoneNumber));
}
// 打印通话日期
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat
.format(mContext.getString(R.string.format_datetime_mdhm),
callDate)));
// 如果位置信息不为空,则打印位置信息
if (!TextUtils.isEmpty(location)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
location));
}
}
// 如果MIME类型表示这是一个普通笔记
else if (DataConstants.NOTE.equals(mimeType)) {
// 获取笔记内容
String content = dataCursor.getString(DATA_COLUMN_CONTENT);
// 如果内容不为空,则打印内容
if (!TextUtils.isEmpty(content)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
content));
}
}
} while (dataCursor.moveToNext()); // 循环直到所有笔记数据都被处理
}
// 关闭Cursor
dataCursor.close();
}
// 在每个笔记之后打印一个行分隔符
try {
ps.write(new byte[] {
Character.LINE_SEPARATOR, // 实际上这里应该是只有行分隔符,后面这个字符可能是误加
// Character.LETTER_NUMBER // 这行应该是错误的,通常我们只需要行分隔符
});
} catch (IOException e) {
// 捕获并打印异常
Log.e(TAG, e.toString());
}
}
/**
* Note will be exported as text which is user readable
*/
public int exportToText() {
// 检查外部存储是否可用
if (!externalStorageAvailable()) {
// 如果外部存储不可用,记录日志并返回存储卡未挂载的状态
Log.d(TAG, "Media was not mounted");
return STATE_SD_CARD_UNMOUONTED;
}
// 获取用于导出文本的输出流
PrintStream ps = getExportToTextPrintStream();
// 如果无法获取输出流,记录错误日志并返回系统错误状态
if (ps == null) {
Log.e(TAG, "get print stream error");
return STATE_SYSTEM_ERROR;
}
// 首先导出文件夹及其笔记
// 使用ContentResolver查询数据库中的文件夹数据
Cursor folderCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI, // 查询的URI
NOTE_PROJECTION, // 查询的列
"(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " // 文件夹类型
+ NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR " // 非垃圾文件夹
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, // 或通话记录文件夹
null, null); // 无排序和选择参数
// 如果查询结果不为空
if (folderCursor != null) {
// 移动到查询结果的第一条记录
if (folderCursor.moveToFirst()) {
do {
// 打印文件夹的名称
String folderName = "";
// 如果是通话记录文件夹,使用特定的字符串
if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
folderName = mContext.getString(R.string.call_record_folder_name);
} else {
// 否则,使用文件夹的摘要(名称)
folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET);
}
// 如果文件夹名称不为空,则格式化并打印
if (!TextUtils.isEmpty(folderName)) {
ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName));
}
// 获取文件夹ID并导出该文件夹下的所有笔记
String folderId = folderCursor.getString(NOTE_COLUMN_ID);
exportFolderToText(folderId, ps);
} while (folderCursor.moveToNext()); // 移动到下一条记录
}
// 关闭Cursor以释放资源
folderCursor.close();
}
// 导出根文件夹中的笔记
// 使用ContentResolver查询数据库中的笔记数据
Cursor noteCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI, // 查询的URI
NOTE_PROJECTION, // 查询的列
NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID // 笔记类型且父ID为0根文件夹
+ "=0", null, null); // 无排序和选择参数
// 如果查询结果不为空
if (noteCursor != null) {
// 移动到查询结果的第一条记录
if (noteCursor.moveToFirst()) {
do {
// 打印笔记的修改日期
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm), // 日期格式
noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); // 笔记的修改日期
// 获取笔记ID并导出该笔记的详细数据
String noteId = noteCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps);
} while (noteCursor.moveToNext()); // 移动到下一条记录
}
// 关闭Cursor以释放资源
noteCursor.close();
}
// 关闭输出流以释放资源
ps.close();
// 返回成功状态
return STATE_SUCCESS;
}
/**
* Get a print stream pointed to the file defined by generateExportedTextFile.
* This method is private and returns a PrintStream object or null if an error occurs.
*/
private PrintStream getExportToTextPrintStream() {
// Call a method to generate a file on the SD card.
File file = generateFileMountedOnSDcard(mContext, R.string.file_path,
R.string.file_name_txt_format);
// If the file generation failed (i.e., file is null), log an error and return null.
if (file == null) {
Log.e(TAG, "create file to exported failed");
return null;
}
// Store the file name and directory for later use.
mFileName = file.getName();
mFileDirectory = mContext.getString(R.string.file_path);
// Initialize a PrintStream object to null.
PrintStream ps = null;
// Try to create a FileOutputStream for the file and wrap it in a PrintStream.
try {
FileOutputStream fos = new FileOutputStream(file);
ps = new PrintStream(fos);
} catch (FileNotFoundException e) {
// If the file was not found, log the error and return null.
e.printStackTrace();
return null;
} catch (NullPointerException e) {
// If a NullPointerException occurs (e.g., due to a null file object), log the error and return null.
e.printStackTrace();
return null;
}
// Return the PrintStream object if no errors occurred.
return ps;
}
/**
* Generate the text file to store imported data on the SD card.
* This method is private and static, returning a File object or null if an error occurs.
*/
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
// Create a StringBuilder to build the file path.
StringBuilder sb = new StringBuilder();
// Append the external storage directory path.
sb.append(Environment.getExternalStorageDirectory());
// Append the directory path from resources.
sb.append(context.getString(filePathResId));
// Create a File object for the directory.
File filedir = new File(sb.toString());
// Append the formatted file name to the StringBuilder.
// The file name includes a date format obtained from resources.
sb.append(context.getString(
fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd),
System.currentTimeMillis())));
// Create a File object for the full file path.
File file = new File(sb.toString());
try {
// If the directory does not exist, create it.
if (!filedir.exists()) {
filedir.mkdir();
}
// If the file does not exist, create it.
if (!file.exists()) {
file.createNewFile();
}
// Return the File object if no errors occurred.
return file;
} catch (SecurityException e) {
// If there is a security exception (e.g., no permission to write to external storage), log the error.
e.printStackTrace();
} catch (IOException e) {
// If an I/O error occurs, log the error.
e.printStackTrace();
}
// Return null if an error occurred.
return null;
}

@ -0,0 +1,145 @@
/*
* 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.
*/
// 导入所需的Android和Java类
package net.micode.notes.gtask.remote;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import net.micode.notes.R;
import net.micode.notes.ui.NotesListActivity;
import net.micode.notes.ui.NotesPreferenceActivity;
// 定义一个继承自AsyncTask的类用于异步执行Google Tasks同步任务
public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {
// 定义一个常量用于表示同步通知的ID
private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;
// 定义一个接口,用于同步完成后的回调
public interface OnCompleteListener {
void onComplete();
}
// 定义类成员变量
private Context mContext;
private NotificationManager mNotifiManager;
private GTaskManager mTaskManager;
private OnCompleteListener mOnCompleteListener;
// 构造函数,初始化成员变量
public GTaskASyncTask(Context context, OnCompleteListener listener) {
mContext = context;
mOnCompleteListener = listener;
mNotifiManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
mTaskManager = GTaskManager.getInstance();
}
// 提供一个方法用于取消同步任务
public void cancelSync() {
mTaskManager.cancelSync();
}
// 提供一个方法用于发布进度更新封装了AsyncTask的publishProgress方法
public void publishProgess(String message) {
publishProgress(new String[] {
message
});
}
// 定义一个方法用于显示通知
private void showNotification(int tickerId, String content) {
// 创建一个Notification对象设置图标、标题和时间戳
Notification notification = new Notification(R.drawable.notification, mContext
.getString(tickerId), System.currentTimeMillis());
// 设置通知的默认属性,如灯光闪烁
notification.defaults = Notification.DEFAULT_LIGHTS;
// 设置通知的标志,使其点击后自动取消
notification.flags = Notification.FLAG_AUTO_CANCEL;
// 根据通知类型创建PendingIntent
PendingIntent pendingIntent;
if (tickerId != R.string.ticker_success) {
// 如果不是成功通知,则跳转到设置活动
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesPreferenceActivity.class), 0);
} else {
// 如果是成功通知,则跳转到笔记列表活动
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
NotesListActivity.class), 0);
}
// 设置通知的详细信息
notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
pendingIntent);
// 发送通知
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
}
// 在后台线程中执行同步任务
@Override
protected Integer doInBackground(Void... unused) {
// 发布登录进度通知
publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity
.getSyncAccountName(mContext)));
// 执行同步任务,并返回结果
return mTaskManager.sync(mContext, this);
}
// 当进度更新时在UI线程中调用此方法
@Override
protected void onProgressUpdate(String... progress) {
// 显示同步中的通知
showNotification(R.string.ticker_syncing, progress[0]);
// 如果上下文是GTaskSyncService的实例则发送广播通知进度
if (mContext instanceof GTaskSyncService) {
((GTaskSyncService) mContext).sendBroadcast(progress[0]);
}
}
// 在后台任务完成后在UI线程中调用此方法
@Override
protected void onPostExecute(Integer result) {
// 根据同步结果显示相应的通知
if (result == GTaskManager.STATE_SUCCESS) {
showNotification(R.string.ticker_success, mContext.getString(
R.string.success_sync_account, mTaskManager.getSyncAccount()));
NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis());
} else if (result == GTaskManager.STATE_NETWORK_ERROR) {
showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network));
} else if (result == GTaskManager.STATE_INTERNAL_ERROR) {
showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal));
} else if (result == GTaskManager.STATE_SYNC_CANCELLED) {
showNotification(R.string.ticker_cancel, mContext
.getString(R.string.error_sync_cancelled));
}
// 如果设置了回调监听器则在新线程中调用其onComplete方法
if (mOnCompleteListener != null) {
new Thread(new Runnable() {
public void run() {
mOnCompleteListener.onComplete();
}
}).start();
}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,297 @@
/*
* 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.
*/
// 定义一个名为GTaskStringUtils的公共类
public class GTaskStringUtils {
// 定义一个公共静态最终字符串常量用于标识动作ID
public final static String GTASK_JSON_ACTION_ID = "action_id";
// 定义一个公共静态最终字符串常量,用于标识动作列表
public final static String GTASK_JSON_ACTION_LIST = "action_list";
// 定义一个公共静态最终字符串常量,用于标识动作类型
public final static String GTASK_JSON_ACTION_TYPE = "action_type";
// 定义一个公共静态最终字符串常量,表示创建动作类型
public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create";
// 定义一个公共静态最终字符串常量,表示获取所有动作类型
public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all";
// 定义一个公共静态最终字符串常量,表示移动动作类型
public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move";
// 定义一个公共静态最终字符串常量,表示更新动作类型
public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update";
// 定义一个公共静态最终字符串常量用于标识创建者ID
public final static String GTASK_JSON_CREATOR_ID = "creator_id";
// 定义一个公共静态最终字符串常量,用于标识子实体
public final static String GTASK_JSON_CHILD_ENTITY = "child_entity";
// 定义一个公共静态最终字符串常量,用于标识客户端版本
public final static String GTASK_JSON_CLIENT_VERSION = "client_version";
// 定义一个公共静态最终字符串常量,用于标识任务是否完成
public final static String GTASK_JSON_COMPLETED = "completed";
// 定义一个公共静态最终字符串常量用于标识当前列表ID
public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id";
// 定义一个公共静态最终字符串常量用于标识默认列表ID
public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id";
// 定义一个公共静态最终字符串常量,用于标识是否已删除
public final static String GTASK_JSON_DELETED = "deleted";
// 定义一个公共静态最终字符串常量,用于标识目标列表
public final static String GTASK_JSON_DEST_LIST = "dest_list";
// 定义一个公共静态最终字符串常量,用于标识目标父实体
public final static String GTASK_JSON_DEST_PARENT = "dest_parent";
// 定义一个公共静态最终字符串常量,用于标识目标父实体类型
public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type";
// 定义一个公共静态最终字符串常量,用于标识实体增量
public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta";
// 定义一个公共静态最终字符串常量,用于标识实体类型
public final static String GTASK_JSON_ENTITY_TYPE = "entity_type";
// 定义一个公共静态最终字符串常量,用于标识是否获取已删除项
public final static String GTASK_JSON_GET_DELETED = "get_deleted";
// 定义一个公共静态最终字符串常量用于标识实体ID
public final static String GTASK_JSON_ID = "id";
// 定义一个公共静态最终字符串常量,用于标识索引
public final static String GTASK_JSON_INDEX = "index";
// 定义一个公共静态最终字符串常量,用于标识最后修改时间
public final static String GTASK_JSON_LAST_MODIFIED = "last_modified";
// 定义一个公共静态最终字符串常量,用于标识最新的同步点
public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point";
// 定义一个公共静态最终字符串常量用于标识列表ID
public final static String GTASK_JSON_LIST_ID = "list_id";
// 定义一个公共静态最终字符串常量,用于标识列表集合
public final static String GTASK_JSON_LISTS = "lists";
// 定义一个公共静态最终字符串常量,用于标识名称
public final static String GTASK_JSON_NAME = "name";
// 定义一个公共静态最终字符串常量用于标识新ID
public final static String GTASK_JSON_NEW_ID = "new_id";
// 定义一个公共静态最终字符串常量,用于标识笔记
public final static String GTASK_JSON_NOTES = "notes";
// 定义一个公共静态最终字符串常量用于标识父实体ID
public final static String GTASK_JSON_PARENT_ID = "parent_id";
// 定义一个公共静态最终字符串常量用于标识前一个兄弟实体的ID
public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id";
// 定义一个公共静态最终字符串常量,用于标识结果集
public final static String GTASK_JSON_RESULTS = "results";
// 定义一个公共静态最终字符串常量,用于标识源列表
public final static String GTASK_JSON_SOURCE_LIST = "source_list";
// 定义一个公共静态最终字符串常量,用于标识任务集合
public final static String GTASK_JSON_TASKS = "tasks";
// 定义一个公共静态最终字符串常量,用于标识类型
public final static String GTASK_JSON_TYPE = "type";
// 定义一个公共静态最终字符串常量,表示组类型
public final static String GTASK_JSON_TYPE_GROUP = "GROUP";
// 定义一个公共静态最终字符串常量,表示任务类型
public final static String GTASK_JSON_TYPE_TASK = "TASK";
// 定义一个公共静态最终字符串常量,用于标识用户
public final static String GTASK_JSON_USER = "user";
// 定义一个公共静态最终字符串常量表示MIUI笔记文件夹前缀
public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]";
// 定义一个公共静态最终字符串常量,表示默认文件夹名称
public final static String FOLDER_DEFAULT = "Default";
// 定义一个公共静态最终字符串常量,表示电话笔记文件夹名称
public final static String FOLDER_CALL_NOTE = "Call_Note";
// 定义一个公共静态最终字符串常量,表示元数据文件夹名称
public final static String FOLDER_META = "METADATA";
// 定义一个公共静态最终字符串常量表示元数据头部ID
public final static String META_HEAD_GTASK_ID = "meta_gid";
// 定义一个公共静态最终字符串常量,表示元数据头部笔记
public final static String META_HEAD_NOTE = "meta_note";
// 定义一个公共静态最终字符串常量,表示元数据头部数据
public final static String META_HEAD_DATA = "meta_data";
// 定义一个公共静态最终字符串常量,表示元数据笔记的名称
public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE";
}

@ -0,0 +1,269 @@
/*
* 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.
*/
// 定义一个名为GTaskSyncService的服务类继承自Service用于同步Google Tasks
package net.micode.notes.gtask.remote;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
// 声明服务类
public class GTaskSyncService extends Service {
// 定义一个常量字符串,用于标识同步操作的类型
public final static String ACTION_STRING_NAME = "sync_action_type";
// 定义同步操作的常量整型值
public final static int ACTION_START_SYNC = 0; // 开始同步
public final static int ACTION_CANCEL_SYNC = 1; // 取消同步
public final static int ACTION_INVALID = 2; // 无效操作
// 定义广播接收器名称和键值对常量
public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service";
public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing"; // 是否正在同步
public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg"; // 同步进度消息
// 定义一个静态的异步任务变量,用于执行同步操作
private static GTaskASyncTask mSyncTask = null;
// 定义一个静态的同步进度消息变量
private static String mSyncProgress = "";
// 开始同步操作的方法
private void startSync() {
if (mSyncTask == null) { // 如果当前没有正在执行的同步任务
mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() {
// 定义一个完成监听器,当异步任务完成时调用
public void onComplete() {
mSyncTask = null; // 清空同步任务变量
sendBroadcast(""); // 发送广播,通知同步完成
stopSelf(); // 停止服务
}
});
sendBroadcast(""); // 发送广播,可能用于通知开始同步
mSyncTask.execute(); // 执行异步任务
}
}
// 取消同步操作的方法
private void cancelSync() {
if (mSyncTask != null) { // 如果当前有正在执行的同步任务
mSyncTask.cancelSync(); // 取消同步任务
}
}
// 当服务被创建时调用
@Override
public void onCreate() {
mSyncTask = null; // 清空同步任务变量
}
// 当服务被启动时调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bundle bundle = intent.getExtras(); // 获取启动服务的Intent中的附加数据
if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { // 如果附加数据不为空且包含操作类型
switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) { // 根据操作类型执行相应的操作
case ACTION_START_SYNC:
startSync(); // 开始同步
break;
case ACTION_CANCEL_SYNC:
cancelSync(); // 取消同步
break;
default:
break;
}
return START_STICKY; // 如果服务被杀死系统会在内存可用时重启服务并传递最后一个Intent
}
return super.onStartCommand(intent, flags, startId); // 如果没有指定操作类型,则调用父类方法
}
// 当系统内存低时调用
@Override
public void onLowMemory() {
if (mSyncTask != null) { // 如果当前有正在执行的同步任务
mSyncTask.cancelSync(); // 取消同步任务以释放内存
}
}
// 绑定服务时调用,此处不提供服务绑定支持
public IBinder onBind(Intent intent) {
return null;
}
// 发送广播通知同步状态的方法
public void sendBroadcast(String msg) {
mSyncProgress = msg; // 更新同步进度消息
Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); // 创建一个新的Intent
intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); // 添加是否正在同步的键值对
intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); // 添加同步进度消息的键值对
sendBroadcast(intent); // 发送广播
}
// 从Activity启动同步服务的方法
public static void startSync(Activity activity) {
GTaskManager.getInstance().setActivityContext(activity); // 设置活动上下文
Intent intent = new Intent(activity, GTaskSyncService.class); // 创建一个新的Intent
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC); // 添加操作类型的键值对
activity.startService(intent); // 启动服务
}
// 从Context取消同步服务的方法
public static void cancelSync(Context context) {
Intent intent = new Intent(context, GTaskSyncService.class); // 创建一个新的Intent
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); // 添加操作类型的键值对
context.startService(intent); // 启动服务
}
// 判断是否正在同步的方法
public static boolean isSyncing() {
return mSyncTask != null; // 返回是否有正在执行的同步任务
}
// 获取同步进度消息的方法
public static String getProgressString() {
return mSyncProgress; // 返回同步进度消息
}
}

@ -0,0 +1,334 @@
/*
* 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.model; // 声明当前类所在的包
import android.content.ContentProviderOperation; // 导入用于构建批量数据库操作的类
import android.content.ContentProviderResult; // 导入用于接收批量操作结果的类
import android.content.ContentUris; // 导入用于生成URI的类这些URI指向数据库中的特定行
import android.content.ContentValues; // 导入用于存储一组键值对的类,这些键值对将被插入到数据库表中
import android.content.Context; // 导入Android应用上下文类
import android.content.OperationApplicationException; // 导入表示操作应用异常的类
import android.net.Uri; // 导入表示统一资源标识符的类
import android.os.RemoteException; // 导入表示远程过程调用异常的类
import android.util.Log; // 导入用于打印日志的类
import net.micode.notes.data.Notes; // 导入应用自定义的Notes类可能是一个包含多个内部类的数据库模型
import net.micode.notes.data.Notes.CallNote; // 导入Notes类中的CallNote内部类可能代表电话笔记
import net.micode.notes.data.Notes.DataColumns; // 导入Notes类中的DataColumns内部类可能包含数据表的列定义
import net.micode.notes.data.Notes.NoteColumns; // 导入Notes类中的NoteColumns内部类可能包含笔记表的列定义
import net.micode.notes.data.Notes.TextNote; // 导入Notes类中的TextNote内部类可能代表文本笔记
*//1
import java.util.ArrayList; // 导入ArrayList类
public class Note { // 声明一个名为Note的公共类
// 类的成员变量定义(在此代码段中未展示)
private ContentValues mNoteDiffValues; // 用于存储笔记的差异数据,以便后续更新数据库
private NoteData mNoteData; // 可能用于存储笔记的详细数据
private static final String TAG = "Note"; // 用于日志记录的标签
/**
* ID
*/
public static synchronized long getNewNoteId(Context context, long folderId) {
// 声明一个ContentValues对象用于存储要插入数据库的新笔记的数据
ContentValues values = new ContentValues();
// 获取当前系统时间(毫秒为单位),作为笔记的创建和修改时间
long createdTime = System.currentTimeMillis();
// 向values中添加笔记的创建日期
values.put(NoteColumns.CREATED_DATE, createdTime);
// 向values中添加笔记的修改日期初始时与创建日期相同
values.put(NoteColumns.MODIFIED_DATE, createdTime);
// 向values中添加笔记的类型此处假设Notes.TYPE_NOTE是一个预定义的常量表示笔记类型
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
// 向values中添加一个标记表示笔记是否在本地被修改过初始化为1可能表示已修改
values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 向values中添加笔记的父ID即它所属的文件夹ID
values.put(NoteColumns.PARENT_ID, folderId);
// 使用ContentResolver向数据库的Notes.CONTENT_NOTE_URI插入新笔记的数据并返回新插入笔记的URI
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
// 初始化noteId为0用于存储从URI解析出的新笔记ID
long noteId = 0;
try {
// 从返回的URI的路径段中获取第二个元素索引为1因为索引从0开始并将其转换为long类型作为新笔记的ID
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
// 如果转换过程中发生数字格式异常则记录错误日志并将noteId保持为0
Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
}
// 检查noteId是否为-1虽然在此处不太可能因为Long.valueOf不会返回-1
// 但为了代码的健壮性,还是进行了检查
if (noteId == -1) {
// 如果noteId为-1则抛出IllegalStateException异常表示获得了错误的笔记ID
throw new IllegalStateException("Wrong note id:" + noteId);
}
// 返回解析出的新笔记ID
return noteId;
}
}*//2
// Note类的构造方法
public Note() {
// 初始化mNoteDiffValues用于存储笔记的差异数据这些数据通常用于更新数据库中的笔记
mNoteDiffValues = new ContentValues();
// 初始化mNoteData可能用于存储笔记的详细数据如文本、语音等
mNoteData = new NoteData();
}
// 设置笔记的某个键值对数据
public void setNoteValue(String key, String value) {
// 将键值对存储到mNoteDiffValues中准备用于更新数据库
mNoteDiffValues.put(key, value);
// 标记笔记为已本地修改
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记的修改日期
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 设置笔记的文本数据
public void setTextData(String key, String value) {
// 调用mNoteData的setTextData方法将文本数据存储到mNoteData中
mNoteData.setTextData(key, value);
}
// 设置文本数据的ID
public void setTextDataId(long id) {
// 调用mNoteData的setTextDataId方法设置文本数据的ID
mNoteData.setTextDataId(id);
}
// 获取文本数据的ID
public long getTextDataId() {
// 返回mNoteData中存储的文本数据ID
return mNoteData.mTextDataId;
}
// 设置通话数据的ID
public void setCallDataId(long id) {
// 调用mNoteData的setCallDataId方法设置通话数据的ID
mNoteData.setCallDataId(id);
}
// 设置通话数据的某个键值对数据
public void setCallData(String key, String value) {
// 调用mNoteData的setCallData方法将通话数据存储到mNoteData中
mNoteData.setCallData(key, value);
}
// 检查笔记是否已本地修改
public boolean isLocalModified() {
// 如果mNoteDiffValues中有数据或者mNoteData标记为已修改则返回true
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
// 同步笔记到服务器或数据库
public boolean syncNote(Context context, long noteId) {
// 检查传入的noteId是否有效如果小于等于0则抛出异常
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 如果笔记没有本地修改则不需要同步直接返回true
if (!isLocalModified()) {
return true;
}
*//3
/**
* In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and
* {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the
* note data info
*/
if (context.getContentResolver().update(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
null) == 0) {
// 如果更新返回0表示没有更新任何行这通常不应该发生
Log.e(TAG, "Update note error, should not happen");
// 不要返回,继续执行后续代码
}
// 清除mNoteDiffValues中的数据因为已经尝试更新到数据库
mNoteDiffValues.clear();
// 检查mNoteData是否标记为已修改并尝试将其推送到ContentResolver
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
// 如果mNoteData标记为已修改但推送失败则返回false
return false;
}
// 如果所有操作都成功则返回true
return true;
}
// NoteData内部类定义开始
private class NoteData {
// 存储文本数据的ID
private long mTextDataId;
// 存储文本数据的ContentValues
private ContentValues mTextDataValues;
// 存储通话数据的ID
private long mCallDataId;
// 存储通话数据的ContentValues
private ContentValues mCallDataValues;
// 用于日志记录的TAG
private static final String TAG = "NoteData";
// NoteData的构造方法
public NoteData() {
// 初始化ContentValues对象
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
// 初始化数据ID为0表示还没有关联的数据
mTextDataId = 0;
mCallDataId = 0;
}
// 检查NoteData是否已修改
boolean isLocalModified() {
// 如果mTextDataValues或mCallDataValues中有数据则返回true
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
// 设置文本数据的ID
void setTextDataId(long id) {
// 检查ID是否有效
if(id <= 0) {
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;
}
// 设置通话数据的ID
void setCallDataId(long id) {
// 检查ID是否有效
if (id <= 0) {
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id;
}
// 设置通话数据
void setCallData(String key, String value) {
// 将键值对存储到mCallDataValues中
mCallDataValues.put(key, value);
// 标记笔记为已本地修改,并更新修改日期
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 设置文本数据
void setTextData(String key, String value) {
// 将键值对存储到mTextDataValues中
mTextDataValues.put(key, value);
// 标记笔记为已本地修改,并更新修改日期
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 将NoteData推送到ContentResolver
Uri pushIntoContentResolver(Context context, long noteId) {
// 检查noteId是否有效
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 创建用于批量操作的内容提供者操作列表
ArrayList<ContentProviderOperation> operationList = new ArrayList<>();
ContentProviderOperation.Builder builder = null;
// 如果mTextDataValues中有数据
if(mTextDataValues.size() > 0) {
// 添加noteId到mTextDataValues中
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
// 如果mTextDataId为0表示是新的文本数据
if (mTextDataId == 0) {
// 插入新的文本数据到ContentResolver
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mTextDataValues);
try {
// 从返回的Uri中提取新的文本数据ID
setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
// 如果提取ID失败则记录错误并清除mTextDataValues
Log.e(TAG, "Insert new text data fail with noteId" + noteId);
mTextDataValues.clear();
return null;
}
} else {
// 如果mTextDataId不为0表示是更新现有的文本数据
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mTextDataId));
builder.withValues(mTextDataValues);
operationList.add(builder.build());
}
// 清除mTextDataValues中的数据因为已经尝试更新或插入到数据库
mTextDataValues.clear();
}
// 如果mCallDataValues中有数据处理逻辑与mTextDataValues相同
if(mCallDataValues.size() > 0) {
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
if (mCallDataId == 0) {
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mCallDataValues);
try {
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
Log.e(TAG, "Insert new call data fail with noteId" + noteId);
mCallDataValues.clear();
return null;
}
} else {
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId));
builder.withValues(mCallDataValues);
operationList.add(builder.build());
}
mCallDataValues.clear();
}
// 如果操作列表不为空,则执行批量操作
if (operationList.size() > 0) {
try {
// 执行批量操作,并返回结果
ContentProviderResult[] results = context.getContentResolver().applyBatch(
Notes.AUTHORITY, operationList);
// 检查结果是否有效并返回相应的Uri或null
return (results == null || results.length == 0 || results[0] == null) ? null
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
} catch (RemoteException e) {
// 记录远程异常
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
} catch (OperationApplicationException e) {
// 记录操作应用异常
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
}
}
// 如果没有任何操作要执行则返回null
return null;
}
}
// Note类定义结束
}

@ -0,0 +1,622 @@
/*
* 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.model;
// 导入所需的Android和Java类
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.net.Uri;
import android.os.RemoteException;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import java.util.ArrayList;
// Note类用于表示和管理笔记数据
public class Note {
// 用于存储笔记的差异值(即需要更新的字段)
private ContentValues mNoteDiffValues;
// 用于存储笔记的具体数据(如文本数据、通话数据等)
private NoteData mNoteData;
// 日志标签
private static final String TAG = "Note";
/**
* ID
*/
public static synchronized long getNewNoteId(Context context, long folderId) {
// 创建一个新的ContentValues对象用于存储要插入数据库的数据
ContentValues values = new ContentValues();
// 获取当前时间,作为笔记的创建和修改时间
long createdTime = System.currentTimeMillis();
values.put(NoteColumns.CREATED_DATE, createdTime);
values.put(NoteColumns.MODIFIED_DATE, createdTime);
// 设置笔记类型为普通笔记
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
// 标记笔记为本地修改
values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 设置笔记所属的文件夹ID
values.put(NoteColumns.PARENT_ID, folderId);
// 向数据库插入新笔记并获取其Uri
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
long noteId = 0;
try {
// 从Uri中提取新笔记的ID
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
// 如果提取ID失败则记录错误日志
Log.e(TAG, "Get note id error :" + e.toString());
noteId = 0;
}
// 如果ID为-1则抛出异常
if (noteId == -1) {
throw new IllegalStateException("Wrong note id:" + noteId);
}
// 返回新笔记的ID
return noteId;
}
// Note类的构造函数
public Note() {
// 初始化差异值存储和内容数据存储
mNoteDiffValues = new ContentValues();
mNoteData = new NoteData();
}
// 设置笔记的差异值
public void setNoteValue(String key, String value) {
mNoteDiffValues.put(key, value);
// 标记笔记为本地修改
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记的修改时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 设置笔记的文本数据
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);
}
// 设置文本数据的ID
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}
// 获取文本数据的ID
public long getTextDataId() {
return mNoteData.mTextDataId;
}
// 设置通话数据的ID
public void setCallDataId(long id) {
mNoteData.setCallDataId(id);
}
// 设置通话数据
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}
// 检查笔记是否有本地修改
public boolean isLocalModified() {
// 如果有差异值或内容数据有本地修改则返回true
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
// 同步笔记到数据库
public boolean syncNote(Context context, long noteId) {
// 检查笔记ID是否有效
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 如果没有本地修改则直接返回true
if (!isLocalModified()) {
return true;
}
// 更新笔记的差异值到数据库
// 注意:即使更新失败,也会继续执行后续代码以确保数据安全性
if (context.getContentResolver().update(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
null) == 0) {
// 如果更新失败,则记录错误日志
Log.e(TAG, "Update note error, should not happen");
// 不返回,继续执行
}
// 清空差异值存储,因为已经同步到数据库
mNoteDiffValues.clear();
// 如果内容数据有本地修改,则尝试将其同步到数据库
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
// 如果同步失败则返回false
return false;
}
// 如果所有操作都成功则返回true
return true;
}
}
// 定义一个私有的内部类NoteData
private class NoteData {
// 文本数据的ID
private long mTextDataId;
// 用于存储文本数据的ContentValues对象
private ContentValues mTextDataValues;
// 通话数据的ID
private long mCallDataId;
// 用于存储通话数据的ContentValues对象
private ContentValues mCallDataValues;
// 用于日志记录的标签
private static final String TAG = "NoteData";
// 构造函数,初始化成员变量
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
}
// 检查本地数据是否被修改
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
// 设置文本数据的ID
void setTextDataId(long id) {
if(id <= 0) {
// 如果ID小于等于0抛出异常
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;
}
// 设置通话数据的ID
void setCallDataId(long id) {
if (id <= 0) {
// 如果ID小于等于0抛出异常
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id;
}
// 设置通话数据
void setCallData(String key, String value) {
mCallDataValues.put(key, value);
// 下面的两行代码似乎有误因为mNoteDiffValues在类中未定义
// mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 设置文本数据
void setTextData(String key, String value) {
mTextDataValues.put(key, value);
// 同样下面的两行代码因为mNoteDiffValues未定义而存在问题
// mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 将数据推送到内容提供者
Uri pushIntoContentResolver(Context context, long noteId) {
// 检查noteId的有效性
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 用于存储内容提供者操作的列表
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = null;
// 如果文本数据有变化
if(mTextDataValues.size() > 0) {
// 添加noteId到文本数据
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
// 如果是新数据,插入新记录
if (mTextDataId == 0) {
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mTextDataValues);
try {
// 从返回的URI中提取新插入的ID
setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
// 如果提取ID失败记录错误并清空数据
Log.e(TAG, "Insert new text data fail with noteId" + noteId);
mTextDataValues.clear();
return null;
}
} else {
// 如果是已有数据,更新记录
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mTextDataId));
builder.withValues(mTextDataValues);
operationList.add(builder.build());
}
// 清空已处理的数据
mTextDataValues.clear();
}
// 如果通话数据有变化
if(mCallDataValues.size() > 0) {
// 添加noteId到通话数据
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
// 如果是新数据,插入新记录
if (mCallDataId == 0) {
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mCallDataValues);
try {
// 从返回的URI中提取新插入的ID
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
// 如果提取ID失败记录错误并清空数据
Log.e(TAG, "Insert new call data fail with noteId" + noteId);
mCallDataValues.clear();
return null;
}
} else {
// 如果是已有数据,更新记录
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId));
builder.withValues(mCallDataValues);
operationList.add(builder.build());
}
// 清空已处理的数据
mCallDataValues.clear();
}
// 如果存在需要执行的操作
if (operationList.size() > 0) {
try {
// 批量执行操作
ContentProviderResult[] results = context.getContentResolver().applyBatch(
Notes.AUTHORITY, operationList);
// 根据执行结果返回相应的URI
return (results == null || results.length == 0 || results[0] == null) ? null
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
} catch (RemoteException e) {
// 捕获远程异常并记录
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
} catch (OperationApplicationException e) {
// 捕获操作应用异常并记录
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
}
}
// 如果没有操作需要执行返回null
return null;
}
}

@ -0,0 +1,405 @@
/*
* 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.tool;
import android.content.Context;
import android.preference.PreferenceManager;
import net.micode.notes.R;
import net.micode.notes.ui.NotesPreferenceActivity;
// 定义一个工具类,用于解析和获取应用中的资源
public class ResourceParser {
// 定义一些颜色常量,用于表示不同的背景色
public static final int YELLOW = 0;
public static final int BLUE = 1;
public static final int WHITE = 2;
public static final int GREEN = 3;
public static final int RED = 4;
// 默认的背景颜色
public static final int BG_DEFAULT_COLOR = YELLOW;
// 定义一些文本大小常量,用于表示不同的字体大小
public static final int TEXT_SMALL = 0;
public static final int TEXT_MEDIUM = 1;
public static final int TEXT_LARGE = 2;
public static final int TEXT_SUPER = 3;
// 默认的字体大小
public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM;
// 内部类,用于管理笔记背景资源
public static class NoteBgResources {
// 定义编辑状态下笔记背景的资源ID数组
private final static int [] BG_EDIT_RESOURCES = new int [] {
R.drawable.edit_yellow,
R.drawable.edit_blue,
R.drawable.edit_white,
R.drawable.edit_green,
R.drawable.edit_red
};
// 定义编辑状态下笔记标题背景的资源ID数组
private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] {
R.drawable.edit_title_yellow,
R.drawable.edit_title_blue,
R.drawable.edit_title_white,
R.drawable.edit_title_green,
R.drawable.edit_title_red
};
// 根据ID获取编辑状态下笔记背景的资源ID
public static int getNoteBgResource(int id) {
return BG_EDIT_RESOURCES[id];
}
// 根据ID获取编辑状态下笔记标题背景的资源ID
public static int getNoteTitleBgResource(int id) {
return BG_EDIT_TITLE_RESOURCES[id];
}
}
// 根据用户设置获取默认的背景颜色ID
public static int getDefaultBgId(Context context) {
// 检查用户是否设置了背景颜色偏好
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) {
// 如果设置了随机返回一个背景颜色ID
return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length);
} else {
// 如果没有设置返回默认的背景颜色ID
return BG_DEFAULT_COLOR;
}
}
// 内部类,用于管理笔记条目背景资源
public static class NoteItemBgResources {
// 定义列表第一个条目背景的资源ID数组
private final static int [] BG_FIRST_RESOURCES = new int [] {
R.drawable.list_yellow_up,
R.drawable.list_blue_up,
R.drawable.list_white_up,
R.drawable.list_green_up,
R.drawable.list_red_up
};
// 定义列表中间条目背景的资源ID数组
private final static int [] BG_NORMAL_RESOURCES = new int [] {
R.drawable.list_yellow_middle,
R.drawable.list_blue_middle,
R.drawable.list_white_middle,
R.drawable.list_green_middle,
R.drawable.list_red_middle
};
// 定义列表最后一个条目背景的资源ID数组
private final static int [] BG_LAST_RESOURCES = new int [] {
R.drawable.list_yellow_down,
R.drawable.list_blue_down,
R.drawable.list_white_down,
R.drawable.list_green_down,
R.drawable.list_red_down,
};
// 定义列表单独条目背景的资源ID数组
private final static int [] BG_SINGLE_RESOURCES = new int [] {
R.drawable.list_yellow_single,
R.drawable.list_blue_single,
R.drawable.list_white_single,
R.drawable.list_green_single,
R.drawable.list_red_single
};
// 根据ID获取列表第一个条目背景的资源ID
public static int getNoteBgFirstRes(int id) {
return BG_FIRST_RESOURCES[id];
}
// 根据ID获取列表最后一个条目背景的资源ID
public static int getNoteBgLastRes(int id) {
return BG_LAST_RESOURCES[id];
}
// 根据ID获取列表单独条目背景的资源ID
public static int getNoteBgSingleRes(int id) {
return BG_SINGLE_RESOURCES[id];
}
// 根据ID获取列表中间条目背景的资源ID
public static int getNoteBgNormalRes(int id) {
return BG_NORMAL_RESOURCES[id];
}
// 获取文件夹背景的资源ID
public static int getFolderBgRes() {
return R.drawable.list_folder;
}
}
// 内部类,用于管理小部件背景资源
public static class WidgetBgResources {
// 定义2x大小小部件背景的资源ID数组
private final static int [] BG_2X_RESOURCES = new int [] {
R.drawable.widget_2x_yellow,
R.drawable.widget_2x_blue,
R.drawable.widget_2x_white,
R.drawable.widget_2x_green,
R.drawable.widget_2x_red,
};
// 根据ID获取2x大小小部件背景的资源ID
public static int getWidget2xBgResource(int id) {
return BG_2X_RESOURCES[id];
}
// 定义4x大小小部件背景的资源ID数组
private final static int [] BG_4X_RESOURCES = new int [] {
R.drawable.widget_4x_yellow,
R.drawable.widget_4x_blue,
R.drawable.widget_4x_white,
R.drawable.widget_4x_green,
R.drawable.widget_4x_red
};
// 根据ID获取4x大小小部件背景的资源ID
public static int getWidget4xBgResource(int id) {
return BG_4X_RESOURCES[id];
}
}
// 内部类,用于管理文本外观资源
public static class TextAppearanceResources {
// 定义文本外观的资源ID数组
private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] {
R.style.TextAppearanceNormal,
R.style.TextAppearanceMedium,
R.style.TextAppearanceLarge,
R.style.TextAppearanceSuper
};
// 根据ID获取文本外观的资源ID
// 注意这里有一个错误处理如果ID超出范围则返回默认的字体大小ID
public static int getTexAppearanceResource(int id) {
if (id >= TEXTAPPEARANCE_RESOURCES.length) {
return BG_DEFAULT_FONT_SIZE;
}
return TEXTAPPEARANCE_RESOURCES[id];
}
// 获取文本外观资源数组的大小
public static int getResourcesSize() {
return TEXTAPPEARANCE_RESOURCES.length;
}
}
}

@ -0,0 +1,812 @@
/*
* 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.model;
// 导入所需的Android和项目内部的类
import android.appwidget.AppWidgetManager;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.tool.ResourceParser.NoteBgResources;
// 定义一个用于处理工作中的笔记的类
public class WorkingNote {
// 笔记对象
private Note mNote;
// 笔记ID
private long mNoteId;
// 笔记内容
private String mContent;
// 笔记模式
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,
DataColumns.MIME_TYPE,
DataColumns.DATA1,
DataColumns.DATA2,
DataColumns.DATA3,
DataColumns.DATA4,
};
// 用于从笔记表中查询笔记元数据的列
public static final String[] NOTE_PROJECTION = new String[] {
NoteColumns.PARENT_ID,
NoteColumns.ALERTED_DATE,
NoteColumns.BG_COLOR_ID,
NoteColumns.WIDGET_ID,
NoteColumns.WIDGET_TYPE,
NoteColumns.MODIFIED_DATE
};
// 定义从DATA_PROJECTION数组中获取数据的列索引
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; // 注意这里可能有误因为DATA_PROJECTION中没有直接对应MODE的列
// 定义从NOTE_PROJECTION数组中获取数据的列索引
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;
// 构造一个新笔记对象
private WorkingNote(Context context, long folderId) {
mContext = context;
mAlertDate = 0;
mModifiedDate = System.currentTimeMillis(); // 设置当前时间为修改日期
mFolderId = folderId;
mNote = new Note(); // 初始化Note对象
mNoteId = 0; // 新笔记ID为0表示未保存
mIsDeleted = false;
mMode = 0; // 初始化模式
mWidgetType = Notes.TYPE_WIDGET_INVALIDE; // 初始化小部件类型为无效
}
// 构造一个已存在的笔记对象
private WorkingNote(Context context, long noteId, long folderId) {
mContext = context;
mNoteId = noteId;
mFolderId = folderId;
mIsDeleted = false;
mNote = new Note();
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()) {
// 从cursor中读取数据并赋值给成员变量
mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN);
mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN);
mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN);
mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN);
mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN);
mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN);
}
cursor.close(); // 关闭cursor
} else {
// 如果查询失败,记录错误日志并抛出异常
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)
}, null);
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); // 注意这里可能有问题因为前面提到DATA_PROJECTION中没有直接对应MODE的列
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);
}
} while (cursor.moveToNext());
}
cursor.close(); // 关闭cursor
} else {
// 如果查询失败,记录错误日志并抛出异常
Log.e(TAG, "No data with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId);
}
}
// 创建一个新的空笔记对象
public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId); // 调用私有构造函数创建新对象
note.setBgColorId(defaultBgColorId); // 设置背景颜色ID
note.setWidgetId(widgetId); // 设置小部件ID
note.setWidgetType(widgetType); // 设置小部件类型
return note; // 返回新创建的笔记对象
}
// 根据ID加载一个已存在的笔记对象
public static WorkingNote load(Context context, long id) {
return new WorkingNote(context, id, 0); // 调用私有构造函数加载已存在的笔记对象文件夹ID默认为0
}
}
// 定义一个同步方法,用于保存笔记
public synchronized boolean saveNote() {
// 检查笔记是否值得保存
if (isWorthSaving()) {
// 如果笔记在数据库中不存在
if (!existInDatabase()) {
// 为笔记分配一个新的ID
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
// 如果分配ID失败记录错误日志并返回false
Log.e(TAG, "Create new note fail with id:" + mNoteId);
return false;
}
}
// 同步笔记数据到数据库
mNote.syncNote(mContext, mNoteId);
// 如果存在与笔记关联的widget则更新widget内容
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE
&& mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
}
// 返回true表示保存成功
return true;
} else {
// 如果笔记不值得保存返回false
return false;
}
}
// 判断笔记是否在数据库中已存在
public boolean existInDatabase() {
return mNoteId > 0;
}
// 判断笔记是否值得保存
private boolean isWorthSaving() {
// 如果笔记被标记为删除,或者内容为空且未存在于数据库中,或者存在于数据库中但未本地修改,则不值得保存
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) {
return false;
} else {
return true;
}
}
// 设置笔记设置状态改变的监听器
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l;
}
// 设置笔记的提醒日期
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);
}
}
// 标记笔记为已删除或未删除
public void markDeleted(boolean mark) {
mIsDeleted = mark;
// 如果存在与笔记关联的widget并且设置了监听器则通知监听器widget已改变
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
}
}
// 设置笔记的背景颜色ID
public void setBgColorId(int id) {
// 如果新的颜色ID与当前不同则更新颜色ID
if (id != mBgColorId) {
mBgColorId = id;
// 如果设置了监听器,通知监听器背景颜色已改变
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onBackgroundColorChanged();
}
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
}
}
// 设置笔记的清单模式
public void setCheckListMode(int mode) {
// 如果新的模式与当前模式不同,则更新模式
if (mMode != mode) {
// 如果设置了监听器,通知监听器清单模式已改变
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode);
}
mMode = mode;
mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
}
}
// 设置笔记的widget类型
public void setWidgetType(int type) {
// 如果新的类型与当前类型不同,则更新类型
if (type != mWidgetType) {
mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
}
}
// 设置笔记的widget ID
public void setWidgetId(int id) {
// 如果新的ID与当前ID不同则更新ID
if (id != mWidgetId) {
mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
}
}
// 设置笔记的工作文本内容
public void setWorkingText(String text) {
// 如果新的文本与当前文本不同,则更新文本
if (!TextUtils.equals(mContent, text)) {
mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent);
}
}
// 将笔记转换为通话记录笔记
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));
}
// 判断笔记是否有提醒日期
public boolean hasClockAlert() {
return (mAlertDate > 0 ? true : false);
}
// 获取笔记的内容
public String getContent() {
return mContent;
}
// 获取笔记的提醒日期
public long getAlertDate() {
return mAlertDate;
}
// 获取笔记的最后修改日期
public long getModifiedDate() {
return mModifiedDate;
}
// 获取笔记的背景颜色资源ID
public int getBgColorResId() {
return NoteBgResources.getNoteBgResource(mBgColorId);
}
// 获取笔记的背景颜色ID
public int getBgColorId() {
return mBgColorId;
}
// 获取笔记的标题背景资源ID
public int getTitleBgResId() {
return NoteBgResources.getNoteTitleBgResource(mBgColorId);
}
// 获取笔记的清单模式
public int getCheckListMode() {
return mMode;
}
// 获取笔记的ID
public long getNoteId() {
return mNoteId;
}
// 获取笔记所属的文件夹ID
public long getFolderId() {
return mFolderId;
}
// 获取笔记的widget ID
public int getWidgetId() {
return mWidgetId;
}
// 获取笔记的widget类型
public int getWidgetType() {
return mWidgetType;
}
// 定义笔记设置状态改变的监听器接口
public interface NoteSettingChangedListener {
// 当笔记的背景颜色改变时调用
void onBackgroundColorChanged();
// 当用户设置提醒时调用
void onClockAlertChanged(long date, boolean set);
// 当用户通过widget创建笔记时调用
void onWidgetChanged();
// 当用户切换清单模式和普通模式时调用
void onCheckListModeChanged(int oldMode, int newMode);
}
Loading…
Cancel
Save