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