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