AlertReceiver.java 7.95 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * 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.
 */

17 18 19
package com.android.calendar.alerts;

import com.android.calendar.R;
20
import com.android.calendar.Utils;
21 22

import android.app.Notification;
23
import android.app.Notification.Builder;
24 25 26 27 28 29 30 31
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.PowerManager;
32
import android.text.TextUtils;
33 34 35
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
36
import android.util.Log;
37

38 39 40
import java.util.Locale;
import java.util.TimeZone;

41 42
/**
 * Receives android.intent.action.EVENT_REMINDER intents and handles
43
 * event reminders.  The intent URI specifies an alert id in the
44 45 46 47 48 49
 * 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.
50 51 52 53
 *
 * To trigger this code after pushing the apk to device:
 * adb shell am broadcast -a "android.intent.action.EVENT_REMINDER"
 *    -n "com.android.calendar/.alerts.AlertReceiver"
54 55
 */
public class AlertReceiver extends BroadcastReceiver {
56 57
    private static final String TAG = "AlertReceiver";

58
    private static final String DELETE_ACTION = "delete";
59

60 61
    static final Object mStartingServiceSync = new Object();
    static PowerManager.WakeLock mStartingService;
62

63 64
    public static final String ACTION_DISMISS_OLD_REMINDERS = "removeOldReminders";

65 66
    @Override
    public void onReceive(Context context, Intent intent) {
67 68 69 70
        if (AlertService.DEBUG) {
            Log.d(TAG, "onReceive: a=" + intent.getAction() + " " + intent.toString());
        }

71
        if (DELETE_ACTION.equals(intent.getAction())) {
72

73 74 75
            /* The user has clicked the "Clear All Notifications"
             * buttons so dismiss all Calendar alerts.
             */
76 77 78
            // TODO Grab a wake lock here?
            Intent serviceIntent = new Intent(context, DismissAllAlarmsService.class);
            context.startService(serviceIntent);
79 80 81 82 83 84
        } else {
            Intent i = new Intent();
            i.setClass(context, AlertService.class);
            i.putExtras(intent);
            i.putExtra("action", intent.getAction());
            Uri uri = intent.getData();
85

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
            // 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);
        }
    }
111

112 113 114 115 116 117 118 119 120 121 122 123 124 125
    /**
     * 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();
                }
            }
        }
    }

126 127 128 129 130 131 132
    /**
     * Creates an alert notification. If high priority, this will set
     * FLAG_HIGH_PRIORITY on the resulting notification and attach the a pending
     * intent. Otherwise, it creates a standard notification.
     */
    public static Notification makeNewAlertNotification(Context context,
            String title, String location, int numReminders,
133
            boolean highPriority, long startMillis, boolean allDay) {
134
        Resources res = context.getResources();
135

136 137 138 139
        // 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);
140

141 142 143 144
        // 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);
145

146 147 148
        if (title == null || title.length() == 0) {
            title = res.getString(R.string.no_title_label);
        }
149

150 151 152
        Builder bob = new Notification.Builder(context);
        bob.setContentTitle(title);
        bob.setSmallIcon(R.drawable.stat_notify_calendar);
153

154 155
        PendingIntent pendingClickIntent = PendingIntent.getActivity(
                context, 0, clickIntent, 0);
156 157
        bob.setContentIntent(pendingClickIntent);
        bob.setDeleteIntent(PendingIntent.getBroadcast(context, 0, deleteIntent, 0));
158
        if (highPriority) {
159 160 161 162 163 164 165 166 167 168 169 170 171 172
            bob.setFullScreenIntent(pendingClickIntent, true);
        }

        if (numReminders > 1) {
            bob.setNumber(numReminders);
        }

        // Format the second line which shows time and location.
        //
        // 1) Show time only for non-all day events
        // 2) No date for today
        // 3) Show "tomorrow" for tomorrow
        // 4) Show date for days beyond that

173 174
        String tz = Utils.getTimeZone(context, null);
        Time time = new Time(tz);
175 176 177 178 179 180 181 182 183 184 185
        time.setToNow();
        int today = Time.getJulianDay(time.toMillis(false), time.gmtoff);
        time.set(startMillis);
        int eventDay = Time.getJulianDay(time.toMillis(false), time.gmtoff);

        int flags = DateUtils.FORMAT_ABBREV_ALL;
        if (!allDay) {
            flags |= DateUtils.FORMAT_SHOW_TIME;
            if (DateFormat.is24HourFormat(context)) {
                flags |= DateUtils.FORMAT_24HOUR;
            }
186
        } else {
187
            flags |= DateUtils.FORMAT_UTC;
188 189 190 191 192 193 194 195 196
        }

        if (eventDay > today + 1) {
            flags |= DateUtils.FORMAT_SHOW_DATE;
        }

        StringBuilder sb = new StringBuilder(Utils.formatDateRange(context, startMillis,
                startMillis, flags));

197 198 199 200 201 202 203 204
        if (!allDay && tz != Time.getCurrentTimezone()) {
            // Assumes time was set to the current tz
            time.set(startMillis);
            boolean isDST = time.isDst != 0;
            sb.append(" ").append(TimeZone.getTimeZone(tz).getDisplayName(
                    isDST, TimeZone.SHORT, Locale.getDefault()));
        }

205 206 207 208 209 210
        if (eventDay == today + 1) {
            // Tomorrow
            sb.append(", ");
            sb.append(context.getString(R.string.tomorrow));
        }

211 212
        String loc;
        if (location != null && !TextUtils.isEmpty(loc = location.trim())) {
213
            sb.append(", ");
214
            sb.append(loc);
215
        }
216
        bob.setContentText(sb.toString());
217

218
        return bob.getNotification();
219 220 221
    }
}