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.
5 #include "ui/message_center/notification_list.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/gfx/image/image.h"
13 #include "ui/message_center/message_center_style.h"
14 #include "ui/message_center/notification.h"
15 #include "ui/message_center/notification_blocker.h"
16 #include "ui/message_center/notification_types.h"
18 namespace message_center
{
22 bool ShouldShowNotificationAsPopup(
23 const Notification
& notification
,
24 const NotificationBlockers
& blockers
) {
25 for (size_t i
= 0; i
< blockers
.size(); ++i
) {
26 if (!blockers
[i
]->ShouldShowNotificationAsPopup(notification
.notifier_id()))
34 bool ComparePriorityTimestampSerial::operator()(Notification
* n1
,
36 if (n1
->priority() > n2
->priority()) // Higher pri go first.
38 if (n1
->priority() < n2
->priority())
40 return CompareTimestampSerial()(n1
, n2
);
43 bool CompareTimestampSerial::operator()(Notification
* n1
, Notification
* n2
) {
44 if (n1
->timestamp() > n2
->timestamp()) // Newer come first.
46 if (n1
->timestamp() < n2
->timestamp())
48 if (n1
->serial_number() > n2
->serial_number()) // Newer come first.
50 if (n1
->serial_number() < n2
->serial_number())
55 NotificationList::NotificationList()
56 : message_center_visible_(false),
60 NotificationList::~NotificationList() {
61 STLDeleteContainerPointers(notifications_
.begin(), notifications_
.end());
64 void NotificationList::SetMessageCenterVisible(
66 std::set
<std::string
>* updated_ids
) {
67 if (message_center_visible_
== visible
)
70 message_center_visible_
= visible
;
75 for (Notifications::iterator iter
= notifications_
.begin();
76 iter
!= notifications_
.end(); ++iter
) {
77 Notification
* notification
= *iter
;
78 bool was_popup
= notification
->shown_as_popup();
79 bool was_read
= notification
->IsRead();
80 if (notification
->priority() < SYSTEM_PRIORITY
)
81 notification
->set_shown_as_popup(true);
82 notification
->set_is_read(true);
83 if (updated_ids
&& !(was_popup
&& was_read
))
84 updated_ids
->insert(notification
->id());
88 void NotificationList::AddNotification(scoped_ptr
<Notification
> notification
) {
89 PushNotification(notification
.Pass());
92 void NotificationList::UpdateNotificationMessage(
93 const std::string
& old_id
,
94 scoped_ptr
<Notification
> new_notification
) {
95 Notifications::iterator iter
= GetNotification(old_id
);
96 if (iter
== notifications_
.end())
99 new_notification
->CopyState(*iter
);
101 // Handles priority promotion. If the notification is already dismissed but
102 // the updated notification has higher priority, it should re-appear as a
103 // toast. Notifications coming from websites through the Web Notification API
104 // will always re-appear on update.
105 if ((*iter
)->priority() < new_notification
->priority() ||
106 new_notification
->notifier_id().type
== NotifierId::WEB_PAGE
) {
107 new_notification
->set_is_read(false);
108 new_notification
->set_shown_as_popup(false);
111 // Do not use EraseNotification and PushNotification, since we don't want to
112 // change unread counts nor to update is_read/shown_as_popup states.
113 Notification
* old
= *iter
;
114 notifications_
.erase(iter
);
117 // We really don't want duplicate IDs.
118 DCHECK(GetNotification(new_notification
->id()) == notifications_
.end());
119 notifications_
.insert(new_notification
.release());
122 void NotificationList::RemoveNotification(const std::string
& id
) {
123 EraseNotification(GetNotification(id
));
126 NotificationList::Notifications
NotificationList::GetNotificationsByNotifierId(
127 const NotifierId
& notifier_id
) {
128 Notifications notifications
;
129 for (Notifications::iterator iter
= notifications_
.begin();
130 iter
!= notifications_
.end(); ++iter
) {
131 if ((*iter
)->notifier_id() == notifier_id
)
132 notifications
.insert(*iter
);
134 return notifications
;
137 bool NotificationList::SetNotificationIcon(const std::string
& notification_id
,
138 const gfx::Image
& image
) {
139 Notifications::iterator iter
= GetNotification(notification_id
);
140 if (iter
== notifications_
.end())
142 (*iter
)->set_icon(image
);
146 bool NotificationList::SetNotificationImage(const std::string
& notification_id
,
147 const gfx::Image
& image
) {
148 Notifications::iterator iter
= GetNotification(notification_id
);
149 if (iter
== notifications_
.end())
151 (*iter
)->set_image(image
);
155 bool NotificationList::SetNotificationButtonIcon(
156 const std::string
& notification_id
, int button_index
,
157 const gfx::Image
& image
) {
158 Notifications::iterator iter
= GetNotification(notification_id
);
159 if (iter
== notifications_
.end())
161 (*iter
)->SetButtonIcon(button_index
, image
);
165 bool NotificationList::HasNotificationOfType(const std::string
& id
,
166 const NotificationType type
) {
167 Notifications::iterator iter
= GetNotification(id
);
168 if (iter
== notifications_
.end())
171 return (*iter
)->type() == type
;
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
)
180 if (!ShouldShowNotificationAsPopup(**iter
, blockers
))
182 if (!(*iter
)->shown_as_popup())
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;
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())
200 // No popups for LOW/MIN priority.
201 if ((*iter
)->priority() < DEFAULT_PRIORITY
)
204 if (!ShouldShowNotificationAsPopup(**iter
, blockers
)) {
206 blocked_ids
->push_back((*iter
)->id());
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
) {
218 result
.insert(*iter
);
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());
228 if ((*iter
)->shown_as_popup())
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);
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);
241 void NotificationList::MarkSinglePopupAsDisplayed(const std::string
& id
) {
242 Notifications::iterator iter
= GetNotification(id
);
243 if (iter
== notifications_
.end())
246 if ((*iter
)->shown_as_popup())
249 if (!(*iter
)->IsRead())
250 (*iter
)->set_is_read(true);
253 NotificationDelegate
* NotificationList::GetNotificationDelegate(
254 const std::string
& id
) {
255 Notifications::iterator iter
= GetNotification(id
);
256 if (iter
== notifications_
.end())
258 return (*iter
)->delegate();
261 void NotificationList::SetQuietMode(bool quiet_mode
) {
262 quiet_mode_
= quiet_mode
;
264 for (Notifications::iterator iter
= notifications_
.begin();
265 iter
!= notifications_
.end();
267 (*iter
)->set_shown_as_popup(true);
272 Notification
* NotificationList::GetNotificationById(const std::string
& id
) {
273 Notifications::iterator iter
= GetNotification(id
);
274 if (iter
!= notifications_
.end())
279 NotificationList::Notifications
NotificationList::GetVisibleNotifications(
280 const NotificationBlockers
& blockers
) const {
281 Notifications result
;
282 for (Notifications::const_iterator iter
= notifications_
.begin();
283 iter
!= notifications_
.end(); ++iter
) {
284 bool should_show
= true;
285 for (size_t i
= 0; i
< blockers
.size(); ++i
) {
286 if (!blockers
[i
]->ShouldShowNotification((*iter
)->notifier_id())) {
292 result
.insert(*iter
);
298 size_t NotificationList::NotificationCount(
299 const NotificationBlockers
& blockers
) const {
300 return GetVisibleNotifications(blockers
).size();
303 size_t NotificationList::UnreadCount(
304 const NotificationBlockers
& blockers
) const {
305 Notifications notifications
= GetVisibleNotifications(blockers
);
306 size_t unread_count
= 0;
307 for (Notifications::const_iterator iter
= notifications
.begin();
308 iter
!= notifications
.end(); ++iter
) {
309 if (!(*iter
)->IsRead())
315 NotificationList::Notifications::iterator
NotificationList::GetNotification(
316 const std::string
& id
) {
317 for (Notifications::iterator iter
= notifications_
.begin();
318 iter
!= notifications_
.end(); ++iter
) {
319 if ((*iter
)->id() == id
)
322 return notifications_
.end();
325 void NotificationList::EraseNotification(Notifications::iterator iter
) {
327 notifications_
.erase(iter
);
330 void NotificationList::PushNotification(scoped_ptr
<Notification
> notification
) {
331 // Ensure that notification.id is unique by erasing any existing
332 // notification with the same id (shouldn't normally happen).
333 Notifications::iterator iter
= GetNotification(notification
->id());
334 bool state_inherited
= false;
335 if (iter
!= notifications_
.end()) {
336 notification
->CopyState(*iter
);
337 state_inherited
= true;
338 EraseNotification(iter
);
340 // Add the notification to the the list and mark it unread and unshown.
341 if (!state_inherited
) {
342 // TODO(mukai): needs to distinguish if a notification is dismissed by
343 // the quiet mode or user operation.
344 notification
->set_is_read(false);
345 notification
->set_shown_as_popup(message_center_visible_
347 || notification
->shown_as_popup());
349 // Take ownership. The notification can only be removed from the list
350 // in EraseNotification(), which will delete it.
351 notifications_
.insert(notification
.release());
354 } // namespace message_center