AlertActivity.java revision 0ef732f240516f9f8b8add982f82244e01ec509b
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
17package com.android.calendar.alerts;
18
19import com.android.calendar.AllInOneActivity;
20import com.android.calendar.AsyncQueryService;
21import com.android.calendar.EventInfoActivity;
22import com.android.calendar.R;
23import com.android.calendar.Utils;
24
25import android.app.Activity;
26import android.app.NotificationManager;
27import android.app.TaskStackBuilder;
28import android.content.ContentValues;
29import android.content.Context;
30import android.content.Intent;
31import android.database.Cursor;
32import android.net.Uri;
33import android.os.Bundle;
34import android.provider.CalendarContract.CalendarAlerts;
35import android.util.Log;
36import android.view.View;
37import android.view.View.OnClickListener;
38import android.widget.AdapterView;
39import android.widget.AdapterView.OnItemClickListener;
40import android.widget.Button;
41import android.widget.ListView;
42
43/**
44 * The alert panel that pops up when there is a calendar event alarm.
45 * This activity is started by an intent that specifies an event id.
46  */
47public class AlertActivity extends Activity implements OnClickListener {
48    private static final String TAG = "AlertActivity";
49
50    private static final String[] PROJECTION = new String[] {
51        CalendarAlerts._ID,              // 0
52        CalendarAlerts.TITLE,            // 1
53        CalendarAlerts.EVENT_LOCATION,   // 2
54        CalendarAlerts.ALL_DAY,          // 3
55        CalendarAlerts.BEGIN,            // 4
56        CalendarAlerts.END,              // 5
57        CalendarAlerts.EVENT_ID,         // 6
58        CalendarAlerts.CALENDAR_COLOR,   // 7
59        CalendarAlerts.RRULE,            // 8
60        CalendarAlerts.HAS_ALARM,        // 9
61        CalendarAlerts.STATE,            // 10
62        CalendarAlerts.ALARM_TIME,       // 11
63    };
64
65    public static final int INDEX_ROW_ID = 0;
66    public static final int INDEX_TITLE = 1;
67    public static final int INDEX_EVENT_LOCATION = 2;
68    public static final int INDEX_ALL_DAY = 3;
69    public static final int INDEX_BEGIN = 4;
70    public static final int INDEX_END = 5;
71    public static final int INDEX_EVENT_ID = 6;
72    public static final int INDEX_COLOR = 7;
73    public static final int INDEX_RRULE = 8;
74    public static final int INDEX_HAS_ALARM = 9;
75    public static final int INDEX_STATE = 10;
76    public static final int INDEX_ALARM_TIME = 11;
77
78    private static final String SELECTION = CalendarAlerts.STATE + "=?";
79    private static final String[] SELECTIONARG = new String[] {
80        Integer.toString(CalendarAlerts.STATE_FIRED)
81    };
82
83    private AlertAdapter mAdapter;
84    private QueryHandler mQueryHandler;
85    private Cursor mCursor;
86    private ListView mListView;
87    private Button mSnoozeAllButton;
88    private Button mDismissAllButton;
89
90
91    private void dismissFiredAlarms() {
92        ContentValues values = new ContentValues(1 /* size */);
93        values.put(PROJECTION[INDEX_STATE], CalendarAlerts.STATE_DISMISSED);
94        String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.STATE_FIRED;
95        mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values,
96                selection, null /* selectionArgs */, Utils.UNDO_DELAY);
97    }
98
99    private void dismissAlarm(long id) {
100        ContentValues values = new ContentValues(1 /* size */);
101        values.put(PROJECTION[INDEX_STATE], CalendarAlerts.STATE_DISMISSED);
102        String selection = CalendarAlerts._ID + "=" + id;
103        mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values,
104                selection, null /* selectionArgs */, Utils.UNDO_DELAY);
105    }
106
107    private class QueryHandler extends AsyncQueryService {
108        public QueryHandler(Context context) {
109            super(context);
110        }
111
112        @Override
113        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
114            // Only set mCursor if the Activity is not finishing. Otherwise close the cursor.
115            if (!isFinishing()) {
116                mCursor = cursor;
117                mAdapter.changeCursor(cursor);
118                mListView.setSelection(cursor.getCount() - 1);
119
120                // The results are in, enable the buttons
121                mSnoozeAllButton.setEnabled(true);
122                mDismissAllButton.setEnabled(true);
123            } else {
124                cursor.close();
125            }
126        }
127
128        @Override
129        protected void onInsertComplete(int token, Object cookie, Uri uri) {
130            if (uri != null) {
131                Long alarmTime = (Long) cookie;
132
133                if (alarmTime != 0) {
134                    // Set a new alarm to go off after the snooze delay.
135                    // TODO make provider schedule this automatically when
136                    // inserting an alarm
137                    AlertUtils.scheduleAlarm(AlertActivity.this, null, alarmTime);
138                }
139            }
140        }
141
142        @Override
143        protected void onUpdateComplete(int token, Object cookie, int result) {
144            // Ignore
145        }
146    }
147
148
149
150    private final OnItemClickListener mViewListener = new OnItemClickListener() {
151
152        @Override
153        public void onItemClick(AdapterView<?> parent, View view, int position,
154                long i) {
155            AlertActivity alertActivity = AlertActivity.this;
156            Cursor cursor = alertActivity.getItemForView(view);
157
158            // Mark this alarm as DISMISSED
159            dismissAlarm(cursor.getLong(INDEX_ROW_ID));
160
161            // build an intent and task stack to start EventInfoActivity with AllInOneActivity
162            // as the parent activity rooted to home.
163            long id = cursor.getInt(AlertActivity.INDEX_EVENT_ID);
164            long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
165            long endMillis = cursor.getLong(AlertActivity.INDEX_END);
166            Intent eventIntent = AlertUtils.buildEventViewIntent(AlertActivity.this, id,
167                    startMillis, endMillis);
168
169            TaskStackBuilder.create(AlertActivity.this)
170                    .addParentStack(EventInfoActivity.class).addNextIntent(eventIntent)
171                    .startActivities();
172
173            alertActivity.finish();
174        }
175    };
176
177    @Override
178    protected void onCreate(Bundle icicle) {
179        super.onCreate(icicle);
180
181        setContentView(R.layout.alert_activity);
182        setTitle(R.string.alert_title);
183
184        mQueryHandler = new QueryHandler(this);
185        mAdapter = new AlertAdapter(this, R.layout.alert_item);
186
187        mListView = (ListView) findViewById(R.id.alert_container);
188        mListView.setItemsCanFocus(true);
189        mListView.setAdapter(mAdapter);
190        mListView.setOnItemClickListener(mViewListener);
191
192        mSnoozeAllButton = (Button) findViewById(R.id.snooze_all);
193        mSnoozeAllButton.setOnClickListener(this);
194        mDismissAllButton = (Button) findViewById(R.id.dismiss_all);
195        mDismissAllButton.setOnClickListener(this);
196
197        // Disable the buttons, since they need mCursor, which is created asynchronously
198        mSnoozeAllButton.setEnabled(false);
199        mDismissAllButton.setEnabled(false);
200    }
201
202    @Override
203    protected void onResume() {
204        super.onResume();
205
206        // If the cursor is null, start the async handler. If it is not null just requery.
207        if (mCursor == null) {
208            Uri uri = CalendarAlerts.CONTENT_URI_BY_INSTANCE;
209            mQueryHandler.startQuery(0, null, uri, PROJECTION, SELECTION,
210                    SELECTIONARG, CalendarAlerts.DEFAULT_SORT_ORDER);
211        } else {
212            if (!mCursor.requery()) {
213                Log.w(TAG, "Cursor#requery() failed.");
214                mCursor.close();
215                mCursor = null;
216            }
217        }
218    }
219
220    @Override
221    protected void onStop() {
222        super.onStop();
223        AlertService.updateAlertNotification(this);
224
225        if (mCursor != null) {
226            mCursor.deactivate();
227        }
228    }
229
230    @Override
231    protected void onDestroy() {
232        super.onDestroy();
233        if (mCursor != null) {
234            mCursor.close();
235        }
236    }
237
238    @Override
239    public void onClick(View v) {
240        if (v == mSnoozeAllButton) {
241            long alarmTime = System.currentTimeMillis() + AlertUtils.SNOOZE_DELAY;
242
243            NotificationManager nm =
244                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
245            nm.cancel(AlertUtils.NOTIFICATION_ID);
246
247            if (mCursor != null) {
248                long scheduleAlarmTime = 0;
249                mCursor.moveToPosition(-1);
250                while (mCursor.moveToNext()) {
251                    long eventId = mCursor.getLong(INDEX_EVENT_ID);
252                    long begin = mCursor.getLong(INDEX_BEGIN);
253                    long end = mCursor.getLong(INDEX_END);
254
255                    // Set the "minutes" to zero to indicate this is a snoozed
256                    // alarm.  There is code in AlertService.java that checks
257                    // this field.
258                    ContentValues values = AlertUtils.makeContentValues(eventId, begin, end,
259                            alarmTime, 0 /* minutes */);
260
261                    // Create a new alarm entry in the CalendarAlerts table
262                    if (mCursor.isLast()) {
263                        scheduleAlarmTime = alarmTime;
264                    }
265                    mQueryHandler.startInsert(0,
266                            scheduleAlarmTime, CalendarAlerts.CONTENT_URI, values,
267                            Utils.UNDO_DELAY);
268                }
269            } else {
270                Log.d(TAG, "Cursor object is null. Ignore the Snooze request.");
271            }
272
273            dismissFiredAlarms();
274            finish();
275        } else if (v == mDismissAllButton) {
276            NotificationManager nm =
277                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
278            nm.cancel(AlertUtils.NOTIFICATION_ID);
279
280            dismissFiredAlarms();
281
282            finish();
283        }
284    }
285
286    public boolean isEmpty() {
287        return mCursor != null ? (mCursor.getCount() == 0) : true;
288    }
289
290    public Cursor getItemForView(View view) {
291        final int index = mListView.getPositionForView(view);
292        if (index < 0) {
293            return null;
294        }
295        return (Cursor) mListView.getAdapter().getItem(index);
296    }
297}
298