Update V8 to version 4.7.50.
[chromium-blink-merge.git] / ui / message_center / message_center_impl.cc
blob1658d9870555b44dc942d4786bd59ca7e1c00788
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>
8 #include <deque>
10 #include "base/memory/scoped_vector.h"
11 #include "base/observer_list.h"
12 #include "ui/message_center/message_center_style.h"
13 #include "ui/message_center/message_center_types.h"
14 #include "ui/message_center/notification.h"
15 #include "ui/message_center/notification_blocker.h"
16 #include "ui/message_center/notification_list.h"
17 #include "ui/message_center/notification_types.h"
19 namespace {
21 base::TimeDelta GetTimeoutForPriority(int priority) {
22 if (priority > message_center::DEFAULT_PRIORITY) {
23 return base::TimeDelta::FromSeconds(
24 message_center::kAutocloseHighPriorityDelaySeconds);
26 return base::TimeDelta::FromSeconds(
27 message_center::kAutocloseDefaultDelaySeconds);
30 } // namespace
32 namespace message_center {
33 namespace internal {
35 // ChangeQueue keeps track of all the changes that we need to make to the
36 // notification list once the visibility is set to VISIBILITY_TRANSIENT.
37 class ChangeQueue {
38 public:
39 enum ChangeType {
40 CHANGE_TYPE_ADD = 0,
41 CHANGE_TYPE_UPDATE,
42 CHANGE_TYPE_DELETE
45 // Change represents an operation made on a notification. Since it contains
46 // the final state of the notification, we only keep the last change for a
47 // particular notification that is in the notification list around. There are
48 // two ids; |id_| is the newest notification id that has been assigned by an
49 // update, and |notification_list_id_| is the id of the notification it should
50 // be updating as it exists in the notification list.
51 class Change {
52 public:
53 Change(ChangeType type,
54 const std::string& id,
55 scoped_ptr<Notification> notification);
56 ~Change();
58 // Used to transfer ownership of the contained notification.
59 scoped_ptr<Notification> PassNotification();
61 Notification* notification() const { return notification_.get(); }
62 // Returns the post-update ID. It means:
63 // - ADD event: ID of the notification to be added.
64 // - UPDATE event: ID of the notification after the change. If the change
65 // doesn't update its ID, this value is same as |notification_list_id|.
66 // - DELETE event: ID of the notification to be deleted.
67 const std::string& id() const { return id_; }
68 ChangeType type() const { return type_; }
69 bool by_user() const { return by_user_; }
70 void set_by_user(bool by_user) { by_user_ = by_user; }
71 // Returns the ID which is used in the notification list. In other word, it
72 // means the ID before the change.
73 const std::string& notification_list_id() const {
74 return notification_list_id_;
76 void set_type(const ChangeType new_type) {
77 type_ = new_type;
79 void ReplaceNotification(scoped_ptr<Notification> new_notification);
81 private:
82 ChangeType type_;
83 std::string id_;
84 std::string notification_list_id_;
85 bool by_user_;
86 scoped_ptr<Notification> notification_;
88 DISALLOW_COPY_AND_ASSIGN(Change);
91 ChangeQueue();
92 ~ChangeQueue();
94 // Called when the message center has appropriate visibility. Modifies
95 // |message_center| but does not retain it. This also causes the queue to
96 // empty itself.
97 void ApplyChanges(MessageCenterImpl* message_center);
99 // Applies only the changes of the given ID.
100 void ApplyChangesForId(MessageCenterImpl* message_center,
101 const std::string& id);
103 // Causes a TYPE_ADD change to be added to the queue.
104 void AddNotification(scoped_ptr<Notification> notification);
106 // Causes a TYPE_UPDATE change to be added to the queue.
107 void UpdateNotification(const std::string& old_id,
108 scoped_ptr<Notification> notification);
110 // Causes a TYPE_DELETE change to be added to the queue.
111 void EraseNotification(const std::string& id, bool by_user);
113 // Returns whether the queue matches an id. The id given will be matched
114 // against the ID of all changes post-update, not the id of the notification
115 // as it stands in the notification list.
116 bool Has(const std::string& id) const;
118 // Returns a Change that can be modified by the caller. ChangeQueue retains
119 // ownership of the Change; pointers should not be retained.
120 Notification* GetLatestNotification(const std::string& id) const;
122 private:
123 void ApplyChangeInternal(MessageCenterImpl* message_center,
124 scoped_ptr<Change> change);
126 ScopedVector<Change> changes_;
128 DISALLOW_COPY_AND_ASSIGN(ChangeQueue);
131 ////////////////////////////////////////////////////////////////////////////////
132 // ChangeFinder
134 struct ChangeFinder {
135 explicit ChangeFinder(const std::string& id) : id(id) {}
136 bool operator()(ChangeQueue::Change* change) { return change->id() == id; }
138 std::string id;
141 ////////////////////////////////////////////////////////////////////////////////
142 // ChangeQueue::Change
144 ChangeQueue::Change::Change(ChangeType type,
145 const std::string& id,
146 scoped_ptr<Notification> notification)
147 : type_(type),
148 notification_list_id_(id),
149 by_user_(false),
150 notification_(notification.Pass()) {
151 DCHECK(!id.empty());
152 DCHECK(type != CHANGE_TYPE_DELETE || notification_.get() == NULL);
154 id_ = notification_ ? notification_->id() : notification_list_id_;
157 ChangeQueue::Change::~Change() {}
159 scoped_ptr<Notification> ChangeQueue::Change::PassNotification() {
160 return notification_.Pass();
163 void ChangeQueue::Change::ReplaceNotification(
164 scoped_ptr<Notification> new_notification) {
165 id_ = new_notification ? new_notification->id() : notification_list_id_;
166 notification_.swap(new_notification);
169 ////////////////////////////////////////////////////////////////////////////////
170 // ChangeQueue
172 ChangeQueue::ChangeQueue() {}
174 ChangeQueue::~ChangeQueue() {}
176 void ChangeQueue::ApplyChanges(MessageCenterImpl* message_center) {
177 // This method is re-entrant.
178 while (!changes_.empty()) {
179 ScopedVector<Change>::iterator iter = changes_.begin();
180 scoped_ptr<Change> change(*iter);
181 // TODO(dewittj): Replace changes_ with a deque.
182 changes_.weak_erase(iter);
183 ApplyChangeInternal(message_center, change.Pass());
187 void ChangeQueue::ApplyChangesForId(MessageCenterImpl* message_center,
188 const std::string& id) {
189 std::deque<Change*> changes_for_id;
190 std::string interesting_id = id;
192 // Traverses the queue in reverse so shat we can track changes which change
193 // the notification's ID.
194 ScopedVector<Change>::iterator iter = changes_.end();
195 while (iter != changes_.begin()) {
196 --iter;
197 if (interesting_id != (*iter)->id())
198 continue;
199 scoped_ptr<Change> change(*iter);
201 interesting_id = change->notification_list_id();
203 iter = changes_.weak_erase(iter);
204 changes_for_id.push_back(change.release());
207 while (!changes_for_id.empty()) {
208 ApplyChangeInternal(
209 message_center, scoped_ptr<Change>(changes_for_id.back()));
210 changes_for_id.pop_back();
214 void ChangeQueue::AddNotification(scoped_ptr<Notification> notification) {
215 std::string id = notification->id();
216 changes_.push_back(
217 new Change(CHANGE_TYPE_ADD, id, notification.Pass()));
220 void ChangeQueue::UpdateNotification(const std::string& old_id,
221 scoped_ptr<Notification> notification) {
222 ScopedVector<Change>::reverse_iterator iter =
223 std::find_if(changes_.rbegin(), changes_.rend(), ChangeFinder(old_id));
224 if (iter == changes_.rend()) {
225 changes_.push_back(
226 new Change(CHANGE_TYPE_UPDATE, old_id, notification.Pass()));
227 return;
230 Change* change = *iter;
231 switch (change->type()) {
232 case CHANGE_TYPE_ADD: {
233 std::string id = notification->id();
234 // Needs to add the change at the last, because if this change updates
235 // its ID, some previous changes may affect new ID.
236 // (eg. Add A, Update B->C, and This update A->B).
237 changes_.erase(--(iter.base()));
238 changes_.push_back(
239 new Change(CHANGE_TYPE_ADD, id, notification.Pass()));
240 break;
242 case CHANGE_TYPE_UPDATE:
243 if (notification->id() == old_id) {
244 // Safe to place the change at the previous place.
245 change->ReplaceNotification(notification.Pass());
246 } else if (change->id() == change->notification_list_id()) {
247 std::string id = notification->id();
248 // Safe to place the change at the last.
249 changes_.erase(--(iter.base()));
250 changes_.push_back(new Change(
251 CHANGE_TYPE_ADD, id, notification.Pass()));
252 } else {
253 // Complex case: gives up to optimize.
254 changes_.push_back(
255 new Change(CHANGE_TYPE_UPDATE, old_id, notification.Pass()));
257 break;
258 case CHANGE_TYPE_DELETE:
259 // DELETE -> UPDATE. Something is wrong. Treats the UPDATE as ADD.
260 changes_.push_back(
261 new Change(CHANGE_TYPE_ADD, old_id, notification.Pass()));
262 break;
263 default:
264 NOTREACHED();
268 void ChangeQueue::EraseNotification(const std::string& id, bool by_user) {
269 ScopedVector<Change>::reverse_iterator iter =
270 std::find_if(changes_.rbegin(), changes_.rend(), ChangeFinder(id));
271 if (iter == changes_.rend()) {
272 scoped_ptr<Change> change(new Change(CHANGE_TYPE_DELETE, id, nullptr));
273 change->set_by_user(by_user);
274 changes_.push_back(change.Pass());
275 return;
278 Change* change = *iter;
279 switch (change->type()) {
280 case CHANGE_TYPE_ADD:
281 // ADD -> DELETE. Just removes both.
282 changes_.erase(--(iter.base()));
283 break;
284 case CHANGE_TYPE_UPDATE:
285 // UPDATE -> DELETE. Changes the previous UPDATE to DELETE.
286 change->set_type(CHANGE_TYPE_DELETE);
287 change->set_by_user(by_user);
288 change->ReplaceNotification(nullptr);
289 break;
290 case CHANGE_TYPE_DELETE:
291 // DELETE -> DELETE. Something is wrong. Combines them with overriding
292 // the |by_user| flag.
293 change->set_by_user(!change->by_user() && by_user);
294 break;
295 default:
296 NOTREACHED();
300 bool ChangeQueue::Has(const std::string& id) const {
301 ScopedVector<Change>::const_iterator iter =
302 std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id));
303 return iter != changes_.end();
306 Notification* ChangeQueue::GetLatestNotification(const std::string& id) const {
307 ScopedVector<Change>::const_iterator iter =
308 std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id));
309 if (iter == changes_.end())
310 return NULL;
312 return (*iter)->notification();
315 void ChangeQueue::ApplyChangeInternal(MessageCenterImpl* message_center,
316 scoped_ptr<Change> change) {
317 switch (change->type()) {
318 case CHANGE_TYPE_ADD:
319 message_center->AddNotificationImmediately(change->PassNotification());
320 break;
321 case CHANGE_TYPE_UPDATE:
322 message_center->UpdateNotificationImmediately(
323 change->notification_list_id(), change->PassNotification());
324 break;
325 case CHANGE_TYPE_DELETE:
326 message_center->RemoveNotificationImmediately(
327 change->notification_list_id(), change->by_user());
328 break;
329 default:
330 NOTREACHED();
334 ////////////////////////////////////////////////////////////////////////////////
335 // PopupTimer
337 PopupTimer::PopupTimer(const std::string& id,
338 base::TimeDelta timeout,
339 base::WeakPtr<PopupTimersController> controller)
340 : id_(id),
341 timeout_(timeout),
342 timer_controller_(controller),
343 timer_(new base::OneShotTimer<PopupTimersController>) {}
345 PopupTimer::~PopupTimer() {
346 if (!timer_)
347 return;
349 if (timer_->IsRunning())
350 timer_->Stop();
353 void PopupTimer::Start() {
354 if (timer_->IsRunning())
355 return;
356 base::TimeDelta timeout_to_close =
357 timeout_ <= passed_ ? base::TimeDelta() : timeout_ - passed_;
358 start_time_ = base::Time::Now();
359 timer_->Start(
360 FROM_HERE,
361 timeout_to_close,
362 base::Bind(
363 &PopupTimersController::TimerFinished, timer_controller_, id_));
366 void PopupTimer::Pause() {
367 if (!timer_ || !timer_->IsRunning())
368 return;
370 timer_->Stop();
371 passed_ += base::Time::Now() - start_time_;
374 void PopupTimer::Reset() {
375 if (timer_)
376 timer_->Stop();
377 passed_ = base::TimeDelta();
380 ////////////////////////////////////////////////////////////////////////////////
381 // PopupTimersController
383 PopupTimersController::PopupTimersController(MessageCenter* message_center)
384 : message_center_(message_center) {
385 message_center_->AddObserver(this);
388 PopupTimersController::~PopupTimersController() {
389 message_center_->RemoveObserver(this);
392 void PopupTimersController::StartTimer(const std::string& id,
393 const base::TimeDelta& timeout) {
394 PopupTimerCollection::const_iterator iter = popup_timers_.find(id);
395 if (iter != popup_timers_.end()) {
396 DCHECK(iter->second);
397 iter->second->Start();
398 return;
401 scoped_ptr<PopupTimer> timer(new PopupTimer(id, timeout, AsWeakPtr()));
403 timer->Start();
404 popup_timers_.insert(id, timer.Pass());
407 void PopupTimersController::StartAll() {
408 for (auto& iter : popup_timers_)
409 iter.second->Start();
412 void PopupTimersController::ResetTimer(const std::string& id,
413 const base::TimeDelta& timeout) {
414 CancelTimer(id);
415 StartTimer(id, timeout);
418 void PopupTimersController::PauseTimer(const std::string& id) {
419 PopupTimerCollection::const_iterator iter = popup_timers_.find(id);
420 if (iter == popup_timers_.end())
421 return;
422 iter->second->Pause();
425 void PopupTimersController::PauseAll() {
426 for (auto& iter : popup_timers_)
427 iter.second->Pause();
430 void PopupTimersController::CancelTimer(const std::string& id) {
431 popup_timers_.erase(id);
434 void PopupTimersController::CancelAll() {
435 popup_timers_.clear();
438 void PopupTimersController::TimerFinished(const std::string& id) {
439 if (!ContainsKey(popup_timers_, id))
440 return;
442 CancelTimer(id);
443 message_center_->MarkSinglePopupAsShown(id, false);
446 void PopupTimersController::OnNotificationDisplayed(
447 const std::string& id,
448 const DisplaySource source) {
449 OnNotificationUpdated(id);
452 void PopupTimersController::OnNotificationUpdated(const std::string& id) {
453 NotificationList::PopupNotifications popup_notifications =
454 message_center_->GetPopupNotifications();
456 if (!popup_notifications.size()) {
457 CancelAll();
458 return;
461 NotificationList::PopupNotifications::const_iterator iter =
462 popup_notifications.begin();
463 for (; iter != popup_notifications.end(); ++iter) {
464 if ((*iter)->id() == id)
465 break;
468 if (iter == popup_notifications.end() || (*iter)->never_timeout()) {
469 CancelTimer(id);
470 return;
473 // Start the timer if not yet.
474 if (popup_timers_.find(id) == popup_timers_.end())
475 StartTimer(id, GetTimeoutForPriority((*iter)->priority()));
478 void PopupTimersController::OnNotificationRemoved(const std::string& id,
479 bool by_user) {
480 CancelTimer(id);
483 } // namespace internal
485 ////////////////////////////////////////////////////////////////////////////////
486 // MessageCenterImpl::NotificationCache
488 MessageCenterImpl::NotificationCache::NotificationCache()
489 : unread_count(0) {}
491 MessageCenterImpl::NotificationCache::~NotificationCache() {}
493 void MessageCenterImpl::NotificationCache::Rebuild(
494 const NotificationList::Notifications& notifications) {
495 visible_notifications = notifications;
496 RecountUnread();
499 void MessageCenterImpl::NotificationCache::RecountUnread() {
500 unread_count = 0;
501 for (const auto& notification : visible_notifications) {
502 if (!notification->IsRead())
503 ++unread_count;
507 ////////////////////////////////////////////////////////////////////////////////
508 // MessageCenterImpl
510 MessageCenterImpl::MessageCenterImpl()
511 : MessageCenter(),
512 popup_timers_controller_(new internal::PopupTimersController(this)),
513 settings_provider_(NULL) {
514 notification_list_.reset(new NotificationList());
515 notification_queue_.reset(new internal::ChangeQueue());
518 MessageCenterImpl::~MessageCenterImpl() {
519 SetNotifierSettingsProvider(NULL);
522 void MessageCenterImpl::AddObserver(MessageCenterObserver* observer) {
523 observer_list_.AddObserver(observer);
526 void MessageCenterImpl::RemoveObserver(MessageCenterObserver* observer) {
527 observer_list_.RemoveObserver(observer);
530 void MessageCenterImpl::AddNotificationBlocker(NotificationBlocker* blocker) {
531 if (std::find(blockers_.begin(), blockers_.end(), blocker) !=
532 blockers_.end()) {
533 return;
535 blocker->AddObserver(this);
536 blockers_.push_back(blocker);
539 void MessageCenterImpl::RemoveNotificationBlocker(
540 NotificationBlocker* blocker) {
541 std::vector<NotificationBlocker*>::iterator iter =
542 std::find(blockers_.begin(), blockers_.end(), blocker);
543 if (iter == blockers_.end())
544 return;
545 blocker->RemoveObserver(this);
546 blockers_.erase(iter);
549 void MessageCenterImpl::OnBlockingStateChanged(NotificationBlocker* blocker) {
550 std::list<std::string> blocked_ids;
551 NotificationList::PopupNotifications popups =
552 notification_list_->GetPopupNotifications(blockers_, &blocked_ids);
554 for (const auto& id : blocked_ids) {
555 // Do not call MessageCenterImpl::MarkSinglePopupAsShown() directly here
556 // just for performance reason. MessageCenterImpl::MarkSinglePopupAsShown()
557 // calls NotificationList::MarkSinglePopupAsShown() and then updates the
558 // unread count, but the whole cache will be recreated below.
559 notification_list_->MarkSinglePopupAsShown(id, true);
560 FOR_EACH_OBSERVER(MessageCenterObserver,
561 observer_list_,
562 OnNotificationUpdated(id));
564 notification_cache_.Rebuild(
565 notification_list_->GetVisibleNotifications(blockers_));
566 FOR_EACH_OBSERVER(MessageCenterObserver,
567 observer_list_,
568 OnBlockingStateChanged(blocker));
571 void MessageCenterImpl::UpdateIconImage(
572 const NotifierId& notifier_id, const gfx::Image& icon) {}
574 void MessageCenterImpl::NotifierGroupChanged() {}
576 void MessageCenterImpl::NotifierEnabledChanged(
577 const NotifierId& notifier_id, bool enabled) {
578 if (!enabled) {
579 RemoveNotificationsForNotifierId(notifier_id);
583 void MessageCenterImpl::SetVisibility(Visibility visibility) {
584 std::set<std::string> updated_ids;
585 notification_list_->SetMessageCenterVisible(
586 (visibility == VISIBILITY_MESSAGE_CENTER), &updated_ids);
587 notification_cache_.RecountUnread();
589 for (const auto& id : updated_ids) {
590 FOR_EACH_OBSERVER(
591 MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
594 if (visibility == VISIBILITY_TRANSIENT)
595 notification_queue_->ApplyChanges(this);
597 FOR_EACH_OBSERVER(MessageCenterObserver,
598 observer_list_,
599 OnCenterVisibilityChanged(visibility));
602 bool MessageCenterImpl::IsMessageCenterVisible() const {
603 return notification_list_->is_message_center_visible();
606 size_t MessageCenterImpl::NotificationCount() const {
607 return notification_cache_.visible_notifications.size();
610 size_t MessageCenterImpl::UnreadNotificationCount() const {
611 return notification_cache_.unread_count;
614 bool MessageCenterImpl::HasPopupNotifications() const {
615 return !IsMessageCenterVisible() &&
616 notification_list_->HasPopupNotifications(blockers_);
619 bool MessageCenterImpl::IsQuietMode() const {
620 return notification_list_->quiet_mode();
623 bool MessageCenterImpl::HasClickedListener(const std::string& id) {
624 scoped_refptr<NotificationDelegate> delegate =
625 notification_list_->GetNotificationDelegate(id);
626 return delegate.get() && delegate->HasClickedListener();
629 message_center::Notification* MessageCenterImpl::FindVisibleNotificationById(
630 const std::string& id) {
631 return notification_list_->GetNotificationById(id);
634 const NotificationList::Notifications&
635 MessageCenterImpl::GetVisibleNotifications() {
636 return notification_cache_.visible_notifications;
639 NotificationList::PopupNotifications
640 MessageCenterImpl::GetPopupNotifications() {
641 return notification_list_->GetPopupNotifications(blockers_, NULL);
644 void MessageCenterImpl::ForceNotificationFlush(const std::string& id) {
645 notification_queue_->ApplyChangesForId(this, id);
648 //------------------------------------------------------------------------------
649 // Client code interface.
650 void MessageCenterImpl::AddNotification(scoped_ptr<Notification> notification) {
651 DCHECK(notification);
652 const std::string id = notification->id();
653 for (size_t i = 0; i < blockers_.size(); ++i)
654 blockers_[i]->CheckState();
656 if (notification_list_->is_message_center_visible()) {
657 notification_queue_->AddNotification(notification.Pass());
658 return;
661 AddNotificationImmediately(notification.Pass());
664 void MessageCenterImpl::AddNotificationImmediately(
665 scoped_ptr<Notification> notification) {
666 const std::string id = notification->id();
668 // Sometimes the notification can be added with the same id and the
669 // |notification_list| will replace the notification instead of adding new.
670 // This is essentially an update rather than addition.
671 bool already_exists = (notification_list_->GetNotificationById(id) != NULL);
672 notification_list_->AddNotification(notification.Pass());
673 notification_cache_.Rebuild(
674 notification_list_->GetVisibleNotifications(blockers_));
676 if (already_exists) {
677 FOR_EACH_OBSERVER(
678 MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
679 } else {
680 FOR_EACH_OBSERVER(
681 MessageCenterObserver, observer_list_, OnNotificationAdded(id));
685 void MessageCenterImpl::UpdateNotification(
686 const std::string& old_id,
687 scoped_ptr<Notification> new_notification) {
688 for (size_t i = 0; i < blockers_.size(); ++i)
689 blockers_[i]->CheckState();
691 if (notification_list_->is_message_center_visible()) {
692 // We will allow notifications that are progress types (and stay progress
693 // types) to be updated even if the message center is open. There are 3
694 // requirements here:
695 // * Notification of type PROGRESS exists with same ID in the center
696 // * There are no queued updates for this notification (they imply a change
697 // that violates the PROGRESS invariant
698 // * The new notification is type PROGRESS.
699 // TODO(dewittj): Ensure this works when the ID is changed by the caller.
700 // This shouldn't be an issue in practice since only W3C notifications
701 // change the ID on update, and they don't have progress type notifications.
702 bool update_keeps_progress_type =
703 new_notification->type() == NOTIFICATION_TYPE_PROGRESS &&
704 !notification_queue_->Has(old_id) &&
705 notification_list_->HasNotificationOfType(old_id,
706 NOTIFICATION_TYPE_PROGRESS);
707 if (!update_keeps_progress_type) {
708 // Updates are allowed only for progress notifications.
709 notification_queue_->UpdateNotification(old_id, new_notification.Pass());
710 return;
714 UpdateNotificationImmediately(old_id, new_notification.Pass());
717 void MessageCenterImpl::UpdateNotificationImmediately(
718 const std::string& old_id,
719 scoped_ptr<Notification> new_notification) {
720 std::string new_id = new_notification->id();
721 notification_list_->UpdateNotificationMessage(old_id,
722 new_notification.Pass());
723 notification_cache_.Rebuild(
724 notification_list_->GetVisibleNotifications(blockers_));
725 if (old_id == new_id) {
726 FOR_EACH_OBSERVER(
727 MessageCenterObserver, observer_list_, OnNotificationUpdated(new_id));
728 } else {
729 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
730 OnNotificationRemoved(old_id, false));
731 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
732 OnNotificationAdded(new_id));
736 void MessageCenterImpl::RemoveNotification(const std::string& id,
737 bool by_user) {
738 if (!by_user && notification_list_->is_message_center_visible()) {
739 notification_queue_->EraseNotification(id, by_user);
740 return;
743 RemoveNotificationImmediately(id, by_user);
746 void MessageCenterImpl::RemoveNotificationImmediately(
747 const std::string& id, bool by_user) {
748 if (FindVisibleNotificationById(id) == NULL)
749 return;
751 // In many cases |id| is a reference to an existing notification instance
752 // but the instance can be destructed in this method. Hence copies the id
753 // explicitly here.
754 std::string copied_id(id);
756 scoped_refptr<NotificationDelegate> delegate =
757 notification_list_->GetNotificationDelegate(copied_id);
758 if (delegate.get())
759 delegate->Close(by_user);
761 notification_list_->RemoveNotification(copied_id);
762 notification_cache_.Rebuild(
763 notification_list_->GetVisibleNotifications(blockers_));
764 FOR_EACH_OBSERVER(MessageCenterObserver,
765 observer_list_,
766 OnNotificationRemoved(copied_id, by_user));
769 void MessageCenterImpl::RemoveNotificationsForNotifierId(
770 const NotifierId& notifier_id) {
771 NotificationList::Notifications notifications =
772 notification_list_->GetNotificationsByNotifierId(notifier_id);
773 for (const auto& notification : notifications)
774 RemoveNotification(notification->id(), false);
775 if (!notifications.empty()) {
776 notification_cache_.Rebuild(
777 notification_list_->GetVisibleNotifications(blockers_));
781 void MessageCenterImpl::RemoveAllNotifications(bool by_user) {
782 // Using not |blockers_| but an empty list since it wants to remove literally
783 // all notifications.
784 RemoveNotifications(by_user, NotificationBlockers());
787 void MessageCenterImpl::RemoveAllVisibleNotifications(bool by_user) {
788 RemoveNotifications(by_user, blockers_);
791 void MessageCenterImpl::RemoveNotifications(
792 bool by_user,
793 const NotificationBlockers& blockers) {
794 const NotificationList::Notifications notifications =
795 notification_list_->GetVisibleNotifications(blockers);
796 std::set<std::string> ids;
797 for (const auto& notification : notifications) {
798 ids.insert(notification->id());
799 scoped_refptr<NotificationDelegate> delegate = notification->delegate();
800 if (delegate.get())
801 delegate->Close(by_user);
802 notification_list_->RemoveNotification(notification->id());
805 if (!ids.empty()) {
806 notification_cache_.Rebuild(
807 notification_list_->GetVisibleNotifications(blockers_));
809 for (const auto& id : ids) {
810 FOR_EACH_OBSERVER(MessageCenterObserver,
811 observer_list_,
812 OnNotificationRemoved(id, by_user));
816 void MessageCenterImpl::SetNotificationIcon(const std::string& notification_id,
817 const gfx::Image& image) {
818 bool updated = false;
819 Notification* queue_notification = notification_queue_->GetLatestNotification(
820 notification_id);
822 if (queue_notification) {
823 queue_notification->set_icon(image);
824 updated = true;
825 } else {
826 updated = notification_list_->SetNotificationIcon(notification_id, image);
829 if (updated) {
830 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
831 OnNotificationUpdated(notification_id));
835 void MessageCenterImpl::SetNotificationImage(const std::string& notification_id,
836 const gfx::Image& image) {
837 bool updated = false;
838 Notification* queue_notification = notification_queue_->GetLatestNotification(
839 notification_id);
841 if (queue_notification) {
842 queue_notification->set_image(image);
843 updated = true;
844 } else {
845 updated = notification_list_->SetNotificationImage(notification_id, image);
848 if (updated) {
849 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
850 OnNotificationUpdated(notification_id));
854 void MessageCenterImpl::SetNotificationButtonIcon(
855 const std::string& notification_id, int button_index,
856 const gfx::Image& image) {
857 bool updated = false;
858 Notification* queue_notification = notification_queue_->GetLatestNotification(
859 notification_id);
861 if (queue_notification) {
862 queue_notification->SetButtonIcon(button_index, image);
863 updated = true;
864 } else {
865 updated = notification_list_->SetNotificationButtonIcon(
866 notification_id, button_index, image);
869 if (updated) {
870 FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
871 OnNotificationUpdated(notification_id));
875 void MessageCenterImpl::DisableNotificationsByNotifier(
876 const NotifierId& notifier_id) {
877 if (settings_provider_) {
878 // TODO(mukai): SetNotifierEnabled can just accept notifier_id?
879 Notifier notifier(notifier_id, base::string16(), true);
880 settings_provider_->SetNotifierEnabled(notifier, false);
881 // The settings provider will call back to remove the notifications
882 // belonging to the notifier id.
883 } else {
884 RemoveNotificationsForNotifierId(notifier_id);
888 void MessageCenterImpl::ClickOnNotification(const std::string& id) {
889 if (FindVisibleNotificationById(id) == NULL)
890 return;
891 if (HasPopupNotifications())
892 MarkSinglePopupAsShown(id, true);
893 scoped_refptr<NotificationDelegate> delegate =
894 notification_list_->GetNotificationDelegate(id);
895 if (delegate.get())
896 delegate->Click();
897 FOR_EACH_OBSERVER(
898 MessageCenterObserver, observer_list_, OnNotificationClicked(id));
901 void MessageCenterImpl::ClickOnNotificationButton(const std::string& id,
902 int button_index) {
903 if (FindVisibleNotificationById(id) == NULL)
904 return;
905 if (HasPopupNotifications())
906 MarkSinglePopupAsShown(id, true);
907 scoped_refptr<NotificationDelegate> delegate =
908 notification_list_->GetNotificationDelegate(id);
909 if (delegate.get())
910 delegate->ButtonClick(button_index);
911 FOR_EACH_OBSERVER(
912 MessageCenterObserver, observer_list_, OnNotificationButtonClicked(
913 id, button_index));
916 void MessageCenterImpl::MarkSinglePopupAsShown(const std::string& id,
917 bool mark_notification_as_read) {
918 if (FindVisibleNotificationById(id) == NULL)
919 return;
920 notification_list_->MarkSinglePopupAsShown(id, mark_notification_as_read);
921 notification_cache_.RecountUnread();
922 FOR_EACH_OBSERVER(
923 MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
926 void MessageCenterImpl::DisplayedNotification(
927 const std::string& id,
928 const DisplaySource source) {
929 if (FindVisibleNotificationById(id) == NULL)
930 return;
932 if (HasPopupNotifications())
933 notification_list_->MarkSinglePopupAsDisplayed(id);
934 notification_cache_.RecountUnread();
935 scoped_refptr<NotificationDelegate> delegate =
936 notification_list_->GetNotificationDelegate(id);
937 if (delegate.get())
938 delegate->Display();
939 FOR_EACH_OBSERVER(
940 MessageCenterObserver,
941 observer_list_,
942 OnNotificationDisplayed(id, source));
945 void MessageCenterImpl::SetNotifierSettingsProvider(
946 NotifierSettingsProvider* provider) {
947 if (settings_provider_) {
948 settings_provider_->RemoveObserver(this);
949 settings_provider_ = NULL;
951 settings_provider_ = provider;
952 if (settings_provider_)
953 settings_provider_->AddObserver(this);
956 NotifierSettingsProvider* MessageCenterImpl::GetNotifierSettingsProvider() {
957 return settings_provider_;
960 void MessageCenterImpl::SetQuietMode(bool in_quiet_mode) {
961 if (in_quiet_mode != notification_list_->quiet_mode()) {
962 notification_list_->SetQuietMode(in_quiet_mode);
963 FOR_EACH_OBSERVER(MessageCenterObserver,
964 observer_list_,
965 OnQuietModeChanged(in_quiet_mode));
967 quiet_mode_timer_.reset();
970 void MessageCenterImpl::EnterQuietModeWithExpire(
971 const base::TimeDelta& expires_in) {
972 if (quiet_mode_timer_) {
973 // Note that the capital Reset() is the method to restart the timer, not
974 // scoped_ptr::reset().
975 quiet_mode_timer_->Reset();
976 } else {
977 notification_list_->SetQuietMode(true);
978 FOR_EACH_OBSERVER(
979 MessageCenterObserver, observer_list_, OnQuietModeChanged(true));
981 quiet_mode_timer_.reset(new base::OneShotTimer<MessageCenterImpl>);
982 quiet_mode_timer_->Start(
983 FROM_HERE,
984 expires_in,
985 base::Bind(
986 &MessageCenterImpl::SetQuietMode, base::Unretained(this), false));
990 void MessageCenterImpl::RestartPopupTimers() {
991 if (popup_timers_controller_)
992 popup_timers_controller_->StartAll();
995 void MessageCenterImpl::PausePopupTimers() {
996 if (popup_timers_controller_)
997 popup_timers_controller_->PauseAll();
1000 void MessageCenterImpl::DisableTimersForTest() {
1001 popup_timers_controller_.reset();
1004 } // namespace message_center