1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.calendar.alerts; 18 19 import android.app.Notification; 20 import android.app.NotificationManager; 21 import android.app.Service; 22 import android.content.ContentResolver; 23 import android.content.ContentUris; 24 import android.content.ContentValues; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.SharedPreferences; 28 import android.database.Cursor; 29 import android.net.Uri; 30 import android.os.Bundle; 31 import android.os.Handler; 32 import android.os.HandlerThread; 33 import android.os.IBinder; 34 import android.os.Looper; 35 import android.os.Message; 36 import android.os.Process; 37 import android.provider.CalendarContract; 38 import android.provider.CalendarContract.Attendees; 39 import android.provider.CalendarContract.CalendarAlerts; 40 import android.text.TextUtils; 41 import android.text.format.DateUtils; 42 import android.text.format.Time; 43 import android.util.Log; 44 45 import com.android.calendar.R; 46 import com.android.calendar.Utils; 47 48 import java.util.ArrayList; 49 import java.util.HashMap; 50 import java.util.List; 51 import java.util.TimeZone; 52 53 /** 54 * This service is used to handle calendar event reminders. 55 */ 56 public class AlertService extends Service { 57 static final boolean DEBUG = true; 58 private static final String TAG = "AlertService"; 59 60 private volatile Looper mServiceLooper; 61 62 static final String[] ALERT_PROJECTION = new String[] { 63 CalendarAlerts._ID, // 0 64 CalendarAlerts.EVENT_ID, // 1 65 CalendarAlerts.STATE, // 2 66 CalendarAlerts.TITLE, // 3 67 CalendarAlerts.EVENT_LOCATION, // 4 68 CalendarAlerts.SELF_ATTENDEE_STATUS, // 5 69 CalendarAlerts.ALL_DAY, // 6 70 CalendarAlerts.ALARM_TIME, // 7 71 CalendarAlerts.MINUTES, // 8 72 CalendarAlerts.BEGIN, // 9 73 CalendarAlerts.END, // 10 74 CalendarAlerts.DESCRIPTION, // 11 75 }; 76 77 private static final int ALERT_INDEX_ID = 0; 78 private static final int ALERT_INDEX_EVENT_ID = 1; 79 private static final int ALERT_INDEX_STATE = 2; 80 private static final int ALERT_INDEX_TITLE = 3; 81 private static final int ALERT_INDEX_EVENT_LOCATION = 4; 82 private static final int ALERT_INDEX_SELF_ATTENDEE_STATUS = 5; 83 private static final int ALERT_INDEX_ALL_DAY = 6; 84 private static final int ALERT_INDEX_ALARM_TIME = 7; 85 private static final int ALERT_INDEX_MINUTES = 8; 86 private static final int ALERT_INDEX_BEGIN = 9; 87 private static final int ALERT_INDEX_END = 10; 88 private static final int ALERT_INDEX_DESCRIPTION = 11; 89 90 private static final String ACTIVE_ALERTS_SELECTION = "(" + CalendarAlerts.STATE + "=? OR " 91 + CalendarAlerts.STATE + "=?) AND " + CalendarAlerts.ALARM_TIME + "<="; 92 93 private static final String[] ACTIVE_ALERTS_SELECTION_ARGS = new String[] { 94 Integer.toString(CalendarAlerts.STATE_FIRED), 95 Integer.toString(CalendarAlerts.STATE_SCHEDULED) 96 }; 97 98 private static final String ACTIVE_ALERTS_SORT = "begin DESC, end DESC"; 99 100 private static final String DISMISS_OLD_SELECTION = CalendarAlerts.END + "<? AND " 101 + CalendarAlerts.STATE + "=?"; 102 103 private static final int MINUTE_MS = 60 * 1000; 104 105 // The grace period before changing a notification's priority bucket. 106 private static final int MIN_DEPRIORITIZE_GRACE_PERIOD_MS = 15 * MINUTE_MS; 107 108 // Hard limit to the number of notifications displayed. 109 public static final int MAX_NOTIFICATIONS = 20; 110 111 // Added wrapper for testing 112 public static class NotificationWrapper { 113 Notification mNotification; 114 long mEventId; 115 long mBegin; 116 long mEnd; 117 ArrayList<NotificationWrapper> mNw; 118 NotificationWrapper(Notification n, int notificationId, long eventId, long startMillis, long endMillis, boolean doPopup)119 public NotificationWrapper(Notification n, int notificationId, long eventId, 120 long startMillis, long endMillis, boolean doPopup) { 121 mNotification = n; 122 mEventId = eventId; 123 mBegin = startMillis; 124 mEnd = endMillis; 125 126 // popup? 127 // notification id? 128 } 129 NotificationWrapper(Notification n)130 public NotificationWrapper(Notification n) { 131 mNotification = n; 132 } 133 add(NotificationWrapper nw)134 public void add(NotificationWrapper nw) { 135 if (mNw == null) { 136 mNw = new ArrayList<NotificationWrapper>(); 137 } 138 mNw.add(nw); 139 } 140 } 141 142 // Added wrapper for testing 143 public static class NotificationMgrWrapper extends NotificationMgr { 144 NotificationManager mNm; 145 NotificationMgrWrapper(NotificationManager nm)146 public NotificationMgrWrapper(NotificationManager nm) { 147 mNm = nm; 148 } 149 150 @Override cancel(int id)151 public void cancel(int id) { 152 mNm.cancel(id); 153 } 154 155 @Override notify(int id, NotificationWrapper nw)156 public void notify(int id, NotificationWrapper nw) { 157 mNm.notify(id, nw.mNotification); 158 } 159 } 160 161 static class NotificationInfo { 162 String eventName; 163 String location; 164 String description; 165 long startMillis; 166 long endMillis; 167 long eventId; 168 boolean allDay; 169 boolean newAlert; 170 NotificationInfo(String eventName, String location, String description, long startMillis, long endMillis, long eventId, boolean allDay, boolean newAlert)171 NotificationInfo(String eventName, String location, String description, long startMillis, 172 long endMillis, long eventId, boolean allDay, boolean newAlert) { 173 this.eventName = eventName; 174 this.location = location; 175 this.description = description; 176 this.startMillis = startMillis; 177 this.endMillis = endMillis; 178 this.eventId = eventId; 179 this.newAlert = newAlert; 180 this.allDay = allDay; 181 } 182 } 183 184 @Override onCreate()185 public void onCreate() { 186 } 187 188 @Override onStartCommand(Intent intent, int flags, int startId)189 public int onStartCommand(Intent intent, int flags, int startId) { 190 return START_REDELIVER_INTENT; 191 } 192 193 @Override onDestroy()194 public void onDestroy() { 195 mServiceLooper.quit(); 196 } 197 198 @Override onBind(Intent intent)199 public IBinder onBind(Intent intent) { 200 return null; 201 } 202 } 203