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"
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"
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
);
31 namespace message_center
{
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.
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.
52 Change(ChangeType type
,
53 const std::string
& id
,
54 scoped_ptr
<Notification
> notification
);
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
) {
78 void ReplaceNotification(scoped_ptr
<Notification
> new_notification
);
83 std::string notification_list_id_
;
85 scoped_ptr
<Notification
> notification_
;
87 DISALLOW_COPY_AND_ASSIGN(Change
);
93 // Called when the message center has appropriate visibility. Modifies
94 // |message_center| but does not retain it. This also causes the queue to
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;
118 ScopedVector
<Change
> changes_
;
120 DISALLOW_COPY_AND_ASSIGN(ChangeQueue
);
123 ////////////////////////////////////////////////////////////////////////////////
126 struct ChangeFinder
{
127 explicit ChangeFinder(const std::string
& id
) : id(id
) {}
128 bool operator()(ChangeQueue::Change
* change
) { return change
->id() == id
; }
133 ////////////////////////////////////////////////////////////////////////////////
134 // ChangeQueue::Change
136 ChangeQueue::Change::Change(ChangeType type
,
137 const std::string
& id
,
138 scoped_ptr
<Notification
> notification
)
140 notification_list_id_(id
),
142 notification_(notification
.Pass()) {
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 ////////////////////////////////////////////////////////////////////////////////
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());
180 case CHANGE_TYPE_UPDATE
:
181 message_center
->UpdateNotification(change
->notification_list_id(),
182 change
->PassNotification());
184 case CHANGE_TYPE_DELETE
:
185 message_center
->RemoveNotification(change
->notification_list_id(),
194 void ChangeQueue::AddNotification(scoped_ptr
<Notification
> notification
) {
195 std::string id
= notification
->id();
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()) {
206 new Change(CHANGE_TYPE_UPDATE
, old_id
, notification
.Pass()));
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()));
219 new Change(CHANGE_TYPE_ADD
, id
, notification
.Pass()));
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()));
233 // Complex case: gives up to optimize.
235 new Change(CHANGE_TYPE_UPDATE
, old_id
, notification
.Pass()));
238 case CHANGE_TYPE_DELETE
:
239 // DELETE -> UPDATE. Something is wrong. Treats the UPDATE as ADD.
241 new Change(CHANGE_TYPE_ADD
, old_id
, notification
.Pass()));
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());
258 Change
* change
= *iter
;
259 switch (change
->type()) {
260 case CHANGE_TYPE_ADD
:
261 // ADD -> DELETE. Just removes both.
262 changes_
.erase(--(iter
.base()));
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);
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
);
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())
292 return (*iter
)->notification();
295 ////////////////////////////////////////////////////////////////////////////////
298 PopupTimer::PopupTimer(const std::string
& id
,
299 base::TimeDelta timeout
,
300 base::WeakPtr
<PopupTimersController
> controller
)
303 timer_controller_(controller
),
304 timer_(new base::OneShotTimer
<PopupTimersController
>) {}
306 PopupTimer::~PopupTimer() {
310 if (timer_
->IsRunning())
314 void PopupTimer::Start() {
315 if (timer_
->IsRunning())
317 base::TimeDelta timeout_to_close
=
318 timeout_
<= passed_
? base::TimeDelta() : timeout_
- passed_
;
319 start_time_
= base::Time::Now();
324 &PopupTimersController::TimerFinished
, timer_controller_
, id_
));
327 void PopupTimer::Pause() {
328 if (!timer_
|| !timer_
->IsRunning())
332 passed_
+= base::Time::Now() - start_time_
;
335 void PopupTimer::Reset() {
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();
362 scoped_ptr
<PopupTimer
> timer(new PopupTimer(id
, timeout
, AsWeakPtr()));
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
) {
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())
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
))
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()) {
422 NotificationList::PopupNotifications::const_iterator iter
=
423 popup_notifications
.begin();
424 for (; iter
!= popup_notifications
.end(); ++iter
) {
425 if ((*iter
)->id() == id
)
429 if (iter
== popup_notifications
.end() || (*iter
)->never_timeout()) {
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
,
444 } // namespace internal
446 ////////////////////////////////////////////////////////////////////////////////
447 // MessageCenterImpl::NotificationCache
449 MessageCenterImpl::NotificationCache::NotificationCache()
452 MessageCenterImpl::NotificationCache::~NotificationCache() {}
454 void MessageCenterImpl::NotificationCache::Rebuild(
455 const NotificationList::Notifications
& notifications
) {
456 visible_notifications
= notifications
;
460 void MessageCenterImpl::NotificationCache::RecountUnread() {
462 for (const auto& notification
: visible_notifications
) {
463 if (!notification
->IsRead())
468 ////////////////////////////////////////////////////////////////////////////////
471 MessageCenterImpl::MessageCenterImpl()
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
) !=
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())
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
,
523 OnNotificationUpdated(id
));
525 notification_cache_
.Rebuild(
526 notification_list_
->GetVisibleNotifications(blockers_
));
527 FOR_EACH_OBSERVER(MessageCenterObserver
,
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
) {
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
) {
552 MessageCenterObserver
, observer_list_
, OnNotificationUpdated(id
));
555 if (visibility
== VISIBILITY_TRANSIENT
)
556 notification_queue_
->ApplyChanges(this);
558 FOR_EACH_OBSERVER(MessageCenterObserver
,
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());
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
) {
628 MessageCenterObserver
, observer_list_
, OnNotificationUpdated(id
));
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());
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
) {
671 MessageCenterObserver
, observer_list_
, OnNotificationUpdated(new_id
));
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
,
682 if (!by_user
&& notification_list_
->is_message_center_visible()) {
683 notification_queue_
->EraseNotification(id
, by_user
);
687 if (FindVisibleNotificationById(id
) == NULL
)
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
);
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
,
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(
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();
740 delegate
->Close(by_user
);
741 notification_list_
->RemoveNotification(notification
->id());
745 notification_cache_
.Rebuild(
746 notification_list_
->GetVisibleNotifications(blockers_
));
748 for (const auto& id
: ids
) {
749 FOR_EACH_OBSERVER(MessageCenterObserver
,
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(
761 if (queue_notification
) {
762 queue_notification
->set_icon(image
);
765 updated
= notification_list_
->SetNotificationIcon(notification_id
, image
);
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(
780 if (queue_notification
) {
781 queue_notification
->set_image(image
);
784 updated
= notification_list_
->SetNotificationImage(notification_id
, image
);
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(
800 if (queue_notification
) {
801 queue_notification
->SetButtonIcon(button_index
, image
);
804 updated
= notification_list_
->SetNotificationButtonIcon(
805 notification_id
, button_index
, image
);
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.
823 RemoveNotificationsForNotifierId(notifier_id
);
827 void MessageCenterImpl::ClickOnNotification(const std::string
& id
) {
828 if (FindVisibleNotificationById(id
) == NULL
)
830 if (HasPopupNotifications())
831 MarkSinglePopupAsShown(id
, true);
832 scoped_refptr
<NotificationDelegate
> delegate
=
833 notification_list_
->GetNotificationDelegate(id
);
837 MessageCenterObserver
, observer_list_
, OnNotificationClicked(id
));
840 void MessageCenterImpl::ClickOnNotificationButton(const std::string
& id
,
842 if (FindVisibleNotificationById(id
) == NULL
)
844 if (HasPopupNotifications())
845 MarkSinglePopupAsShown(id
, true);
846 scoped_refptr
<NotificationDelegate
> delegate
=
847 notification_list_
->GetNotificationDelegate(id
);
849 delegate
->ButtonClick(button_index
);
851 MessageCenterObserver
, observer_list_
, OnNotificationButtonClicked(
855 void MessageCenterImpl::MarkSinglePopupAsShown(const std::string
& id
,
856 bool mark_notification_as_read
) {
857 if (FindVisibleNotificationById(id
) == NULL
)
859 notification_list_
->MarkSinglePopupAsShown(id
, mark_notification_as_read
);
860 notification_cache_
.RecountUnread();
862 MessageCenterObserver
, observer_list_
, OnNotificationUpdated(id
));
865 void MessageCenterImpl::DisplayedNotification(
866 const std::string
& id
,
867 const DisplaySource source
) {
868 if (FindVisibleNotificationById(id
) == NULL
)
871 if (HasPopupNotifications())
872 notification_list_
->MarkSinglePopupAsDisplayed(id
);
873 notification_cache_
.RecountUnread();
874 scoped_refptr
<NotificationDelegate
> delegate
=
875 notification_list_
->GetNotificationDelegate(id
);
879 MessageCenterObserver
,
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
,
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();
916 notification_list_
->SetQuietMode(true);
918 MessageCenterObserver
, observer_list_
, OnQuietModeChanged(true));
920 quiet_mode_timer_
.reset(new base::OneShotTimer
<MessageCenterImpl
>);
921 quiet_mode_timer_
->Start(
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