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/message_center/message_center_style.h"
13 #include "ui/message_center/notification.h"
14 #include "ui/message_center/notification_blocker.h"
15 #include "ui/message_center/notification_types.h"
17 namespace message_center
{
21 bool ShouldShowNotificationAsPopup(
22 const NotifierId
& notifier_id
,
23 const std::vector
<NotificationBlocker
*>& blockers
) {
24 for (size_t i
= 0; i
< blockers
.size(); ++i
) {
25 if (!blockers
[i
]->ShouldShowNotificationAsPopup(notifier_id
))
33 bool ComparePriorityTimestampSerial::operator()(Notification
* n1
,
35 if (n1
->priority() > n2
->priority()) // Higher pri go first.
37 if (n1
->priority() < n2
->priority())
39 return CompareTimestampSerial()(n1
, n2
);
42 bool CompareTimestampSerial::operator()(Notification
* n1
, Notification
* n2
) {
43 if (n1
->timestamp() > n2
->timestamp()) // Newer come first.
45 if (n1
->timestamp() < n2
->timestamp())
47 if (n1
->serial_number() > n2
->serial_number()) // Newer come first.
49 if (n1
->serial_number() < n2
->serial_number())
54 NotificationList::NotificationList()
55 : 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
;
77 for (Notifications::iterator iter
= notifications_
.begin();
78 iter
!= notifications_
.end(); ++iter
) {
79 Notification
* notification
= *iter
;
80 if (notification
->priority() < SYSTEM_PRIORITY
)
81 notification
->set_shown_as_popup(true);
82 notification
->set_is_read(true);
84 !(notification
->shown_as_popup() && notification
->is_read())) {
85 updated_ids
->insert(notification
->id());
90 void NotificationList::AddNotification(scoped_ptr
<Notification
> notification
) {
91 PushNotification(notification
.Pass());
94 void NotificationList::UpdateNotificationMessage(
95 const std::string
& old_id
,
96 scoped_ptr
<Notification
> new_notification
) {
97 Notifications::iterator iter
= GetNotification(old_id
);
98 if (iter
== notifications_
.end())
101 new_notification
->CopyState(*iter
);
103 // Handles priority promotion. If the notification is already dismissed but
104 // the updated notification has higher priority, it should re-appear as a
106 if ((*iter
)->priority() < new_notification
->priority()) {
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 void NotificationList::RemoveAllNotifications() {
127 for (Notifications::iterator loopiter
= notifications_
.begin();
128 loopiter
!= notifications_
.end(); ) {
129 Notifications::iterator curiter
= loopiter
++;
130 EraseNotification(curiter
);
135 NotificationList::Notifications
NotificationList::GetNotificationsByNotifierId(
136 const NotifierId
& notifier_id
) {
137 Notifications notifications
;
138 for (Notifications::iterator iter
= notifications_
.begin();
139 iter
!= notifications_
.end(); ++iter
) {
140 if ((*iter
)->notifier_id() == notifier_id
)
141 notifications
.insert(*iter
);
143 return notifications
;
146 bool NotificationList::SetNotificationIcon(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_icon(image
);
155 bool NotificationList::SetNotificationImage(const std::string
& notification_id
,
156 const gfx::Image
& image
) {
157 Notifications::iterator iter
= GetNotification(notification_id
);
158 if (iter
== notifications_
.end())
160 (*iter
)->set_image(image
);
164 bool NotificationList::SetNotificationButtonIcon(
165 const std::string
& notification_id
, int button_index
,
166 const gfx::Image
& image
) {
167 Notifications::iterator iter
= GetNotification(notification_id
);
168 if (iter
== notifications_
.end())
170 (*iter
)->SetButtonIcon(button_index
, image
);
174 bool NotificationList::HasNotification(const std::string
& id
) {
175 return GetNotification(id
) != notifications_
.end();
178 bool NotificationList::HasNotificationOfType(const std::string
& id
,
179 const NotificationType type
) {
180 Notifications::iterator iter
= GetNotification(id
);
181 if (iter
== notifications_
.end())
184 return (*iter
)->type() == type
;
187 bool NotificationList::HasPopupNotifications(
188 const std::vector
<NotificationBlocker
*>& blockers
) {
189 for (Notifications::iterator iter
= notifications_
.begin();
190 iter
!= notifications_
.end(); ++iter
) {
191 if ((*iter
)->priority() < DEFAULT_PRIORITY
)
193 if (!ShouldShowNotificationAsPopup((*iter
)->notifier_id(), blockers
))
195 if (!(*iter
)->shown_as_popup())
201 NotificationList::PopupNotifications
NotificationList::GetPopupNotifications(
202 const std::vector
<NotificationBlocker
*>& blockers
,
203 std::list
<std::string
>* blocked_ids
) {
204 PopupNotifications result
;
205 size_t default_priority_popup_count
= 0;
207 // Collect notifications that should be shown as popups. Start from oldest.
208 for (Notifications::const_reverse_iterator iter
= notifications_
.rbegin();
209 iter
!= notifications_
.rend(); iter
++) {
210 if ((*iter
)->shown_as_popup())
213 // No popups for LOW/MIN priority.
214 if ((*iter
)->priority() < DEFAULT_PRIORITY
)
217 if (!ShouldShowNotificationAsPopup((*iter
)->notifier_id(), blockers
)) {
219 blocked_ids
->push_back((*iter
)->id());
223 // Checking limits. No limits for HIGH/MAX priority. DEFAULT priority
224 // will return at most kMaxVisiblePopupNotifications entries. If the
225 // popup entries are more, older entries are used. see crbug.com/165768
226 if ((*iter
)->priority() == DEFAULT_PRIORITY
&&
227 default_priority_popup_count
++ >= kMaxVisiblePopupNotifications
) {
231 result
.insert(*iter
);
236 void NotificationList::MarkSinglePopupAsShown(
237 const std::string
& id
, bool mark_notification_as_read
) {
238 Notifications::iterator iter
= GetNotification(id
);
239 DCHECK(iter
!= notifications_
.end());
241 if ((*iter
)->shown_as_popup())
244 // System notification is marked as shown only when marked as read.
245 if ((*iter
)->priority() != SYSTEM_PRIORITY
|| mark_notification_as_read
)
246 (*iter
)->set_shown_as_popup(true);
248 // The popup notification is already marked as read when it's displayed.
249 // Set the is_read() back to false if necessary.
250 if (!mark_notification_as_read
) {
251 (*iter
)->set_is_read(false);
256 void NotificationList::MarkSinglePopupAsDisplayed(const std::string
& id
) {
257 Notifications::iterator iter
= GetNotification(id
);
258 if (iter
== notifications_
.end())
261 if ((*iter
)->shown_as_popup())
264 if (!(*iter
)->is_read()) {
265 (*iter
)->set_is_read(true);
270 void NotificationList::MarkNotificationAsExpanded(const std::string
& id
) {
271 Notifications::iterator iter
= GetNotification(id
);
272 if (iter
!= notifications_
.end())
273 (*iter
)->set_is_expanded(true);
276 NotificationDelegate
* NotificationList::GetNotificationDelegate(
277 const std::string
& id
) {
278 Notifications::iterator iter
= GetNotification(id
);
279 if (iter
== notifications_
.end())
281 return (*iter
)->delegate();
284 void NotificationList::SetQuietMode(bool quiet_mode
) {
285 quiet_mode_
= quiet_mode
;
287 for (Notifications::iterator iter
= notifications_
.begin();
288 iter
!= notifications_
.end();
290 (*iter
)->set_shown_as_popup(true);
295 const NotificationList::Notifications
& NotificationList::GetNotifications() {
296 return notifications_
;
299 size_t NotificationList::NotificationCount() const {
300 return notifications_
.size();
303 NotificationList::Notifications::iterator
NotificationList::GetNotification(
304 const std::string
& id
) {
305 for (Notifications::iterator iter
= notifications_
.begin();
306 iter
!= notifications_
.end(); ++iter
) {
307 if ((*iter
)->id() == id
)
310 return notifications_
.end();
313 void NotificationList::EraseNotification(Notifications::iterator iter
) {
314 if (!(*iter
)->is_read() && (*iter
)->priority() > MIN_PRIORITY
)
317 notifications_
.erase(iter
);
320 void NotificationList::PushNotification(scoped_ptr
<Notification
> notification
) {
321 // Ensure that notification.id is unique by erasing any existing
322 // notification with the same id (shouldn't normally happen).
323 Notifications::iterator iter
= GetNotification(notification
->id());
324 bool state_inherited
= false;
325 if (iter
!= notifications_
.end()) {
326 notification
->CopyState(*iter
);
327 state_inherited
= true;
328 EraseNotification(iter
);
329 // if |iter| is unread, EraseNotification decrements |unread_count_| but
330 // actually the count is unchanged since |notification| will be added.
331 if (!notification
->is_read())
334 // Add the notification to the the list and mark it unread and unshown.
335 if (!state_inherited
) {
336 // TODO(mukai): needs to distinguish if a notification is dismissed by
337 // the quiet mode or user operation.
338 notification
->set_is_read(false);
339 notification
->set_shown_as_popup(message_center_visible_
|| quiet_mode_
);
340 if (notification
->priority() > MIN_PRIORITY
)
343 // Take ownership. The notification can only be removed from the list
344 // in EraseNotification(), which will delete it.
345 notifications_
.insert(notification
.release());
348 } // namespace message_center