ALless 2 months ago
parent 8bbab2b346
commit adb7623f79

@ -65,17 +65,34 @@ public class Note {
return noteId;
}
/**
*
*
*/
public Note() {
// 初始化内容差异值容器,用于存储待更新的字段
mNoteDiffValues = new ContentValues();
// 初始化笔记数据对象,用于存储笔记的完整数据
mNoteData = new NoteData();
}
/**
*
* @param key
* @param value
*/
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);
}

@ -72,15 +72,18 @@ public class WorkingNote {
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
NoteColumns.PARENT_ID, // 父文件夹ID所属文件夹
NoteColumns.ALERTED_DATE, // 提醒日期(毫秒值)
NoteColumns.BG_COLOR_ID, // 背景颜色ID
NoteColumns.WIDGET_ID, // 桌面小部件ID
NoteColumns.WIDGET_TYPE, // 小部件类型
NoteColumns.MODIFIED_DATE // 最后修改日期(毫秒值)
};
private static final int DATA_ID_COLUMN = 0;
private static final int DATA_CONTENT_COLUMN = 1;

@ -37,11 +37,18 @@ import java.io.PrintStream;
public class BackupUtils {
/**
*
* @param context
* @return
*/
private static final String TAG = "BackupUtils";
// Singleton stuff
private static BackupUtils sInstance;
public static synchronized BackupUtils getInstance(Context context) {
// 使用双重检查锁定模式确保线程安全
// 且只在首次调用时创建实例(懒汉式单例)
if (sInstance == null) {
sInstance = new BackupUtils(context);
}

@ -72,14 +72,38 @@ public class DataUtils {
return false;
}
/**
*
* @param resolver ContentResolver
* @param id ID
* @param srcFolderId ID
* @param desFolderId ID
*/
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
// 创建内容值对象,用于存储要更新的字段和值
ContentValues values = new ContentValues();
// 设置新的父文件夹ID目标文件夹
values.put(NoteColumns.PARENT_ID, desFolderId);
// 记录原始父文件夹ID源文件夹
// 可能用于撤销操作或同步冲突解决
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
// 标记笔记已被本地修改
// 触发同步机制将变更上传到服务器
values.put(NoteColumns.LOCAL_MODIFIED, 1);
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
}
// 执行更新操作
// 使用ContentUris.withAppendedId构建特定笔记的URI
// 无筛选条件和参数直接更新指定ID的笔记
resolver.update(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id),
values,
null,
null
);
}
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
long folderId) {
if (ids == null) {

@ -1,19 +1,3 @@
/*
* 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.ui;
import android.app.Activity;
@ -39,21 +23,29 @@ import net.micode.notes.tool.DataUtils;
import java.io.IOException;
/**
*
*/
public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener {
// 笔记ID和摘要
private long mNoteId;
private String mSnippet;
// 摘要预览最大长度
private static final int SNIPPET_PREW_MAX_LEN = 60;
// 媒体播放器,用于播放闹钟声音
MediaPlayer mPlayer;
@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
@ -61,11 +53,15 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
}
// 获取启动Activity的Intent
Intent intent = getIntent();
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;
@ -74,35 +70,53 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
return;
}
// 创建媒体播放器实例
mPlayer = new MediaPlayer();
// 检查笔记是否存在且有效
if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) {
// 显示闹钟提醒对话框
showActionDialog();
// 播放闹钟声音
playAlarmSound();
} else {
// 笔记不存在则关闭Activity
finish();
}
}
/**
*
* @return
*/
private boolean isScreenOn() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
return pm.isScreenOn();
}
/**
*
*/
private void playAlarmSound() {
// 获取默认闹钟铃声URI
Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
// 获取静音模式下受影响的音频流设置
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 e) {
// TODO Auto-generated catch block
@ -119,20 +133,33 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
}
/**
*
*/
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:
// 启动笔记编辑Activity并传递笔记ID
Intent intent = new Intent(this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, mNoteId);
@ -143,11 +170,19 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD
}
}
/**
*
*/
public void onDismiss(DialogInterface dialog) {
// 停止闹钟声音
stopAlarmSound();
// 关闭Activity
finish();
}
/**
*
*/
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop();

@ -27,39 +27,59 @@ import android.database.Cursor;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
/**
*
*
*/
public class AlarmInitReceiver extends BroadcastReceiver {
// 查询笔记数据时需要的字段
private static final String [] PROJECTION = new String [] {
NoteColumns.ID,
NoteColumns.ALERTED_DATE
NoteColumns.ID, // 笔记ID
NoteColumns.ALERTED_DATE // 提醒日期
};
// 字段索引常量方便从Cursor中获取数据
private static final int COLUMN_ID = 0;
private static final int COLUMN_ALERTED_DATE = 1;
@Override
public void onReceive(Context context, Intent intent) {
// 获取当前系统时间
long currentDate = System.currentTimeMillis();
// 查询所有设置了提醒且提醒时间在当前时间之后的笔记
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用于在闹钟触发时启动AlarmReceiver
Intent sender = new Intent(context, AlarmReceiver.class);
// 设置Intent的数据URI包含笔记ID
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID)));
// 创建PendingIntent用于在将来某个时间点执行Intent
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0);
// 获取AlarmManager系统服务
AlarmManager alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
// 设置闹钟使用RTC_WAKEUP类型确保在指定时间唤醒设备并触发提醒
alarmManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext());
}
// 关闭Cursor释放资源
c.close();
}
}
}
}

@ -20,11 +20,18 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* 广
* 广Activity
*/
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 设置Intent的目标组件为闹钟提醒Activity
intent.setClass(context, AlarmAlertActivity.class);
// 添加FLAG_ACTIVITY_NEW_TASK标志确保在广播接收器中可以启动Activity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 启动闹钟提醒Activity
context.startActivity(intent);
}
}

@ -457,12 +457,18 @@ public class DateTimePicker extends FrameLayout {
mAmPmSpinner.setVisibility(View.VISIBLE);
}
}
/**
*
* (1224)
*/
private void updateHourControl() {
// 判断当前是否为24小时制显示模式
if (mIs24HourView) {
// 设置24小时制下的小时范围(0-23)
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);
} else {
// 设置12小时制下的小时范围(1-12)
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);
}

@ -72,17 +72,39 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener
mOnDateTimeSetListener = callBack;
}
/**
*
* @param date
*/
/**
*
* @param date
*/
private void updateTitle(long date) {
// 设置日期时间格式化标志:显示年、月、日、时、分
int flag =
DateUtils.FORMAT_SHOW_YEAR |
DateUtils.FORMAT_SHOW_DATE |
DateUtils.FORMAT_SHOW_TIME;
DateUtils.FORMAT_SHOW_YEAR | // 显示年份
DateUtils.FORMAT_SHOW_DATE | // 显示日期(月、日)
DateUtils.FORMAT_SHOW_TIME; // 显示时间(时、分)
// 根据当前时间显示模式添加相应标志
// 注意此处存在逻辑问题三元运算符两侧都是FORMAT_24HOUR
// 正确写法应为: mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_12HOUR
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;
// 使用DateUtils格式化日期时间并设置为对话框标题
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));
}
/**
*
* @param arg0
* @param arg1
*/
public void onClick(DialogInterface arg0, int arg1) {
// 检查是否设置了日期时间设置监听器
if (mOnDateTimeSetListener != null) {
// 调用监听器的回调方法,传递当前设置的日期时间(毫秒值)
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
}
}

@ -27,17 +27,32 @@ import android.widget.PopupMenu.OnMenuItemClickListener;
import net.micode.notes.R;
/**
* PopupMenu
*
*/
public class DropdownMenu {
// 关联的按钮视图、弹出菜单实例和菜单对象
private Button mButton;
private PopupMenu mPopupMenu;
private Menu mMenu;
/**
*
* @param context
* @param button
* @param menuId ID
*/
public DropdownMenu(Context context, Button button, int menuId) {
mButton = button;
// 设置按钮背景为下拉图标
mButton.setBackgroundResource(R.drawable.dropdown_icon);
// 创建PopupMenu实例并关联按钮
mPopupMenu = new PopupMenu(context, mButton);
mMenu = mPopupMenu.getMenu();
// 从资源文件加载菜单布局
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
// 设置按钮点击事件,点击时显示下拉菜单
mButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mPopupMenu.show();
@ -45,17 +60,30 @@ public class DropdownMenu {
});
}
/**
*
* @param listener
*/
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
if (mPopupMenu != null) {
mPopupMenu.setOnMenuItemClickListener(listener);
}
}
/**
* ID
* @param id ID
* @return MenuItem
*/
public MenuItem findItem(int id) {
return mMenu.findItem(id);
}
/**
*
* @param title
*/
public void setTitle(CharSequence title) {
mButton.setText(title);
}
}
}

@ -63,18 +63,33 @@ public class FoldersListAdapter extends CursorAdapter {
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
}
/**
*
*
*/
private class FolderListItem extends LinearLayout {
// 文件夹名称文本视图
private TextView mName;
/**
*
* @param context
*/
public FolderListItem(Context context) {
super(context);
// 加载文件夹列表项布局到当前LinearLayout
inflate(context, R.layout.folder_list_item, this);
// 获取布局中的文件夹名称文本视图
mName = (TextView) findViewById(R.id.tv_folder_name);
}
/**
*
* @param name
*/
public void bind(String name) {
mName.setText(name);
}
}
}

@ -151,14 +151,26 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private Pattern mPattern;
@Override
/**
*
*
*/
protected void onCreate(Bundle savedInstanceState) {
// 调用父类方法完成基础初始化
super.onCreate(savedInstanceState);
// 设置当前活动的布局为笔记编辑界面
this.setContentView(R.layout.note_edit);
// 检查是否为首次创建且初始状态失败
// savedInstanceState为null表示首次创建
// initActivityState负责从Intent解析并设置活动状态
if (savedInstanceState == null && !initActivityState(getIntent())) {
// 初始化失败时关闭活动并返回
finish();
return;
}
// 初始化资源(视图引用、监听器等)
initResources();
}

@ -122,19 +122,33 @@ public class NoteEditText extends EditText {
}
@Override
/**
*
*
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
// 处理回车键
case KeyEvent.KEYCODE_ENTER:
// 如果设置了文本变化监听器,则不拦截回车键事件
// 返回false表示继续传递事件给父类或默认处理
if (mOnTextViewChangeListener != null) {
return false;
}
break;
// 处理删除键
case KeyEvent.KEYCODE_DEL:
// 记录删除操作前的光标位置
// 用于后续可能的删除操作逻辑处理
mSelectionStartBeforeDelete = getSelectionStart();
break;
default:
break;
}
// 其他按键事件交由父类处理
return super.onKeyDown(keyCode, event);
}

@ -214,11 +214,22 @@ public class NoteItemData {
return (mAlertDate > 0);
}
/**
*
* @return true
*/
public boolean isCallRecord() {
// 条件父文件夹ID为通话记录文件夹ID且电话号码不为空
return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber));
}
/**
* Cursor
* @param cursor Cursor
* @return Notes
*/
public static int getNoteType(Cursor cursor) {
// 通过预定义的列索引获取笔记类型字段值
return cursor.getInt(TYPE_COLUMN);
}
}

@ -73,11 +73,16 @@ public class NotesListAdapter extends CursorAdapter {
return mChoiceMode;
}
/**
*
* @param mode truefalse退
*/
public void setChoiceMode(boolean mode) {
// 清空已选择的索引集合,重置选择状态
mSelectedIndex.clear();
// 更新选择模式标志
mChoiceMode = mode;
}
public void selectAll(boolean checked) {
Cursor cursor = getCursor();
for (int i = 0; i < getCount(); i++) {

@ -425,15 +425,27 @@ public class NotesPreferenceActivity extends PreferenceActivity {
}
@Override
/**
*
* ActionBar/
*/
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// 处理Home/返回按钮点击事件
case android.R.id.home:
// 点击返回按钮返回到笔记列表Activity
// 创建返回笔记列表的Intent
Intent intent = new Intent(this, NotesListActivity.class);
// 添加FLAG_ACTIVITY_CLEAR_TOP标志
// 1. 如果目标Activity(NotesListActivity)已存在于栈中
// 2. 则清除该Activity之上的所有Activity
// 3. 并将目标Activity移到栈顶而不是创建新实例
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// 启动笔记列表Activity
startActivity(intent);
return true;
default:
// 其他菜单项交给父类处理
return false;
}
}

@ -46,14 +46,30 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
private static final String TAG = "NoteWidgetProvider";
@Override
/**
*
*
*/
public void onDeleted(Context context, int[] appWidgetIds) {
// 创建内容值对象,用于存储要更新的字段和值
ContentValues values = new ContentValues();
// 将笔记的小部件ID设置为无效值
// AppWidgetManager.INVALID_APPWIDGET_ID = -1
// 表示该笔记不再关联任何桌面小部件
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
// 遍历所有被删除的小部件ID
for (int i = 0; i < appWidgetIds.length; i++) {
context.getContentResolver().update(Notes.CONTENT_NOTE_URI,
values,
NoteColumns.WIDGET_ID + "=?",
new String[] { String.valueOf(appWidgetIds[i])});
// 执行更新操作
// 筛选条件只更新WIDGET_ID等于当前被删除小部件ID的笔记
// 参数数组将小部件ID转换为字符串作为筛选条件参数
context.getContentResolver().update(
Notes.CONTENT_NOTE_URI, // 笔记内容URI
values, // 要更新的字段和值
NoteColumns.WIDGET_ID + "=?", // 筛选条件小部件ID等于指定值
new String[] { String.valueOf(appWidgetIds[i]) } // 筛选条件参数
);
}
}

@ -24,24 +24,49 @@ import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser;
/**
* 2x
* 2x
*/
public class NoteWidgetProvider_2x extends NoteWidgetProvider {
@Override
/**
*
*
*/
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// 委托给父类实现通用的小部件更新逻辑
super.update(context, appWidgetManager, appWidgetIds);
}
@Override
/**
* ID
* @return 2xID
*/
protected int getLayoutId() {
// 返回适合2x尺寸的小部件布局
return R.layout.widget_2x;
}
@Override
/**
* ID
* @param bgId ID
* @return 2xID
*/
protected int getBgResourceId(int bgId) {
// 根据背景颜色ID获取对应的2x尺寸小部件背景资源
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);
}
@Override
/**
*
* @return 2x
*/
protected int getWidgetType() {
// 返回表示2x尺寸小部件的类型常量
return Notes.TYPE_WIDGET_2X;
}
}

Loading…
Cancel
Save