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.ContentUris;
245c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.content.ContentValues;
255fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.content.Context;
265c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Chengimport android.content.CursorLoader;
275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.content.Intent;
285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.content.SharedPreferences;
295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.database.Cursor;
305fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.net.Uri;
31d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scottimport android.os.Parcel;
325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.provider.Settings;
335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport android.text.format.DateFormat;
345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
355fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectimport java.util.Calendar;
368304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrookimport java.util.HashSet;
378304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrookimport java.util.Set;
385fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project/**
405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project * The Alarms provider supplies info about Alarm Clock settings
415fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project */
425fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Projectpublic class Alarms {
435fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    static final String PREFERENCES = "AlarmClock";
455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
46d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This action triggers the AlarmReceiver as well as the AlarmKlaxon. It
47d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // is a public action used in the manifest for receiving Alarm broadcasts
48d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // from the alarm manager.
49fa954248b41b567dfa2ddd7bd063d3936a51758eDaniel Sandler    public static final String ALARM_ALERT_ACTION = "com.android.deskclock.ALARM_ALERT";
505fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
51a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    // A public action sent by AlarmKlaxon when the alarm has stopped sounding
52a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    // for any reason (e.g. because it has been dismissed from AlarmAlertFullScreen,
53a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    // or killed due to an incoming phone call, etc).
54a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    public static final String ALARM_DONE_ACTION = "com.android.deskclock.ALARM_DONE";
55a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram
56a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    // AlarmAlertFullScreen listens for this broadcast intent, so that other applications
57a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    // can snooze the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION).
58a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    public static final String ALARM_SNOOZE_ACTION = "com.android.deskclock.ALARM_SNOOZE";
59a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram
60a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    // AlarmAlertFullScreen listens for this broadcast intent, so that other applications
61a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    // can dismiss the alarm (after ALARM_ALERT_ACTION and before ALARM_DONE_ACTION).
62a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram    public static final String ALARM_DISMISS_ACTION = "com.android.deskclock.ALARM_DISMISS";
63a3aba0c93c31e89045cca669418e85acfb4e22fbDavid Ingram
649e33fe399ce41766dc0a2d6e8f3e2fef0d30f6c1Robyn Coultas    // A public action sent by AlarmAlertFullScreen when a snoozed alarm was dismissed due
659e33fe399ce41766dc0a2d6e8f3e2fef0d30f6c1Robyn Coultas    // to it handling ALARM_DISMISS_ACTION cancelled
669e33fe399ce41766dc0a2d6e8f3e2fef0d30f6c1Robyn Coultas    public static final String ALARM_SNOOZE_CANCELLED = "com.android.deskclock.ALARM_SNOOZE_CANCELLED";
679e33fe399ce41766dc0a2d6e8f3e2fef0d30f6c1Robyn Coultas
685c464d35f230912053d7a5873dd6b59ca6e11852Isaac Katzenelson    // A broadcast sent every time the next alarm time is set in the system
695c464d35f230912053d7a5873dd6b59ca6e11852Isaac Katzenelson    public static final String NEXT_ALARM_TIME_SET = "com.android.deskclock.NEXT_ALARM_TIME_SET";
705c464d35f230912053d7a5873dd6b59ca6e11852Isaac Katzenelson
71d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This is a private action used by the AlarmKlaxon to update the UI to
72d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // show the alarm has been killed.
73d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_KILLED = "alarm_killed";
745fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
75d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // Extra in the ALARM_KILLED intent to indicate to the user how long the
76d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // alarm played before being killed.
77d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_KILLED_TIMEOUT = "alarm_killed_timeout";
785fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
79be452965e9b8467d2f640ccee1002119bb7d2761Robyn Coultas    // Extra in the ALARM_KILLED intent to indicate when alarm was replaced
80be452965e9b8467d2f640ccee1002119bb7d2761Robyn Coultas    public static final String ALARM_REPLACED = "alarm_replaced";
81be452965e9b8467d2f640ccee1002119bb7d2761Robyn Coultas
82d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This string is used to indicate a silent alarm in the db.
83d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_ALERT_SILENT = "silent";
845fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
85d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This intent is sent from the notification when the user cancels the
86d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // snooze alert.
87d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String CANCEL_SNOOZE = "cancel_snooze";
885fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
89d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This string is used when passing an Alarm object through an intent.
90d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_INTENT_EXTRA = "intent.extra.alarm";
915fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
92d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This extra is the raw Alarm object data. It is used in the
93d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // AlarmManagerService to avoid a ClassNotFoundException when filling in
94d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // the Intent extras.
95d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_RAW_DATA = "intent.extra.alarm_raw";
965fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
978304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    private static final String PREF_SNOOZE_IDS = "snooze_ids";
988304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    private static final String PREF_SNOOZE_TIME = "snooze_time";
995fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
100d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private final static String DM12 = "E h:mm aa";
101bababb66c17c665d374313da47e2f3734adec83aPatrick Scott    private final static String DM24 = "E kk:mm";
1025fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
103d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private final static String M12 = "h:mm aa";
1041ebd23eaa82ab560f5c7d8aeca8df7512df8424ePatrick Scott    // Shared with DigitalClock
1051ebd23eaa82ab560f5c7d8aeca8df7512df8424ePatrick Scott    final static String M24 = "kk:mm";
1065fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1078304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    final static int INVALID_ALARM_ID = -1;
1088304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
1095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
1106064d3f7aabcb073dc3f917e049bc04c67fb6b29Patrick Scott     * Creates a new Alarm and fills in the given alarm's id.
1115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
112e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott    public static long addAlarm(Context context, Alarm alarm) {
113e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        ContentValues values = createContentValues(alarm);
1146064d3f7aabcb073dc3f917e049bc04c67fb6b29Patrick Scott        Uri uri = context.getContentResolver().insert(
1156064d3f7aabcb073dc3f917e049bc04c67fb6b29Patrick Scott                Alarm.Columns.CONTENT_URI, values);
1166064d3f7aabcb073dc3f917e049bc04c67fb6b29Patrick Scott        alarm.id = (int) ContentUris.parseId(uri);
117e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott
118e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        long timeInMillis = calculateAlarm(alarm);
119e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        if (alarm.enabled) {
120e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott            clearSnoozeIfNeeded(context, timeInMillis);
121e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        }
122e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        setNextAlert(context);
123e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        return timeInMillis;
1245fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
1255fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1265fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
1275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Removes an existing Alarm.  If this alarm is snoozing, disables
1285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * snooze.  Sets next alert.
1295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
130bb13b216f986fc75dbd82d38f2bd6b2fbeb08abdPatrick Scott    public static void deleteAlarm(Context context, int alarmId) {
1318304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        if (alarmId == INVALID_ALARM_ID) return;
1325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        ContentResolver contentResolver = context.getContentResolver();
1345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        /* If alarm is snoozing, lose it */
135d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        disableSnoozeAlert(context, alarmId);
1365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
137d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Uri uri = ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, alarmId);
138d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        contentResolver.delete(uri, "", null);
1395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setNextAlert(context);
1415fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
1425fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    public static CursorLoader getAlarmsCursorLoader(Context context) {
1455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        return new CursorLoader(context, Alarm.Columns.CONTENT_URI,
1465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng                Alarm.Columns.ALARM_QUERY_COLUMNS, null, null, Alarm.Columns.DEFAULT_SORT_ORDER);
1475c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng    }
1485c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng
1495fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
1505fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Queries all alarms
1515fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @return cursor over all alarms
1525fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
153d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static Cursor getAlarmsCursor(ContentResolver contentResolver) {
1545fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return contentResolver.query(
155d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                Alarm.Columns.CONTENT_URI, Alarm.Columns.ALARM_QUERY_COLUMNS,
156d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                null, null, Alarm.Columns.DEFAULT_SORT_ORDER);
1575fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
1585fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
159d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // Private method to get a more limited set of alarms from the database.
160d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private static Cursor getFilteredAlarmsCursor(
161d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            ContentResolver contentResolver) {
162d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        return contentResolver.query(Alarm.Columns.CONTENT_URI,
163d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                Alarm.Columns.ALARM_QUERY_COLUMNS, Alarm.Columns.WHERE_ENABLED,
164d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                null, null);
1655fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
1665fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
167e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott    private static ContentValues createContentValues(Alarm alarm) {
168e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        ContentValues values = new ContentValues(8);
169e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        // Set the alarm_time value if this alarm does not repeat. This will be
170e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        // used later to disable expire alarms.
171e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        long time = 0;
172e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        if (!alarm.daysOfWeek.isRepeatSet()) {
173e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott            time = calculateAlarm(alarm);
174e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        }
175e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott
1760cb70993e26f300f92423bfced0d8cb3efc3f304Chiao Cheng        // -1 means generate new id.
1770cb70993e26f300f92423bfced0d8cb3efc3f304Chiao Cheng        if (alarm.id != -1) {
1780cb70993e26f300f92423bfced0d8cb3efc3f304Chiao Cheng            values.put(Alarm.Columns._ID, alarm.id);
1790cb70993e26f300f92423bfced0d8cb3efc3f304Chiao Cheng        }
1800cb70993e26f300f92423bfced0d8cb3efc3f304Chiao Cheng
181e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        values.put(Alarm.Columns.ENABLED, alarm.enabled ? 1 : 0);
182e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        values.put(Alarm.Columns.HOUR, alarm.hour);
183e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        values.put(Alarm.Columns.MINUTES, alarm.minutes);
184501a153616bd44880b587447788990d83f433a8fPatrick Scott        values.put(Alarm.Columns.ALARM_TIME, time);
185e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        values.put(Alarm.Columns.DAYS_OF_WEEK, alarm.daysOfWeek.getCoded());
186e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        values.put(Alarm.Columns.VIBRATE, alarm.vibrate);
187e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        values.put(Alarm.Columns.MESSAGE, alarm.label);
188e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott
189e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        // A null alert Uri indicates a silent alarm.
190e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        values.put(Alarm.Columns.ALERT, alarm.alert == null ? ALARM_ALERT_SILENT
191e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott                : alarm.alert.toString());
192e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott
193e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        return values;
194e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott    }
195e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott
196e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott    private static void clearSnoozeIfNeeded(Context context, long alarmTime) {
197e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        // If this alarm fires before the next snooze, clear the snooze to
198e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        // enable this alarm.
1995c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, 0);
2008304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
2018304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        // Get the list of snoozed alarms
2028304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final Set<String> snoozedIds = prefs.getStringSet(PREF_SNOOZE_IDS, new HashSet<String>());
2038304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        for (String snoozedAlarm : snoozedIds) {
2048304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            final long snoozeTime = prefs.getLong(getAlarmPrefSnoozeTimeKey(snoozedAlarm), 0);
2058304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            if (alarmTime < snoozeTime) {
2068304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                final int alarmId = Integer.parseInt(snoozedAlarm);
2078304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                clearSnoozePreference(context, prefs, alarmId);
2088304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            }
209e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        }
210e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott    }
211e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott
2125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
213d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott     * Return an Alarm object representing the alarm id in the database.
214d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott     * Returns null if no alarm exists.
2155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
216d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static Alarm getAlarm(ContentResolver contentResolver, int alarmId) {
2175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Cursor cursor = contentResolver.query(
218d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, alarmId),
219d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                Alarm.Columns.ALARM_QUERY_COLUMNS,
220d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                null, null, null);
221d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Alarm alarm = null;
222d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (cursor != null) {
223d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            if (cursor.moveToFirst()) {
224d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                alarm = new Alarm(cursor);
225d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            }
226d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            cursor.close();
227d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        }
228d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        return alarm;
2295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
2305fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
2315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
2325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
2335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * A convenience method to set an alarm in the Alarms
2345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * content provider.
2355c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng     * @return Time when the alarm will fire. Or < 1 if update failed.
2365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
237e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott    public static long setAlarm(Context context, Alarm alarm) {
238e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        ContentValues values = createContentValues(alarm);
2395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        ContentResolver resolver = context.getContentResolver();
2405c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        long rowsUpdated = resolver.update(
241e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott                ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, alarm.id),
242e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott                values, null, null);
2435c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        if (rowsUpdated < 1) {
2445c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            Log.e("Error updating alarm " + alarm);
2455c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng            return rowsUpdated;
2465c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        }
2475fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
248e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        long timeInMillis = calculateAlarm(alarm);
249c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott
250e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        if (alarm.enabled) {
251232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott            // Disable the snooze if we just changed the snoozed alarm. This
252232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott            // only does work if the snoozed alarm is the same as the given
253232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott            // alarm.
254232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott            // TODO: disableSnoozeAlert should have a better name.
255232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott            disableSnoozeAlert(context, alarm.id);
256232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott
257232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott            // Disable the snooze if this alarm fires before the snoozed alarm.
258232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott            // This works on every alarm since the user most likely intends to
259232725e8c1b1b85a44857cedcc842dcd2c956dc2Patrick Scott            // have the modified alarm fire next.
260e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott            clearSnoozeIfNeeded(context, timeInMillis);
261c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        }
262c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott
2635fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setNextAlert(context);
264c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott
265c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        return timeInMillis;
2665fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
2675fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
2685fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
2695fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * A convenience method to enable or disable an alarm.
2705fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     *
2715fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param id             corresponds to the _id column
2725fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param enabled        corresponds to the ENABLED column
2735fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
2745fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
275d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static void enableAlarm(
2765fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            final Context context, final int id, boolean enabled) {
2775fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        enableAlarmInternal(context, id, enabled);
2785fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setNextAlert(context);
2795fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
2805fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
281d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private static void enableAlarmInternal(final Context context,
282d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            final int id, boolean enabled) {
283d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        enableAlarmInternal(context, getAlarm(context.getContentResolver(), id),
284d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                enabled);
285d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    }
2865fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
287d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private static void enableAlarmInternal(final Context context,
288d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            final Alarm alarm, boolean enabled) {
28922924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott        if (alarm == null) {
29022924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott            return;
29122924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott        }
292d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        ContentResolver resolver = context.getContentResolver();
2935fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
2945fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        ContentValues values = new ContentValues(2);
295d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.ENABLED, enabled ? 1 : 0);
2965fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
297d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // If we are enabling the alarm, calculate alarm time since the time
298d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // value in Alarm may be old.
2995fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        if (enabled) {
300d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            long time = 0;
301d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            if (!alarm.daysOfWeek.isRepeatSet()) {
302e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott                time = calculateAlarm(alarm);
3035fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            }
304d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            values.put(Alarm.Columns.ALARM_TIME, time);
30522924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott        } else {
30622924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott            // Clear the snooze if the id matches.
30722924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott            disableSnoozeAlert(context, alarm.id);
3085fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
3095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
310d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        resolver.update(ContentUris.withAppendedId(
311d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                Alarm.Columns.CONTENT_URI, alarm.id), values, null, null);
3125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
3135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
3148304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    private static Alarm calculateNextAlert(final Context context) {
315d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        long minTime = Long.MAX_VALUE;
31698948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott        long now = System.currentTimeMillis();
3175c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        final SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, 0);
3188304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
3198304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        Set<Alarm> alarms = new HashSet<Alarm>();
3208304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
3218304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        // We need to to build the list of alarms from both the snoozed list and the scheduled
3228304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        // list.  For a non-repeating alarm, when it goes of, it becomes disabled.  A snoozed
3238304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        // non-repeating alarm is not in the active list in the database.
3248304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
3258304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        // first go through the snoozed alarms
3268304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final Set<String> snoozedIds = prefs.getStringSet(PREF_SNOOZE_IDS, new HashSet<String>());
3278304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        for (String snoozedAlarm : snoozedIds) {
3288304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            final int alarmId = Integer.parseInt(snoozedAlarm);
3298304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            final Alarm a = getAlarm(context.getContentResolver(), alarmId);
3308304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            alarms.add(a);
3318304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        }
3328304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
3338304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        // Now add the scheduled alarms
3348304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final Cursor cursor = getFilteredAlarmsCursor(context.getContentResolver());
335d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (cursor != null) {
33699ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden            try {
33799ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                if (cursor.moveToFirst()) {
3388304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                    do {
3398304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                        final Alarm a = new Alarm(cursor);
3408304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                        alarms.add(a);
3418304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                    } while (cursor.moveToNext());
3428304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                }
34399ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden            } finally {
34499ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                cursor.close();
3455fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            }
3465fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
3478304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
3488304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        Alarm alarm = null;
3498304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
3508304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        for (Alarm a : alarms) {
3518304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            // A time of 0 indicates this is a repeating alarm, so
3528304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            // calculate the time to get the next alert.
3538304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            if (a.time == 0) {
3548304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                a.time = calculateAlarm(a);
3558304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            }
3568304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
3578304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            // Update the alarm if it has been snoozed
3588304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            updateAlarmTimeForSnooze(prefs, a);
3598304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
3608304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            if (a.time < now) {
3618304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                Log.v("Disabling expired alarm set for " + Log.formatTime(a.time));
3628304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                // Expired alarm, disable it and move along.
3638304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                enableAlarmInternal(context, a, false);
3648304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                continue;
3658304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            }
3668304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            if (a.time < minTime) {
3678304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                minTime = a.time;
3688304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                alarm = a;
3698304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            }
3708304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        }
3718304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
372d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        return alarm;
3735fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
3745fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
3755fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
3765fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Disables non-repeating alarms that have passed.  Called at
3775fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * boot.
3785fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
3795fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    public static void disableExpiredAlarms(final Context context) {
380d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Cursor cur = getFilteredAlarmsCursor(context.getContentResolver());
3815fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        long now = System.currentTimeMillis();
3825fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
38399ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden        try {
38499ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden            if (cur.moveToFirst()) {
38599ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                do {
38699ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                    Alarm alarm = new Alarm(cur);
38799ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                    // A time of 0 means this alarm repeats. If the time is
38899ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                    // non-zero, check if the time is before now.
38999ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                    if (alarm.time != 0 && alarm.time < now) {
39099ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                        Log.v("Disabling expired alarm set for " +
39199ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                              Log.formatTime(alarm.time));
39299ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                        enableAlarmInternal(context, alarm, false);
39399ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                    }
39499ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden                } while (cur.moveToNext());
39599ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden            }
39699ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden        } finally {
39799ae7660f1e5e4645c889e78e26d44de20a7caf3Andy McFadden            cur.close();
3985fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
3995fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
4005fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4015fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
4025fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Called at system startup, on time/timezone change, and whenever
4035fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * the user changes alarm settings.  Activates snooze if set,
4045fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * otherwise loads all alarms, activates next alert.
4055fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
4065fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    public static void setNextAlert(final Context context) {
4078304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final Alarm alarm = calculateNextAlert(context);
4088304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        if (alarm != null) {
4098304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            enableAlert(context, alarm, alarm.time);
4108304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        } else {
4118304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            disableAlert(context);
4125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
4135c464d35f230912053d7a5873dd6b59ca6e11852Isaac Katzenelson        Intent i = new Intent(NEXT_ALARM_TIME_SET);
4145c464d35f230912053d7a5873dd6b59ca6e11852Isaac Katzenelson        context.sendBroadcast(i);
4155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
4165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
4185fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Sets alert in AlarmManger and StatusBar.  This is what will
4195fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * actually launch the alert when the alarm triggers.
4205fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     *
421d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott     * @param alarm Alarm.
4225fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param atTimeInMillis milliseconds since epoch
4235fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
424d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private static void enableAlert(Context context, final Alarm alarm,
425d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            final long atTimeInMillis) {
4265fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        AlarmManager am = (AlarmManager)
4275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                context.getSystemService(Context.ALARM_SERVICE);
4285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4291e34a1bead76f4c3fa6e2baec327e5846f4c23fdRobyn Coultas        // Intentionally verbose: always log the alarm time to provide useful
4301e34a1bead76f4c3fa6e2baec327e5846f4c23fdRobyn Coultas        // information in bug reports.
4311e34a1bead76f4c3fa6e2baec327e5846f4c23fdRobyn Coultas        Log.v("Alarm set for id=" + alarm.id + " " + Log.formatTime(atTimeInMillis));
432d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
433d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Intent intent = new Intent(ALARM_ALERT_ACTION);
434d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
435d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // XXX: This is a slight hack to avoid an exception in the remote
436d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // AlarmManagerService process. The AlarmManager adds extra data to
437d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // this Intent which causes it to inflate. Since the remote process
438d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // does not know about the Alarm class, it throws a
439d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // ClassNotFoundException.
440d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        //
441d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // To avoid this, we marshall the data ourselves and then parcel a plain
442d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // byte[] array. The AlarmReceiver class knows to build the Alarm
443d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // object from the byte[] array.
444d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Parcel out = Parcel.obtain();
445d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        alarm.writeToParcel(out, 0);
446d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        out.setDataPosition(0);
447d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        intent.putExtra(ALARM_RAW_DATA, out.marshall());
448d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
4495fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        PendingIntent sender = PendingIntent.getBroadcast(
4505fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
4515fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
452d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);
4535fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4545fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setStatusBarIcon(context, true);
4555fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4565fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Calendar c = Calendar.getInstance();
457e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        c.setTimeInMillis(atTimeInMillis);
4585fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        String timeString = formatDayAndTime(context, c);
4595fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        saveNextAlarm(context, timeString);
4605fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
4615fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4625fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
4639e33fe399ce41766dc0a2d6e8f3e2fef0d30f6c1Robyn Coultas     * Disables alert in AlarmManager and StatusBar.
4645fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     *
4655c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng     * @param context The context
4665fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
467d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    static void disableAlert(Context context) {
4685fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        AlarmManager am = (AlarmManager)
4695fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                context.getSystemService(Context.ALARM_SERVICE);
4705fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        PendingIntent sender = PendingIntent.getBroadcast(
471d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                context, 0, new Intent(ALARM_ALERT_ACTION),
472d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                PendingIntent.FLAG_CANCEL_CURRENT);
4735fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        am.cancel(sender);
4745fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setStatusBarIcon(context, false);
4751e34a1bead76f4c3fa6e2baec327e5846f4c23fdRobyn Coultas        // Intentionally verbose: always log the lack of a next alarm to provide useful
4761e34a1bead76f4c3fa6e2baec327e5846f4c23fdRobyn Coultas        // information in bug reports.
4771e34a1bead76f4c3fa6e2baec327e5846f4c23fdRobyn Coultas        Log.v("No next alarm");
4785fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        saveNextAlarm(context, "");
4795fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
4805fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
481d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    static void saveSnoozeAlert(final Context context, final int id,
482d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            final long time) {
4835c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, 0);
4848304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        if (id == INVALID_ALARM_ID) {
4858304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            clearAllSnoozePreferences(context, prefs);
486d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        } else {
4878304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            final Set<String> snoozedIds =
4888304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                    prefs.getStringSet(PREF_SNOOZE_IDS, new HashSet<String>());
4898304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            snoozedIds.add(Integer.toString(id));
4908304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            final SharedPreferences.Editor ed = prefs.edit();
4918304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            ed.putStringSet(PREF_SNOOZE_IDS, snoozedIds);
4928304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            ed.putLong(getAlarmPrefSnoozeTimeKey(id), time);
493c6098ef1fc69fe117343cc2e3db0d2b97b2daa6fBrad Fitzpatrick            ed.apply();
4945d6f5fa51fa7fd13784a73199161deabec5bc898Patrick Scott        }
495d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // Set the next alert after updating the snooze.
496d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        setNextAlert(context);
4975fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
4985fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4998304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    private static String getAlarmPrefSnoozeTimeKey(int id) {
5008304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        return getAlarmPrefSnoozeTimeKey(Integer.toString(id));
5018304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    }
5028304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
5038304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    private static String getAlarmPrefSnoozeTimeKey(String id) {
5048304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        return PREF_SNOOZE_TIME + id;
5058304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    }
5068304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
5075fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
508d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott     * Disable the snooze alert if the given id matches the snooze id.
5095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
510d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    static void disableSnoozeAlert(final Context context, final int id) {
5115c3795c271bc6160f0ae2056627e9e96ffdc335cChiao Cheng        SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, 0);
5128304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        if (hasAlarmBeenSnoozed(prefs, id)) {
513d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            // This is the same id so clear the shared prefs.
5148304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            clearSnoozePreference(context, prefs, id);
515d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        }
5165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
5175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
518e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott    // Helper to remove the snooze preference. Do not use clear because that
519c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott    // will erase the clock preferences. Also clear the snooze notification in
520c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott    // the window shade.
521c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott    private static void clearSnoozePreference(final Context context,
5228304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            final SharedPreferences prefs, final int id) {
5238304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final String alarmStr = Integer.toString(id);
5248304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final Set<String> snoozedIds =
5258304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                prefs.getStringSet(PREF_SNOOZE_IDS, new HashSet<String>());
5268304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        if (snoozedIds.contains(alarmStr)) {
527c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            NotificationManager nm = (NotificationManager)
528c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott                    context.getSystemService(Context.NOTIFICATION_SERVICE);
5298304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            nm.cancel(id);
530c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        }
531c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott
532c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        final SharedPreferences.Editor ed = prefs.edit();
5338304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        snoozedIds.remove(alarmStr);
5348304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        ed.putStringSet(PREF_SNOOZE_IDS, snoozedIds);
5358304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        ed.remove(getAlarmPrefSnoozeTimeKey(alarmStr));
5368304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        ed.apply();
5378304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    }
5388304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
5398304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    private static void clearAllSnoozePreferences(final Context context,
5408304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            final SharedPreferences prefs) {
5418304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        NotificationManager nm = (NotificationManager)
5428304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                context.getSystemService(Context.NOTIFICATION_SERVICE);
5438304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final Set<String> snoozedIds =
5448304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook                prefs.getStringSet(PREF_SNOOZE_IDS, new HashSet<String>());
5458304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final SharedPreferences.Editor ed = prefs.edit();
5468304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        for (String snoozeId : snoozedIds) {
5478304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            nm.cancel(Integer.parseInt(snoozeId));
5488304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            ed.remove(getAlarmPrefSnoozeTimeKey(snoozeId));
5498304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        }
5508304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
5518304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        ed.remove(PREF_SNOOZE_IDS);
552c6098ef1fc69fe117343cc2e3db0d2b97b2daa6fBrad Fitzpatrick        ed.apply();
5538304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    }
5548304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
5558304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    private static boolean hasAlarmBeenSnoozed(final SharedPreferences prefs, final int alarmId) {
5568304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final Set<String> snoozedIds = prefs.getStringSet(PREF_SNOOZE_IDS, null);
5578304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook
5588304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        // Return true if there a valid snoozed alarmId was saved
5598304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        return snoozedIds != null && snoozedIds.contains(Integer.toString(alarmId));
5608304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    }
561e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott
5625fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
5638304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook     * Updates the specified Alarm with the additional snooze time.
5648304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook     * Returns a boolean indicating whether the alarm was updated.
5655fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
5668304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook    private static boolean updateAlarmTimeForSnooze(
5678304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            final SharedPreferences prefs, final Alarm alarm) {
5688304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        if (!hasAlarmBeenSnoozed(prefs, alarm.id)) {
5698304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook            // No need to modify the alarm
570d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            return false;
571d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        }
572d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
5738304c6e63ee1ff86208bac6f79285905027e95e8Paul Westbrook        final long time = prefs.getLong(getAlarmPrefSnoozeTimeKey(alarm.id), -1);
574d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // The time in the database is either 0 (repeating) or a specific time
575d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // for a non-repeating alarm. Update this value so the AlarmReceiver
576d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // has the right time to compare.
577d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        alarm.time = time;
578d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
5795fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return true;
5805fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
5815fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
5825fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
5835fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Tells the StatusBar whether the alarm is enabled or disabled
5845fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
5855fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    private static void setStatusBarIcon(Context context, boolean enabled) {
586fe8dd39ee5e173f15337d09c36aa453a55364e98Patrick Scott        Intent alarmChanged = new Intent("android.intent.action.ALARM_CHANGED");
5875fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        alarmChanged.putExtra("alarmSet", enabled);
5885fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        context.sendBroadcast(alarmChanged);
5895fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
5905fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
591e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott    private static long calculateAlarm(Alarm alarm) {
592e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott        return calculateAlarm(alarm.hour, alarm.minutes, alarm.daysOfWeek)
593e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott                .getTimeInMillis();
594e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott    }
595e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott
5965fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
5975fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Given an alarm in hours and minutes, return a time suitable for
5985fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * setting in AlarmManager.
5995fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
600e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott    static Calendar calculateAlarm(int hour, int minute,
601e46be904bd76dff5a13aeef12e9bfeddac7bbe81Patrick Scott            Alarm.DaysOfWeek daysOfWeek) {
6025fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
6035fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        // start with now
6045fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Calendar c = Calendar.getInstance();
6055fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.setTimeInMillis(System.currentTimeMillis());
6065fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
6075fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        int nowHour = c.get(Calendar.HOUR_OF_DAY);
6085fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        int nowMinute = c.get(Calendar.MINUTE);
6095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
6105fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        // if alarm is behind current time, advance one day
6115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        if (hour < nowHour  ||
6125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            hour == nowHour && minute <= nowMinute) {
6135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            c.add(Calendar.DAY_OF_YEAR, 1);
6145fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
6155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.set(Calendar.HOUR_OF_DAY, hour);
6165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.set(Calendar.MINUTE, minute);
6175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.set(Calendar.SECOND, 0);
6185fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.set(Calendar.MILLISECOND, 0);
6195fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
6205fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        int addDays = daysOfWeek.getNextAlarm(c);
6215fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        if (addDays > 0) c.add(Calendar.DAY_OF_WEEK, addDays);
6225fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return c;
6235fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
6245fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
6255fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    static String formatTime(final Context context, int hour, int minute,
626d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                             Alarm.DaysOfWeek daysOfWeek) {
6275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Calendar c = calculateAlarm(hour, minute, daysOfWeek);
6285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return formatTime(context, c);
6295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
6305fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
6315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /* used by AlarmAlert */
6325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    static String formatTime(final Context context, Calendar c) {
6335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        String format = get24HourMode(context) ? M24 : M12;
6345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return (c == null) ? "" : (String)DateFormat.format(format, c);
6355fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
6365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
6375fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
6385fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Shows day and time -- used for lock screen
6395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
6405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    private static String formatDayAndTime(final Context context, Calendar c) {
6415fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        String format = get24HourMode(context) ? DM24 : DM12;
6425fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return (c == null) ? "" : (String)DateFormat.format(format, c);
6435fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
6445fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
6455fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
6465fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Save time of the next alarm, as a formatted string, into the system
6475fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * settings so those who care can make use of it.
6485fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
6495fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    static void saveNextAlarm(final Context context, String timeString) {
6505fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Settings.System.putString(context.getContentResolver(),
6515fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                                  Settings.System.NEXT_ALARM_FORMATTED,
6525fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                                  timeString);
6535fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
6545fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
6555fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
6565fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @return true if clock is set to 24-hour mode
6575fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
658421751e187dfa61bc1e48b52cdaf366628b06dd4Isaac Katzenelson    public static boolean get24HourMode(final Context context) {
6595fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return android.text.format.DateFormat.is24HourFormat(context);
6605fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
6615fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project}
662