/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.calendar; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.os.PowerManager; import android.preference.PreferenceManager; import android.provider.Calendar.CalendarAlerts; /** * Receives android.intent.action.EVENT_REMINDER intents and handles * event reminders. The intent URI specifies an alert id in the * CalendarAlerts database table. This class also receives the * BOOT_COMPLETED intent so that it can add a status bar notification * if there are Calendar event alarms that have not been dismissed. * It also receives the TIME_CHANGED action so that it can fire off * snoozed alarms that have become ready. The real work is done in * the AlertService class. */ public class AlertReceiver extends BroadcastReceiver { private static final String[] ALERT_PROJECTION = new String[] { CalendarAlerts.TITLE, // 0 CalendarAlerts.EVENT_LOCATION, // 1 }; private static final int ALERT_INDEX_TITLE = 0; private static final int ALERT_INDEX_EVENT_LOCATION = 1; private static final String DELETE_ACTION = "delete"; static final Object mStartingServiceSync = new Object(); static PowerManager.WakeLock mStartingService; @Override public void onReceive(Context context, Intent intent) { if (DELETE_ACTION.equals(intent.getAction())) { /* The user has clicked the "Clear All Notifications" * buttons so dismiss all Calendar alerts. */ // TODO Grab a wake lock here? Intent serviceIntent = new Intent(context, DismissAllAlarmsService.class); context.startService(serviceIntent); } else { Intent i = new Intent(); i.setClass(context, AlertService.class); i.putExtras(intent); i.putExtra("action", intent.getAction()); Uri uri = intent.getData(); // This intent might be a BOOT_COMPLETED so it might not have a Uri. if (uri != null) { i.putExtra("uri", uri.toString()); } beginStartingService(context, i); } } /** * Start the service to process the current event notifications, acquiring * the wake lock before returning to ensure that the service will run. */ public static void beginStartingService(Context context, Intent intent) { synchronized (mStartingServiceSync) { if (mStartingService == null) { PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "StartingAlertService"); mStartingService.setReferenceCounted(false); } mStartingService.acquire(); context.startService(intent); } } /** * Called back by the service when it has finished processing notifications, * releasing the wake lock if the service is now stopping. */ public static void finishStartingService(Service service, int startId) { synchronized (mStartingServiceSync) { if (mStartingService != null) { if (service.stopSelfResult(startId)) { mStartingService.release(); } } } } public static void updateAlertNotification(Context context) { // This can be called regularly to synchronize the alert notification // with the contents of the CalendarAlerts table. ContentResolver cr = context.getContentResolver(); if (cr == null) { return; } String selection = CalendarAlerts.STATE + "=" + CalendarAlerts.FIRED; Cursor alertCursor = CalendarAlerts.query(cr, ALERT_PROJECTION, selection, null); NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (alertCursor == null) { nm.cancel(AlertActivity.NOTIFICATION_ID); return; } if (!alertCursor.moveToFirst()) { alertCursor.close(); nm.cancel(AlertActivity.NOTIFICATION_ID); return; } // Check the settings to see if alerts are disabled SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); String reminderType = prefs.getString(CalendarPreferenceActivity.KEY_ALERTS_TYPE, CalendarPreferenceActivity.ALERT_TYPE_STATUS_BAR); if (reminderType.equals(CalendarPreferenceActivity.ALERT_TYPE_OFF)) { return; } String title = alertCursor.getString(ALERT_INDEX_TITLE); String location = alertCursor.getString(ALERT_INDEX_EVENT_LOCATION); Notification notification = AlertReceiver.makeNewAlertNotification(context, title, location, alertCursor.getCount()); alertCursor.close(); nm.notify(0, notification); } public static Notification makeNewAlertNotification(Context context, String title, String location, int numReminders) { Resources res = context.getResources(); // Create an intent triggered by clicking on the status icon. Intent clickIntent = new Intent(); clickIntent.setClass(context, AlertActivity.class); clickIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Create an intent triggered by clicking on the "Clear All Notifications" button Intent deleteIntent = new Intent(); deleteIntent.setClass(context, AlertReceiver.class); deleteIntent.setAction(DELETE_ACTION); if (title == null || title.length() == 0) { title = res.getString(R.string.no_title_label); } String helperString; if (numReminders > 1) { String format; if (numReminders == 2) { format = res.getString(R.string.alert_missed_events_single); } else { format = res.getString(R.string.alert_missed_events_multiple); } helperString = String.format(format, numReminders - 1); } else { helperString = location; } Notification notification = new Notification( R.drawable.stat_notify_calendar, null, System.currentTimeMillis()); notification.setLatestEventInfo(context, title, helperString, PendingIntent.getActivity(context, 0, clickIntent, 0)); notification.deleteIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0); return notification; } }