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