AlertService.java revision 146de36083f6ce8b7e8a1f974d3990594a36bfec
1146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/* 2146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 4146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * you may not use this file except in compliance with the License. 6146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * You may obtain a copy of the License at 7146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 8146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * 10146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * See the License for the specific language governing permissions and 14146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * limitations under the License. 15146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 16146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 17146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpackage com.android.calendar; 18146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 19146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.app.AlarmManager; 20146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.app.Notification; 21146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.app.NotificationManager; 22146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.app.Service; 23146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.ContentResolver; 24146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.ContentValues; 25146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Context; 26146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Intent; 27146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.SharedPreferences; 28146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.database.Cursor; 29146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.net.Uri; 30146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Bundle; 31146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Handler; 32146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.HandlerThread; 33146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.IBinder; 34146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Looper; 35146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Message; 36146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Process; 37146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.preference.PreferenceManager; 38146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar; 39146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Attendees; 40146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.CalendarAlerts; 41146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Instances; 42146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Reminders; 43146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.TextUtils; 44146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.DateUtils; 45146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.Time; 46146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.util.Log; 47146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.LayoutInflater; 48146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.View; 49146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 50146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/** 51146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * This service is used to handle calendar event reminders. 52146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */ 53146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpublic class AlertService extends Service { 54146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final String TAG = "AlertService"; 55146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 56146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private volatile Looper mServiceLooper; 57146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private volatile ServiceHandler mServiceHandler; 58146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 59146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final String[] ALERT_PROJECTION = new String[] { 60146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts._ID, // 0 61146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.EVENT_ID, // 1 62146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.STATE, // 2 63146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.TITLE, // 3 64146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.EVENT_LOCATION, // 4 65146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.SELF_ATTENDEE_STATUS, // 5 66146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.ALL_DAY, // 6 67146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.ALARM_TIME, // 7 68146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.MINUTES, // 8 69146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.BEGIN, // 9 70146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project }; 71146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 72146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // We just need a simple projection that returns any column 73146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final String[] ALERT_PROJECTION_SMALL = new String[] { 74146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts._ID, // 0 75146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project }; 76146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 77146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_ID = 0; 78146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_EVENT_ID = 1; 79146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_STATE = 2; 80146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_TITLE = 3; 81146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_EVENT_LOCATION = 4; 82146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_SELF_ATTENDEE_STATUS = 5; 83146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_ALL_DAY = 6; 84146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_ALARM_TIME = 7; 85146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_MINUTES = 8; 86146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int ALERT_INDEX_BEGIN = 9; 87146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 88146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private String[] INSTANCE_PROJECTION = { Instances.BEGIN, Instances.END }; 89146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int INSTANCES_INDEX_BEGIN = 0; 90146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final int INSTANCES_INDEX_END = 1; 91146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 92146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // We just need a simple projection that returns any column 93146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private static final String[] REMINDER_PROJECTION_SMALL = new String[] { 94146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Reminders._ID, // 0 95146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project }; 96146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 97146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void processMessage(Message msg) { 98146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Bundle bundle = (Bundle) msg.obj; 99146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // On reboot, update the notification bar with the contents of the 101146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // CalendarAlerts table. 102146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String action = bundle.getString("action"); 103146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (action.equals(Intent.ACTION_BOOT_COMPLETED) 104146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project || action.equals(Intent.ACTION_TIME_CHANGED)) { 105146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project doTimeChanged(); 106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The Uri specifies an entry in the CalendarAlerts table 110146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Uri alertUri = Uri.parse(bundle.getString("uri")); 111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 112146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "uri: " + alertUri); 113146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 114146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 115146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ContentResolver cr = getContentResolver(); 116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Cursor alertCursor = cr.query(alertUri, ALERT_PROJECTION, 117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project null /* selection */, null, null /* sort order */); 118146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 119146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long alertId, eventId, instanceId, alarmTime; 120146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int minutes; 121146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String eventName; 122146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String location; 123146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project boolean allDay; 124146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project boolean declined = false; 125146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project try { 126146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (alertCursor == null || !alertCursor.moveToFirst()) { 127146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This can happen if the event was deleted. 128146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "alert not found"); 130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 132146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 133146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertId = alertCursor.getLong(ALERT_INDEX_ID); 134146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project eventId = alertCursor.getLong(ALERT_INDEX_EVENT_ID); 135146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project minutes = alertCursor.getInt(ALERT_INDEX_MINUTES); 136146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project eventName = alertCursor.getString(ALERT_INDEX_TITLE); 137146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project location = alertCursor.getString(ALERT_INDEX_EVENT_LOCATION); 138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project allDay = alertCursor.getInt(ALERT_INDEX_ALL_DAY) != 0; 139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alarmTime = alertCursor.getLong(ALERT_INDEX_ALARM_TIME); 140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project declined = alertCursor.getInt(ALERT_INDEX_SELF_ATTENDEE_STATUS) == 141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Attendees.ATTENDEE_STATUS_DECLINED; 142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If the event was declined, then mark the alarm DISMISSED, 144146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // otherwise, mark the alarm FIRED. 145146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int newState = CalendarAlerts.FIRED; 146146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (declined) { 147146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project newState = CalendarAlerts.DISMISSED; 148146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 149146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertCursor.updateInt(ALERT_INDEX_STATE, newState); 150146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertCursor.commitUpdates(); 151146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } finally { 152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (alertCursor != null) { 153146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertCursor.close(); 154146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 155146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 156146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 157146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Do not show an alert if the event was declined 158146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (declined) { 159146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 160146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "event declined, alert cancelled"); 161146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 162146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 163146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 164146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 165146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long beginTime = bundle.getLong(Calendar.EVENT_BEGIN_TIME, 0); 166146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long endTime = bundle.getLong(Calendar.EVENT_END_TIME, 0); 167146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 168146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Check if this alarm is still valid. The time of the event may 169146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // have been changed, or the reminder may have been changed since 170146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // this alarm was set. First, search for an instance in the Instances 171146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // that has the same event id and the same begin and end time. 172146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Then check for a reminder in the Reminders table to ensure that 173146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // the reminder minutes is consistent with this alarm. 174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String selection = Instances.EVENT_ID + "=" + eventId; 175146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Cursor instanceCursor = Instances.query(cr, INSTANCE_PROJECTION, 176146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project beginTime, endTime, selection, Instances.DEFAULT_SORT_ORDER); 177146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long instanceBegin = 0, instanceEnd = 0; 178146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project try { 179146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (instanceCursor == null || !instanceCursor.moveToFirst()) { 180146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Delete this alarm from the CalendarAlerts table 181146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cr.delete(alertUri, null /* selection */, null /* selection args */); 182146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 183146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "instance not found, alert cancelled"); 184146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 185146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 186146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 187146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project instanceBegin = instanceCursor.getLong(INSTANCES_INDEX_BEGIN); 188146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project instanceEnd = instanceCursor.getLong(INSTANCES_INDEX_END); 189146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } finally { 190146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (instanceCursor != null) { 191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project instanceCursor.close(); 192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Check that a reminder for this event exists with the same number 196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // of minutes. But snoozed alarms have minutes = 0, so don't do this 197146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // check for snoozed alarms. 198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (minutes > 0) { 199146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project selection = Reminders.EVENT_ID + "=" + eventId 200146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + " AND " + Reminders.MINUTES + "=" + minutes; 201146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Cursor reminderCursor = cr.query(Reminders.CONTENT_URI, REMINDER_PROJECTION_SMALL, 202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project selection, null /* selection args */, null /* sort order */); 203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project try { 204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (reminderCursor == null || reminderCursor.getCount() == 0) { 205146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Delete this alarm from the CalendarAlerts table 206146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cr.delete(alertUri, null /* selection */, null /* selection args */); 207146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 208146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "reminder not found, alert cancelled"); 209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 210146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } finally { 213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (reminderCursor != null) { 214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project reminderCursor.close(); 215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If the event time was changed and the event has already ended, 220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // then don't sound the alarm. 221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (alarmTime > instanceEnd) { 222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Delete this alarm from the CalendarAlerts table 223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cr.delete(alertUri, null /* selection */, null /* selection args */); 224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "event ended, alert cancelled"); 226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If minutes > 0, then this is a normal alarm (not a snoozed alarm) 231146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // so check for duplicate alarms. A duplicate alarm can occur when 232146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // the start time of an event is changed to an earlier time. The 233146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // later alarm (that was first scheduled for the later event time) 234146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // should be discarded. 235146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long computedAlarmTime = instanceBegin - minutes * DateUtils.MINUTE_IN_MILLIS; 236146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (minutes > 0 && computedAlarmTime != alarmTime) { 237146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // If the event time was changed to a later time, then the computed 238146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // alarm time is in the future and we shouldn't sound this alarm. 239146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (computedAlarmTime > alarmTime) { 240146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Delete this alarm from the CalendarAlerts table 241146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cr.delete(alertUri, null /* selection */, null /* selection args */); 242146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 243146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "event postponed, alert cancelled"); 244146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 245146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 246146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 247146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Check for another alarm in the CalendarAlerts table that has the 249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // same event id and the same "minutes". This can occur 250146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // if the event start time was changed to an earlier time and the 251146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // alarm for the later time goes off. To avoid discarding alarms 252146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // for repeating events (that have the same event id), we check 253146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // that the other alarm fired recently (within an hour of this one). 254146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long recently = alarmTime - 60 * DateUtils.MINUTE_IN_MILLIS; 255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project selection = CalendarAlerts.EVENT_ID + "=" + eventId 256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + " AND " + CalendarAlerts.TABLE_NAME + "." + CalendarAlerts._ID 257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + "!=" + alertId 258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + " AND " + CalendarAlerts.MINUTES + "=" + minutes 259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + " AND " + CalendarAlerts.ALARM_TIME + ">" + recently 260146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + " AND " + CalendarAlerts.ALARM_TIME + "<=" + alarmTime; 261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertCursor = CalendarAlerts.query(cr, ALERT_PROJECTION_SMALL, selection, null); 262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (alertCursor != null) { 263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project try { 264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (alertCursor.getCount() > 0) { 265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Delete this alarm from the CalendarAlerts table 266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cr.delete(alertUri, null /* selection */, null /* selection args */); 267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 268146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "duplicate alarm, alert cancelled"); 269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 272146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } finally { 273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertCursor.close(); 274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Find all the alerts that have fired but have not been dismissed 279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project selection = CalendarAlerts.STATE + "=" + CalendarAlerts.FIRED; 280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertCursor = CalendarAlerts.query(cr, ALERT_PROJECTION, selection, null); 281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (alertCursor == null || alertCursor.getCount() == 0) { 283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "no fired alarms found"); 285146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 286146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 287146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int numReminders = alertCursor.getCount(); 290146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project try { 291146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project while (alertCursor.moveToNext()) { 292146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long otherEventId = alertCursor.getLong(ALERT_INDEX_EVENT_ID); 293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long otherAlertId = alertCursor.getLong(ALERT_INDEX_ID); 294146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int otherAlarmState = alertCursor.getInt(ALERT_INDEX_STATE); 295146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long otherBeginTime = alertCursor.getLong(ALERT_INDEX_BEGIN); 296146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (otherEventId == eventId && otherAlertId != alertId 297146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project && otherAlarmState == CalendarAlerts.FIRED 298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project && otherBeginTime == beginTime) { 299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This event already has an alert that fired and has not 300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // been dismissed. This can happen if an event has 301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // multiple reminders. Do not count this as a separate 302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // reminder. But we do want to sound the alarm and vibrate 303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // the phone, if necessary. 304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "multiple alarms for this event"); 306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 307146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project numReminders -= 1; 308146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } finally { 311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertCursor.close(); 312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 313146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 314146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 315146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "creating new alarm notification, numReminders: " + numReminders); 316146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 317146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Notification notification = AlertReceiver.makeNewAlertNotification(this, eventName, 318146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project location, numReminders); 319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Generate either a pop-up dialog, status bar notification, or 321146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // neither. Pop-up dialog and status bar notification may include a 322146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // sound, an alert, or both. A status bar notification also includes 323146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // a toast. 324146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 325146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String reminderType = prefs.getString(CalendarPreferenceActivity.KEY_ALERTS_TYPE, 326146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarPreferenceActivity.ALERT_TYPE_STATUS_BAR); 327146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 328146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (reminderType.equals(CalendarPreferenceActivity.ALERT_TYPE_OFF)) { 329146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (Log.isLoggable(TAG, Log.DEBUG)) { 330146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.d(TAG, "alert preference is OFF"); 331146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 332146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return; 333146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 334146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 335146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project NotificationManager nm = 336146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 337146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project boolean reminderVibrate = 338146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prefs.getBoolean(CalendarPreferenceActivity.KEY_ALERTS_VIBRATE, false); 339146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String reminderRingtone = 340146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project prefs.getString(CalendarPreferenceActivity.KEY_ALERTS_RINGTONE, null); 341146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 342146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Possibly generate a vibration 343146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (reminderVibrate) { 344146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project notification.defaults |= Notification.DEFAULT_VIBRATE; 345146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 346146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 347146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Possibly generate a sound. If 'Silent' is chosen, the ringtone string will be empty. 348146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project notification.sound = TextUtils.isEmpty(reminderRingtone) ? null : Uri 349146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project .parse(reminderRingtone); 350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 351146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (reminderType.equals(CalendarPreferenceActivity.ALERT_TYPE_ALERTS)) { 352146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Intent alertIntent = new Intent(); 353146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertIntent.setClass(this, AlertActivity.class); 354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project alertIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project startActivity(alertIntent); 356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } else { 357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project LayoutInflater inflater; 358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 359146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project View view = inflater.inflate(R.layout.alert_toast, null); 360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 361146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project AlertAdapter.updateView(this, view, eventName, location, beginTime, endTime, allDay); 362146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // Record the notify time in the CalendarAlerts table. 365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // This is used for debugging missed alarms. 366146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ContentValues values = new ContentValues(); 367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long currentTime = System.currentTimeMillis(); 368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project values.put(CalendarAlerts.NOTIFY_TIME, currentTime); 369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project cr.update(alertUri, values, null /* where */, null /* args */); 370146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 371146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // The notification time should be pretty close to the reminder time 372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // that the user set for this event. If the notification is late, then 373146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // that's a bug and we should log an error. 374146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project if (currentTime > alarmTime + DateUtils.MINUTE_IN_MILLIS) { 375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project long minutesLate = (currentTime - alarmTime) / DateUtils.MINUTE_IN_MILLIS; 376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project int flags = DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_TIME; 377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String alarmTimeStr = DateUtils.formatDateTime(this, alarmTime, flags); 378146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project String currentTimeStr = DateUtils.formatDateTime(this, currentTime, flags); 379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Log.w(TAG, "Calendar reminder alarm for event id " + eventId 380146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + " is " + minutesLate + " minute(s) late;" 381146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + " expected alarm at: " + alarmTimeStr 382146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project + " but got it at: " + currentTimeStr); 383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project nm.notify(0, notification); 386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 387146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 388146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private void doTimeChanged() { 389146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project ContentResolver cr = getContentResolver(); 390146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Object service = getSystemService(Context.ALARM_SERVICE); 391146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project AlarmManager manager = (AlarmManager) service; 392146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project CalendarAlerts.rescheduleMissedAlarms(cr, this, manager); 393146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project AlertReceiver.updateAlertNotification(this); 394146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 395146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project private final class ServiceHandler extends Handler { 397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public ServiceHandler(Looper looper) { 398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project super(looper); 399146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 401146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 402146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void handleMessage(Message msg) { 403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project processMessage(msg); 404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // NOTE: We MUST not call stopSelf() directly, since we need to 405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project // make sure the wake lock acquired by AlertReceiver is released. 406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project AlertReceiver.finishStartingService(AlertService.this, msg.arg1); 407146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 408146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project }; 409146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 410146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 411146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void onCreate() { 412146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project HandlerThread thread = new HandlerThread("AlertService", 413146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Process.THREAD_PRIORITY_BACKGROUND); 414146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project thread.start(); 415146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 416146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mServiceLooper = thread.getLooper(); 417146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mServiceHandler = new ServiceHandler(mServiceLooper); 418146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 419146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 420146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 421146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void onStart(Intent intent, int startId) { 422146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project Message msg = mServiceHandler.obtainMessage(); 423146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project msg.arg1 = startId; 424146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project msg.obj = intent.getExtras(); 425146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mServiceHandler.sendMessage(msg); 426146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 427146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 428146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 429146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public void onDestroy() { 430146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project mServiceLooper.quit(); 431146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 432146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project 433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project @Override 434146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project public IBinder onBind(Intent intent) { 435146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project return null; 436146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project } 437146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project} 438