Add ICU message format support
[chromium-blink-merge.git] / ui / message_center / message_center_impl.cc
blobb54f183449958b0ac199c4c19fdc42b0f1c23dde
1 // Copyright (c) 2013 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/message_center_impl.h"
7 #include <algorithm>
9 #include "base/memory/scoped_vector.h"
10 #include "base/observer_list.h"
11 #include "ui/message_center/message_center_style.h"
12 #include "ui/message_center/message_center_types.h"
13 #include "ui/message_center/notification.h"
14 #include "ui/message_center/notification_blocker.h"
15 #include "ui/message_center/notification_list.h"
16 #include "ui/message_center/notification_types.h"
18 namespace {
20 base::TimeDelta GetTimeoutForPriority(int priority) {
21 if (priority > message_center::DEFAULT_PRIORITY) {
22 return base::TimeDelta::FromSeconds(
23 message_center::kAutocloseHighPriorityDelaySeconds);
25 return base::TimeDelta::FromSeconds(
26 message_center::kAutocloseDefaultDelaySeconds);
29 } // namespace
31 namespace message_center {
32 namespace internal {
34 // ChangeQueue keeps track of all the changes that we need to make to the
35 // notification list once the visibility is set to VISIBILITY_TRANSIENT.
36 class ChangeQueue {
37 public:
38 enum ChangeType {
39 CHANGE_TYPE_ADD = 0,
40 CHANGE_TYPE_UPDATE,
41 CHANGE_TYPE_DELETE
44 // Change represents an operation made on a notification. Since it contains
45 // the final state of the notification, we only keep the last change for a
46 // particular notification that is in the notification list around. There are
47 // two ids; |id_| is the newest notification id that has been assigned by an
48 // update, and |notification_list_id_| is the id of the notification it should
49 // be updating as it exists in the notification list.
50 class Change {
51 public:
52 Change(ChangeType type,
53 const std::string& id,
54 scoped_ptr<Notification> notification);
55 ~Change();
57 // Used to transfer ownership of the contained notification.
58 scoped_ptr<Notification> PassNotification();
60 Notification* notification() const { return notification_.get(); }
61 // Returns the post-update ID. It means:
62 // - ADD event: ID of the notification to be added.
63 // - UPDATE event: ID of the notification after the change. If the change
64 // doesn't update its ID, this value is same as |notification_list_id|.
65 // - DELETE event: ID of the notification to be deleted.
66 const std::string& id() const { return id_; }
67 ChangeType type() const { return type_; }
68 bool by_user() const { return by_user_; }
69 void set_by_user(bool by_user) { by_user_ = by_user; }
70 // Returns the ID which is used in the notification list. In other word, it
71 // means the ID before the change.
72 const std::string& notification_list_id() const {
73 return notification_list_id_;
75 void set_type(const ChangeType new_type) {
76 type_ = new_type;
78 void ReplaceNotification(scoped_ptr<Notification> new_notification);
80 private:
81 ChangeType type_;
82 std::string id_;
83 std::string notification_list_id_;
84 bool by_user_;
85 scoped_ptr<Notification> notification_;
87 DISALLOW_COPY_AND_ASSIGN(Change);
90 ChangeQueue();
91 ~ChangeQueue();
93 // Called when the message center has appropriate visibility. Modifies
94 // |message_center| but does not retain it. This also causes the queue to
95 // empty itself.
96 void ApplyChanges(MessageCenter* message_center);
98 // Causes a TYPE_ADD change to be added to the queue.
99 void AddNotification(scoped_ptr<Notification> notification);
101 // Causes a TYPE_UPDATE change to be added to the queue.
102 void UpdateNotification(const std::string& old_id,
103 scoped_ptr<Notification> notification);
105 // Causes a TYPE_DELETE change to be added to the queue.
106 void EraseNotification(const std::string& id, bool by_user);
108 // Returns whether the queue matches an id. The id given will be matched
109 // against the ID of all changes post-update, not the id of the notification
110 // as it stands in the notification list.
111 bool Has(const std::string& id) const;
113 // Returns a Change that can be modified by the caller. ChangeQueue retains
114 // ownership of the Change; pointers should not be retained.
115 Notification* GetLatestNotification(const std::string& id) const;
117 private:
118 ScopedVector<Change> changes_;
120 DISALLOW_COPY_AND_ASSIGN(ChangeQueue);
123 ////////////////////////////////////////////////////////////////////////////////
124 // ChangeFinder
126 struct ChangeFinder {
127 explicit ChangeFinder(const std::string& id) : id(id) {}
128 bool operator()(ChangeQueue::Change* change) { return change->id() == id; }
130 std::string id;
133 ////////////////////////////////////////////////////////////////////////////////
134 // ChangeQueue::Change
136 ChangeQueue::Change::Change(ChangeType type,
137 const std::string& id,
138 scoped_ptr<Notification> notification)
139 : type_(type),
140 notification_list_id_(id),
141 by_user_(false),
142 notification_(notification.Pass()) {
143 DCHECK(!id.empty());
144 DCHECK(type != CHANGE_TYPE_DELETE || notification_.get() == NULL);
146 id_ = notification_ ? notification_->id() : notification_list_id_;
149 ChangeQueue::Change::~Change() {}
151 scoped_ptr<Notification> ChangeQueue::Change::PassNotification() {
152 return notification_.Pass();
155 void ChangeQueue::Change::ReplaceNotification(
156 scoped_ptr<Notification> new_notification) {
157 id_ = new_notification ? new_notification->id() : notification_list_id_;
158 notification_.swap(new_notification);
161 ////////////////////////////////////////////////////////////////////////////////
162 // ChangeQueue
164 ChangeQueue::ChangeQueue() {}
166 ChangeQueue::~ChangeQueue() {}
168 void ChangeQueue::ApplyChanges(MessageCenter* message_center) {
169 // This method is re-entrant.
170 while (!changes_.empty()) {
171 ScopedVector<Change>::iterator iter = changes_.begin();
172 scoped_ptr<Change> change(*iter);
173 // TODO(dewittj): Replace changes_ with a deque.
174 changes_.weak_erase(iter);
175 // |message_center| is taking ownership of each element here.
176 switch (change->type()) {
177 case CHANGE_TYPE_ADD:
178 message_center->AddNotification(change->PassNotification());
179 break;
180 case CHANGE_TYPE_UPDATE:
181 message_center->UpdateNotification(change->notification_list_id(),
182 change->PassNotification());
183 break;
184 case CHANGE_TYPE_DELETE:
185 message_center->RemoveNotification(change->notification_list_id(),
186 change->by_user());
187 break;
188 default:
189 NOTREACHED();
194 void ChangeQueue::AddNotification(scoped_ptr<Notification> notification) {
195 std::string id = notification->id();
196 changes_.push_back(
197 new Change(CHANGE_TYPE_ADD, id, notification.Pass()));
200 void ChangeQueue::UpdateNotification(const std::string& old_id,
201 scoped_ptr<Notification> notification) {
202 ScopedVector<Change>::reverse_iterator iter =
203 std::find_if(changes_.rbegin(), changes_.rend(), ChangeFinder(old_id));
204 if (iter == changes_.rend()) {
205 changes_.push_back(
206 new Change(CHANGE_TYPE_UPDATE, old_id, notification.Pass()));
207 return;
210 Change* change = *iter;
211 switch (change->type()) {
212 case CHANGE_TYPE_ADD: {
213 std::string id = notification->id();
214 // Needs to add the change at the last, because if this change updates
215 // its ID, some previous changes may affect new ID.
216 // (eg. Add A, Update B->C, and This update A->B).
217 changes_.erase(--(iter.base()));
218 changes_.push_back(
219 new Change(CHANGE_TYPE_ADD, id, notification.Pass()));
220 break;
222 case CHANGE_TYPE_UPDATE:
223 if (notification->id() == old_id) {
224 // Safe to place the change at the previous place.
225 change->ReplaceNotification(notification.Pass());
226 } else if (change->id() == change->notification_list_id()) {
227 std::string id = notification->id();
228 // Safe to place the change at the last.
229 changes_.erase(--(iter.base()));
230 changes_.push_back(new Change(
231 CHANGE_TYPE_ADD, id, notification.Pass()));
232 } else {
233 // Complex case: gives up to optimize.
234 changes_.push_back(
235 new Change(CHANGE_TYPE_UPDATE, old_id, notification.Pass()));
237 break;
238 case CHANGE_TYPE_DELETE:
239 // DELETE -> UPDATE. Something is wrong. Treats the UPDATE as ADD.
240 changes_.push_back(
241 new Change(CHANGE_TYPE_ADD, old_id, notification.Pass()));
242 break;
243 default:
244 NOTREACHED();
248 void ChangeQueue::EraseNotification(const std::string& id, bool by_user) {
249 ScopedVector<Change>::reverse_iterator iter =
250 std::find_if(changes_.rbegin(), changes_.rend(), ChangeFinder(id));
251 if (iter == changes_.rend()) {
252 scoped_ptr<Change> change(new Change(CHANGE_TYPE_DELETE, id, nullptr));
253 change->set_by_user(by_user);
254 changes_.push_back(change.Pass());
255 return;
258 Change* change = *iter;
259 switch (change->type()) {
260 case CHANGE_TYPE_ADD:
261 // ADD -> DELETE. Just removes both.
262 changes_.erase(--(iter.base()));
263 break;
264 case CHANGE_TYPE_UPDATE:
265 // UPDATE -> DELETE. Changes the previous UPDATE to DELETE.
266 change->set_type(CHANGE_TYPE_DELETE);
267 change->set_by_user(by_user);
268 change->ReplaceNotification(nullptr);
269 break;
270 case CHANGE_TYPE_DELETE:
271 // DELETE -> DELETE. Something is wrong. Combines them with overriding
272 // the |by_user| flag.
273 change->set_by_user(!change->by_user() && by_user);
274 break;
275 default:
276 NOTREACHED();
280 bool ChangeQueue::Has(const std::string& id) const {
281 ScopedVector<Change>::const_iterator iter =
282 std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id));
283 return iter != changes_.end();
286 Notification* ChangeQueue::GetLatestNotification(const std::string& id) const {
287 ScopedVector<Change>::const_iterator iter =
288 std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id));
289 if (iter == changes_.end())
290 return NULL;
292 return (*iter)->notification();
295 ////////////////////////////////////////////////////////////////////////////////
296 // PopupTimer
298 PopupTimer::PopupTimer(const std::string& id,
299 base::TimeDelta timeout,
300 base::WeakPtr<PopupTimersController> controller)
301 : id_(id),
302 timeout_(timeout),
303 timer_controller_(controller),
304 timer_(new base::OneShotTimer<PopupTimersController>) {}
306 PopupTimer::~PopupTimer() {
307 if (!timer_)
308 return;
310 if (timer_->IsRunning())
311 timer_->Stop();
314 void PopupTimer::Start() {
315 if (timer_->IsRunning())
316 return;
317 base::TimeDelta timeout_to_close =
318 timeout_ <= passed_ ? base::TimeDelta() : timeout_ - passed_;
319 start_time_ = base::Time::Now();
320 timer_->Start(
321 FROM_HERE,
322 timeout_to_close,
323 base::Bind(
324 &PopupTimersController::TimerFinished, timer_controller_, id_));
327 void PopupTimer::Pause() {
328 if (!timer_ || !timer_->IsRunning())
329 return;
331 timer_->Stop();
332 passed_ += base::Time::Now() - start_time_;
335 void PopupTimer::Reset() {
336 if (timer_)
337 timer_->Stop();
338 passed_ = base::TimeDelta();
341 ////////////////////////////////////////////////////////////////////////////////
342 // PopupTimersController
344 PopupTimersController::PopupTimersController(MessageCenter* message_center)
345 : message_center_(message_center) {
346 message_center_->AddObserver(this);
349 PopupTimersController::~PopupTimersController() {
350 message_center_->RemoveObserver(this);
353 void PopupTimersController::StartTimer(const std::string& id,
354 const base::TimeDelta& timeout) {
355 PopupTimerCollection::const_iterator iter = popup_timers_.find(id);
356 if (iter != popup_timers_.end()) {
357 DCHECK(iter->second);
358 iter->second->Start();
359 return;
362 scoped_ptr<PopupTimer> timer(new PopupTimer(id, timeout, AsWeakPtr()));
364 timer->Start();
365 popup_timers_.insert(id, timer.Pass());
368 void PopupTimersController::StartAll() {
369 for (auto& iter : popup_timers_)
370 iter.second->Start();
373 void PopupTimersController::ResetTimer(const std::string& id,
374 const base::TimeDelta& timeout) {
375 CancelTimer(id);
376 StartTimer(id, timeout);
379 void PopupTimersController::PauseTimer(const std::string& id) {
380 PopupTimerCollection::const_iterator iter = popup_timers_.find(id);
381 if (iter == popup_timers_.end())
382 return;
383 iter->second->Pause();
386 void PopupTimersController::PauseAll() {
387 for (auto& iter : popup_timers_)
388 iter.second->Pause();
391 void PopupTimersController::CancelTimer(const std::string& id) {
392 popup_timers_.erase(id);
395 void PopupTimersController::CancelAll() {
396 popup_timers_.clear();
399 void PopupTimersController::TimerFinished(const std::string& id) {
400 if (!ContainsKey(popup_timers_, id))
401 return;
403 CancelTimer(id);
404 message_center_->MarkSinglePopupAsShown(id, false);
407 void PopupTimersController::OnNotificationDisplayed(
408 const std::string& id,
409 const DisplaySource source) {
410 OnNotificationUpdated(id);
413 void PopupTimersController::OnNotificationUpdated(const std::string& id) {
414 NotificationList::PopupNotifications popup_notifications =
415 message_center_->GetPopupNotifications();
417 if (!popup_notifications.size()) {
418 CancelAll();
419 return;
422 NotificationList::PopupNotifications::const_iterator iter =
423 popup_notifications.begin();
424 for (; iter != popup_notifications.end(); ++iter) {
425 if ((*iter)->id() == id)
426 break;
429 if (iter == popup_notifications.end() || (*iter)->never_timeout()) {
430 CancelTimer(id);
431 return;
434 // Start the timer if not yet.
435 if (popup_timers_.find(id) == popup_timers_.end())
436 StartTimer(id, GetTimeoutForPriority((*iter)->priority()));
439 void PopupTimersController::OnNotificationRemoved(const std::string& id,
440 bool by_user) {
441 CancelTimer(id);
444 } // namespace internal
446 ////////////////////////////////////////////////////////////////////////////////
447 // MessageCenterImpl::NotificationCache
449 MessageCenterImpl::NotificationCache::NotificationCache()
450 : unread_count(0) {}
452 MessageCenterImpl::NotificationCache::~NotificationCache() {}
454 void MessageCenterImpl::NotificationCache::Rebuild(
455 const NotificationList::Notifications& notifications) {
456 visible_notifications = notifications;
457 RecountUnread();
460 void MessageCenterImpl::NotificationCache::RecountUnread() {
461 unread_count = 0;
462 for (const auto& notification : visible_notifications) {
463 if (!notification->IsRead())
464 ++unread_count;
468 ////////////////////////////////////////////////////////////////////////////////
469 // MessageCenterImpl
471 MessageCenterImpl::MessageCenterImpl()
472 : MessageCenter(),
473 popup_timers_controller_(new internal::PopupTimersController(this)),
474 settings_provider_(NULL) {
475 notification_list_.reset(new NotificationList());
476 notification_queue_.reset(new internal::ChangeQueue());
479 MessageCenterImpl::~MessageCenterImpl() {
480 SetNotifierSettingsProvider(NULL);
483 void MessageCenterImpl::AddObserver(MessageCenterObserver* observer) {
484 observer_list_.AddObserver(observer);
487 void MessageCenterImpl::RemoveObserver(MessageCenterObserver* observer) {
488 observer_list_.RemoveObserver(observer);
491 void MessageCenterImpl::AddNotificationBlocker(NotificationBlocker* blocker) {
492 if (std::find(blockers_.begin(), blockers_.end(), blocker) !=
493 blockers_.end()) {
494 return;
496 blocker->AddObserver(this);
497 blockers_.push_back(blocker);
500 void MessageCenterImpl::RemoveNotificationBlocker(
501 NotificationBlocker* blocker) {
502 std::vector<NotificationBlocker*>::iterator iter =
503 std::find(blockers_.begin(), blockers_.end(), blocker);
504 if (iter == blockers_.end())
505 return;
506 blocker->RemoveObserver(this);
507 blockers_.erase(iter);
510 void MessageCenterImpl::OnBlockingStateChanged(NotificationBlocker* blocker) {
511 std::list<std::string> blocked_ids;
512 NotificationList::PopupNotifications popups =
513 notification_list_->GetPopupNotifications(blockers_, &blocked_ids);
515 for (const auto& id : blocked_ids) {
516 // Do not call MessageCenterImpl::MarkSinglePopupAsShown() directly here
517 // just for performance reason. MessageCenterImpl::MarkSinglePopupAsShown()
518 // calls NotificationList::MarkSinglePopupAsShown() and then updates the
519 // unread count, but the whole cache will be recreated below.
520 notification_list_->MarkSinglePopupAsShown(id, true);
521 FOR_EACH_OBSERVER(MessageCenterObserver,
522 observer_list_,
523 OnNotificationUpdated(id));
525 notification_cache_.Rebuild(
526 notification_list_->GetVisibleNotifications(blockers_));
527 FOR_EACH_OBSERVER(MessageCenterObserver,
528 observer_list_,
529 OnBlockingStateChanged(blocker));
532 void MessageCenterImpl::UpdateIconImage(
533 const NotifierId& notifier_id, const gfx::Image& icon) {}
535 void MessageCenterImpl::NotifierGroupChanged() {}
537 void MessageCenterImpl::NotifierEnabledChanged(
538 const NotifierId& notifier_id, bool enabled) {
539 if (!enabled) {
540 RemoveNotificationsForNotifierId(notifier_id);
544 void MessageCenterImpl::SetVisibility(Visibility visibility) {
545 std::set<std::string> updated_ids;
546 notification_list_->SetMessageCenterVisible(
547 (visibility == VISIBILITY_MESSAGE_CENTER), &updated_ids);
548 notification_cache_.RecountUnread();
550 for (const auto& id : updated_ids) {
551 FOR_EACH_OBSERVER(
552 MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
555 if (visibility == VISIBILITY_TRANSIENT)
556 notification_queue_->ApplyChanges(this);
558 FOR_EACH_OBSERVER(MessageCenterObserver,
559 observer_list_,
560 OnCenterVisibilityChanged(visibility));
563 bool MessageCenterImpl::IsMessageCenterVisible() const {
564 return notification_list_->is_message_center_visible();
567 size_t MessageCenterImpl::NotificationCount() const {
568 return notification_cache_.visible_notifications.size();
571 size_t MessageCenterImpl::UnreadNotificationCount() const {
572 return notification_cache_.unread_count;
575 bool MessageCenterImpl::HasPopupNotifications() const {
576 return !IsMessageCenterVisible() &&
577 notification_list_->HasPopupNotifications(blockers_);
580 bool MessageCenterImpl::IsQuietMode() const {
581 return notification_list_->quiet_mode();
584 bool MessageCenterImpl::HasClickedListener(const std::string& id) {
585 scoped_refptr<NotificationDelegate> delegate =
586 notification_list_->GetNotificationDelegate(id);
587 return delegate.get() && delegate->HasClickedListener();
590 message_center::Notification* MessageCenterImpl::FindVisibleNotificationById(
591 const std::string& id) {
592 return notification_list_->GetNotificationById(id);
595 const NotificationList::Notifications&
596 MessageCenterImpl::GetVisibleNotifications() {
597 return notification_cache_.visible_notifications;
600 NotificationList::PopupNotifications
601 MessageCenterImpl::GetPopupNotifications() {
602 return notification_list_->GetPopupNotifications(blockers_, NULL);
605 //------------------------------------------------------------------------------
606 // Client code interface.
607 void MessageCenterImpl::AddNotification(scoped_ptr<Notification> notification) {
608 DCHECK(notification);
609 const std::string id = notification->id();
610 for (size_t i = 0; i < blockers_.size(); ++i)
611 blockers_[i]->CheckState();
613 if (notification_list_->is_message_center_visible()) {
614 notification_queue_->AddNotification(notification.Pass());
615 return;
618 // Sometimes the notification can be added with the same id and the
619 // |notification_list| will replace the notification instead of adding new.
620 // This is essentially an update rather than addition.
621 bool already_exists = (notification_list_->GetNotificationById(id) != NULL);
622 notification_list_->AddNotification(notification.Pass());
623 notification_cache_.Rebuild(
624 notification_list_->GetVisibleNotifications(blockers_));
626 if (already_exists) {
627 FOR_EACH_OBSERVER(
628 MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
629 } else {
630 FOR_EACH_OBSERVER(
631 MessageCenterObserver, observer_list_, OnNotificationAdded(id));
635 void MessageCenterImpl::UpdateNotification(
636 const std::string& old_id,
637 scoped_ptr<Notification> new_notification) {
638 for (size_t i = 0; i < blockers_.size(); ++i)
639 blockers_[i]->CheckState();
641 if (notification_list_->is_message_center_visible()) {
642 // We will allow notifications that are progress types (and stay progress
643 // types) to be updated even if the message center is open. There are 3
644 // requirements here:
645 // * Notification of type PROGRESS exists with same ID in the center
646 // * There are no queued updates for this notification (they imply a change
647 // that violates the PROGRESS invariant
648 // * The new notification is type PROGRESS.
649 // TODO(dewittj): Ensure this works when the ID is changed by the caller.
650 // This shouldn't be an issue in practice since only W3C notifications
651 // change the ID on update, and they don't have progress type notifications.
652 bool update_keeps_progress_type =
653 new_notification->type() == NOTIFICATION_TYPE_PROGRESS &&
654 !notification_queue_->Has(old_id) &&
655 notification_list_->HasNotificationOfType(old_id,
656 NOTIFICATION_TYPE_PROGRESS);
657 if (!update_keeps_progress_type) {
658 // Updates are allowed only for progress notifications.
659 notification_queue_->UpdateNotification(old_id, new_notification.Pass());
660 return;
664 std::string new_id = new_notification->id();
665 notification_list_->UpdateNotificationMessage(old_id,
666 new_notification.Pass());
667 notification_cache_.Rebuild(
668 notification_list_->GetVisibleNotifications(blockers_));
669 if (old_id == new_id) {
670 FOR_EACH_OBSERVER(
671 MessageCenterObserver, observer_list_, OnNotificationUpdated(new_id));
672 } else {
673 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
674 OnNotificationRemoved(old_id, false));
675 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
676 OnNotificationAdded(new_id));
680 void MessageCenterImpl::RemoveNotification(const std::string& id,
681 bool by_user) {
682 if (!by_user && notification_list_->is_message_center_visible()) {
683 notification_queue_->EraseNotification(id, by_user);
684 return;
687 if (FindVisibleNotificationById(id) == NULL)
688 return;
690 // In many cases |id| is a reference to an existing notification instance
691 // but the instance can be destructed in RemoveNotification(). Hence
692 // copies the id explicitly here.
693 std::string copied_id(id);
695 scoped_refptr<NotificationDelegate> delegate =
696 notification_list_->GetNotificationDelegate(copied_id);
697 if (delegate.get())
698 delegate->Close(by_user);
700 notification_list_->RemoveNotification(copied_id);
701 notification_cache_.Rebuild(
702 notification_list_->GetVisibleNotifications(blockers_));
703 FOR_EACH_OBSERVER(MessageCenterObserver,
704 observer_list_,
705 OnNotificationRemoved(copied_id, by_user));
708 void MessageCenterImpl::RemoveNotificationsForNotifierId(
709 const NotifierId& notifier_id) {
710 NotificationList::Notifications notifications =
711 notification_list_->GetNotificationsByNotifierId(notifier_id);
712 for (const auto& notification : notifications)
713 RemoveNotification(notification->id(), false);
714 if (!notifications.empty()) {
715 notification_cache_.Rebuild(
716 notification_list_->GetVisibleNotifications(blockers_));
720 void MessageCenterImpl::RemoveAllNotifications(bool by_user) {
721 // Using not |blockers_| but an empty list since it wants to remove literally
722 // all notifications.
723 RemoveNotifications(by_user, NotificationBlockers());
726 void MessageCenterImpl::RemoveAllVisibleNotifications(bool by_user) {
727 RemoveNotifications(by_user, blockers_);
730 void MessageCenterImpl::RemoveNotifications(
731 bool by_user,
732 const NotificationBlockers& blockers) {
733 const NotificationList::Notifications notifications =
734 notification_list_->GetVisibleNotifications(blockers);
735 std::set<std::string> ids;
736 for (const auto& notification : notifications) {
737 ids.insert(notification->id());
738 scoped_refptr<NotificationDelegate> delegate = notification->delegate();
739 if (delegate.get())
740 delegate->Close(by_user);
741 notification_list_->RemoveNotification(notification->id());
744 if (!ids.empty()) {
745 notification_cache_.Rebuild(
746 notification_list_->GetVisibleNotifications(blockers_));
748 for (const auto& id : ids) {
749 FOR_EACH_OBSERVER(MessageCenterObserver,
750 observer_list_,
751 OnNotificationRemoved(id, by_user));
755 void MessageCenterImpl::SetNotificationIcon(const std::string& notification_id,
756 const gfx::Image& image) {
757 bool updated = false;
758 Notification* queue_notification = notification_queue_->GetLatestNotification(
759 notification_id);
761 if (queue_notification) {
762 queue_notification->set_icon(image);
763 updated = true;
764 } else {
765 updated = notification_list_->SetNotificationIcon(notification_id, image);
768 if (updated) {
769 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
770 OnNotificationUpdated(notification_id));
774 void MessageCenterImpl::SetNotificationImage(const std::string& notification_id,
775 const gfx::Image& image) {
776 bool updated = false;
777 Notification* queue_notification = notification_queue_->GetLatestNotification(
778 notification_id);
780 if (queue_notification) {
781 queue_notification->set_image(image);
782 updated = true;
783 } else {
784 updated = notification_list_->SetNotificationImage(notification_id, image);
787 if (updated) {
788 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
789 OnNotificationUpdated(notification_id));
793 void MessageCenterImpl::SetNotificationButtonIcon(
794 const std::string& notification_id, int button_index,
795 const gfx::Image& image) {
796 bool updated = false;
797 Notification* queue_notification = notification_queue_->GetLatestNotification(
798 notification_id);
800 if (queue_notification) {
801 queue_notification->SetButtonIcon(button_index, image);
802 updated = true;
803 } else {
804 updated = notification_list_->SetNotificationButtonIcon(
805 notification_id, button_index, image);
808 if (updated) {
809 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
810 OnNotificationUpdated(notification_id));
814 void MessageCenterImpl::DisableNotificationsByNotifier(
815 const NotifierId& notifier_id) {
816 if (settings_provider_) {
817 // TODO(mukai): SetNotifierEnabled can just accept notifier_id?
818 Notifier notifier(notifier_id, base::string16(), true);
819 settings_provider_->SetNotifierEnabled(notifier, false);
820 // The settings provider will call back to remove the notifications
821 // belonging to the notifier id.
822 } else {
823 RemoveNotificationsForNotifierId(notifier_id);
827 void MessageCenterImpl::ClickOnNotification(const std::string& id) {
828 if (FindVisibleNotificationById(id) == NULL)
829 return;
830 if (HasPopupNotifications())
831 MarkSinglePopupAsShown(id, true);
832 scoped_refptr<NotificationDelegate> delegate =
833 notification_list_->GetNotificationDelegate(id);
834 if (delegate.get())
835 delegate->Click();
836 FOR_EACH_OBSERVER(
837 MessageCenterObserver, observer_list_, OnNotificationClicked(id));
840 void MessageCenterImpl::ClickOnNotificationButton(const std::string& id,
841 int button_index) {
842 if (FindVisibleNotificationById(id) == NULL)
843 return;
844 if (HasPopupNotifications())
845 MarkSinglePopupAsShown(id, true);
846 scoped_refptr<NotificationDelegate> delegate =
847 notification_list_->GetNotificationDelegate(id);
848 if (delegate.get())
849 delegate->ButtonClick(button_index);
850 FOR_EACH_OBSERVER(
851 MessageCenterObserver, observer_list_, OnNotificationButtonClicked(
852 id, button_index));
855 void MessageCenterImpl::MarkSinglePopupAsShown(const std::string& id,
856 bool mark_notification_as_read) {
857 if (FindVisibleNotificationById(id) == NULL)
858 return;
859 notification_list_->MarkSinglePopupAsShown(id, mark_notification_as_read);
860 notification_cache_.RecountUnread();
861 FOR_EACH_OBSERVER(
862 MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
865 void MessageCenterImpl::DisplayedNotification(
866 const std::string& id,
867 const DisplaySource source) {
868 if (FindVisibleNotificationById(id) == NULL)
869 return;
871 if (HasPopupNotifications())
872 notification_list_->MarkSinglePopupAsDisplayed(id);
873 notification_cache_.RecountUnread();
874 scoped_refptr<NotificationDelegate> delegate =
875 notification_list_->GetNotificationDelegate(id);
876 if (delegate.get())
877 delegate->Display();
878 FOR_EACH_OBSERVER(
879 MessageCenterObserver,
880 observer_list_,
881 OnNotificationDisplayed(id, source));
884 void MessageCenterImpl::SetNotifierSettingsProvider(
885 NotifierSettingsProvider* provider) {
886 if (settings_provider_) {
887 settings_provider_->RemoveObserver(this);
888 settings_provider_ = NULL;
890 settings_provider_ = provider;
891 if (settings_provider_)
892 settings_provider_->AddObserver(this);
895 NotifierSettingsProvider* MessageCenterImpl::GetNotifierSettingsProvider() {
896 return settings_provider_;
899 void MessageCenterImpl::SetQuietMode(bool in_quiet_mode) {
900 if (in_quiet_mode != notification_list_->quiet_mode()) {
901 notification_list_->SetQuietMode(in_quiet_mode);
902 FOR_EACH_OBSERVER(MessageCenterObserver,
903 observer_list_,
904 OnQuietModeChanged(in_quiet_mode));
906 quiet_mode_timer_.reset();
909 void MessageCenterImpl::EnterQuietModeWithExpire(
910 const base::TimeDelta& expires_in) {
911 if (quiet_mode_timer_) {
912 // Note that the capital Reset() is the method to restart the timer, not
913 // scoped_ptr::reset().
914 quiet_mode_timer_->Reset();
915 } else {
916 notification_list_->SetQuietMode(true);
917 FOR_EACH_OBSERVER(
918 MessageCenterObserver, observer_list_, OnQuietModeChanged(true));
920 quiet_mode_timer_.reset(new base::OneShotTimer<MessageCenterImpl>);
921 quiet_mode_timer_->Start(
922 FROM_HERE,
923 expires_in,
924 base::Bind(
925 &MessageCenterImpl::SetQuietMode, base::Unretained(this), false));
929 void MessageCenterImpl::RestartPopupTimers() {
930 if (popup_timers_controller_)
931 popup_timers_controller_->StartAll();
934 void MessageCenterImpl::PausePopupTimers() {
935 if (popup_timers_controller_)
936 popup_timers_controller_->PauseAll();
939 void MessageCenterImpl::DisableTimersForTest() {
940 popup_timers_controller_.reset();
943 } // namespace message_center