AlertActivity.java revision 0000fa426da7fbfd35f16bf43556e861dfcf6667
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.annotation.SuppressLint; 20import android.app.Activity; 21import android.app.NotificationManager; 22import android.app.TaskStackBuilder; 23import android.content.ContentValues; 24import android.content.Context; 25import android.content.Intent; 26import android.database.Cursor; 27import android.net.Uri; 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; 43import com.android.calendar.alerts.GlobalDismissManager.AlarmId; 44 45import java.util.LinkedList; 46import java.util.List; 47 48/** 49 * The alert panel that pops up when there is a calendar event alarm. 50 * This activity is started by an intent that specifies an event id. 51 */ 52public class AlertActivity extends Activity implements OnClickListener { 53 private static final String TAG = "AlertActivity"; 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.CALENDAR_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.STATE_FIRED) 86 }; 87 88 private AlertAdapter mAdapter; 89 private QueryHandler mQueryHandler; 90 private Cursor mCursor; 91 private ListView mListView; 92 private Button mDismissAllButton; 93 94 95 private void dismissFiredAlarms() { 96 ContentValues values = new ContentValues(1 /* size */); 97 values.put(PROJECTION[INDEX_STATE], CalendarAlerts.STATE_DISMISSED); 98 String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.STATE_FIRED; 99 mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values, 100 selection, null /* selectionArgs */, Utils.UNDO_DELAY); 101 102 if (mCursor == null) { 103 Log.e(TAG, "Unable to globally dismiss all notifications because cursor was null."); 104 return; 105 } 106 if (mCursor.isClosed()) { 107 Log.e(TAG, "Unable to globally dismiss all notifications because cursor was closed."); 108 return; 109 } 110 if (!mCursor.moveToFirst()) { 111 Log.e(TAG, "Unable to globally dismiss all notifications because cursor was empty."); 112 return; 113 } 114 115 List<AlarmId> alarmIds = new LinkedList<AlarmId>(); 116 do { 117 long eventId = mCursor.getLong(INDEX_EVENT_ID); 118 long eventStart = mCursor.getLong(INDEX_BEGIN); 119 alarmIds.add(new AlarmId(eventId, eventStart)); 120 } while (mCursor.moveToNext()); 121 initiateGlobalDismiss(alarmIds); 122 } 123 124 private void dismissAlarm(long id, long eventId, long startTime) { 125 ContentValues values = new ContentValues(1 /* size */); 126 values.put(PROJECTION[INDEX_STATE], CalendarAlerts.STATE_DISMISSED); 127 String selection = CalendarAlerts._ID + "=" + id; 128 mQueryHandler.startUpdate(0, null, CalendarAlerts.CONTENT_URI, values, 129 selection, null /* selectionArgs */, Utils.UNDO_DELAY); 130 131 List<AlarmId> alarmIds = new LinkedList<AlarmId>(); 132 alarmIds.add(new AlarmId(eventId, startTime)); 133 initiateGlobalDismiss(alarmIds); 134 } 135 136 private void initiateGlobalDismiss(List<AlarmId> alarmIds) { 137 GlobalDismissManager.dismissGlobally(getApplicationContext(), alarmIds); 138 } 139 140 private class QueryHandler extends AsyncQueryService { 141 public QueryHandler(Context context) { 142 super(context); 143 } 144 145 @Override 146 protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 147 // Only set mCursor if the Activity is not finishing. Otherwise close the cursor. 148 if (!isFinishing()) { 149 mCursor = cursor; 150 mAdapter.changeCursor(cursor); 151 mListView.setSelection(cursor.getCount() - 1); 152 153 // The results are in, enable the buttons 154 mDismissAllButton.setEnabled(true); 155 } else { 156 cursor.close(); 157 } 158 } 159 160 @Override 161 protected void onUpdateComplete(int token, Object cookie, int result) { 162 // Ignore 163 } 164 } 165 166 private final OnItemClickListener mViewListener = new OnItemClickListener() { 167 168 @SuppressLint("NewApi") 169 @Override 170 public void onItemClick(AdapterView<?> parent, View view, int position, 171 long i) { 172 AlertActivity alertActivity = AlertActivity.this; 173 Cursor cursor = alertActivity.getItemForView(view); 174 175 long alarmId = cursor.getLong(INDEX_ROW_ID); 176 long eventId = cursor.getLong(AlertActivity.INDEX_EVENT_ID); 177 long startMillis = cursor.getLong(AlertActivity.INDEX_BEGIN); 178 179 // Mark this alarm as DISMISSED 180 dismissAlarm(alarmId, eventId, startMillis); 181 182 // build an intent and task stack to start EventInfoActivity with AllInOneActivity 183 // as the parent activity rooted to home. 184 long endMillis = cursor.getLong(AlertActivity.INDEX_END); 185 Intent eventIntent = AlertUtils.buildEventViewIntent(AlertActivity.this, eventId, 186 startMillis, endMillis); 187 188 if (Utils.isJellybeanOrLater()) { 189 TaskStackBuilder.create(AlertActivity.this).addParentStack(EventInfoActivity.class) 190 .addNextIntent(eventIntent).startActivities(); 191 } else { 192 alertActivity.startActivity(eventIntent); 193 } 194 195 alertActivity.finish(); 196 } 197 }; 198 199 @Override 200 protected void onCreate(Bundle icicle) { 201 super.onCreate(icicle); 202 203 setContentView(R.layout.alert_activity); 204 setTitle(R.string.alert_title); 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 mDismissAllButton = (Button) findViewById(R.id.dismiss_all); 215 mDismissAllButton.setOnClickListener(this); 216 217 // Disable the buttons, since they need mCursor, which is created asynchronously 218 mDismissAllButton.setEnabled(false); 219 } 220 221 @Override 222 protected void onResume() { 223 super.onResume(); 224 225 // If the cursor is null, start the async handler. If it is not null just requery. 226 if (mCursor == null) { 227 Uri uri = CalendarAlerts.CONTENT_URI_BY_INSTANCE; 228 mQueryHandler.startQuery(0, null, uri, PROJECTION, SELECTION, SELECTIONARG, 229 CalendarContract.CalendarAlerts.DEFAULT_SORT_ORDER); 230 } else { 231 if (!mCursor.requery()) { 232 Log.w(TAG, "Cursor#requery() failed."); 233 mCursor.close(); 234 mCursor = null; 235 } 236 } 237 } 238 239 void closeActivityIfEmpty() { 240 if (mCursor != null && !mCursor.isClosed() && mCursor.getCount() == 0) { 241 AlertActivity.this.finish(); 242 } 243 } 244 245 @Override 246 protected void onStop() { 247 super.onStop(); 248 AlertService.updateAlertNotification(this); 249 250 if (mCursor != null) { 251 mCursor.deactivate(); 252 } 253 } 254 255 @Override 256 protected void onDestroy() { 257 super.onDestroy(); 258 if (mCursor != null) { 259 mCursor.close(); 260 } 261 } 262 263 @Override 264 public void onClick(View v) { 265 if (v == mDismissAllButton) { 266 NotificationManager nm = 267 (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 268 nm.cancelAll(); 269 270 dismissFiredAlarms(); 271 272 finish(); 273 } 274 } 275 276 public boolean isEmpty() { 277 return mCursor != null ? (mCursor.getCount() == 0) : true; 278 } 279 280 public Cursor getItemForView(View view) { 281 final int index = mListView.getPositionForView(view); 282 if (index < 0) { 283 return null; 284 } 285 return (Cursor) mListView.getAdapter().getItem(index); 286 } 287} 288