AlertActivity.java revision b8d0a58e51251f4d65917fc27c86f9f0822478a9
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.Build;
28import android.os.Bundle;
29import android.provider.CalendarContract;
30import android.provider.CalendarContract.CalendarAlerts;
31import android.util.Log;
32import android.view.View;
33import android.view.View.OnClickListener;
34import android.widget.AdapterView;
35import android.widget.AdapterView.OnItemClickListener;
36import android.widget.Button;
37import android.widget.ListView;
38
39import com.android.calendar.AsyncQueryService;
40import com.android.calendar.EventInfoActivity;
41import com.android.calendar.R;
42import com.android.calendar.Utils;
43
44/**
45 * The alert panel that pops up when there is a calendar event alarm.
46 * This activity is started by an intent that specifies an event id.
47  */
48public class AlertActivity extends Activity implements OnClickListener {
49    private static final String TAG = "AlertActivity";
50
51    private static final String[] PROJECTION = new String[] {
52        CalendarAlerts._ID,              // 0
53        CalendarAlerts.TITLE,            // 1
54        CalendarAlerts.EVENT_LOCATION,   // 2
55        CalendarAlerts.ALL_DAY,          // 3
56        CalendarAlerts.BEGIN,            // 4
57        CalendarAlerts.END,              // 5
58        CalendarAlerts.EVENT_ID,         // 6
59        CalendarAlerts.CALENDAR_COLOR,   // 7
60        CalendarAlerts.RRULE,            // 8
61        CalendarAlerts.HAS_ALARM,        // 9
62        CalendarAlerts.STATE,            // 10
63        CalendarAlerts.ALARM_TIME,       // 11
64    };
65
66    public static final int INDEX_ROW_ID = 0;
67    public static final int INDEX_TITLE = 1;
68    public static final int INDEX_EVENT_LOCATION = 2;
69    public static final int INDEX_ALL_DAY = 3;
70    public static final int INDEX_BEGIN = 4;
71    public static final int INDEX_END = 5;
72    public static final int INDEX_EVENT_ID = 6;
73    public static final int INDEX_COLOR = 7;
74    public static final int INDEX_RRULE = 8;
75    public static final int INDEX_HAS_ALARM = 9;
76    public static final int INDEX_STATE = 10;
77    public static final int INDEX_ALARM_TIME = 11;
78
79    private static final String SELECTION = CalendarAlerts.STATE + "=?";
80    private static final String[] SELECTIONARG = new String[] {
81        Integer.toString(CalendarAlerts.STATE_FIRED)
82    };
83
84    private AlertAdapter mAdapter;
85    private QueryHandler mQueryHandler;
86    private Cursor mCursor;
87    private ListView mListView;
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                mDismissAllButton.setEnabled(true);
122            } else {
123                cursor.close();
124            }
125        }
126
127        @Override
128        protected void onInsertComplete(int token, Object cookie, Uri uri) {
129            if (uri != null) {
130                Long alarmTime = (Long) cookie;
131
132                if (alarmTime != 0) {
133                    // Set a new alarm to go off after the snooze delay.
134                    // TODO make provider schedule this automatically when
135                    // inserting an alarm
136                    AlertUtils.scheduleAlarm(AlertActivity.this, null, alarmTime);
137                }
138            }
139        }
140
141        @Override
142        protected void onUpdateComplete(int token, Object cookie, int result) {
143            // Ignore
144        }
145    }
146
147
148
149    private final OnItemClickListener mViewListener = new OnItemClickListener() {
150
151        @Override
152        public void onItemClick(AdapterView<?> parent, View view, int position,
153                long i) {
154            AlertActivity alertActivity = AlertActivity.this;
155            Cursor cursor = alertActivity.getItemForView(view);
156
157            // Mark this alarm as DISMISSED
158            dismissAlarm(cursor.getLong(INDEX_ROW_ID));
159
160            // build an intent and task stack to start EventInfoActivity with AllInOneActivity
161            // as the parent activity rooted to home.
162            long id = cursor.getInt(AlertActivity.INDEX_EVENT_ID);
163            long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN);
164            long endMillis = cursor.getLong(AlertActivity.INDEX_END);
165            Intent eventIntent = AlertUtils.buildEventViewIntent(AlertActivity.this, id,
166                    startMillis, endMillis);
167
168            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
169                alertActivity.startActivity(eventIntent);
170            } else {
171                TaskStackBuilder.create(AlertActivity.this).addParentStack(EventInfoActivity.class)
172                        .addNextIntent(eventIntent).startActivities();
173            }
174
175            alertActivity.finish();
176        }
177    };
178
179    @Override
180    protected void onCreate(Bundle icicle) {
181        super.onCreate(icicle);
182
183        setContentView(R.layout.alert_activity);
184        setTitle(R.string.alert_title);
185
186        mQueryHandler = new QueryHandler(this);
187        mAdapter = new AlertAdapter(this, R.layout.alert_item);
188
189        mListView = (ListView) findViewById(R.id.alert_container);
190        mListView.setItemsCanFocus(true);
191        mListView.setAdapter(mAdapter);
192        mListView.setOnItemClickListener(mViewListener);
193
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        mDismissAllButton.setEnabled(false);
199    }
200
201    @Override
202    protected void onResume() {
203        super.onResume();
204
205        // If the cursor is null, start the async handler. If it is not null just requery.
206        if (mCursor == null) {
207            Uri uri = CalendarAlerts.CONTENT_URI_BY_INSTANCE;
208            mQueryHandler.startQuery(0, null, uri, PROJECTION, SELECTION, SELECTIONARG,
209                    CalendarContract.CalendarAlerts.DEFAULT_SORT_ORDER);
210        } else {
211            if (!mCursor.requery()) {
212                Log.w(TAG, "Cursor#requery() failed.");
213                mCursor.close();
214                mCursor = null;
215            }
216        }
217    }
218
219    @Override
220    protected void onStop() {
221        super.onStop();
222        AlertService.updateAlertNotification(this);
223
224        if (mCursor != null) {
225            mCursor.deactivate();
226        }
227    }
228
229    @Override
230    protected void onDestroy() {
231        super.onDestroy();
232        if (mCursor != null) {
233            mCursor.close();
234        }
235    }
236
237    @Override
238    public void onClick(View v) {
239        if (v == mDismissAllButton) {
240            NotificationManager nm =
241                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
242            nm.cancelAll();
243
244            dismissFiredAlarms();
245
246            finish();
247        }
248    }
249
250    public boolean isEmpty() {
251        return mCursor != null ? (mCursor.getCount() == 0) : true;
252    }
253
254    public Cursor getItemForView(View view) {
255        final int index = mListView.getPositionForView(view);
256        if (index < 0) {
257            return null;
258        }
259        return (Cursor) mListView.getAdapter().getItem(index);
260    }
261}
262