Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / message_center / notification_list.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/message_center/notification_list.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/stl_util.h"
10 #include "base/time/time.h"
11 #include "base/values.h"
12 #include "ui/message_center/message_center_style.h"
13 #include "ui/message_center/notification.h"
14 #include "ui/message_center/notification_types.h"
15
16 namespace message_center {
17
18 namespace {
19
20 bool ShouldShowNotificationAsPopup(
21     const Notification& notification,
22     const NotificationBlockers& blockers) {
23   for (size_t i = 0; i < blockers.size(); ++i) {
24     if (!blockers[i]->ShouldShowNotificationAsPopup(notification.notifier_id()))
25       return false;
26   }
27   return true;
28 }
29
30 }  // namespace
31
32 bool ComparePriorityTimestampSerial::operator()(Notification* n1,
33                                                 Notification* n2) {
34   if (n1->priority() > n2->priority())  // Higher pri go first.
35     return true;
36   if (n1->priority() < n2->priority())
37     return false;
38   return CompareTimestampSerial()(n1, n2);
39 }
40
41 bool CompareTimestampSerial::operator()(Notification* n1, Notification* n2) {
42   if (n1->timestamp() > n2->timestamp())  // Newer come first.
43     return true;
44   if (n1->timestamp() < n2->timestamp())
45     return false;
46   if (n1->serial_number() > n2->serial_number())  // Newer come first.
47     return true;
48   if (n1->serial_number() < n2->serial_number())
49     return false;
50   return false;
51 }
52
53 NotificationList::NotificationList()
54     : message_center_visible_(false),
55       quiet_mode_(false) {
56 }
57
58 NotificationList::~NotificationList() {
59   STLDeleteContainerPointers(notifications_.begin(), notifications_.end());
60 }
61
62 void NotificationList::SetMessageCenterVisible(
63     bool visible,
64     std::set<std::string>* updated_ids) {
65   if (message_center_visible_ == visible)
66     return;
67
68   message_center_visible_ = visible;
69
70   if (!visible)
71     return;
72
73   for (Notifications::iterator iter = notifications_.begin();
74        iter != notifications_.end(); ++iter) {
75     Notification* notification = *iter;
76     bool was_popup = notification->shown_as_popup();
77     bool was_read = notification->IsRead();
78     if (notification->priority() < SYSTEM_PRIORITY)
79       notification->set_shown_as_popup(true);
80     notification->set_is_read(true);
81     if (updated_ids && !(was_popup && was_read))
82       updated_ids->insert(notification->id());
83   }
84 }
85
86 void NotificationList::AddNotification(scoped_ptr<Notification> notification) {
87   PushNotification(notification.Pass());
88 }
89
90 void NotificationList::UpdateNotificationMessage(
91     const std::string& old_id,
92     scoped_ptr<Notification> new_notification) {
93   Notifications::iterator iter = GetNotification(old_id);
94   if (iter == notifications_.end())
95     return;
96
97   new_notification->CopyState(*iter);
98
99   // Handles priority promotion. If the notification is already dismissed but
100   // the updated notification has higher priority, it should re-appear as a
101   // toast.
102   if ((*iter)->priority() < new_notification->priority()) {
103     new_notification->set_is_read(false);
104     new_notification->set_shown_as_popup(false);
105   }
106
107   // Do not use EraseNotification and PushNotification, since we don't want to
108   // change unread counts nor to update is_read/shown_as_popup states.
109   Notification* old = *iter;
110   notifications_.erase(iter);
111   delete old;
112
113   // We really don't want duplicate IDs.
114   DCHECK(GetNotification(new_notification->id()) == notifications_.end());
115   notifications_.insert(new_notification.release());
116 }
117
118 void NotificationList::RemoveNotification(const std::string& id) {
119   EraseNotification(GetNotification(id));
120 }
121
122 NotificationList::Notifications NotificationList::GetNotificationsByNotifierId(
123         const NotifierId& notifier_id) {
124   Notifications notifications;
125   for (Notifications::iterator iter = notifications_.begin();
126        iter != notifications_.end(); ++iter) {
127     if ((*iter)->notifier_id() == notifier_id)
128       notifications.insert(*iter);
129   }
130   return notifications;
131 }
132
133 bool NotificationList::SetNotificationIcon(const std::string& notification_id,
134                                            const gfx::Image& image) {
135   Notifications::iterator iter = GetNotification(notification_id);
136   if (iter == notifications_.end())
137     return false;
138   (*iter)->set_icon(image);
139   return true;
140 }
141
142 bool NotificationList::SetNotificationImage(const std::string& notification_id,
143                                             const gfx::Image& image) {
144   Notifications::iterator iter = GetNotification(notification_id);
145   if (iter == notifications_.end())
146     return false;
147   (*iter)->set_image(image);
148   return true;
149 }
150
151 bool NotificationList::SetNotificationButtonIcon(
152     const std::string& notification_id, int button_index,
153     const gfx::Image& image) {
154   Notifications::iterator iter = GetNotification(notification_id);
155   if (iter == notifications_.end())
156     return false;
157   (*iter)->SetButtonIcon(button_index, image);
158   return true;
159 }
160
161 bool NotificationList::HasNotification(const std::string& id) {
162   return GetNotification(id) != notifications_.end();
163 }
164
165 bool NotificationList::HasNotificationOfType(const std::string& id,
166                                              const NotificationType type) {
167   Notifications::iterator iter = GetNotification(id);
168   if (iter == notifications_.end())
169     return false;
170
171   return (*iter)->type() == type;
172 }
173
174 bool NotificationList::HasPopupNotifications(
175     const NotificationBlockers& blockers) {
176   for (Notifications::iterator iter = notifications_.begin();
177        iter != notifications_.end(); ++iter) {
178     if ((*iter)->priority() < DEFAULT_PRIORITY)
179       break;
180     if (!ShouldShowNotificationAsPopup(**iter, blockers))
181       continue;
182     if (!(*iter)->shown_as_popup())
183       return true;
184   }
185   return false;
186 }
187
188 NotificationList::PopupNotifications NotificationList::GetPopupNotifications(
189     const NotificationBlockers& blockers,
190     std::list<std::string>* blocked_ids) {
191   PopupNotifications result;
192   size_t default_priority_popup_count = 0;
193
194   // Collect notifications that should be shown as popups. Start from oldest.
195   for (Notifications::const_reverse_iterator iter = notifications_.rbegin();
196        iter != notifications_.rend(); iter++) {
197     if ((*iter)->shown_as_popup())
198       continue;
199
200     // No popups for LOW/MIN priority.
201     if ((*iter)->priority() < DEFAULT_PRIORITY)
202       continue;
203
204     if (!ShouldShowNotificationAsPopup(**iter, blockers)) {
205       if (blocked_ids)
206         blocked_ids->push_back((*iter)->id());
207       continue;
208     }
209
210     // Checking limits. No limits for HIGH/MAX priority. DEFAULT priority
211     // will return at most kMaxVisiblePopupNotifications entries. If the
212     // popup entries are more, older entries are used. see crbug.com/165768
213     if ((*iter)->priority() == DEFAULT_PRIORITY &&
214         default_priority_popup_count++ >= kMaxVisiblePopupNotifications) {
215       continue;
216     }
217
218     result.insert(*iter);
219   }
220   return result;
221 }
222
223 void NotificationList::MarkSinglePopupAsShown(
224     const std::string& id, bool mark_notification_as_read) {
225   Notifications::iterator iter = GetNotification(id);
226   DCHECK(iter != notifications_.end());
227
228   if ((*iter)->shown_as_popup())
229     return;
230
231   // System notification is marked as shown only when marked as read.
232   if ((*iter)->priority() != SYSTEM_PRIORITY || mark_notification_as_read)
233     (*iter)->set_shown_as_popup(true);
234
235   // The popup notification is already marked as read when it's displayed.
236   // Set the is_read() back to false if necessary.
237   if (!mark_notification_as_read)
238     (*iter)->set_is_read(false);
239 }
240
241 void NotificationList::MarkSinglePopupAsDisplayed(const std::string& id) {
242   Notifications::iterator iter = GetNotification(id);
243   if (iter == notifications_.end())
244     return;
245
246   if ((*iter)->shown_as_popup())
247     return;
248
249   if (!(*iter)->IsRead())
250     (*iter)->set_is_read(true);
251 }
252
253 NotificationDelegate* NotificationList::GetNotificationDelegate(
254     const std::string& id) {
255   Notifications::iterator iter = GetNotification(id);
256   if (iter == notifications_.end())
257     return NULL;
258   return (*iter)->delegate();
259 }
260
261 void NotificationList::SetQuietMode(bool quiet_mode) {
262   quiet_mode_ = quiet_mode;
263   if (quiet_mode_) {
264     for (Notifications::iterator iter = notifications_.begin();
265          iter != notifications_.end();
266          ++iter) {
267       (*iter)->set_shown_as_popup(true);
268     }
269   }
270 }
271
272 NotificationList::Notifications NotificationList::GetVisibleNotifications(
273     const NotificationBlockers& blockers) const {
274   Notifications result;
275   for (Notifications::const_iterator iter = notifications_.begin();
276        iter != notifications_.end(); ++iter) {
277     bool should_show = true;
278     for (size_t i = 0; i < blockers.size(); ++i) {
279       if (!blockers[i]->ShouldShowNotification((*iter)->notifier_id())) {
280         should_show = false;
281         break;
282       }
283     }
284     if (should_show)
285       result.insert(*iter);
286   }
287
288   return result;
289 }
290
291 size_t NotificationList::NotificationCount(
292     const NotificationBlockers& blockers) const {
293   return GetVisibleNotifications(blockers).size();
294 }
295
296 size_t NotificationList::UnreadCount(
297     const NotificationBlockers& blockers) const {
298   Notifications notifications = GetVisibleNotifications(blockers);
299   size_t unread_count = 0;
300   for (Notifications::const_iterator iter = notifications.begin();
301        iter != notifications.end(); ++iter) {
302     if (!(*iter)->IsRead())
303       ++unread_count;
304   }
305   return unread_count;
306 }
307
308 NotificationList::Notifications::iterator NotificationList::GetNotification(
309     const std::string& id) {
310   for (Notifications::iterator iter = notifications_.begin();
311        iter != notifications_.end(); ++iter) {
312     if ((*iter)->id() == id)
313       return iter;
314   }
315   return notifications_.end();
316 }
317
318 void NotificationList::EraseNotification(Notifications::iterator iter) {
319   delete *iter;
320   notifications_.erase(iter);
321 }
322
323 void NotificationList::PushNotification(scoped_ptr<Notification> notification) {
324   // Ensure that notification.id is unique by erasing any existing
325   // notification with the same id (shouldn't normally happen).
326   Notifications::iterator iter = GetNotification(notification->id());
327   bool state_inherited = false;
328   if (iter != notifications_.end()) {
329     notification->CopyState(*iter);
330     state_inherited = true;
331     EraseNotification(iter);
332   }
333   // Add the notification to the the list and mark it unread and unshown.
334   if (!state_inherited) {
335     // TODO(mukai): needs to distinguish if a notification is dismissed by
336     // the quiet mode or user operation.
337     notification->set_is_read(false);
338     notification->set_shown_as_popup(message_center_visible_
339                                      || quiet_mode_
340                                      || notification->shown_as_popup());
341   }
342   // Take ownership. The notification can only be removed from the list
343   // in EraseNotification(), which will delete it.
344   notifications_.insert(notification.release());
345 }
346
347 }  // namespace message_center