DeskClock分析文档
? AlarmReceiver类继承BroadcastReceiver,该类重写onReceive()方法,定义
了NotificationManager()和updateNotification()。 ?
onReceive()方法接受系统发来的广播
@Override
public void onReceive(Context context, Intent intent) { //杀死闹铃
if (Alarms.ALARM_KILLED.equals(intent.getAction())) {Log.e(\
// The alarm has been killed, update the notification updateNotification(context, (Alarm) //手动杀死
intent.getParcelableExtra(Alarms.ALARM_INTENT_EXTRA),
//超时杀死
intent.getIntExtra(Alarms.ALARM_KILLED_TIMEOUT, -1)); return;
} else if (Alarms.CANCEL_SNOOZE.equals(intent.getAction())) { Log.e(\
Alarms.saveSnoozeAlert(context, -1, -1); return; }
Alarm alarm = null; //
final byte[] data =
intent.getByteArrayExtra(Alarms.ALARM_RAW_DATA); if (data != null) {Log.e(\ Parcel in = Parcel.obtain();
in.unmarshall(data, 0, data.length); in.setDataPosition(0);
alarm = Alarm.CREATOR.createFromParcel(in); }
if (alarm == null) {Log.e(\
Log.v(\intent\
return; }
// Intentionally verbose: always log the alarm time to provide useful
// information in bug reports.
16
DeskClock分析文档
long now = System.currentTimeMillis(); SimpleDateFormat format =
new SimpleDateFormat(\
Log.v(\ + format.format(new Date(alarm.time)));
if (now > alarm.time + STALE_WINDOW * 1000) {Log.e(\ if (Log.LOGV) {
Log.v(\ } return; }
// 保证cpu唤醒前,通过AlarmAlertWakeLock和AlarmAlert将 AlarmAlertWakeLock.acquireCpuWakeLock(context);
/* Close dialogs and window shade */ Intent closeDialogs = new
Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); context.sendBroadcast(closeDialogs);
//决定哪些活动开始基于keyguard的状态. Class c = AlarmAlert.class;
KeyguardManager km = (KeyguardManager) context.getSystemService( Context.KEYGUARD_SERVICE);Log.e(\ if (km.inKeyguardRestrictedInputMode()) {Log.e(\
// 使用全屏活动以保证安全.
c = AlarmAlertFullScreen.class; }
/* launch UI, explicitly stating that this is not due to user action * so that the current app's notification management is not disturbed */
Intent alarmAlert = new Intent(context, c);
alarmAlert.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm); alarmAlert.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION); context.startActivity(alarmAlert);
// 如果snooze,禁用.
Alarms.disableSnoozeAlert(context, alarm.id); // 如果没有重复,禁用
17
DeskClock分析文档
if (!alarm.daysOfWeek.isRepeatSet()) {Log.e(\ Alarms.enableAlarm(context, alarm.id, false); } else {Log.e(\
//如果有下一个警报。enableAlarm通知setNextAler,避免调用它的两次. Alarms.setNextAlert(context); }
// 启用闹铃和震动装置.
Intent playAlarm = new Intent(Alarms.ALARM_ALERT_ACTION); playAlarm.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm); context.startService(playAlarm);
Intent notify = new Intent(context, AlarmAlert.class); notify.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm);
PendingIntent pendingNotify = PendingIntent.getActivity(context, alarm.id, notify, 0);
String label = alarm.getLabelOrDefault(context); Log.e(\
Notification n = new Notification(R.drawable.stat_notify_alarm, label, alarm.time);
n.setLatestEventInfo(context, label,
context.getString(R.string.alarm_notify_text), pendingNotify);
n.flags |= Notification.FLAG_SHOW_LIGHTS | Notification.FLAG_ONGOING_EVENT; n.defaults |= Notification.DEFAULT_LIGHTS;
NotificationManager nm = getNotificationManager(context); nm.notify(alarm.id, n);
}
? updateNotification()方法更新消息 private void updateNotification(Context context, Alarm alarm, int timeout) {
NotificationManager nm = getNotificationManager(context);
// If the alarm is null, just cancel the notification. if (alarm == null) {
if (Log.LOGV) {Log.e(\
18
DeskClock分析文档
Log.v(\ } return; }
// 当点击,发出SetAlarm.
Intent viewAlarm = new Intent(context, SetAlarm.class); viewAlarm.putExtra(Alarms.ALARM_ID, alarm.id); PendingIntent intent =
PendingIntent.getActivity(context, alarm.id, viewAlarm, 0);
//更新通知显示警报已经消失.
String label = alarm.getLabelOrDefault(context); Log.e(\
Notification n = new Notification(R.drawable.stat_notify_alarm, label, alarm.time);
n.setLatestEventInfo(context, label,
context.getString(R.string.alarm_alert_alert_silenced, timeout),
intent);
n.flags |= Notification.FLAG_AUTO_CANCEL;
// We have to cancel the original notification since it is in the // ongoing section and we want the \plain
// notification. nm.cancel(alarm.id); nm.notify(alarm.id, n); } }
19
DeskClock分析文档
三.设置闹钟参数
? SetAlarm继承PreferenceActivity,它是一个参数设置界面和参数存储的Activity。
? PreferenceActivity 继承ListActivity 它是以一个列表的形式在展现内容,它最主要的特
点是添加Preference可以让控件的状态持久化储存,举个例子 比如用户选中checkbox后 退出应用然后在进入应用,这时用户希望看到的是checkbox被选中,所以软件须要记录用户每次操作的过程并且持久储存,在进入应用的时候须要判断这些久储存的数据然后将系统控件的状态呈现在UI中。
尤其是软件开发肯定会有一堆设置选项,每次进入Activity都去手动的去取储存的数据,这样代码会变得很复杂很麻烦。 这个时候Preference就出来了,它就是专门解决这些特殊的选项保存与读取的显示。用户每次操作事件它会及时的以键值对的形式记录在SharedPreferences中,Activity每次启动它会自动帮我们完成数据的读取以及UI的显示。
Android开发中一共为我们提供了4个组件,分别是CheckBoxPreference组件、EditTextPreference组件、ListPreference组件、RingtonePreference组件
SetAlarm类的作用是储存闹钟参数界面的设置。
? Alarm.java闹钟参数界面
· 启动:private CheckBoxPreference mEnabledPref; · 时间:private Preference mTimePref; · 重复: private RepeatPreference mRepeatPref; · 铃声: private AlarmPreference mAlarmPref; · 震动: private CheckBoxPreference mVibratePref · 标签:private EditTextPreference mLabel;
? 以下代码是SetAlarm中onCreate方法
@Override
protected void onCreate(Bundle icicle) { super.onCreate(icicle); Log.e(\ //获得set_alarm的布局文件 setContentView(R.layout.set_alarm);
addPreferencesFromResource(R.xml.alarm_prefs); mLabel = (EditTextPreference) findPreference(\
//为Label设置监听
mLabel.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference p,
20