15fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project/* 25fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 35fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * 45fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 55fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * you may not use this file except in compliance with the License. 65fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * You may obtain a copy of the License at 75fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * 85fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 95fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * 105fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * See the License for the specific language governing permissions and 145fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * limitations under the License. 155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 17fa954248b41b567dfa2ddd7bd063d3936a51758eDaniel Sandlerpackage com.android.deskclock; 185fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 195fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.app.AlarmManager; 20c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scottimport android.app.NotificationManager; 215fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.app.PendingIntent; 225fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.content.ContentResolver; 235fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.content.ContentValues; 245fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.content.ContentUris; 255fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.content.Context; 265fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.content.Intent; 275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.content.SharedPreferences; 285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.database.Cursor; 295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.net.Uri; 30d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scottimport android.os.Parcel; 315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.provider.Settings; 325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.text.format.DateFormat; 335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport java.util.Calendar; 35eb142ac59aa8039c409b5fe4f50a130f16960d41Eric Fischerimport java.text.DateFormatSymbols; 365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 375fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project/** 385fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * The Alarms provider supplies info about Alarm Clock settings 395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectpublic class Alarms { 415fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 42d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // This action triggers the AlarmReceiver as well as the AlarmKlaxon. It 43d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // is a public action used in the manifest for receiving Alarm broadcasts 44d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // from the alarm manager. 45fa954248b41b567dfa2ddd7bd063d3936a51758eDaniel Sandler public static final String ALARM_ALERT_ACTION = "com.android.deskclock.ALARM_ALERT"; 465fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 47a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram // A public action sent by AlarmKlaxon when the alarm has stopped sounding 48a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram // for any reason (e.g. because it has been dismissed from AlarmAlertFullScreen, 49a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram // or killed due to an incoming phone call, etc). 50a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram public static final String ALARM_DONE_ACTION = "com.android.deskclock.ALARM_DONE"; 51a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram 52a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram // AlarmAlertFullScreen listens for this broadcast intent, so that other applications 53a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram // can snooze the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION). 54a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram public static final String ALARM_SNOOZE_ACTION = "com.android.deskclock.ALARM_SNOOZE"; 55a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram 56a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram // AlarmAlertFullScreen listens for this broadcast intent, so that other applications 57a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram // can dismiss the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION). 58a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram public static final String ALARM_DISMISS_ACTION = "com.android.deskclock.ALARM_DISMISS"; 59a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram 60d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // This is a private action used by the AlarmKlaxon to update the UI to 61d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // show the alarm has been killed. 62d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static final String ALARM_KILLED = "alarm_killed"; 635fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 64d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // Extra in the ALARM_KILLED intent to indicate to the user how long the 65d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // alarm played before being killed. 66d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static final String ALARM_KILLED_TIMEOUT = "alarm_killed_timeout"; 675fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 68d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // This string is used to indicate a silent alarm in the db. 69d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static final String ALARM_ALERT_SILENT = "silent"; 705fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 71d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // This intent is sent from the notification when the user cancels the 72d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // snooze alert. 73d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static final String CANCEL_SNOOZE = "cancel_snooze"; 745fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 75d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // This string is used when passing an Alarm object through an intent. 76d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static final String ALARM_INTENT_EXTRA = "intent.extra.alarm"; 775fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 78d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // This extra is the raw Alarm object data. It is used in the 79d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // AlarmManagerService to avoid a ClassNotFoundException when filling in 80d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // the Intent extras. 81d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static final String ALARM_RAW_DATA = "intent.extra.alarm_raw"; 825fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 83d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // This string is used to identify the alarm id passed to SetAlarm from the 84d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // list of alarms. 85d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static final String ALARM_ID = "alarm_id"; 865fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 87d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott final static String PREF_SNOOZE_ID = "snooze_id"; 88d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott final static String PREF_SNOOZE_TIME = "snooze_time"; 895fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 90d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott private final static String DM12 = "E h:mm aa"; 91d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott private final static String DM24 = "E k:mm"; 925fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 93d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott private final static String M12 = "h:mm aa"; 941ebd23eaa82ab560f5c7d8aeca8df7512df8424ePatrick Scott // Shared with DigitalClock 951ebd23eaa82ab560f5c7d8aeca8df7512df8424ePatrick Scott final static String M24 = "kk:mm"; 965fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 975fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 986064d3f7aabcb073dc3f917e049bc04c67fb6b29Patrick Scott * Creates a new Alarm and fills in the given alarm's id. 995fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 100e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott public static long addAlarm(Context context, Alarm alarm) { 101e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott ContentValues values = createContentValues(alarm); 1026064d3f7aabcb073dc3f917e049bc04c67fb6b29Patrick Scott Uri uri = context.getContentResolver().insert( 1036064d3f7aabcb073dc3f917e049bc04c67fb6b29Patrick Scott Alarm.Columns.CONTENT_URI, values); 1046064d3f7aabcb073dc3f917e049bc04c67fb6b29Patrick Scott alarm.id = (int) ContentUris.parseId(uri); 105e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott 106e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott long timeInMillis = calculateAlarm(alarm); 107e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott if (alarm.enabled) { 108e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott clearSnoozeIfNeeded(context, timeInMillis); 109e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott } 110e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott setNextAlert(context); 111e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott return timeInMillis; 1125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 1135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 1145fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 1155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Removes an existing Alarm. If this alarm is snoozing, disables 1165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * snooze. Sets next alert. 1175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 118d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static void deleteAlarm( 1195fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project Context context, int alarmId) { 1205fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 1215fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project ContentResolver contentResolver = context.getContentResolver(); 1225fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /* If alarm is snoozing, lose it */ 123d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott disableSnoozeAlert(context, alarmId); 1245fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 125d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Uri uri = ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, alarmId); 126d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott contentResolver.delete(uri, "", null); 1275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 1285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project setNextAlert(context); 1295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 1305fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 1315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 1325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Queries all alarms 1335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * @return cursor over all alarms 1345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 135d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static Cursor getAlarmsCursor(ContentResolver contentResolver) { 1365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project return contentResolver.query( 137d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm.Columns.CONTENT_URI, Alarm.Columns.ALARM_QUERY_COLUMNS, 138d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott null, null, Alarm.Columns.DEFAULT_SORT_ORDER); 1395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 1405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 141d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // Private method to get a more limited set of alarms from the database. 142d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott private static Cursor getFilteredAlarmsCursor( 143d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott ContentResolver contentResolver) { 144d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott return contentResolver.query(Alarm.Columns.CONTENT_URI, 145d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm.Columns.ALARM_QUERY_COLUMNS, Alarm.Columns.WHERE_ENABLED, 146d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott null, null); 1475fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 1485fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 149e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott private static ContentValues createContentValues(Alarm alarm) { 150e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott ContentValues values = new ContentValues(8); 151e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott // Set the alarm_time value if this alarm does not repeat. This will be 152e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott // used later to disable expire alarms. 153e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott long time = 0; 154e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott if (!alarm.daysOfWeek.isRepeatSet()) { 155e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott time = calculateAlarm(alarm); 156e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott } 157e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott 158e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott values.put(Alarm.Columns.ENABLED, alarm.enabled ? 1 : 0); 159e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott values.put(Alarm.Columns.HOUR, alarm.hour); 160e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott values.put(Alarm.Columns.MINUTES, alarm.minutes); 161e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott values.put(Alarm.Columns.ALARM_TIME, alarm.time); 162e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott values.put(Alarm.Columns.DAYS_OF_WEEK, alarm.daysOfWeek.getCoded()); 163e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott values.put(Alarm.Columns.VIBRATE, alarm.vibrate); 164e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott values.put(Alarm.Columns.MESSAGE, alarm.label); 165e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott 166e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott // A null alert Uri indicates a silent alarm. 167e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott values.put(Alarm.Columns.ALERT, alarm.alert == null ? ALARM_ALERT_SILENT 168e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott : alarm.alert.toString()); 169e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott 170e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott return values; 171e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott } 172e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott 173e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott private static void clearSnoozeIfNeeded(Context context, long alarmTime) { 174e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott // If this alarm fires before the next snooze, clear the snooze to 175e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott // enable this alarm. 176e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott SharedPreferences prefs = 177e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott context.getSharedPreferences(AlarmClock.PREFERENCES, 0); 178e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott long snoozeTime = prefs.getLong(PREF_SNOOZE_TIME, 0); 179e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott if (alarmTime < snoozeTime) { 180e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott clearSnoozePreference(context, prefs); 181e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott } 182e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott } 183e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott 1845fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 185d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott * Return an Alarm object representing the alarm id in the database. 186d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott * Returns null if no alarm exists. 1875fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 188d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static Alarm getAlarm(ContentResolver contentResolver, int alarmId) { 1895fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project Cursor cursor = contentResolver.query( 190d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, alarmId), 191d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm.Columns.ALARM_QUERY_COLUMNS, 192d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott null, null, null); 193d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm alarm = null; 194d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (cursor != null) { 195d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (cursor.moveToFirst()) { 196d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott alarm = new Alarm(cursor); 197d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } 198d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott cursor.close(); 199d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } 200d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott return alarm; 2015fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 2025fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 2035fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 2045fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 2055fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * A convenience method to set an alarm in the Alarms 2065fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * content provider. 207c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott * @return Time when the alarm will fire. 2085fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 209e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott public static long setAlarm(Context context, Alarm alarm) { 210e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott ContentValues values = createContentValues(alarm); 2115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project ContentResolver resolver = context.getContentResolver(); 212e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott resolver.update( 213e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, alarm.id), 214e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott values, null, null); 2155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 216e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott long timeInMillis = calculateAlarm(alarm); 217c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott 218e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott if (alarm.enabled) { 219232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott // Disable the snooze if we just changed the snoozed alarm. This 220232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott // only does work if the snoozed alarm is the same as the given 221232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott // alarm. 222232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott // TODO: disableSnoozeAlert should have a better name. 223232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott disableSnoozeAlert(context, alarm.id); 224232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott 225232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott // Disable the snooze if this alarm fires before the snoozed alarm. 226232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott // This works on every alarm since the user most likely intends to 227232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott // have the modified alarm fire next. 228e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott clearSnoozeIfNeeded(context, timeInMillis); 229c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott } 230c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott 2315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project setNextAlert(context); 232c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott 233c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott return timeInMillis; 2345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 2355fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 2365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 2375fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * A convenience method to enable or disable an alarm. 2385fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * 2395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * @param id corresponds to the _id column 2405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * @param enabled corresponds to the ENABLED column 2415fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 2425fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 243d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static void enableAlarm( 2445fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project final Context context, final int id, boolean enabled) { 2455fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project enableAlarmInternal(context, id, enabled); 2465fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project setNextAlert(context); 2475fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 2485fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 249d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott private static void enableAlarmInternal(final Context context, 250d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott final int id, boolean enabled) { 251d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott enableAlarmInternal(context, getAlarm(context.getContentResolver(), id), 252d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott enabled); 253d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } 2545fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 255d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott private static void enableAlarmInternal(final Context context, 256d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott final Alarm alarm, boolean enabled) { 25722924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott if (alarm == null) { 25822924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott return; 25922924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott } 260d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott ContentResolver resolver = context.getContentResolver(); 2615fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 2625fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project ContentValues values = new ContentValues(2); 263d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott values.put(Alarm.Columns.ENABLED, enabled ? 1 : 0); 2645fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 265d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // If we are enabling the alarm, calculate alarm time since the time 266d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // value in Alarm may be old. 2675fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project if (enabled) { 268d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott long time = 0; 269d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (!alarm.daysOfWeek.isRepeatSet()) { 270e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott time = calculateAlarm(alarm); 2715fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 272d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott values.put(Alarm.Columns.ALARM_TIME, time); 27322924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott } else { 27422924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott // Clear the snooze if the id matches. 27522924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott disableSnoozeAlert(context, alarm.id); 2765fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 2775fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 278d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott resolver.update(ContentUris.withAppendedId( 279d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm.Columns.CONTENT_URI, alarm.id), values, null, null); 2805fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 2815fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 282d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott public static Alarm calculateNextAlert(final Context context) { 283d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm alarm = null; 284d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott long minTime = Long.MAX_VALUE; 28598948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott long now = System.currentTimeMillis(); 286d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Cursor cursor = getFilteredAlarmsCursor(context.getContentResolver()); 287d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (cursor != null) { 288d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (cursor.moveToFirst()) { 289d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott do { 290d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm a = new Alarm(cursor); 291d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // A time of 0 indicates this is a repeating alarm, so 292d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // calculate the time to get the next alert. 293d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (a.time == 0) { 294e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott a.time = calculateAlarm(a); 29598948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott } else if (a.time < now) { 29698948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott // Expired alarm, disable it and move along. 29798948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott enableAlarmInternal(context, a, false); 29898948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott continue; 299d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } 300d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (a.time < minTime) { 301d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott minTime = a.time; 302d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott alarm = a; 303d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } 304d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } while (cursor.moveToNext()); 3055fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 306d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott cursor.close(); 3075fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 308d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott return alarm; 3095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 3105fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 3115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 3125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Disables non-repeating alarms that have passed. Called at 3135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * boot. 3145fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 3155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project public static void disableExpiredAlarms(final Context context) { 316d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Cursor cur = getFilteredAlarmsCursor(context.getContentResolver()); 3175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project long now = System.currentTimeMillis(); 3185fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 3195fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project if (cur.moveToFirst()) { 3205fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project do { 321d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm alarm = new Alarm(cur); 322d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // A time of 0 means this alarm repeats. If the time is 323d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // non-zero, check if the time is before now. 324d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (alarm.time != 0 && alarm.time < now) { 325d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (Log.LOGV) { 326d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Log.v("** DISABLE " + alarm.id + " now " + now +" set " 327d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott + alarm.time); 328d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } 329d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott enableAlarmInternal(context, alarm, false); 3305fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 3315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } while (cur.moveToNext()); 3325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 3335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project cur.close(); 3345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 3355fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 3365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 3375fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Called at system startup, on time/timezone change, and whenever 3385fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * the user changes alarm settings. Activates snooze if set, 3395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * otherwise loads all alarms, activates next alert. 3405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 3415fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project public static void setNextAlert(final Context context) { 342d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (!enableSnoozeAlert(context)) { 343d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm alarm = calculateNextAlert(context); 344d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (alarm != null) { 345d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott enableAlert(context, alarm, alarm.time); 3465fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } else { 347d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott disableAlert(context); 3485fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 3495fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 3505fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 3515fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 3525fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 3535fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Sets alert in AlarmManger and StatusBar. This is what will 3545fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * actually launch the alert when the alarm triggers. 3555fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * 356d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott * @param alarm Alarm. 3575fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * @param atTimeInMillis milliseconds since epoch 3585fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 359d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott private static void enableAlert(Context context, final Alarm alarm, 360d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott final long atTimeInMillis) { 3615fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project AlarmManager am = (AlarmManager) 3625fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project context.getSystemService(Context.ALARM_SERVICE); 3635fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 364d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (Log.LOGV) { 365d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Log.v("** setAlert id " + alarm.id + " atTime " + atTimeInMillis); 3665d6f5fa51fa7fd13784a73199161deabec5bc898Patrick Scott } 367d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott 368d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Intent intent = new Intent(ALARM_ALERT_ACTION); 369d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott 370d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // XXX: This is a slight hack to avoid an exception in the remote 371d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // AlarmManagerService process. The AlarmManager adds extra data to 372d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // this Intent which causes it to inflate. Since the remote process 373d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // does not know about the Alarm class, it throws a 374d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // ClassNotFoundException. 375d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // 376d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // To avoid this, we marshall the data ourselves and then parcel a plain 377d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // byte[] array. The AlarmReceiver class knows to build the Alarm 378d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // object from the byte[] array. 379d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Parcel out = Parcel.obtain(); 380d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott alarm.writeToParcel(out, 0); 381d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott out.setDataPosition(0); 382d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott intent.putExtra(ALARM_RAW_DATA, out.marshall()); 383d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott 3845fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project PendingIntent sender = PendingIntent.getBroadcast( 3855fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); 3865fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 387d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender); 3885fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 3895fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project setStatusBarIcon(context, true); 3905fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 3915fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project Calendar c = Calendar.getInstance(); 392e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott c.setTimeInMillis(atTimeInMillis); 3935fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project String timeString = formatDayAndTime(context, c); 3945fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project saveNextAlarm(context, timeString); 3955fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 3965fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 3975fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 3985fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Disables alert in AlarmManger and StatusBar. 3995fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * 4005fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * @param id Alarm ID. 4015fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 402d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott static void disableAlert(Context context) { 4035fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project AlarmManager am = (AlarmManager) 4045fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project context.getSystemService(Context.ALARM_SERVICE); 4055fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project PendingIntent sender = PendingIntent.getBroadcast( 406d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott context, 0, new Intent(ALARM_ALERT_ACTION), 407d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott PendingIntent.FLAG_CANCEL_CURRENT); 4085fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project am.cancel(sender); 4095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project setStatusBarIcon(context, false); 4105fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project saveNextAlarm(context, ""); 4115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 4125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 413d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott static void saveSnoozeAlert(final Context context, final int id, 414d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott final long time) { 4155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project SharedPreferences prefs = context.getSharedPreferences( 4165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project AlarmClock.PREFERENCES, 0); 417d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (id == -1) { 418c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott clearSnoozePreference(context, prefs); 419d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } else { 420c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott SharedPreferences.Editor ed = prefs.edit(); 421d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott ed.putInt(PREF_SNOOZE_ID, id); 422d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott ed.putLong(PREF_SNOOZE_TIME, time); 423e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott ed.commit(); 4245d6f5fa51fa7fd13784a73199161deabec5bc898Patrick Scott } 425d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // Set the next alert after updating the snooze. 426d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott setNextAlert(context); 4275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 4285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 4295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 430d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott * Disable the snooze alert if the given id matches the snooze id. 4315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 432d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott static void disableSnoozeAlert(final Context context, final int id) { 4335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project SharedPreferences prefs = context.getSharedPreferences( 4345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project AlarmClock.PREFERENCES, 0); 435d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott int snoozeId = prefs.getInt(PREF_SNOOZE_ID, -1); 436d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (snoozeId == -1) { 437d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // No snooze set, do nothing. 438d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott return; 439d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } else if (snoozeId == id) { 440d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // This is the same id so clear the shared prefs. 441c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott clearSnoozePreference(context, prefs); 442d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } 4435fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 4445fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 445e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott // Helper to remove the snooze preference. Do not use clear because that 446c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott // will erase the clock preferences. Also clear the snooze notification in 447c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott // the window shade. 448c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott private static void clearSnoozePreference(final Context context, 449c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott final SharedPreferences prefs) { 450c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott final int alarmId = prefs.getInt(PREF_SNOOZE_ID, -1); 451c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott if (alarmId != -1) { 452c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott NotificationManager nm = (NotificationManager) 453c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott context.getSystemService(Context.NOTIFICATION_SERVICE); 454c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott nm.cancel(alarmId); 455c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott } 456c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott 457c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott final SharedPreferences.Editor ed = prefs.edit(); 458e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott ed.remove(PREF_SNOOZE_ID); 459e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott ed.remove(PREF_SNOOZE_TIME); 460e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott ed.commit(); 461e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott }; 462e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott 4635fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 4645fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * If there is a snooze set, enable it in AlarmManager 4655fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * @return true if snooze is set 4665fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 4675fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project private static boolean enableSnoozeAlert(final Context context) { 4685fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project SharedPreferences prefs = context.getSharedPreferences( 4695fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project AlarmClock.PREFERENCES, 0); 4705fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 4715fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project int id = prefs.getInt(PREF_SNOOZE_ID, -1); 472d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott if (id == -1) { 473d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott return false; 474d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott } 475d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott long time = prefs.getLong(PREF_SNOOZE_TIME, -1); 476d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott 477d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // Get the alarm from the db. 478d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott final Alarm alarm = getAlarm(context.getContentResolver(), id); 47922924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott if (alarm == null) { 48022924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott return false; 48122924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott } 482d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // The time in the database is either 0 (repeating) or a specific time 483d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // for a non-repeating alarm. Update this value so the AlarmReceiver 484d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott // has the right time to compare. 485d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott alarm.time = time; 486d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott 487d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott enableAlert(context, alarm, time); 4885fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project return true; 4895fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 4905fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 4915fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 4925fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Tells the StatusBar whether the alarm is enabled or disabled 4935fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 4945fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project private static void setStatusBarIcon(Context context, boolean enabled) { 495fe8dd39ee5e173f15337d09c36aa453a55364e98Patrick Scott Intent alarmChanged = new Intent("android.intent.action.ALARM_CHANGED"); 4965fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project alarmChanged.putExtra("alarmSet", enabled); 4975fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project context.sendBroadcast(alarmChanged); 4985fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 4995fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 500e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott private static long calculateAlarm(Alarm alarm) { 501e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott return calculateAlarm(alarm.hour, alarm.minutes, alarm.daysOfWeek) 502e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott .getTimeInMillis(); 503e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott } 504e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott 5055fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 5065fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Given an alarm in hours and minutes, return a time suitable for 5075fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * setting in AlarmManager. 5085fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 509e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott static Calendar calculateAlarm(int hour, int minute, 510e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott Alarm.DaysOfWeek daysOfWeek) { 5115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 5125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project // start with now 5135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project Calendar c = Calendar.getInstance(); 5145fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project c.setTimeInMillis(System.currentTimeMillis()); 5155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 5165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project int nowHour = c.get(Calendar.HOUR_OF_DAY); 5175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project int nowMinute = c.get(Calendar.MINUTE); 5185fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 5195fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project // if alarm is behind current time, advance one day 5205fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project if (hour < nowHour || 5215fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project hour == nowHour && minute <= nowMinute) { 5225fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project c.add(Calendar.DAY_OF_YEAR, 1); 5235fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 5245fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project c.set(Calendar.HOUR_OF_DAY, hour); 5255fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project c.set(Calendar.MINUTE, minute); 5265fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project c.set(Calendar.SECOND, 0); 5275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project c.set(Calendar.MILLISECOND, 0); 5285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 5295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project int addDays = daysOfWeek.getNextAlarm(c); 5305fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project if (addDays > 0) c.add(Calendar.DAY_OF_WEEK, addDays); 5315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project return c; 5325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 5335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 5345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project static String formatTime(final Context context, int hour, int minute, 535d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott Alarm.DaysOfWeek daysOfWeek) { 5365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project Calendar c = calculateAlarm(hour, minute, daysOfWeek); 5375fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project return formatTime(context, c); 5385fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 5395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 5405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /* used by AlarmAlert */ 5415fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project static String formatTime(final Context context, Calendar c) { 5425fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project String format = get24HourMode(context) ? M24 : M12; 5435fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project return (c == null) ? "" : (String)DateFormat.format(format, c); 5445fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 5455fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 5465fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 5475fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Shows day and time -- used for lock screen 5485fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 5495fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project private static String formatDayAndTime(final Context context, Calendar c) { 5505fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project String format = get24HourMode(context) ? DM24 : DM12; 5515fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project return (c == null) ? "" : (String)DateFormat.format(format, c); 5525fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 5535fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 5545fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 5555fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * Save time of the next alarm, as a formatted string, into the system 5565fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * settings so those who care can make use of it. 5575fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 5585fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project static void saveNextAlarm(final Context context, String timeString) { 5595fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project Settings.System.putString(context.getContentResolver(), 5605fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project Settings.System.NEXT_ALARM_FORMATTED, 5615fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project timeString); 5625fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 5635fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project 5645fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project /** 5655fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * @return true if clock is set to 24-hour mode 5665fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */ 5675fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project static boolean get24HourMode(final Context context) { 5685fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project return android.text.format.DateFormat.is24HourFormat(context); 5695fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project } 5705fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project} 571