• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.provider.Calendar.EVENT_BEGIN_TIME;
20 import static android.provider.Calendar.EVENT_END_TIME;
21 
22 import android.app.Activity;
23 import android.app.AlarmManager;
24 import android.app.NotificationManager;
25 import android.content.AsyncQueryHandler;
26 import android.content.ContentResolver;
27 import android.content.ContentUris;
28 import android.content.ContentValues;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.res.TypedArray;
32 import android.database.Cursor;
33 import android.net.Uri;
34 import android.os.Bundle;
35 import android.provider.Calendar.CalendarAlerts;
36 import android.provider.Calendar.CalendarAlertsColumns;
37 import android.provider.Calendar.Events;
38 import android.view.View;
39 import android.view.ViewGroup;
40 import android.view.WindowManager;
41 import android.view.View.OnClickListener;
42 import android.widget.AdapterView;
43 import android.widget.Button;
44 import android.widget.ListView;
45 import android.widget.AdapterView.OnItemClickListener;
46 
47 /**
48  * The alert panel that pops up when there is a calendar event alarm.
49  * This activity is started by an intent that specifies an event id.
50   */
51 public class AlertActivity extends Activity {
52 
53     // The default snooze delay: 5 minutes
54     public static final long SNOOZE_DELAY = 5 * 60 * 1000L;
55 
56     private static final String[] PROJECTION = new String[] {
57         CalendarAlerts._ID,              // 0
58         CalendarAlerts.TITLE,            // 1
59         CalendarAlerts.EVENT_LOCATION,   // 2
60         CalendarAlerts.ALL_DAY,          // 3
61         CalendarAlerts.BEGIN,            // 4
62         CalendarAlerts.END,              // 5
63         CalendarAlerts.EVENT_ID,         // 6
64         CalendarAlerts.COLOR,            // 7
65         CalendarAlerts.RRULE,            // 8
66         CalendarAlerts.HAS_ALARM,        // 9
67         CalendarAlerts.STATE,            // 10
68         CalendarAlerts.ALARM_TIME,       // 11
69     };
70 
71     public static final int INDEX_ROW_ID = 0;
72     public static final int INDEX_TITLE = 1;
73     public static final int INDEX_EVENT_LOCATION = 2;
74     public static final int INDEX_ALL_DAY = 3;
75     public static final int INDEX_BEGIN = 4;
76     public static final int INDEX_END = 5;
77     public static final int INDEX_EVENT_ID = 6;
78     public static final int INDEX_COLOR = 7;
79     public static final int INDEX_RRULE = 8;
80     public static final int INDEX_HAS_ALARM = 9;
81     public static final int INDEX_STATE = 10;
82     public static final int INDEX_ALARM_TIME = 11;
83 
84     private static final String SELECTION = CalendarAlerts.STATE + "=?";
85     private static final String[] SELECTIONARG = new String[] {
86         Integer.toString(CalendarAlerts.FIRED)
87     };
88 
89     // We use one notification id for all events so that we don't clutter
90     // the notification screen.  It doesn't matter what the id is, as long
91     // as it is used consistently everywhere.
92     public static final int NOTIFICATION_ID = 0;
93 
94     private ContentResolver mResolver;
95     private AlertAdapter mAdapter;
96     private QueryHandler mQueryHandler;
97     private Cursor mCursor;
98     private ListView mListView;
99     private Button mSnoozeAllButton;
100     private Button mDismissAllButton;
101 
102 
dismissFiredAlarms()103     private void dismissFiredAlarms() {
104         ContentValues values = new ContentValues(1 /* size */);
105         values.put(PROJECTION[INDEX_STATE], CalendarAlerts.DISMISSED);
106         String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.FIRED;
107         mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values,
108                 selection, null /* selectionArgs */);
109     }
110 
dismissAlarm(long id)111     private void dismissAlarm(long id) {
112         ContentValues values = new ContentValues(1 /* size */);
113         values.put(PROJECTION[INDEX_STATE], CalendarAlerts.DISMISSED);
114         String selection = CalendarAlerts._ID + "=" + id;
115         mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values,
116                 selection, null /* selectionArgs */);
117     }
118 
119     private class QueryHandler extends AsyncQueryHandler {
QueryHandler(ContentResolver cr)120         public QueryHandler(ContentResolver cr) {
121             super(cr);
122         }
123 
124         @Override
onQueryComplete(int token, Object cookie, Cursor cursor)125         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
126             // Only set mCursor if the Activity is not finishing. Otherwise close the cursor.
127             if (!isFinishing()) {
128                 mCursor = cursor;
129                 mAdapter.changeCursor(cursor);
130 
131                 // The results are in, enable the buttons
132                 mSnoozeAllButton.setEnabled(true);
133                 mDismissAllButton.setEnabled(true);
134             } else {
135                 cursor.close();
136             }
137         }
138 
139         @Override
onInsertComplete(int token, Object cookie, Uri uri)140         protected void onInsertComplete(int token, Object cookie, Uri uri) {
141             if (uri != null) {
142                 Long alarmTime = (Long) cookie;
143 
144                 if (alarmTime != 0) {
145                     // Set a new alarm to go off after the snooze delay.
146                     AlarmManager alarmManager =
147                             (AlarmManager) getSystemService(Context.ALARM_SERVICE);
148                     CalendarAlerts.scheduleAlarm(AlertActivity.this, alarmManager, alarmTime);
149                 }
150             }
151         }
152 
153         @Override
onUpdateComplete(int token, Object cookie, int result)154         protected void onUpdateComplete(int token, Object cookie, int result) {
155             // Ignore
156         }
157     }
158 
makeContentValues(long eventId, long begin, long end, long alarmTime, int minutes)159     private static ContentValues makeContentValues(long eventId, long begin, long end,
160             long alarmTime, int minutes) {
161         ContentValues values = new ContentValues();
162         values.put(CalendarAlerts.EVENT_ID, eventId);
163         values.put(CalendarAlerts.BEGIN, begin);
164         values.put(CalendarAlerts.END, end);
165         values.put(CalendarAlerts.ALARM_TIME, alarmTime);
166         long currentTime = System.currentTimeMillis();
167         values.put(CalendarAlerts.CREATION_TIME, currentTime);
168         values.put(CalendarAlerts.RECEIVED_TIME, 0);
169         values.put(CalendarAlerts.NOTIFY_TIME, 0);
170         values.put(CalendarAlerts.STATE, CalendarAlertsColumns.SCHEDULED);
171         values.put(CalendarAlerts.MINUTES, minutes);
172         return values;
173     }
174 
175     private OnItemClickListener mViewListener = new OnItemClickListener() {
176 
177         public void onItemClick(AdapterView<?> parent, View view, int position,
178                 long i) {
179             AlertActivity alertActivity = AlertActivity.this;
180             Cursor cursor = alertActivity.getItemForView(view);
181 
182             long id = cursor.getInt(AlertActivity.INDEX_EVENT_ID);
183             long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
184             long endMillis = cursor.getLong(AlertActivity.INDEX_END);
185 
186             Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, id);
187             Intent intent = new Intent(Intent.ACTION_VIEW, uri);
188             intent.setClass(alertActivity, EventInfoActivity.class);
189             intent.putExtra(EVENT_BEGIN_TIME, startMillis);
190             intent.putExtra(EVENT_END_TIME, endMillis);
191 
192             // Mark this alarm as DISMISSED
193             dismissAlarm(cursor.getLong(INDEX_ROW_ID));
194 
195             startActivity(intent);
196             alertActivity.finish();
197         }
198     };
199 
200     @Override
onCreate(Bundle icicle)201     protected void onCreate(Bundle icicle) {
202         super.onCreate(icicle);
203 
204         setContentView(R.layout.alert_activity);
205         setTitle(R.string.alert_title);
206 
207         WindowManager.LayoutParams lp = getWindow().getAttributes();
208         lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
209         lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
210 
211         getWindow().setAttributes(lp);
212 
213         mResolver = getContentResolver();
214         mQueryHandler = new QueryHandler(mResolver);
215         mAdapter = new AlertAdapter(this, R.layout.alert_item);
216 
217         mListView = (ListView) findViewById(R.id.alert_container);
218         mListView.setItemsCanFocus(true);
219         mListView.setAdapter(mAdapter);
220         mListView.setOnItemClickListener(mViewListener);
221 
222         mSnoozeAllButton = (Button) findViewById(R.id.snooze_all);
223         mSnoozeAllButton.setOnClickListener(mSnoozeAllListener);
224         mDismissAllButton = (Button) findViewById(R.id.dismiss_all);
225         mDismissAllButton.setOnClickListener(mDismissAllListener);
226 
227         // Disable the buttons, since they need mCursor, which is created asynchronously
228         mSnoozeAllButton.setEnabled(false);
229         mDismissAllButton.setEnabled(false);
230     }
231 
232     @Override
onResume()233     protected void onResume() {
234         super.onResume();
235 
236         // If the cursor is null, start the async handler. If it is not null just requery.
237         if (mCursor == null) {
238             Uri uri = CalendarAlerts.CONTENT_URI_BY_INSTANCE;
239             mQueryHandler.startQuery(0, null, uri, PROJECTION, SELECTION,
240                     SELECTIONARG, CalendarAlerts.DEFAULT_SORT_ORDER);
241         } else {
242             mCursor.requery();
243         }
244     }
245 
246     @Override
onStop()247     protected void onStop() {
248         super.onStop();
249         AlertService.updateAlertNotification(this);
250 
251         if (mCursor != null) {
252             mCursor.deactivate();
253         }
254     }
255 
256     @Override
onDestroy()257     protected void onDestroy() {
258         super.onDestroy();
259         if (mCursor != null) {
260             mCursor.close();
261         }
262     }
263 
264     private OnClickListener mSnoozeAllListener = new OnClickListener() {
265         public void onClick(View v) {
266             long alarmTime = System.currentTimeMillis() + SNOOZE_DELAY;
267 
268             NotificationManager nm =
269                 (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
270             nm.cancel(NOTIFICATION_ID);
271 
272             long scheduleAlarmTime = 0;
273             mCursor.moveToPosition(-1);
274             while (mCursor.moveToNext()) {
275                 long eventId = mCursor.getLong(INDEX_EVENT_ID);
276                 long begin = mCursor.getLong(INDEX_BEGIN);
277                 long end = mCursor.getLong(INDEX_END);
278 
279                 // Set the "minutes" to zero to indicate this is a snoozed
280                 // alarm.  There is code in AlertService.java that checks
281                 // this field.
282                 ContentValues values =
283                         makeContentValues(eventId, begin, end, alarmTime, 0 /* minutes */);
284 
285                 // Create a new alarm entry in the CalendarAlerts table
286                 if (mCursor.isLast()) {
287                     scheduleAlarmTime = alarmTime;
288                 }
289                 mQueryHandler.startInsert(0, scheduleAlarmTime, CalendarAlerts.CONTENT_URI, values);
290             }
291 
292             dismissFiredAlarms();
293 
294             finish();
295         }
296     };
297 
298     private OnClickListener mDismissAllListener = new OnClickListener() {
299         public void onClick(View v) {
300             NotificationManager nm =
301                 (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
302             nm.cancel(NOTIFICATION_ID);
303 
304             dismissFiredAlarms();
305 
306             finish();
307         }
308     };
309 
isEmpty()310     public boolean isEmpty() {
311         return (mCursor.getCount() == 0);
312     }
313 
getItemForView(View view)314     public Cursor getItemForView(View view) {
315         int index = mListView.getPositionForView(view);
316         if (index < 0) {
317             return null;
318         }
319         return (Cursor) mListView.getAdapter().getItem(index);
320     }
321 }
322