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