1. 简单闹钟实现

1、建立一个AlarmReceiver继承入BroadcastReceiver,并在AndroidManifest.xml声明

publicstatic class AlarmReceiver extends BroadcastReceiver { 
 @Override
 public void onReceive(Context context, Intent intent) {
 Toast.makeText(context, "闹钟提示:时间到!",Toast.LENGTH_LONG).show(); 
 } 
 }


2、建立Intent和PendingIntent,来调用目标组件。

Intentintent = new Intent(this, AlarmReceiver.class); 
 PendingIntentpendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);



3、设置闹钟
获取闹钟管理的实例:

AlarmManageralarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);


设置单次闹钟:

alarmManager.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + (5*1000), pendingIntent);


设置周期闹钟:

alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + (10*1000), (24*60*60*1000),pendingIntent);
  1. Android闹钟数据存储

闹钟数据存储主要分两种存储方式:

  1. 以ContentProvide实现数据存储

ContentProvide形式存储的数据主要包括:闹钟是否已启动,闹钟时间(时:分),闹钟日期,闹钟振动,闹钟标签等内容。

  1. 以SharePreference实现数据存储。

SharePreference形式存储的数据主要包括:闹钟贪睡时间ID,闹钟时间(时:分)。

  1. 时钟主界面

Android 闹钟会触发音频焦点吗_Android 闹钟会触发音频焦点吗

主界面实现函数为DeskClock.java类实现的,mNextAlarm显示下一个闹铃的时间,如果没有闹铃,则该控件隐藏掉。

在函数refreshAlarm()中获得下一个闹铃时间。

  1. 设置闹钟

Android 闹钟会触发音频焦点吗_Android 闹钟会触发音频焦点吗_02

在Android系统中,闹钟列表界面有类AlarmClock.java类实现的,当选择添加一个类时,调用

privatevoid addNewAlarm() {
startActivity(newIntent(this, SetAlarm.class));
}

当修改已有的闹钟时,通过获得修改闹钟的ID,进入闹钟设置界面

publicboolean onContextItemSelected(final MenuItem item) {
finalAdapterContextMenuInfo info =
(AdapterContextMenuInfo)item.getMenuInfo();
finalint id = (int) info.id;
…..

caseR.id.edit_alarm:

Intentintent = new Intent(this, SetAlarm.class);
intent.putExtra(Alarms.ALARM_ID,id);
startActivity(intent);
returntrue;
}

Android 闹钟会触发音频焦点吗_Android 闹钟会触发音频焦点吗_03

在闹钟的设置界面由SetAlarm.java类实现的。该类继承了父类PreferenceActivity,同时实现了接口TimePickerDialog.OnTimeSetListener和接口Preference.OnPreferenceChangeListener。

在该界面可以实现闹钟是否启动,闹钟时间,闹钟日期,闹钟振动,闹钟标签等内容选择,当选择完成后调用SaveAlarm函数,通过Alarms类中的接口函数AddAlarm或SetAlarm将数据存储。

private longsaveAlarm() {
Alarm alarm =new Alarm();
alarm.id =mId;
alarm.enabled= mEnabledPref.isChecked();
alarm.hour =mHour;
alarm.minutes= mMinutes;
alarm.daysOfWeek= mRepeatPref.getDaysOfWeek();
alarm.vibrate= mVibratePref.isChecked();
alarm.label =mLabel.getText();
alarm.alert =mAlarmPref.getAlert();
long time;
if (alarm.id== -1) {
time =Alarms.addAlarm(this, alarm);
mId =alarm.id;
} else {
time =Alarms.setAlarm(this, alarm);
}
return time;
}
  1. 保存闹钟

Android系统中闹钟数据存储,删除,修改等工作由类Alarms.java完成。

AddAlarm添加一个闹钟

deleteAlarm删除一个闹钟存储数据

deleteAllAlarm删除所有的闹钟存储数据

disableAlert取消该闹钟

disableSnoozeAlert取消贪睡闹钟

enableAlarm闹钟enable选项修改

enableAlert启动该闹钟

setAlarm重设闹钟数据

setNextAlert设置系统下一个闹钟,首先比较已有闹钟的时间,选择最接近系统的闹钟,然后判断是否有贪睡闹钟,如果有,则比较贪睡闹钟与设置闹钟的时间设置,最终选择最近的闹钟。

publicstatic void setNextAlert(final Context context) {
Alarmalarm = calculateNextAlert(context);
longtime = getSnoozeAlert(context);
if((alarm != null && alarm.time <= time) 
||(alarm != null && time == -1)) { 
enableAlert(context,alarm, alarm.time);
}
elseif((alarm != null && time < alarm.time) 
||(alarm == null && time != -1)) {
enableSnoozeAlert(context);
}
else{
disableAlert(context);
} }


calculateNextAlert计算距离系统时间最近的闹钟,并获取

saveSnoozeAlert函数将闹钟贪睡后的贪睡闹钟以SharePerference形式进行保存。

staticvoid saveSnoozeAlert(final Context context, final int id,
finallong time) {
SharedPreferencesprefs = context.getSharedPreferences(
AlarmClock.PREFERENCES,0);
if(id == -1) {
clearSnoozePreference(context,prefs);
}else {
SharedPreferences.Editored = prefs.edit();
ed.putInt(PREF_SNOOZE_ID,id);
ed.putLong(PREF_SNOOZE_TIME,time);
ed.apply();
}
//Set the next alert after updating the snooze.
setNextAlert(context);
}


  1. 执行闹钟

通过函数enableAlert向系统发送广播

privatestatic void enableAlert(Context context, final Alarm alarm,
finallong atTimeInMillis) {
AlarmManager am =(AlarmManager)
context.getSystemService(Context.ALARM_SERVICE);

if(Log.LOGV) {
Log.v("**setAlert id " + alarm.id + " atTime " +atTimeInMillis);
}

Intentintent = new Intent(ALARM_ALERT_ACTION);
Parcelout = Parcel.obtain();
alarm.writeToParcel(out,0);
out.setDataPosition(0);
intent.putExtra(ALARM_RAW_DATA,out.marshall());

PendingIntent sender= PendingIntent.getBroadcast(
context, 0, intent,PendingIntent.FLAG_CANCEL_CURRENT);

am.set(AlarmManager.POWER_OFF_WAKEUP,atTimeInMillis, sender);
alarm_flag_setup(context,atTimeInMillis,alarm);

setStatusBarIcon(context,true);
Calendarc = Calendar.getInstance();
c.setTimeInMillis(atTimeInMillis);
StringtimeString = formatDayAndTime(context, c);
saveNextAlarm(context,timeString);
}

当系统获取该广播后,Android系统按照所设置的时间启动闹钟服务。

  1. 闹钟响应

广播接收类AlarmReceiver在AndroidManifest.xml文件中注册内容如下:

<receiverandroid:name="AlarmReceiver">
<intent-filter>
<actionandroid:name="com.android.deskclock.ALARM_ALERT" />
<actionandroid:name="alarm_killed" />
<actionandroid:name="cancel_snooze" />
<actionandroid:name="android.intent.action.ACTION_SHUTDOWN" />
<actionandroid:name="android.intent.action.FAKE_SHUTDOWN_ON" />
<actionandroid:name="android.intent.action.ACTION_SHUTDOWN" />
<actionandroid:name="android.intent.action.FAKE_BOOT_COMPLETED" />
</intent-filter>
</receiver>

当闹钟按照所设置的时间,发送广播消息com.android.deskclock.ALARM_ALERT后,将启动AlarmReceiver中OnReceive函数。

在OnReceive中主要做如下工作:

  1. 如果该闹钟是贪睡闹钟,则清除掉该闹钟数据;
  2. 如果该闹钟是重复执行,则计算获得距离当前系统时间最近的一个闹钟作为下一个闹钟;
  3. 判断手机是否关机,如果关机,则return;
  4. 关闭dialog,将窗口灰置;
  5. 启动闹钟铃声服务;
  6. 修改状态栏等操作;


闹钟铃声服务由AlarmKlaxon.java类完成。

当在闹钟弹出窗口后,点击确定,则发出stopService广播,关闭闹钟铃声,同时设置闹钟贪睡时间,点击取消,则发送stopService广播,关闭闹钟。

Android 闹钟会触发音频焦点吗_Android 闹钟会触发音频焦点吗_04

在锁屏界面闹钟响应时,AlarmAlertFullScreen.java完成

在非锁屏界面下响应时,AlarmAlertextends AlarmAlertFullScreen完成,主要是2秒屏幕响应时间

  1. 问题

1/最多可以实现几个闹钟贪睡

2/如果有两个闹钟响起,前面一个会停止,后面一个会响起

3/每设置一次闹钟,闹钟列表就重新比较一次,得到时间最近的闹钟

4/闹钟重复设置,存储数据计算