Alarms.java revision 22924b6afee333e16fb62a19f1ac044c87c528b5
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
47d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This is a private action used by the AlarmKlaxon to update the UI to
48d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // show the alarm has been killed.
49d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_KILLED = "alarm_killed";
505fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
51d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // Extra in the ALARM_KILLED intent to indicate to the user how long the
52d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // alarm played before being killed.
53d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_KILLED_TIMEOUT = "alarm_killed_timeout";
545fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
55d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This string is used to indicate a silent alarm in the db.
56d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_ALERT_SILENT = "silent";
575fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
58d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This intent is sent from the notification when the user cancels the
59d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // snooze alert.
60d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String CANCEL_SNOOZE = "cancel_snooze";
615fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
62d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This string is used when passing an Alarm object through an intent.
63d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_INTENT_EXTRA = "intent.extra.alarm";
645fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
65d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This extra is the raw Alarm object data. It is used in the
66d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // AlarmManagerService to avoid a ClassNotFoundException when filling in
67d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // the Intent extras.
68d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_RAW_DATA = "intent.extra.alarm_raw";
695fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
70d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // This string is used to identify the alarm id passed to SetAlarm from the
71d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // list of alarms.
72d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static final String ALARM_ID = "alarm_id";
735fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
74d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    final static String PREF_SNOOZE_ID = "snooze_id";
75d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    final static String PREF_SNOOZE_TIME = "snooze_time";
765fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
77d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private final static String DM12 = "E h:mm aa";
78d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private final static String DM24 = "E k:mm";
795fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
80d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private final static String M12 = "h:mm aa";
811ebd23eaa82ab560f5c7d8aeca8df7512df8424ePatrick Scott    // Shared with DigitalClock
821ebd23eaa82ab560f5c7d8aeca8df7512df8424ePatrick Scott    final static String M24 = "kk:mm";
835fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
845fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
855fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Creates a new Alarm.
865fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
87d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static Uri addAlarm(ContentResolver contentResolver) {
885fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        ContentValues values = new ContentValues();
89d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.HOUR, 8);
90d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        return contentResolver.insert(Alarm.Columns.CONTENT_URI, values);
915fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
925fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
935fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
945fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Removes an existing Alarm.  If this alarm is snoozing, disables
955fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * snooze.  Sets next alert.
965fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
97d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static void deleteAlarm(
985fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            Context context, int alarmId) {
995fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1005fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        ContentResolver contentResolver = context.getContentResolver();
1015fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        /* If alarm is snoozing, lose it */
102d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        disableSnoozeAlert(context, alarmId);
1035fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
104d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Uri uri = ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, alarmId);
105d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        contentResolver.delete(uri, "", null);
1065fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1075fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setNextAlert(context);
1085fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
1095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1105fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
1115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Queries all alarms
1125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @return cursor over all alarms
1135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
114d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static Cursor getAlarmsCursor(ContentResolver contentResolver) {
1155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return contentResolver.query(
116d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                Alarm.Columns.CONTENT_URI, Alarm.Columns.ALARM_QUERY_COLUMNS,
117d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                null, null, Alarm.Columns.DEFAULT_SORT_ORDER);
1185fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
1195fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
120d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    // Private method to get a more limited set of alarms from the database.
121d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private static Cursor getFilteredAlarmsCursor(
122d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            ContentResolver contentResolver) {
123d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        return contentResolver.query(Alarm.Columns.CONTENT_URI,
124d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                Alarm.Columns.ALARM_QUERY_COLUMNS, Alarm.Columns.WHERE_ENABLED,
125d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                null, null);
1265fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
1275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
129d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott     * Return an Alarm object representing the alarm id in the database.
130d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott     * Returns null if no alarm exists.
1315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
132d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static Alarm getAlarm(ContentResolver contentResolver, int alarmId) {
1335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Cursor cursor = contentResolver.query(
134d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, alarmId),
135d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                Alarm.Columns.ALARM_QUERY_COLUMNS,
136d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                null, null, null);
137d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Alarm alarm = null;
138d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (cursor != null) {
139d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            if (cursor.moveToFirst()) {
140d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                alarm = new Alarm(cursor);
141d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            }
142d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            cursor.close();
143d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        }
144d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        return alarm;
1455fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
1465fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1475fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1485fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
1495fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * A convenience method to set an alarm in the Alarms
1505fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * content provider.
1515fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     *
1525fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param id             corresponds to the _id column
1535fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param enabled        corresponds to the ENABLED column
1545fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param hour           corresponds to the HOUR column
1555fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param minutes        corresponds to the MINUTES column
1565fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param daysOfWeek     corresponds to the DAYS_OF_WEEK column
1575fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param time           corresponds to the ALARM_TIME column
1585fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param vibrate        corresponds to the VIBRATE column
1595fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param message        corresponds to the MESSAGE column
1605fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param alert          corresponds to the ALERT column
161c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott     * @return Time when the alarm will fire.
1625fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
163c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott    public static long setAlarm(
1645fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            Context context, int id, boolean enabled, int hour, int minutes,
165d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            Alarm.DaysOfWeek daysOfWeek, boolean vibrate, String message,
1665fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            String alert) {
1675fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1685fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        ContentValues values = new ContentValues(8);
1695fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        ContentResolver resolver = context.getContentResolver();
170d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // Set the alarm_time value if this alarm does not repeat. This will be
171d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // used later to disable expired alarms.
172d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        long time = 0;
173d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (!daysOfWeek.isRepeatSet()) {
174d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            time = calculateAlarm(hour, minutes, daysOfWeek).getTimeInMillis();
175d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        }
1765fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
1775fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        if (Log.LOGV) Log.v(
1785fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                "**  setAlarm * idx " + id + " hour " + hour + " minutes " +
1795fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                minutes + " enabled " + enabled + " time " + time);
1805fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
181d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.ENABLED, enabled ? 1 : 0);
182d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.HOUR, hour);
183d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.MINUTES, minutes);
184d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.ALARM_TIME, time);
185d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.DAYS_OF_WEEK, daysOfWeek.getCoded());
186d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.VIBRATE, vibrate);
187d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.MESSAGE, message);
188d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.ALERT, alert);
189d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        resolver.update(ContentUris.withAppendedId(Alarm.Columns.CONTENT_URI, id),
1905fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                        values, null, null);
1915fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
192c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        long timeInMillis =
193c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott                calculateAlarm(hour, minutes, daysOfWeek).getTimeInMillis();
194c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott
195c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        if (enabled) {
196c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            // If this alarm fires before the next snooze, clear the snooze to
197c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            // enable this alarm.
198c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            SharedPreferences prefs = context.getSharedPreferences(
199c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott                    AlarmClock.PREFERENCES, 0);
200c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            long snoozeTime = prefs.getLong(PREF_SNOOZE_TIME, 0);
201c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            if (timeInMillis < snoozeTime) {
202c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott                clearSnoozePreference(context, prefs);
203c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            }
204c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        }
205c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott
2065fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setNextAlert(context);
207c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott
208c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        return timeInMillis;
2095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
2105fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
2115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
2125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * A convenience method to enable or disable an alarm.
2135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     *
2145fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param id             corresponds to the _id column
2155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param enabled        corresponds to the ENABLED column
2165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
2175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
218d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static void enableAlarm(
2195fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            final Context context, final int id, boolean enabled) {
2205fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        enableAlarmInternal(context, id, enabled);
2215fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setNextAlert(context);
2225fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
2235fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
224d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private static void enableAlarmInternal(final Context context,
225d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            final int id, boolean enabled) {
226d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        enableAlarmInternal(context, getAlarm(context.getContentResolver(), id),
227d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                enabled);
228d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    }
2295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
230d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private static void enableAlarmInternal(final Context context,
231d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            final Alarm alarm, boolean enabled) {
23222924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott        if (alarm == null) {
23322924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott            return;
23422924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott        }
235d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        ContentResolver resolver = context.getContentResolver();
2365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
2375fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        ContentValues values = new ContentValues(2);
238d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        values.put(Alarm.Columns.ENABLED, enabled ? 1 : 0);
2395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
240d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // If we are enabling the alarm, calculate alarm time since the time
241d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // value in Alarm may be old.
2425fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        if (enabled) {
243d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            long time = 0;
244d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            if (!alarm.daysOfWeek.isRepeatSet()) {
245d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                time = calculateAlarm(alarm.hour, alarm.minutes,
246d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                        alarm.daysOfWeek).getTimeInMillis();
2475fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            }
248d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            values.put(Alarm.Columns.ALARM_TIME, time);
24922924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott        } else {
25022924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott            // Clear the snooze if the id matches.
25122924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott            disableSnoozeAlert(context, alarm.id);
2525fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
2535fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
254d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        resolver.update(ContentUris.withAppendedId(
255d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                Alarm.Columns.CONTENT_URI, alarm.id), values, null, null);
2565fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
2575fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
258d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    public static Alarm calculateNextAlert(final Context context) {
259d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Alarm alarm = null;
260d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        long minTime = Long.MAX_VALUE;
26198948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott        long now = System.currentTimeMillis();
262d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Cursor cursor = getFilteredAlarmsCursor(context.getContentResolver());
263d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (cursor != null) {
264d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            if (cursor.moveToFirst()) {
265d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                do {
266d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    Alarm a = new Alarm(cursor);
267d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    // A time of 0 indicates this is a repeating alarm, so
268d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    // calculate the time to get the next alert.
269d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    if (a.time == 0) {
270d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                        a.time = calculateAlarm(a.hour, a.minutes, a.daysOfWeek)
271d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                                .getTimeInMillis();
27298948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott                    } else if (a.time < now) {
27398948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott                        // Expired alarm, disable it and move along.
27498948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott                        enableAlarmInternal(context, a, false);
27598948f9ce1dabcc79350a847baf220635b0c087aPatrick Scott                        continue;
276d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    }
277d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    if (a.time < minTime) {
278d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                        minTime = a.time;
279d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                        alarm = a;
280d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    }
281d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                } while (cursor.moveToNext());
2825fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            }
283d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            cursor.close();
2845fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
285d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        return alarm;
2865fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
2875fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
2885fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
2895fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Disables non-repeating alarms that have passed.  Called at
2905fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * boot.
2915fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
2925fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    public static void disableExpiredAlarms(final Context context) {
293d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Cursor cur = getFilteredAlarmsCursor(context.getContentResolver());
2945fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        long now = System.currentTimeMillis();
2955fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
2965fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        if (cur.moveToFirst()) {
2975fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            do {
298d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                Alarm alarm = new Alarm(cur);
299d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                // A time of 0 means this alarm repeats. If the time is
300d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                // non-zero, check if the time is before now.
301d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                if (alarm.time != 0 && alarm.time < now) {
302d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    if (Log.LOGV) {
303d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                        Log.v("** DISABLE " + alarm.id + " now " + now +" set "
304d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                                + alarm.time);
305d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    }
306d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                    enableAlarmInternal(context, alarm, false);
3075fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                }
3085fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            } while (cur.moveToNext());
3095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
3105fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        cur.close();
3115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
3125fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
3135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
3145fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Called at system startup, on time/timezone change, and whenever
3155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * the user changes alarm settings.  Activates snooze if set,
3165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * otherwise loads all alarms, activates next alert.
3175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
3185fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    public static void setNextAlert(final Context context) {
319d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (!enableSnoozeAlert(context)) {
320d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            Alarm alarm = calculateNextAlert(context);
321d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            if (alarm != null) {
322d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                enableAlert(context, alarm, alarm.time);
3235fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            } else {
324d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                disableAlert(context);
3255fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            }
3265fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
3275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
3285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
3295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
3305fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Sets alert in AlarmManger and StatusBar.  This is what will
3315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * actually launch the alert when the alarm triggers.
3325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     *
333d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott     * @param alarm Alarm.
3345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param atTimeInMillis milliseconds since epoch
3355fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
336d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    private static void enableAlert(Context context, final Alarm alarm,
337d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            final long atTimeInMillis) {
3385fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        AlarmManager am = (AlarmManager)
3395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                context.getSystemService(Context.ALARM_SERVICE);
3405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
341d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (Log.LOGV) {
342d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            Log.v("** setAlert id " + alarm.id + " atTime " + atTimeInMillis);
3435d6f5fa51fa7fd13784a73199161deabec5bc898Patrick Scott        }
344d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
345d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Intent intent = new Intent(ALARM_ALERT_ACTION);
346d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
347d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // XXX: This is a slight hack to avoid an exception in the remote
348d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // AlarmManagerService process. The AlarmManager adds extra data to
349d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // this Intent which causes it to inflate. Since the remote process
350d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // does not know about the Alarm class, it throws a
351d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // ClassNotFoundException.
352d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        //
353d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // To avoid this, we marshall the data ourselves and then parcel a plain
354d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // byte[] array. The AlarmReceiver class knows to build the Alarm
355d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // object from the byte[] array.
356d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        Parcel out = Parcel.obtain();
357d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        alarm.writeToParcel(out, 0);
358d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        out.setDataPosition(0);
359d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        intent.putExtra(ALARM_RAW_DATA, out.marshall());
360d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
3615fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        PendingIntent sender = PendingIntent.getBroadcast(
3625fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
3635fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
364d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender);
3655fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
3665fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setStatusBarIcon(context, true);
3675fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
3685fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Calendar c = Calendar.getInstance();
3695fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.setTime(new java.util.Date(atTimeInMillis));
3705fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        String timeString = formatDayAndTime(context, c);
3715fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        saveNextAlarm(context, timeString);
3725fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
3735fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
3745fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
3755fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Disables alert in AlarmManger and StatusBar.
3765fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     *
3775fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param id Alarm ID.
3785fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
379d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    static void disableAlert(Context context) {
3805fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        AlarmManager am = (AlarmManager)
3815fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                context.getSystemService(Context.ALARM_SERVICE);
3825fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        PendingIntent sender = PendingIntent.getBroadcast(
383d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                context, 0, new Intent(ALARM_ALERT_ACTION),
384d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                PendingIntent.FLAG_CANCEL_CURRENT);
3855fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        am.cancel(sender);
3865fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        setStatusBarIcon(context, false);
3875fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        saveNextAlarm(context, "");
3885fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
3895fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
390d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    static void saveSnoozeAlert(final Context context, final int id,
391d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            final long time) {
3925fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        SharedPreferences prefs = context.getSharedPreferences(
3935fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                AlarmClock.PREFERENCES, 0);
394d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (id == -1) {
395c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            clearSnoozePreference(context, prefs);
396d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        } else {
397c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            SharedPreferences.Editor ed = prefs.edit();
398d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            ed.putInt(PREF_SNOOZE_ID, id);
399d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            ed.putLong(PREF_SNOOZE_TIME, time);
400e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott            ed.commit();
4015d6f5fa51fa7fd13784a73199161deabec5bc898Patrick Scott        }
402d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // Set the next alert after updating the snooze.
403d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        setNextAlert(context);
4045fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
4055fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4065fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
407d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott     * Disable the snooze alert if the given id matches the snooze id.
4085fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
409d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    static void disableSnoozeAlert(final Context context, final int id) {
4105fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        SharedPreferences prefs = context.getSharedPreferences(
4115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                AlarmClock.PREFERENCES, 0);
412d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        int snoozeId = prefs.getInt(PREF_SNOOZE_ID, -1);
413d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (snoozeId == -1) {
414d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            // No snooze set, do nothing.
415d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            return;
416d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        } else if (snoozeId == id) {
417d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            // This is the same id so clear the shared prefs.
418c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            clearSnoozePreference(context, prefs);
419d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        }
4205fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
4215fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
422e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott    // Helper to remove the snooze preference. Do not use clear because that
423c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott    // will erase the clock preferences. Also clear the snooze notification in
424c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott    // the window shade.
425c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott    private static void clearSnoozePreference(final Context context,
426c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            final SharedPreferences prefs) {
427c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        final int alarmId = prefs.getInt(PREF_SNOOZE_ID, -1);
428c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        if (alarmId != -1) {
429c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            NotificationManager nm = (NotificationManager)
430c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott                    context.getSystemService(Context.NOTIFICATION_SERVICE);
431c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott            nm.cancel(alarmId);
432c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        }
433c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott
434c7edd6ea840e25cb04d090b6c29dc96c04d2be40Patrick Scott        final SharedPreferences.Editor ed = prefs.edit();
435e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott        ed.remove(PREF_SNOOZE_ID);
436e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott        ed.remove(PREF_SNOOZE_TIME);
437e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott        ed.commit();
438e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott    };
439e77fa5af5ac139f69ad504dbadd6f6aaab8c064dPatrick Scott
4405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
4415fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * If there is a snooze set, enable it in AlarmManager
4425fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @return true if snooze is set
4435fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
4445fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    private static boolean enableSnoozeAlert(final Context context) {
4455fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        SharedPreferences prefs = context.getSharedPreferences(
4465fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                AlarmClock.PREFERENCES, 0);
4475fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4485fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        int id = prefs.getInt(PREF_SNOOZE_ID, -1);
449d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        if (id == -1) {
450d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott            return false;
451d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        }
452d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        long time = prefs.getLong(PREF_SNOOZE_TIME, -1);
453d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
454d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // Get the alarm from the db.
455d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        final Alarm alarm = getAlarm(context.getContentResolver(), id);
45622924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott        if (alarm == null) {
45722924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott            return false;
45822924b6afee333e16fb62a19f1ac044c87c528b5Patrick Scott        }
459d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // The time in the database is either 0 (repeating) or a specific time
460d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // for a non-repeating alarm. Update this value so the AlarmReceiver
461d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        // has the right time to compare.
462d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        alarm.time = time;
463d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott
464d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott        enableAlert(context, alarm, time);
4655fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return true;
4665fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
4675fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4685fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
4695fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Tells the StatusBar whether the alarm is enabled or disabled
4705fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
4715fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    private static void setStatusBarIcon(Context context, boolean enabled) {
4725fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Intent alarmChanged = new Intent(Intent.ACTION_ALARM_CHANGED);
4735fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        alarmChanged.putExtra("alarmSet", enabled);
4745fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        context.sendBroadcast(alarmChanged);
4755fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
4765fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4775fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
4785fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Given an alarm in hours and minutes, return a time suitable for
4795fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * setting in AlarmManager.
4805fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param hour Always in 24 hour 0-23
4815fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param minute 0-59
4825fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @param daysOfWeek 0-59
4835fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
484d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott    static Calendar calculateAlarm(int hour, int minute, Alarm.DaysOfWeek daysOfWeek) {
4855fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4865fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        // start with now
4875fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Calendar c = Calendar.getInstance();
4885fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.setTimeInMillis(System.currentTimeMillis());
4895fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4905fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        int nowHour = c.get(Calendar.HOUR_OF_DAY);
4915fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        int nowMinute = c.get(Calendar.MINUTE);
4925fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
4935fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        // if alarm is behind current time, advance one day
4945fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        if (hour < nowHour  ||
4955fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            hour == nowHour && minute <= nowMinute) {
4965fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project            c.add(Calendar.DAY_OF_YEAR, 1);
4975fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        }
4985fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.set(Calendar.HOUR_OF_DAY, hour);
4995fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.set(Calendar.MINUTE, minute);
5005fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.set(Calendar.SECOND, 0);
5015fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        c.set(Calendar.MILLISECOND, 0);
5025fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
5035fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        int addDays = daysOfWeek.getNextAlarm(c);
5045fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        /* Log.v("** TIMES * " + c.getTimeInMillis() + " hour " + hour +
5055fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project           " minute " + minute + " dow " + c.get(Calendar.DAY_OF_WEEK) + " from now " +
5065fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project           addDays); */
5075fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        if (addDays > 0) c.add(Calendar.DAY_OF_WEEK, addDays);
5085fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return c;
5095fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
5105fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
5115fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    static String formatTime(final Context context, int hour, int minute,
512d776e51cec79901a0d656bba7b1f3780cceac57dPatrick Scott                             Alarm.DaysOfWeek daysOfWeek) {
5135fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Calendar c = calculateAlarm(hour, minute, daysOfWeek);
5145fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return formatTime(context, c);
5155fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
5165fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
5175fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /* used by AlarmAlert */
5185fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    static String formatTime(final Context context, Calendar c) {
5195fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        String format = get24HourMode(context) ? M24 : M12;
5205fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return (c == null) ? "" : (String)DateFormat.format(format, c);
5215fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
5225fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
5235fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
5245fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Shows day and time -- used for lock screen
5255fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
5265fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    private static String formatDayAndTime(final Context context, Calendar c) {
5275fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        String format = get24HourMode(context) ? DM24 : DM12;
5285fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return (c == null) ? "" : (String)DateFormat.format(format, c);
5295fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
5305fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
5315fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
5325fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * Save time of the next alarm, as a formatted string, into the system
5335fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * settings so those who care can make use of it.
5345fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
5355fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    static void saveNextAlarm(final Context context, String timeString) {
5365fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        Settings.System.putString(context.getContentResolver(),
5375fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                                  Settings.System.NEXT_ALARM_FORMATTED,
5385fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project                                  timeString);
5395fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
5405fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project
5415fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    /**
5425fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     * @return true if clock is set to 24-hour mode
5435fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project     */
5445fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    static boolean get24HourMode(final Context context) {
5455fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project        return android.text.format.DateFormat.is24HourFormat(context);
5465fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project    }
5475fedae0fb8cc29db88719329d52bdd62aad14277The Android Open Source Project}
548