Code drop from //branches/cupcake/...@124589
[android/platform/packages/apps/Calendar.git] / src / com / android / calendar / AlertActivity.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 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.Context;
30 import android.content.Intent;
31 import android.content.res.TypedArray;
32 import android.database.Cursor;
33 import android.graphics.PixelFormat;
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.Events;
39 import android.view.View;
40 import android.view.ViewGroup;
41 import android.view.Window;
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_TITLE = 1;
74     public static final int INDEX_EVENT_LOCATION = 2;
75     public static final int INDEX_ALL_DAY = 3;
76     public static final int INDEX_BEGIN = 4;
77     public static final int INDEX_END = 5;
78     public static final int INDEX_EVENT_ID = 6;
79     public static final int INDEX_COLOR = 7;
80     public static final int INDEX_RRULE = 8;
81     public static final int INDEX_HAS_ALARM = 9;
82     public static final int INDEX_STATE = 10;
83     public static final int INDEX_ALARM_TIME = 11;
84     
85     // We use one notification id for all events so that we don't clutter
86     // the notification screen.  It doesn't matter what the id is, as long
87     // as it is used consistently everywhere.
88     public static final int NOTIFICATION_ID = 0;
89     
90     private ContentResolver mResolver;
91     private AlertAdapter mAdapter;
92     private QueryHandler mQueryHandler;
93     private Cursor mCursor;
94     private ListView mListView;
95     private Button mSnoozeAllButton;
96     private Button mDismissAllButton;
97     
98     private class QueryHandler extends AsyncQueryHandler {
99         public QueryHandler(ContentResolver cr) {
100             super(cr);
101         }
102
103         @Override
104         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
105             // Only set mCursor if the Activity is not finishing. Otherwise close the cursor.
106             if (!isFinishing()) {
107                 mCursor = cursor;
108                 mAdapter.changeCursor(cursor);
109                 
110                 // The results are in, enable the buttons
111                 mSnoozeAllButton.setEnabled(true);
112                 mDismissAllButton.setEnabled(true);
113             } else {
114                 cursor.close();
115             }
116         }
117         
118     }
119     
120     private OnItemClickListener mViewListener = new OnItemClickListener() {
121
122         public void onItemClick(AdapterView parent, View view, int position,
123                 long i) {
124             AlertActivity alertActivity = AlertActivity.this;
125             Cursor cursor = alertActivity.getItemForView(view);
126             
127             long id = cursor.getInt(AlertActivity.INDEX_EVENT_ID);
128             long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
129             long endMillis = cursor.getLong(AlertActivity.INDEX_END);
130             
131             Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, id);
132             Intent intent = new Intent(Intent.ACTION_VIEW, uri);
133             intent.setClass(alertActivity, EventInfoActivity.class);
134             intent.putExtra(EVENT_BEGIN_TIME, startMillis);
135             intent.putExtra(EVENT_END_TIME, endMillis);
136             
137             // Mark this alarm as DISMISSED
138             cursor.updateInt(INDEX_STATE, CalendarAlerts.DISMISSED);
139             cursor.commitUpdates();
140             
141             startActivity(intent);
142             alertActivity.finish();
143         }
144     };
145     
146     @Override
147     protected void onCreate(Bundle icicle) {
148         super.onCreate(icicle);
149         
150         requestWindowFeature(Window.FEATURE_NO_TITLE);
151         setContentView(R.layout.alert_activity);
152         
153         WindowManager.LayoutParams lp = getWindow().getAttributes();
154         lp.width = ViewGroup.LayoutParams.FILL_PARENT;
155         lp.height = ViewGroup.LayoutParams.FILL_PARENT;
156         
157         // Get the dim amount from the theme
158         TypedArray a = obtainStyledAttributes(com.android.internal.R.styleable.Theme);
159         lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f);
160         a.recycle();
161
162         getWindow().setAttributes(lp);
163         getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
164         
165         mResolver = getContentResolver();
166         mQueryHandler = new QueryHandler(mResolver);
167         mAdapter = new AlertAdapter(this, R.layout.alert_item);
168         
169         mListView = (ListView) findViewById(R.id.alert_container);
170         mListView.setItemsCanFocus(true);
171         mListView.setAdapter(mAdapter);
172         mListView.setOnItemClickListener(mViewListener);
173         
174         mSnoozeAllButton = (Button) findViewById(R.id.snooze_all);
175         mSnoozeAllButton.setOnClickListener(mSnoozeAllListener);
176         mDismissAllButton = (Button) findViewById(R.id.dismiss_all);
177         mDismissAllButton.setOnClickListener(mDismissAllListener);
178
179         // Disable the buttons, since they need mCursor, which is created asynchronously
180         mSnoozeAllButton.setEnabled(false);
181         mDismissAllButton.setEnabled(false);
182     }
183     
184     @Override
185     protected void onResume() {
186         super.onResume();
187         
188         // If the cursor is null, start the async handler. If it is not null just requery.
189         if (mCursor == null) {
190             Uri uri = CalendarAlerts.CONTENT_URI_BY_INSTANCE;
191             String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.FIRED;
192             mQueryHandler.startQuery(0, null, uri, PROJECTION, selection, 
193                     null /* selection args */, CalendarAlerts.DEFAULT_SORT_ORDER);
194         } else {
195             mCursor.requery();
196         }
197     }
198     
199     @Override
200     protected void onStop() {
201         super.onStop();
202         AlertReceiver.updateAlertNotification(this);
203         
204         if (mCursor != null) {
205             mCursor.deactivate();
206         }
207     }
208     
209     @Override
210     protected void onDestroy() {
211         super.onDestroy();
212         if (mCursor != null) {
213             mCursor.close();
214         }
215     }
216     
217     private OnClickListener mSnoozeAllListener = new OnClickListener() {
218         public void onClick(View v) {
219             NotificationManager nm =
220                 (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
221             nm.cancel(NOTIFICATION_ID);
222             mCursor.moveToPosition(-1);
223             while (mCursor.moveToNext()) {
224                 long eventId = mCursor.getLong(INDEX_EVENT_ID);
225                 long begin = mCursor.getLong(INDEX_BEGIN);
226                 long end = mCursor.getLong(INDEX_END);
227                 long alarmTime = mCursor.getLong(INDEX_ALARM_TIME);
228
229                 // Mark this alarm as DISMISSED
230                 mCursor.updateInt(INDEX_STATE, CalendarAlerts.DISMISSED);
231                 
232                 // Create a new alarm entry in the CalendarAlerts table
233                 long now = System.currentTimeMillis();
234                 alarmTime = now + SNOOZE_DELAY;
235                 
236                 // Set the "minutes" to zero to indicate this is a snoozed
237                 // alarm.  There is code in AlertService.java that checks
238                 // this field.
239                 Uri uri = CalendarAlerts.insert(mResolver, eventId,
240                         begin, end, alarmTime, 0 /* minutes */);
241                 
242                 // Set a new alarm to go off after the snooze delay.
243                 Intent intent = new Intent(Calendar.EVENT_REMINDER_ACTION);
244                 intent.setData(uri);
245                 intent.putExtra(Calendar.EVENT_BEGIN_TIME, begin);
246                 intent.putExtra(Calendar.EVENT_END_TIME, end);
247                 
248                 PendingIntent sender = PendingIntent.getBroadcast(AlertActivity.this,
249                         0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
250                 Object service = getSystemService(Context.ALARM_SERVICE);
251                 AlarmManager alarmManager = (AlarmManager) service;
252                 alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, sender);
253             }
254             mCursor.commitUpdates();
255             finish();
256         }
257     };
258     
259     private OnClickListener mDismissAllListener = new OnClickListener() {
260         public void onClick(View v) {
261             NotificationManager nm =
262                 (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
263             nm.cancel(NOTIFICATION_ID);
264             mCursor.moveToPosition(-1);
265             while (mCursor.moveToNext()) {
266                 mCursor.updateInt(INDEX_STATE, CalendarAlerts.DISMISSED);
267             }
268             mCursor.commitUpdates();
269             finish();
270         }
271     };
272     
273     public boolean isEmpty() {
274         return (mCursor.getCount() == 0);
275     }
276     
277     public Cursor getItemForView(View view) {
278         int index = mListView.getPositionForView(view);
279         if (index < 0) {
280             return null;
281         }
282         return (Cursor) mListView.getAdapter().getItem(index);
283     }
284 }