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