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  */
16 package com.android.deskclock.alarms;
17 
18 import android.app.PendingIntent;
19 import android.app.Service;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.res.Resources;
23 import android.support.v4.app.NotificationCompat;
24 import android.support.v4.app.NotificationManagerCompat;
25 
26 import com.android.deskclock.AlarmClockFragment;
27 import com.android.deskclock.AlarmUtils;
28 import com.android.deskclock.DeskClock;
29 import com.android.deskclock.LogUtils;
30 import com.android.deskclock.R;
31 import com.android.deskclock.provider.Alarm;
32 import com.android.deskclock.provider.AlarmInstance;
33 
34 public final class AlarmNotifications {
35     public static final String EXTRA_NOTIFICATION_ID = "extra_notification_id";
36 
showLowPriorityNotification(Context context, AlarmInstance instance)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 
showHighPriorityNotification(Context context, AlarmInstance instance)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 
showSnoozeNotification(Context context, AlarmInstance instance)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 
showMissedNotification(Context context, AlarmInstance instance)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 
showAlarmNotification(Service service, AlarmInstance instance)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 
clearNotification(Context context, AlarmInstance instance)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      */
updateNotification(Context context, AlarmInstance instance)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 
createViewAlarmIntent(Context context, AlarmInstance instance)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