Revert of Removing Chrome Gamepad transition cruft (https://codereview.chromium.org...
[chromium-blink-merge.git] / ui / message_center / notification_list.cc
blob4b0709ba92a700c4edb99a6634c92d7112583b93
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"
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"
16 namespace message_center {
18 namespace {
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;
27 return true;
30 } // namespace
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);
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;
53 NotificationList::NotificationList()
54 : message_center_visible_(false),
55 quiet_mode_(false) {
58 NotificationList::~NotificationList() {
59 STLDeleteContainerPointers(notifications_.begin(), notifications_.end());
62 void NotificationList::SetMessageCenterVisible(
63 bool visible,
64 std::set<std::string>* updated_ids) {
65 if (message_center_visible_ == visible)
66 return;
68 message_center_visible_ = visible;
70 if (!visible)
71 return;
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());
86 void NotificationList::AddNotification(scoped_ptr<Notification> notification) {
87 PushNotification(notification.Pass());
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;
97 new_notification->CopyState(*iter);
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);
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;
113 // We really don't want duplicate IDs.
114 DCHECK(GetNotification(new_notification->id()) == notifications_.end());
115 notifications_.insert(new_notification.release());
118 void NotificationList::RemoveNotification(const std::string& id) {
119 EraseNotification(GetNotification(id));
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);
130 return notifications;
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;
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;
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;
161 bool NotificationList::HasNotification(const std::string& id) {
162 return GetNotification(id) != notifications_.end();
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;
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)
179 break;
180 if (!ShouldShowNotificationAsPopup(**iter, blockers))
181 continue;
182 if (!(*iter)->shown_as_popup())
183 return true;
185 return false;
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())
198 continue;
200 // No popups for LOW/MIN priority.
201 if ((*iter)->priority() < DEFAULT_PRIORITY)
202 continue;
204 if (!ShouldShowNotificationAsPopup(**iter, blockers)) {
205 if (blocked_ids)
206 blocked_ids->push_back((*iter)->id());
207 continue;
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;
218 result.insert(*iter);
220 return result;
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())
229 return;
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())
244 return;
246 if ((*iter)->shown_as_popup())
247 return;
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())
257 return NULL;
258 return (*iter)->delegate();
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);
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;
284 if (should_show)
285 result.insert(*iter);
288 return result;
291 size_t NotificationList::NotificationCount(
292 const NotificationBlockers& blockers) const {
293 return GetVisibleNotifications(blockers).size();
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;
305 return unread_count;
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;
315 return notifications_.end();
318 void NotificationList::EraseNotification(Notifications::iterator iter) {
319 delete *iter;
320 notifications_.erase(iter);
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);
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());
342 // Take ownership. The notification can only be removed from the list
343 // in EraseNotification(), which will delete it.
344 notifications_.insert(notification.release());
347 } // namespace message_center