AlertActivity.java revision 8f7f1abe54f206c490d2683f80646f514d98939b
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 android.app.Activity;
20import android.app.NotificationManager;
21import android.app.TaskStackBuilder;
22import android.content.ContentValues;
23import android.content.Context;
24import android.content.Intent;
25import android.database.Cursor;
26import android.net.Uri;
27import android.os.Bundle;
28import android.provider.CalendarContract;
29import android.provider.CalendarContract.CalendarAlerts;
30import android.util.Log;
31import android.view.View;
32import android.view.View.OnClickListener;
33import android.widget.AdapterView;
34import android.widget.AdapterView.OnItemClickListener;
35import android.widget.Button;
36import android.widget.ListView;
37
38import com.android.calendar.AsyncQueryService;
39import com.android.calendar.EventInfoActivity;
40import com.android.calendar.R;
41import com.android.calendar.Utils;
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 + "=? AND " +
79            CalendarAlerts.END + "<?";
80
81    private AlertAdapter mAdapter;
82    private QueryHandler mQueryHandler;
83    private Cursor mCursor;
84    private ListView mListView;
85    private Button mDismissAllButton;
86
87
88    private void dismissFiredAlarmsForPastEvents() {
89        ContentValues values = new ContentValues(1 /* size */);
90        values.put(PROJECTION[INDEX_STATE], CalendarAlerts.STATE_DISMISSED);
91        String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.STATE_FIRED + " AND " +
92                CalendarAlerts.END + "<" + Long.toString(System.currentTimeMillis());
93        mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values,
94                selection, null /* selectionArgs */, Utils.UNDO_DELAY);
95    }
96
97    private void dismissAlarm(long id) {
98        ContentValues values = new ContentValues(1 /* size */);
99        values.put(PROJECTION[INDEX_STATE], CalendarAlerts.STATE_DISMISSED);
100        String selection = CalendarAlerts._ID + "=" + id;
101        mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values,
102                selection, null /* selectionArgs */, Utils.UNDO_DELAY);
103    }
104
105    private class QueryHandler extends AsyncQueryService {
106        public QueryHandler(Context context) {
107            super(context);
108        }
109
110        @Override
111        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
112            // Only set mCursor if the Activity is not finishing. Otherwise close the cursor.
113            if (!isFinishing()) {
114                mCursor = cursor;
115                mAdapter.changeCursor(cursor);
116                mListView.setSelection(cursor.getCount() - 1);
117
118                // The results are in, enable the buttons
119                mDismissAllButton.setEnabled(true);
120            } else {
121                cursor.close();
122            }
123        }
124
125        @Override
126        protected void onInsertComplete(int token, Object cookie, Uri uri) {
127            if (uri != null) {
128                Long alarmTime = (Long) cookie;
129
130                if (alarmTime != 0) {
131                    // Set a new alarm to go off after the snooze delay.
132                    // TODO make provider schedule this automatically when
133                    // inserting an alarm
134                    AlertUtils.scheduleAlarm(AlertActivity.this, null, alarmTime);
135                }
136            }
137        }
138
139        @Override
140        protected void onUpdateComplete(int token, Object cookie, int result) {
141            // Ignore
142        }
143    }
144
145
146
147    private final OnItemClickListener mViewListener = new OnItemClickListener() {
148
149        @Override
150        public void onItemClick(AdapterView<?> parent, View view, int position,
151                long i) {
152            AlertActivity alertActivity = AlertActivity.this;
153            Cursor cursor = alertActivity.getItemForView(view);
154
155            // Mark this alarm as DISMISSED
156            dismissAlarm(cursor.getLong(INDEX_ROW_ID));
157
158            // build an intent and task stack to start EventInfoActivity with AllInOneActivity
159            // as the parent activity rooted to home.
160            long id = cursor.getInt(AlertActivity.INDEX_EVENT_ID);
161            long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
162            long endMillis = cursor.getLong(AlertActivity.INDEX_END);
163            Intent eventIntent = AlertUtils.buildEventViewIntent(AlertActivity.this, id,
164                    startMillis, endMillis);
165
166            TaskStackBuilder.create(AlertActivity.this)
167                    .addParentStack(EventInfoActivity.class).addNextIntent(eventIntent)
168                    .startActivities();
169
170            alertActivity.finish();
171        }
172    };
173
174    @Override
175    protected void onCreate(Bundle icicle) {
176        super.onCreate(icicle);
177
178        setContentView(R.layout.alert_activity);
179        setTitle(R.string.past_alerts_title);
180
181        mQueryHandler = new QueryHandler(this);
182        mAdapter = new AlertAdapter(this, R.layout.alert_item);
183
184        mListView = (ListView) findViewById(R.id.alert_container);
185        mListView.setItemsCanFocus(true);
186        mListView.setAdapter(mAdapter);
187        mListView.setOnItemClickListener(mViewListener);
188
189        mDismissAllButton = (Button) findViewById(R.id.dismiss_all);
190        mDismissAllButton.setOnClickListener(this);
191
192        // Disable the buttons, since they need mCursor, which is created asynchronously
193        mDismissAllButton.setEnabled(false);
194    }
195
196    @Override
197    protected void onResume() {
198        super.onResume();
199
200        // If the cursor is null, start the async handler. If it is not null just requery.
201        if (mCursor == null) {
202            Uri uri = CalendarAlerts.CONTENT_URI_BY_INSTANCE;
203            String[] selectionArgs = new String[] {
204                    Integer.toString(CalendarAlerts.STATE_FIRED),
205                    Long.toString(System.currentTimeMillis())
206            };
207            mQueryHandler.startQuery(0, null, uri, PROJECTION, SELECTION, selectionArgs,
208                    CalendarContract.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, false);
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 == mDismissAllButton) {
239            NotificationManager nm =
240                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
241            nm.cancel(AlertUtils.EXPIRED_GROUP_NOTIFICATION_ID);
242
243            dismissFiredAlarmsForPastEvents();
244
245            finish();
246        }
247    }
248
249    public boolean isEmpty() {
250        return mCursor != null ? (mCursor.getCount() == 0) : true;
251    }
252
253    public Cursor getItemForView(View view) {
254        final int index = mListView.getPositionForView(view);
255        if (index < 0) {
256            return null;
257        }
258        return (Cursor) mListView.getAdapter().getItem(index);
259    }
260}
261