1/*
2 * Copyright (C) 2013 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 */
16package com.android.deskclock.alarms;
17
18import android.app.PendingIntent;
19import android.app.Service;
20import android.content.Context;
21import android.content.Intent;
22import android.content.res.Resources;
23import android.support.v4.app.NotificationCompat;
24import android.support.v4.app.NotificationManagerCompat;
25
26import com.android.deskclock.AlarmClockFragment;
27import com.android.deskclock.AlarmUtils;
28import com.android.deskclock.DeskClock;
29import com.android.deskclock.LogUtils;
30import com.android.deskclock.R;
31import com.android.deskclock.provider.Alarm;
32import com.android.deskclock.provider.AlarmInstance;
33
34public final class AlarmNotifications {
35    public static final String EXTRA_NOTIFICATION_ID = "extra_notification_id";
36
37    public static void showLowPriorityNotification(Context context, AlarmInstance instance) {
38        LogUtils.v("Displaying low priority notification for alarm instance: " + instance.mId);
39
40        NotificationCompat.Builder notification = new NotificationCompat.Builder(context)
41                .setContentTitle(context.getString(
42                        R.string.alarm_alert_predismiss_title))
43                .setContentText(AlarmUtils.getAlarmText(context, instance,
44                        true /* includeLabel */))
45                .setSmallIcon(R.drawable.stat_notify_alarm)
46                .setAutoCancel(false)
47                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
48                .setCategory(NotificationCompat.CATEGORY_ALARM)
49                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
50                .setLocalOnly(true);
51
52        // Setup up hide notification
53        Intent hideIntent = AlarmStateManager.createStateChangeIntent(context,
54                AlarmStateManager.ALARM_DELETE_TAG, instance,
55                AlarmInstance.HIDE_NOTIFICATION_STATE);
56        notification.setDeleteIntent(PendingIntent.getService(context, instance.hashCode(),
57                hideIntent, PendingIntent.FLAG_UPDATE_CURRENT));
58
59        // Setup up dismiss action
60        Intent dismissIntent = AlarmStateManager.createStateChangeIntent(context,
61                AlarmStateManager.ALARM_DISMISS_TAG, instance, AlarmInstance.PREDISMISSED_STATE);
62        notification.addAction(R.drawable.ic_alarm_off_24dp,
63                context.getString(R.string.alarm_alert_dismiss_now_text),
64                PendingIntent.getService(context, instance.hashCode(),
65                        dismissIntent, PendingIntent.FLAG_UPDATE_CURRENT));
66
67        // Setup content action if instance is owned by alarm
68        Intent viewAlarmIntent = createViewAlarmIntent(context, instance);
69        notification.setContentIntent(PendingIntent.getActivity(context, instance.hashCode(),
70                viewAlarmIntent, PendingIntent.FLAG_UPDATE_CURRENT));
71
72        NotificationManagerCompat nm = NotificationManagerCompat.from(context);
73        nm.notify(instance.hashCode(), notification.build());
74    }
75
76    public static void showHighPriorityNotification(Context context, AlarmInstance instance) {
77        LogUtils.v("Displaying high priority notification for alarm instance: " + instance.mId);
78
79        NotificationCompat.Builder notification = new NotificationCompat.Builder(context)
80                .setContentTitle(context.getString(R.string.alarm_alert_predismiss_title))
81                .setContentText(AlarmUtils.getAlarmText(context, instance,
82                        true /* includeLabel */))
83                .setSmallIcon(R.drawable.stat_notify_alarm)
84                .setAutoCancel(false)
85                .setOngoing(true)
86                .setGroup(Integer.toString(instance.hashCode()))
87                .setGroupSummary(true)
88                .setPriority(NotificationCompat.PRIORITY_HIGH)
89                .setCategory(NotificationCompat.CATEGORY_ALARM)
90                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
91                .setLocalOnly(true);
92
93        // Setup up dismiss action
94        Intent dismissIntent = AlarmStateManager.createStateChangeIntent(context,
95                AlarmStateManager.ALARM_DISMISS_TAG, instance, AlarmInstance.PREDISMISSED_STATE);
96        notification.addAction(R.drawable.ic_alarm_off_24dp,
97                context.getString(R.string.alarm_alert_dismiss_now_text),
98                PendingIntent.getService(context, instance.hashCode(),
99                        dismissIntent, PendingIntent.FLAG_UPDATE_CURRENT));
100
101        // Setup content action if instance is owned by alarm
102        Intent viewAlarmIntent = createViewAlarmIntent(context, instance);
103        notification.setContentIntent(PendingIntent.getActivity(context, instance.hashCode(),
104                viewAlarmIntent, PendingIntent.FLAG_UPDATE_CURRENT));
105
106        NotificationManagerCompat nm = NotificationManagerCompat.from(context);
107        nm.notify(instance.hashCode(), notification.build());
108    }
109
110    public static void showSnoozeNotification(Context context, AlarmInstance instance) {
111        LogUtils.v("Displaying snoozed notification for alarm instance: " + instance.mId);
112
113        NotificationCompat.Builder notification = new NotificationCompat.Builder(context)
114                .setContentTitle(instance.getLabelOrDefault(context))
115                .setContentText(context.getString(R.string.alarm_alert_snooze_until,
116                        AlarmUtils.getFormattedTime(context, instance.getAlarmTime())))
117                .setSmallIcon(R.drawable.stat_notify_alarm)
118                .setAutoCancel(false)
119                .setOngoing(true)
120                .setPriority(NotificationCompat.PRIORITY_MAX)
121                .setCategory(NotificationCompat.CATEGORY_ALARM)
122                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
123                .setLocalOnly(true);
124
125        // Setup up dismiss action
126        Intent dismissIntent = AlarmStateManager.createStateChangeIntent(context,
127                AlarmStateManager.ALARM_DISMISS_TAG, instance, AlarmInstance.DISMISSED_STATE);
128        notification.addAction(R.drawable.ic_alarm_off_24dp,
129                context.getString(R.string.alarm_alert_dismiss_text),
130                PendingIntent.getService(context, instance.hashCode(),
131                        dismissIntent, PendingIntent.FLAG_UPDATE_CURRENT));
132
133        // Setup content action if instance is owned by alarm
134        Intent viewAlarmIntent = createViewAlarmIntent(context, instance);
135        notification.setContentIntent(PendingIntent.getActivity(context, instance.hashCode(),
136                viewAlarmIntent, PendingIntent.FLAG_UPDATE_CURRENT));
137
138        NotificationManagerCompat nm = NotificationManagerCompat.from(context);
139        nm.notify(instance.hashCode(), notification.build());
140    }
141
142    public static void showMissedNotification(Context context, AlarmInstance instance) {
143        LogUtils.v("Displaying missed notification for alarm instance: " + instance.mId);
144
145        String label = instance.mLabel;
146        String alarmTime = AlarmUtils.getFormattedTime(context, instance.getAlarmTime());
147        NotificationCompat.Builder notification = new NotificationCompat.Builder(context)
148                .setContentTitle(context.getString(R.string.alarm_missed_title))
149                .setContentText(instance.mLabel.isEmpty() ? alarmTime :
150                        context.getString(R.string.alarm_missed_text, alarmTime, label))
151                .setSmallIcon(R.drawable.stat_notify_alarm)
152                .setPriority(NotificationCompat.PRIORITY_HIGH)
153                .setCategory(NotificationCompat.CATEGORY_ALARM)
154                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
155                .setLocalOnly(true);
156
157        final int hashCode = instance.hashCode();
158
159        // Setup dismiss intent
160        Intent dismissIntent = AlarmStateManager.createStateChangeIntent(context,
161                AlarmStateManager.ALARM_DISMISS_TAG, instance, AlarmInstance.DISMISSED_STATE);
162        notification.setDeleteIntent(PendingIntent.getService(context, hashCode,
163                dismissIntent, PendingIntent.FLAG_UPDATE_CURRENT));
164
165        // Setup content intent
166        Intent showAndDismiss = AlarmInstance.createIntent(context, AlarmStateManager.class,
167                instance.mId);
168        showAndDismiss.putExtra(EXTRA_NOTIFICATION_ID, hashCode);
169        showAndDismiss.setAction(AlarmStateManager.SHOW_AND_DISMISS_ALARM_ACTION);
170        notification.setContentIntent(PendingIntent.getBroadcast(context, hashCode,
171                showAndDismiss, PendingIntent.FLAG_UPDATE_CURRENT));
172
173        NotificationManagerCompat nm = NotificationManagerCompat.from(context);
174        nm.notify(hashCode, notification.build());
175    }
176
177    public static void showAlarmNotification(Service service, AlarmInstance instance) {
178        LogUtils.v("Displaying alarm notification for alarm instance: " + instance.mId);
179
180        Resources resources = service.getResources();
181        NotificationCompat.Builder notification = new NotificationCompat.Builder(service)
182                .setContentTitle(instance.getLabelOrDefault(service))
183                .setContentText(AlarmUtils.getFormattedTime(service, instance.getAlarmTime()))
184                .setSmallIcon(R.drawable.stat_notify_alarm)
185                .setOngoing(true)
186                .setAutoCancel(false)
187                .setDefaults(NotificationCompat.DEFAULT_LIGHTS)
188                .setWhen(0)
189                .setCategory(NotificationCompat.CATEGORY_ALARM)
190                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
191                .setLocalOnly(true);
192
193        // Setup Snooze Action
194        Intent snoozeIntent = AlarmStateManager.createStateChangeIntent(service,
195                AlarmStateManager.ALARM_SNOOZE_TAG, instance, AlarmInstance.SNOOZE_STATE);
196        snoozeIntent.putExtra(AlarmStateManager.FROM_NOTIFICATION_EXTRA, true);
197        PendingIntent snoozePendingIntent = PendingIntent.getService(service, instance.hashCode(),
198                snoozeIntent,
199                PendingIntent.FLAG_UPDATE_CURRENT);
200        notification.addAction(R.drawable.ic_snooze_24dp,
201                resources.getString(R.string.alarm_alert_snooze_text), snoozePendingIntent);
202
203        // Setup Dismiss Action
204        Intent dismissIntent = AlarmStateManager.createStateChangeIntent(service,
205                AlarmStateManager.ALARM_DISMISS_TAG, instance, AlarmInstance.DISMISSED_STATE);
206        dismissIntent.putExtra(AlarmStateManager.FROM_NOTIFICATION_EXTRA, true);
207        PendingIntent dismissPendingIntent = PendingIntent.getService(service,
208                instance.hashCode(), dismissIntent, PendingIntent.FLAG_UPDATE_CURRENT);
209        notification.addAction(R.drawable.ic_alarm_off_24dp,
210                resources.getString(R.string.alarm_alert_dismiss_text),
211                dismissPendingIntent);
212
213        // Setup Content Action
214        Intent contentIntent = AlarmInstance.createIntent(service, AlarmActivity.class,
215                instance.mId);
216        notification.setContentIntent(PendingIntent.getActivity(service,
217                instance.hashCode(), contentIntent, PendingIntent.FLAG_UPDATE_CURRENT));
218
219        // Setup fullscreen intent
220        Intent fullScreenIntent = AlarmInstance.createIntent(service, AlarmActivity.class,
221                instance.mId);
222        // set action, so we can be different then content pending intent
223        fullScreenIntent.setAction("fullscreen_activity");
224        fullScreenIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
225                Intent.FLAG_ACTIVITY_NO_USER_ACTION);
226        notification.setFullScreenIntent(PendingIntent.getActivity(service,
227                instance.hashCode(), fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT), true);
228        notification.setPriority(NotificationCompat.PRIORITY_MAX);
229
230        clearNotification(service, instance);
231        service.startForeground(instance.hashCode(), notification.build());
232    }
233
234    public static void clearNotification(Context context, AlarmInstance instance) {
235        LogUtils.v("Clearing notifications for alarm instance: " + instance.mId);
236        NotificationManagerCompat nm = NotificationManagerCompat.from(context);
237        nm.cancel(instance.hashCode());
238    }
239
240    /**
241     * Updates the notification for an existing alarm. Use if the label has changed.
242     */
243    public static void updateNotification(Context context, AlarmInstance instance) {
244        switch (instance.mAlarmState) {
245            case AlarmInstance.LOW_NOTIFICATION_STATE:
246                showLowPriorityNotification(context, instance);
247                break;
248            case AlarmInstance.HIGH_NOTIFICATION_STATE:
249                showHighPriorityNotification(context, instance);
250                break;
251            case AlarmInstance.SNOOZE_STATE:
252                showSnoozeNotification(context, instance);
253                break;
254            case AlarmInstance.MISSED_STATE:
255                showMissedNotification(context, instance);
256                break;
257            default:
258                LogUtils.d("No notification to update");
259        }
260    }
261
262    public static Intent createViewAlarmIntent(Context context, AlarmInstance instance) {
263        long alarmId = instance.mAlarmId == null ? Alarm.INVALID_ID : instance.mAlarmId;
264        Intent viewAlarmIntent = Alarm.createIntent(context, DeskClock.class, alarmId);
265        viewAlarmIntent.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX);
266        viewAlarmIntent.putExtra(AlarmClockFragment.SCROLL_TO_ALARM_INTENT_EXTRA, alarmId);
267        viewAlarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
268        return viewAlarmIntent;
269    }
270}
271