package com.android.deskclock;
import android.app.AlarmManager;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.ContentValues;
// from the alarm manager.
public static final String ALARM_ALERT_ACTION = "com.android.deskclock.ALARM_ALERT";
+ // A public action sent by AlarmKlaxon when the alarm has stopped sounding
+ // for any reason (e.g. because it has been dismissed from AlarmAlertFullScreen,
+ // or killed due to an incoming phone call, etc).
+ public static final String ALARM_DONE_ACTION = "com.android.deskclock.ALARM_DONE";
+
+ // AlarmAlertFullScreen listens for this broadcast intent, so that other applications
+ // can snooze the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION).
+ public static final String ALARM_SNOOZE_ACTION = "com.android.deskclock.ALARM_SNOOZE";
+
+ // AlarmAlertFullScreen listens for this broadcast intent, so that other applications
+ // can dismiss the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION).
+ public static final String ALARM_DISMISS_ACTION = "com.android.deskclock.ALARM_DISMISS";
+
// This is a private action used by the AlarmKlaxon to update the UI to
// show the alarm has been killed.
public static final String ALARM_KILLED = "alarm_killed";
/**
* Creates a new Alarm.
*/
- public static Uri addAlarm(ContentResolver contentResolver) {
- ContentValues values = new ContentValues();
- values.put(Alarm.Columns.HOUR, 8);
- return contentResolver.insert(Alarm.Columns.CONTENT_URI, values);
+ public static long addAlarm(Context context, Alarm alarm) {
+ ContentValues values = createContentValues(alarm);
+ context.getContentResolver().insert(Alarm.Columns.CONTENT_URI, values);
+
+ long timeInMillis = calculateAlarm(alarm);
+ if (alarm.enabled) {
+ clearSnoozeIfNeeded(context, timeInMillis);
+ }
+ setNextAlert(context);
+ return timeInMillis;
}
/**
null, null);
}
+ private static ContentValues createContentValues(Alarm alarm) {
+ ContentValues values = new ContentValues(8);
+ // Set the alarm_time value if this alarm does not repeat. This will be
+ // used later to disable expire alarms.
+ long time = 0;
+ if (!alarm.daysOfWeek.isRepeatSet()) {
+ time = calculateAlarm(alarm);
+ }
+
+ values.put(Alarm.Columns.ENABLED, alarm.enabled ? 1 : 0);
+ values.put(Alarm.Columns.HOUR, alarm.hour);
+ values.put(Alarm.Columns.MINUTES, alarm.minutes);
+ values.put(Alarm.Columns.ALARM_TIME, alarm.time);
+ values.put(Alarm.Columns.DAYS_OF_WEEK, alarm.daysOfWeek.getCoded());
+ values.put(Alarm.Columns.VIBRATE, alarm.vibrate);
+ values.put(Alarm.Columns.MESSAGE, alarm.label);
+
+ // A null alert Uri indicates a silent alarm.
+ values.put(Alarm.Columns.ALERT, alarm.alert == null ? ALARM_ALERT_SILENT
+ : alarm.alert.toString());
+
+ return values;
+ }
+
+ private static void clearSnoozeIfNeeded(Context context, long alarmTime) {
+ // If this alarm fires before the next snooze, clear the snooze to
+ // enable this alarm.
+ SharedPreferences prefs =
+ context.getSharedPreferences(AlarmClock.PREFERENCES, 0);
+ long snoozeTime = prefs.getLong(PREF_SNOOZE_TIME, 0);
+ if (alarmTime < snoozeTime) {
+ clearSnoozePreference(context, prefs);
+ }
+ }
+
/**
* Return an Alarm object representing the alarm id in the database.
* Returns null if no alarm exists.
/**
* A convenience method to set an alarm in the Alarms
* content provider.
- *
- * @param id corresponds to the _id column
- * @param enabled corresponds to the ENABLED column
- * @param hour corresponds to the HOUR column
- * @param minutes corresponds to the MINUTES column
- * @param daysOfWeek corresponds to the DAYS_OF_WEEK column
- * @param time corresponds to the ALARM_TIME column
- * @param vibrate corresponds to the VIBRATE column
- * @param message corresponds to the MESSAGE column
- * @param alert corresponds to the ALERT column
+ * @return Time when the alarm will fire.
*/
- public static void setAlarm(
- Context context, int id, boolean enabled, int hour, int minutes,
- Alarm.DaysOfWeek daysOfWeek, boolean vibrate, String message,
- String alert) {
-
- ContentValues values = new ContentValues(8);
+ public static long setAlarm(Context context, Alarm alarm) {
+ ContentValues values = createContentValues(alarm);
ContentResolver resolver = context.getContentResolver();
- // Set the alarm_time value if this alarm does not repeat. This will be
- // used later to disable expired alarms.
- long time = 0;
- if (!daysOfWeek.isRepeatSet()) {
- time = calculateAlarm(hour, minutes, daysOfWeek).getTimeInMillis();
+ resolver.update(
+ ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, alarm.id),
+ values, null, null);
+
+ long timeInMillis = calculateAlarm(alarm);
+
+ if (alarm.enabled) {
+ // Disable the snooze if we just changed the snoozed alarm. This
+ // only does work if the snoozed alarm is the same as the given
+ // alarm.
+ // TODO: disableSnoozeAlert should have a better name.
+ disableSnoozeAlert(context, alarm.id);
+
+ // Disable the snooze if this alarm fires before the snoozed alarm.
+ // This works on every alarm since the user most likely intends to
+ // have the modified alarm fire next.
+ clearSnoozeIfNeeded(context, timeInMillis);
}
- if (Log.LOGV) Log.v(
- "** setAlarm * idx " + id + " hour " + hour + " minutes " +
- minutes + " enabled " + enabled + " time " + time);
-
- values.put(Alarm.Columns.ENABLED, enabled ? 1 : 0);
- values.put(Alarm.Columns.HOUR, hour);
- values.put(Alarm.Columns.MINUTES, minutes);
- values.put(Alarm.Columns.ALARM_TIME, time);
- values.put(Alarm.Columns.DAYS_OF_WEEK, daysOfWeek.getCoded());
- values.put(Alarm.Columns.VIBRATE, vibrate);
- values.put(Alarm.Columns.MESSAGE, message);
- values.put(Alarm.Columns.ALERT, alert);
- resolver.update(ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, id),
- values, null, null);
-
setNextAlert(context);
+
+ return timeInMillis;
}
/**
private static void enableAlarmInternal(final Context context,
final Alarm alarm, boolean enabled) {
+ if (alarm == null) {
+ return;
+ }
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues(2);
if (enabled) {
long time = 0;
if (!alarm.daysOfWeek.isRepeatSet()) {
- time = calculateAlarm(alarm.hour, alarm.minutes,
- alarm.daysOfWeek).getTimeInMillis();
+ time = calculateAlarm(alarm);
}
values.put(Alarm.Columns.ALARM_TIME, time);
+ } else {
+ // Clear the snooze if the id matches.
+ disableSnoozeAlert(context, alarm.id);
}
resolver.update(ContentUris.withAppendedId(
// A time of 0 indicates this is a repeating alarm, so
// calculate the time to get the next alert.
if (a.time == 0) {
- a.time = calculateAlarm(a.hour, a.minutes, a.daysOfWeek)
- .getTimeInMillis();
+ a.time = calculateAlarm(a);
} else if (a.time < now) {
// Expired alarm, disable it and move along.
enableAlarmInternal(context, a, false);
setStatusBarIcon(context, true);
Calendar c = Calendar.getInstance();
- c.setTime(new java.util.Date(atTimeInMillis));
+ c.setTimeInMillis(atTimeInMillis);
String timeString = formatDayAndTime(context, c);
saveNextAlarm(context, timeString);
}
final long time) {
SharedPreferences prefs = context.getSharedPreferences(
AlarmClock.PREFERENCES, 0);
- SharedPreferences.Editor ed = prefs.edit();
if (id == -1) {
- clearSnoozePreference(ed);
+ clearSnoozePreference(context, prefs);
} else {
+ SharedPreferences.Editor ed = prefs.edit();
ed.putInt(PREF_SNOOZE_ID, id);
ed.putLong(PREF_SNOOZE_TIME, time);
ed.commit();
return;
} else if (snoozeId == id) {
// This is the same id so clear the shared prefs.
- clearSnoozePreference(prefs.edit());
+ clearSnoozePreference(context, prefs);
}
}
// Helper to remove the snooze preference. Do not use clear because that
- // will erase the clock preferences.
- private static void clearSnoozePreference(final SharedPreferences.Editor ed) {
+ // will erase the clock preferences. Also clear the snooze notification in
+ // the window shade.
+ private static void clearSnoozePreference(final Context context,
+ final SharedPreferences prefs) {
+ final int alarmId = prefs.getInt(PREF_SNOOZE_ID, -1);
+ if (alarmId != -1) {
+ NotificationManager nm = (NotificationManager)
+ context.getSystemService(Context.NOTIFICATION_SERVICE);
+ nm.cancel(alarmId);
+ }
+
+ final SharedPreferences.Editor ed = prefs.edit();
ed.remove(PREF_SNOOZE_ID);
ed.remove(PREF_SNOOZE_TIME);
ed.commit();
// Get the alarm from the db.
final Alarm alarm = getAlarm(context.getContentResolver(), id);
+ if (alarm == null) {
+ return false;
+ }
// The time in the database is either 0 (repeating) or a specific time
// for a non-repeating alarm. Update this value so the AlarmReceiver
// has the right time to compare.
* Tells the StatusBar whether the alarm is enabled or disabled
*/
private static void setStatusBarIcon(Context context, boolean enabled) {
- Intent alarmChanged = new Intent(Intent.ACTION_ALARM_CHANGED);
+ Intent alarmChanged = new Intent("android.intent.action.ALARM_CHANGED");
alarmChanged.putExtra("alarmSet", enabled);
context.sendBroadcast(alarmChanged);
}
+ private static long calculateAlarm(Alarm alarm) {
+ return calculateAlarm(alarm.hour, alarm.minutes, alarm.daysOfWeek)
+ .getTimeInMillis();
+ }
+
/**
* Given an alarm in hours and minutes, return a time suitable for
* setting in AlarmManager.
- * @param hour Always in 24 hour 0-23
- * @param minute 0-59
- * @param daysOfWeek 0-59
*/
- static Calendar calculateAlarm(int hour, int minute, Alarm.DaysOfWeek daysOfWeek) {
+ static Calendar calculateAlarm(int hour, int minute,
+ Alarm.DaysOfWeek daysOfWeek) {
// start with now
Calendar c = Calendar.getInstance();
c.set(Calendar.MILLISECOND, 0);
int addDays = daysOfWeek.getNextAlarm(c);
- /* Log.v("** TIMES * " + c.getTimeInMillis() + " hour " + hour +
- " minute " + minute + " dow " + c.get(Calendar.DAY_OF_WEEK) + " from now " +
- addDays); */
if (addDays > 0) c.add(Calendar.DAY_OF_WEEK, addDays);
return c;
}