代码注释

yanxingxv
STRIV1 8 months ago
parent fda339a03a
commit 9289dd03a6

@ -0,0 +1,159 @@
/*
* 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;
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。
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; // 用于播放提醒声音的 MediaPlayer。
@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 {
mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); // 从 Intent 中获取便签 ID。
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(); // 初始化 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);
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) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (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);
}
// DialogInterface.OnClickListener 的实现,处理对话框按钮点击事件。
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_NEGATIVE:
Intent intent = new Intent(this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, mNoteId);
startActivity(intent);
break;
default:
break;
}
}
// DialogInterface.OnDismissListener 的实现,处理对话框消失事件。
public void onDismiss(DialogInterface dialog) {
stopAlarmSound();
finish();
}
// 停止提醒声音。
private void stopAlarmSound() {
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
mPlayer = null;
}
}
}

@ -0,0 +1,75 @@
/*
* 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.AlarmManager; // 引入AlarmManager类用于设置闹钟
import android.app.PendingIntent; // 引入PendingIntent类表示延迟的Intent
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类处理笔记数据
import net.micode.notes.data.Notes.NoteColumns; // 引入NoteColumns类表示Notes表的列
public class AlarmInitReceiver extends BroadcastReceiver { // 定义一个继承自BroadcastReceiver的类
// 定义查询需要的列
private static final String [] PROJECTION = new String [] {
NoteColumns.ID, // 获取笔记的ID列
NoteColumns.ALERTED_DATE // 获取提醒时间列
};
// 列索引常量
private static final int COLUMN_ID = 0; // 第0列是ID列
private static final int COLUMN_ALERTED_DATE = 1; // 第1列是提醒时间列
@Override
public void onReceive(Context context, Intent intent) { // 重写onReceive方法接收广播
long currentDate = System.currentTimeMillis(); // 获取当前的系统时间(以毫秒为单位)
// 查询数据库,获取需要提醒的笔记,且提醒时间大于当前时间
Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI, // 查询URI为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用于发送广播
sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); // 设置Intent的数据笔记的ID
// 创建PendingIntent表示在指定时间执行AlarmReceiver广播
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0);
// 获取系统的AlarmManager服务
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// 设置闹钟使用RTC_WAKEUP模式当到达指定的提醒时间时唤醒设备并触发PendingIntent
alarmManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent);
} while (c.moveToNext()); // 如果查询结果中还有下一条记录,则继续处理
}
c.close(); // 关闭Cursor
}
}
}

@ -0,0 +1,35 @@
/*
* 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.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
// AlarmReceiver 类继承自 BroadcastReceiver用于接收便签提醒的广播事件。
public class AlarmReceiver extends BroadcastReceiver {
// onReceive 方法是 BroadcastReceiver 的回调方法,当接收到广播时被调用。
@Override
public void onReceive(Context context, Intent intent) {
// 设置 intent 的目标类为 AlarmAlertActivity。
intent.setClass(context, AlarmAlertActivity.class);
// 为 intent 添加 FLAG_ACTIVITY_NEW_TASK 标志,使得在新的任务栈中启动 Activity。
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 在给定的上下文中启动 AlarmAlertActivity。
context.startActivity(intent);
}
}

@ -0,0 +1,222 @@
/*
* 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 java.text.DateFormatSymbols;
import java.util.Calendar;
import net.micode.notes.R;
import android.content.Context;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.NumberPicker;
// DateTimePicker 类继承自 FrameLayout用于提供一个日期时间选择器。
public class DateTimePicker extends FrameLayout {
// 默认启用状态。
private static final boolean DEFAULT_ENABLE_STATE = true;
// 半天的小时数和全天的小时数。
private static final int HOURS_IN_HALF_DAY = 12;
private static final int HOURS_IN_ALL_DAY = 24;
// 一周的天数。
private static final int DAYS_IN_ALL_WEEK = 7;
// 日期选择器的最小值和最大值。
private static final int DATE_SPINNER_MIN_VAL = 0;
private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1;
// 24小时制和12小时制下小时选择器的最小值和最大值。
private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0;
private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23;
private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1;
private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12;
// 分钟选择器的最小值和最大值。
private static final int MINUT_SPINNER_MIN_VAL = 0;
private static final int MINUT_SPINNER_MAX_VAL = 59;
// 上下午选择器的最小值和最大值。
private static final int AMPM_SPINNER_MIN_VAL = 0;
private static final int AMPM_SPINNER_MAX_VAL = 1;
// 日期、小时、分钟和上下午的 NumberPicker 控件。
private final NumberPicker mDateSpinner;
private final NumberPicker mHourSpinner;
private final NumberPicker mMinuteSpinner;
private final NumberPicker mAmPmSpinner;
// 用于存储日期的 Calendar 对象。
private Calendar mDate;
// 日期显示值数组。
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];
// 表示是否为上午的布尔值。
private boolean mIsAm;
// 表示是否为24小时视图的布尔值。
private boolean mIs24HourView;
// 控件的启用状态。
private boolean mIsEnabled = DEFAULT_ENABLE_STATE;
// 正在初始化的布尔值。
private boolean mInitialising;
// 日期时间改变监听器。
private OnDateTimeChangedListener mOnDateTimeChangedListener;
// 日期改变监听器。
private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 更新日期并通知日期时间改变。
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal);
updateDateControl();
onDateTimeChanged();
}
};
// 小时改变监听器。
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 更新小时并通知日期时间改变。
// 处理12小时制下上下午的转换。
boolean isDateChanged = false;
Calendar cal = Calendar.getInstance();
if (!mIs24HourView) {
if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
} else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
}
if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY ||
oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
mIsAm = !mIsAm;
updateAmPmControl();
}
} else {
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
}
}
int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
mDate.set(Calendar.HOUR_OF_DAY, newHour);
onDateTimeChanged();
if (isDateChanged) {
setCurrentYear(cal.get(Calendar.YEAR));
setCurrentMonth(cal.get(Calendar.MONTH));
setCurrentDay(cal.get(Calendar.DAY_OF_MONTH));
}
}
};
// 分钟改变监听器。
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 更新分钟并通知日期时间改变。
int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0;
if (oldVal == maxValue && newVal == minValue) {
offset += 1;
} else if (oldVal == minValue && newVal == maxValue) {
offset -= 1;
}
if (offset != 0) {
mDate.add(Calendar.HOUR_OF_DAY, offset);
mHourSpinner.setValue(getCurrentHour());
updateDateControl();
int newHour = getCurrentHourOfDay();
if (newHour >= HOURS_IN_HALF_DAY) {
mIsAm = false;
updateAmPmControl();
} else {
mIsAm = true;
updateAmPmControl();
}
}
mDate.set(Calendar.MINUTE, newVal);
onDateTimeChanged();
}
};
// 上下午改变监听器。
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 更新上下午并通知日期时间改变。
mIsAm = !mIsAm;
if (mIsAm) {
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);
} else {
mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY);
}
updateAmPmControl();
onDateTimeChanged();
}
};
// 日期时间改变监听器接口。
public interface OnDateTimeChangedListener {
void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute);
}
// DateTimePicker 的构造函数。
public DateTimePicker(Context context) {
this(context, System.currentTimeMillis());
}
public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context));
}
public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context);
mDate = Calendar.getInstance();
mInitialising = true;
mIsAm = getCurrentHourOfDay() >= HOURS_IN_HALF_DAY;
inflate(context, R.layout.datetime_picker, this);
// 初始化日期、小时、分钟和上下午的 NumberPicker 控件。
mDateSpinner = (NumberPicker) findViewById(R.id.date);
mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);
mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);
mDateSpinner.setOnValueChangedListener(mOnDateChangedListener);
mHourSpinner = (NumberPicker) findViewById(R.id.hour);
mHourSpinner.setOnValueChangedListener(mOnHourChangedListener);
mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL);
mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL);
mMinuteSpinner.setOnLongPressUpdateInterval(100);
mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener);
//

@ -0,0 +1,98 @@
/*
* 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 java.util.Calendar; // 引入Calendar类用于处理日期和时间
import net.micode.notes.R; // 引入R文件用于获取资源ID
import net.micode.notes.ui.DateTimePicker; // 引入自定义的DateTimePicker控件
import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener; // 引入DateTimePicker控件的监听器
import android.app.AlertDialog; // 引入AlertDialog类用于创建对话框
import android.content.Context; // 引入Context类用于访问应用程序上下文
import android.content.DialogInterface; // 引入DialogInterface类用于处理对话框的按钮事件
import android.content.DialogInterface.OnClickListener; // 引入OnClickListener接口用于按钮点击事件
import android.text.format.DateFormat; // 引入DateFormat类用于格式化日期和时间
import android.text.format.DateUtils; // 引入DateUtils类用于时间格式化与操作
// 定义一个自定义的DateTimePickerDialog类继承自AlertDialog
public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
private Calendar mDate = Calendar.getInstance(); // 用于保存当前日期和时间
private boolean mIs24HourView; // 标记是否为24小时制显示
private OnDateTimeSetListener mOnDateTimeSetListener; // 回调接口,用于在日期和时间设置后通知调用者
private DateTimePicker mDateTimePicker; // 自定义的日期时间选择器
// 定义回调接口,用于在用户设置日期时间后进行处理
public interface OnDateTimeSetListener {
void OnDateTimeSet(AlertDialog dialog, long date); // 回调方法,传递设置的日期时间
}
// 构造函数,初始化对话框,设置默认日期时间
public DateTimePickerDialog(Context context, long date) {
super(context); // 调用父类构造函数初始化AlertDialog
mDateTimePicker = new DateTimePicker(context); // 初始化DateTimePicker控件
setView(mDateTimePicker); // 设置对话框的内容视图为DateTimePicker控件
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() { // 设置日期时间变化的监听器
public void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
mDate.set(Calendar.YEAR, year); // 设置选中的年
mDate.set(Calendar.MONTH, month); // 设置选中的月
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); // 设置选中的天
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay); // 设置选中的小时
mDate.set(Calendar.MINUTE, minute); // 设置选中的分钟
updateTitle(mDate.getTimeInMillis()); // 更新对话框标题显示的日期时间
}
});
mDate.setTimeInMillis(date); // 将传入的日期时间(毫秒)设置为当前日期
mDate.set(Calendar.SECOND, 0); // 将秒设置为0
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis()); // 设置DateTimePicker控件的初始日期
setButton(context.getString(R.string.datetime_dialog_ok), this); // 设置“确认”按钮,并指定点击时的行为
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null); // 设置“取消”按钮
set24HourView(DateFormat.is24HourFormat(this.getContext())); // 设置是否为24小时制显示
updateTitle(mDate.getTimeInMillis()); // 初始化时更新对话框的标题
}
// 设置是否使用24小时制
public void set24HourView(boolean is24HourView) {
mIs24HourView = is24HourView;
}
// 设置日期时间设置完成后的回调监听器
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
mOnDateTimeSetListener = callBack;
}
// 更新对话框标题,显示当前选中的日期时间
private void updateTitle(long date) {
// 设置日期时间显示的格式
int flag =
DateUtils.FORMAT_SHOW_YEAR | // 显示年份
DateUtils.FORMAT_SHOW_DATE | // 显示日期
DateUtils.FORMAT_SHOW_TIME; // 显示时间
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR; // 如果是24小时制显示24小时格式
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); // 格式化日期时间并设置为对话框标题
}
// 确认按钮点击事件的处理
public void onClick(DialogInterface arg0, int arg1) {
if (mOnDateTimeSetListener != null) {
// 调用回调接口,传递设置的日期时间
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
}
}
}

@ -0,0 +1,63 @@
/*
* 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.content.Context; // 引入Context类用于访问应用程序的上下文
import android.view.Menu; // 引入Menu类用于操作菜单
import android.view.MenuItem; // 引入MenuItem类用于菜单项的处理
import android.view.View; // 引入View类用于视图的操作
import android.view.View.OnClickListener; // 引入OnClickListener接口用于处理点击事件
import android.widget.Button; // 引入Button类用于显示按钮
import android.widget.PopupMenu; // 引入PopupMenu类用于显示弹出菜单
import android.widget.PopupMenu.OnMenuItemClickListener; // 引入PopupMenu的菜单项点击监听器
public class DropdownMenu {
private Button mButton; // 用于显示的按钮,点击后弹出菜单
private PopupMenu mPopupMenu; // 弹出菜单的实例
private Menu mMenu; // 菜单项的集合
// 构造函数初始化DropdownMenu设置按钮及其弹出菜单
public DropdownMenu(Context context, Button button, int menuId) {
mButton = button; // 获取传入的按钮对象
mButton.setBackgroundResource(R.drawable.dropdown_icon); // 设置按钮的背景图标为下拉菜单图标
mPopupMenu = new PopupMenu(context, mButton); // 初始化PopupMenu指定按钮作为弹出菜单的锚点
mMenu = mPopupMenu.getMenu(); // 获取PopupMenu中的Menu对象
mPopupMenu.getMenuInflater().inflate(menuId, mMenu); // 使用传入的menuId加载菜单资源
mButton.setOnClickListener(new OnClickListener() { // 为按钮设置点击事件监听器
public void onClick(View v) {
mPopupMenu.show(); // 当按钮被点击时,显示弹出菜单
}
});
}
// 设置菜单项点击事件监听器
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
if (mPopupMenu != null) {
mPopupMenu.setOnMenuItemClickListener(listener); // 设置PopupMenu的菜单项点击监听器
}
}
// 根据菜单项的ID查找菜单项
public MenuItem findItem(int id) {
return mMenu.findItem(id); // 在菜单中查找具有指定ID的菜单项
}
// 设置按钮的文本
public void setTitle(CharSequence title) {
mButton.setText(title); // 设置按钮的文本为传入的title
}
}

@ -1,89 +0,0 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui;
import android.content.Context;
import android.database.Cursor;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
// FoldersListAdapter 是一个自定义的 CursorAdapter用于显示文件夹列表。
public class FoldersListAdapter extends CursorAdapter {
// 定义查询数据库时需要的列。
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
};
// 定义列索引常量。
public static final int ID_COLUMN = 0;
public static final int NAME_COLUMN = 1;
// FoldersListAdapter 的构造函数。
public FoldersListAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}
// 新建视图的方法,返回一个 FolderListItem 实例。
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new FolderListItem(context);
}
// 绑定视图与数据的方法。
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof FolderListItem) {
String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
((FolderListItem) view).bind(folderName);
}
}
// 根据位置获取文件夹名称的方法。
public String getFolderName(Context context, int position) {
Cursor cursor = (Cursor) getItem(position);
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
}
// FolderListItem 是一个内部类,表示列表中的单个文件夹项。
private class FolderListItem extends LinearLayout {
private TextView mName; // 用于显示文件夹名称的 TextView。
// FolderListItem 的构造函数。
public FolderListItem(Context context) {
super(context);
inflate(context, R.layout.folder_list_item, this);
mName = (TextView) findViewById(R.id.tv_folder_name);
}
// 绑定文件夹名称的方法。
public void bind(String name) {
mName.setText(name);
}
}
}

@ -0,0 +1,144 @@
/*
* 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.widget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.util.Log;
import android.widget.RemoteViews;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.tool.ResourceParser;
import net.micode.notes.ui.NoteEditActivity;
import net.micode.notes.ui.NotesListActivity;
// 继承自AppWidgetProvider的抽象类用于管理便签小部件。
public abstract class NoteWidgetProvider extends AppWidgetProvider {
// 定义查询数据库时需要的列。
public static final String [] PROJECTION = new String [] {
NoteColumns.ID,
NoteColumns.BG_COLOR_ID,
NoteColumns.SNIPPET
};
// 定义列索引常量。
public static final int COLUMN_ID = 0;
public static final int COLUMN_BG_COLOR_ID = 1;
public static final int COLUMN_SNIPPET = 2;
// 日志标签用于Logcat中识别日志来源。
private static final String TAG = "NoteWidgetProvider";
// 当小部件被删除时调用更新数据库中对应的笔记widget id为无效值。
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
ContentValues values = new ContentValues();
values.put(NoteColumns.WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_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])});
}
}
// 获取小部件相关的笔记信息。
private Cursor getNoteWidgetInfo(Context context, int widgetId) {
return context.getContentResolver().query(Notes.CONTENT_NOTE_URI,
PROJECTION,
NoteColumns.WIDGET_ID + "=? AND " + NoteColumns.PARENT_ID + "<>?",
new String[] { String.valueOf(widgetId), String.valueOf(Notes.ID_TRASH_FOLER) },
null);
}
// 更新小部件显示。
protected void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
update(context, appWidgetManager, appWidgetIds, false);
}
// 更新小部件显示,考虑隐私模式。
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds,
boolean privacyMode) {
for (int i = 0; i < appWidgetIds.length; i++) {
if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) {
int bgId = ResourceParser.getDefaultBgId(context);
String snippet = "";
Intent intent = new Intent(context, NoteEditActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType());
Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]);
if (c != null && c.moveToFirst()) {
if (c.getCount() > 1) {
Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]);
c.close();
return;
}
snippet = c.getString(COLUMN_SNIPPET);
bgId = c.getInt(COLUMN_BG_COLOR_ID);
intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID));
intent.setAction(Intent.ACTION_VIEW);
} else {
snippet = context.getResources().getString(R.string.widget_havenot_content);
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
}
if (c != null) {
c.close();
}
// 设置小部件的布局和行为。
RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId());
rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId));
intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId);
/**
* 宿PendingIntent
*/
PendingIntent pendingIntent = null;
if (privacyMode) {
rv.setTextViewText(R.id.widget_text,
context.getString(R.string.widget_under_visit_mode));
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent(
context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
} else {
rv.setTextViewText(R.id.widget_text, snippet);
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
rv.setOnClickPendingIntent(R.id.widget_text, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
}
}
// 获取背景资源ID的方法需由子类实现。
protected abstract int getBgResourceId(int bgId);
// 获取布局ID的方法需由子类实现。
protected abstract int getLayoutId();
// 获取小部件类型的方法,需由子类实现。
protected abstract int getWidgetType();
}

@ -0,0 +1,55 @@
/*
* 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.widget;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser;
// NoteWidgetProvider_2x 是 NoteWidgetProvider 的具体实现类用于提供2x2网格大小的便签小部件。
public class NoteWidgetProvider_2x extends NoteWidgetProvider {
// 当小部件需要更新时调用此方法。
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// 调用父类的 update 方法来执行更新。
super.update(context, appWidgetManager, appWidgetIds);
}
// 返回小部件的布局资源ID。
@Override
protected int getLayoutId() {
// 返回2x2网格小部件的布局资源ID。
return R.layout.widget_2x;
}
// 根据传入的背景ID返回对应的资源ID。
@Override
protected int getBgResourceId(int bgId) {
// 使用 ResourceParser 类的静态方法来获取2x2网格小部件的背景资源ID。
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);
}
// 返回小部件的类型。
@Override
protected int getWidgetType() {
// 返回小部件的类型为TYPE_WIDGET_2X这是一个定义在Notes类中的常量。
return Notes.TYPE_WIDGET_2X;
}
}

@ -0,0 +1,55 @@
/*
* 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.widget;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.ResourceParser;
// NoteWidgetProvider_4x 类继承自 NoteWidgetProvider 类用于提供4x4网格大小的便签小部件。
public class NoteWidgetProvider_4x extends NoteWidgetProvider {
// 当小部件需要更新时,系统会调用此方法。
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// 调用父类的 update 方法来更新小部件。
super.update(context, appWidgetManager, appWidgetIds);
}
// 返回小部件的布局资源ID。
@Override
protected int getLayoutId() {
// 返回4x4网格小部件的布局资源ID。
return R.layout.widget_4x;
}
// 根据传入的背景ID返回对应的资源ID。
@Override
protected int getBgResourceId(int bgId) {
// 使用 ResourceParser 类的静态方法来获取4x4网格小部件的背景资源ID。
return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId);
}
// 返回小部件的类型。
@Override
protected int getWidgetType() {
// 返回小部件的类型为TYPE_WIDGET_4X这是一个定义在Notes类中的常量。
return Notes.TYPE_WIDGET_4X;
}
}
Loading…
Cancel
Save