ea2d549f525f9df95ffef0997da7f70491beedd9
[android/platform/packages/apps/Calendar.git] / src / com / android / calendar / AlertReceiver.java
1 /*
2  * Copyright (C) 2007 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;
18
19 import android.app.Notification;
20 import android.app.NotificationManager;
21 import android.app.PendingIntent;
22 import android.app.Service;
23 import android.content.BroadcastReceiver;
24 import android.content.ContentResolver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.res.Resources;
28 import android.database.Cursor;
29 import android.net.Uri;
30 import android.os.PowerManager;
31 import android.provider.Calendar.CalendarAlerts;
32
33 /**
34  * Receives android.intent.action.EVENT_REMINDER intents and handles
35  * event reminders.  The intent URI specifies an alert id in the 
36  * CalendarAlerts database table.  This class also receives the
37  * BOOT_COMPLETED intent so that it can add a status bar notification
38  * if there are Calendar event alarms that have not been dismissed.
39  * It also receives the TIME_CHANGED action so that it can fire off
40  * snoozed alarms that have become ready.  The real work is done in
41  * the AlertService class.
42  */
43 public class AlertReceiver extends BroadcastReceiver {
44     
45     private static final String[] ALERT_PROJECTION = new String[] { 
46         CalendarAlerts.TITLE,           // 0
47         CalendarAlerts.EVENT_LOCATION,  // 1
48     };
49     private static final int ALERT_INDEX_TITLE = 0;
50     private static final int ALERT_INDEX_EVENT_LOCATION = 1;
51     
52     private static final String DELETE_ACTION = "delete";
53     
54     private static final String[] PROJECTION = new String[] { 
55         CalendarAlerts._ID,              // 0
56         CalendarAlerts.STATE,            // 1
57     };
58     
59     public static final int INDEX_STATE = 1;
60     
61     static final Object mStartingServiceSync = new Object();
62     static PowerManager.WakeLock mStartingService;
63     
64     @Override
65     public void onReceive(Context context, Intent intent) {
66         if (DELETE_ACTION.equals(intent.getAction())) {
67             
68             /* The user has clicked the "Clear All Notifications"
69              * buttons so dismiss all Calendar alerts.
70              */
71             dismissAllEvents(context);
72         } else {
73             Intent i = new Intent();
74             i.setClass(context, AlertService.class);
75             i.putExtras(intent);
76             i.putExtra("action", intent.getAction());
77             Uri uri = intent.getData();
78             
79             // This intent might be a BOOT_COMPLETED so it might not have a Uri.
80             if (uri != null) {
81                 i.putExtra("uri", uri.toString());
82             }
83             beginStartingService(context, i);
84         }
85     }
86     
87     private void dismissAllEvents(Context context) {
88         Uri uri = CalendarAlerts.CONTENT_URI_BY_INSTANCE;
89         String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.FIRED;
90         ContentResolver resolver = context.getContentResolver();
91         Cursor cursor = resolver.query(uri, PROJECTION, selection, null, null);
92         if (cursor != null) {
93             cursor.moveToPosition(-1);
94             while (cursor.moveToNext()) {
95                 cursor.updateInt(INDEX_STATE, CalendarAlerts.DISMISSED);
96             }
97             cursor.commitUpdates();
98             cursor.close();
99         }
100     }
101
102     /**
103      * Start the service to process the current event notifications, acquiring
104      * the wake lock before returning to ensure that the service will run.
105      */
106     public static void beginStartingService(Context context, Intent intent) {
107         synchronized (mStartingServiceSync) {
108             if (mStartingService == null) {
109                 PowerManager pm =
110                     (PowerManager)context.getSystemService(Context.POWER_SERVICE);
111                 mStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
112                         "StartingAlertService");
113                 mStartingService.setReferenceCounted(false);
114             }
115             mStartingService.acquire();
116             context.startService(intent);
117         }
118     }
119     
120     /**
121      * Called back by the service when it has finished processing notifications,
122      * releasing the wake lock if the service is now stopping.
123      */
124     public static void finishStartingService(Service service, int startId) {
125         synchronized (mStartingServiceSync) {
126             if (mStartingService != null) {
127                 if (service.stopSelfResult(startId)) {
128                     mStartingService.release();
129                 }
130             }
131         }
132     }
133     
134     public static void updateAlertNotification(Context context) {
135         // This can be called regularly to synchronize the alert notification
136         // with the contents of the CalendarAlerts table.
137         
138         ContentResolver cr = context.getContentResolver();
139         
140         if (cr == null) {
141             return;
142         }
143         
144         String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.FIRED;
145         Cursor alertCursor = CalendarAlerts.query(cr, ALERT_PROJECTION, selection, null);
146         
147         NotificationManager nm = 
148                 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
149         
150         if (alertCursor == null) {
151             nm.cancel(AlertActivity.NOTIFICATION_ID);
152             return;
153         }
154
155         if (!alertCursor.moveToFirst()) {
156             alertCursor.close();
157             nm.cancel(AlertActivity.NOTIFICATION_ID);
158             return;
159         }
160         
161         String title = alertCursor.getString(ALERT_INDEX_TITLE);
162         String location = alertCursor.getString(ALERT_INDEX_EVENT_LOCATION);
163         
164         Notification notification = AlertReceiver.makeNewAlertNotification(context, title, 
165                 location, alertCursor.getCount());
166         alertCursor.close();
167         
168         nm.notify(0, notification);
169     }
170     
171     public static Notification makeNewAlertNotification(Context context, String title, 
172             String location, int numReminders) {
173         Resources res = context.getResources();
174         
175         // Create an intent triggered by clicking on the status icon.
176         Intent clickIntent = new Intent();
177         clickIntent.setClass(context, AlertActivity.class);
178         clickIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
179         
180         // Create an intent triggered by clicking on the "Clear All Notifications" button
181         Intent deleteIntent = new Intent();
182         deleteIntent.setClass(context, AlertReceiver.class);
183         deleteIntent.setAction(DELETE_ACTION);
184         
185         if (title == null || title.length() == 0) {
186             title = res.getString(R.string.no_title_label);
187         }
188         
189         String helperString;
190         if (numReminders > 1) {
191             String format;
192             if (numReminders == 2) {
193                 format = res.getString(R.string.alert_missed_events_single);
194             } else {
195                 format = res.getString(R.string.alert_missed_events_multiple);
196             }
197             helperString = String.format(format, numReminders - 1);
198         } else {
199             helperString = location;
200         }
201         
202         Notification notification = new Notification(
203                 R.drawable.stat_notify_calendar,
204                 null,
205                 System.currentTimeMillis());
206         notification.setLatestEventInfo(context,
207                 title,
208                 helperString,
209                 PendingIntent.getActivity(context, 0, clickIntent, 0));
210         notification.deleteIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0);
211         
212         return notification;
213     }
214 }
215