Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / message_center / message_center_impl.cc
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.
4
5 #include "ui/message_center/message_center_impl.h"
6
7 #include <algorithm>
8
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/message_center_util.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"
18
19 namespace {
20
21 base::TimeDelta GetTimeoutForPriority(int priority) {
22   if (priority > message_center::DEFAULT_PRIORITY) {
23     return base::TimeDelta::FromSeconds(
24         message_center::kAutocloseHighPriorityDelaySeconds);
25   }
26   return base::TimeDelta::FromSeconds(
27       message_center::kAutocloseDefaultDelaySeconds);
28 }
29
30 }  // namespace
31
32 namespace message_center {
33 namespace internal {
34
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
43   };
44
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();
57
58     // Used to transfer ownership of the contained notification.
59     scoped_ptr<Notification> PassNotification();
60
61     Notification* notification() const { return notification_.get(); }
62     const std::string& id() const { return id_; }
63     ChangeType type() const { return type_; }
64     bool by_user() const { return by_user_; }
65     void set_by_user(bool by_user) { by_user_ = by_user; }
66     const std::string& notification_list_id() const {
67       return notification_list_id_;
68     }
69     void set_notification_list_id(const std::string& id) {
70       notification_list_id_ = id;
71     }
72
73    private:
74     const ChangeType type_;
75     const std::string id_;
76     std::string notification_list_id_;
77     bool by_user_;
78     scoped_ptr<Notification> notification_;
79
80     DISALLOW_COPY_AND_ASSIGN(Change);
81   };
82
83   ChangeQueue();
84   ~ChangeQueue();
85
86   // Called when the message center has appropriate visibility.  Modifies
87   // |message_center| but does not retain it.  This also causes the queue to
88   // empty itself.
89   void ApplyChanges(MessageCenter* message_center);
90
91   // Causes a TYPE_ADD change to be added to the queue.
92   void AddNotification(scoped_ptr<Notification> notification);
93
94   // Causes a TYPE_UPDATE change to be added to the queue.
95   void UpdateNotification(const std::string& old_id,
96                           scoped_ptr<Notification> notification);
97
98   // Causes a TYPE_DELETE change to be added to the queue.
99   void EraseNotification(const std::string& id, bool by_user);
100
101   // Returns whether the queue matches an id.  The id given will be matched
102   // against the ID of all changes post-update, not the id of the notification
103   // as it stands in the notification list.
104   bool Has(const std::string& id) const;
105
106   // Returns a Change that can be modified by the caller.  ChangeQueue retains
107   // ownership of the Change; pointers should not be retained.
108   Notification* GetLatestNotification(const std::string& id) const;
109
110  private:
111   void Replace(const std::string& id, scoped_ptr<Change> change);
112
113   ScopedVector<Change> changes_;
114 };
115
116 ////////////////////////////////////////////////////////////////////////////////
117 // ChangeFinder
118
119 struct ChangeFinder {
120   explicit ChangeFinder(const std::string& id) : id(id) {}
121   bool operator()(ChangeQueue::Change* change) { return change->id() == id; }
122
123   std::string id;
124 };
125
126 ////////////////////////////////////////////////////////////////////////////////
127 // ChangeQueue::Change
128
129 ChangeQueue::Change::Change(ChangeType type,
130                             const std::string& id,
131                             scoped_ptr<Notification> notification)
132     : type_(type),
133       id_(id),
134       notification_list_id_(id),
135       by_user_(false),
136       notification_(notification.Pass()) {
137   DCHECK(!id.empty() &&
138          (type != CHANGE_TYPE_DELETE || notification_.get() == NULL));
139 }
140
141 ChangeQueue::Change::~Change() {}
142
143 scoped_ptr<Notification> ChangeQueue::Change::PassNotification() {
144   return notification_.Pass();
145 }
146
147 ////////////////////////////////////////////////////////////////////////////////
148 // ChangeQueue
149
150 ChangeQueue::ChangeQueue() {}
151
152 ChangeQueue::~ChangeQueue() {}
153
154 void ChangeQueue::ApplyChanges(MessageCenter* message_center) {
155   // This method is re-entrant.
156   while (!changes_.empty()) {
157     ScopedVector<Change>::iterator iter = changes_.begin();
158     scoped_ptr<Change> change(*iter);
159     // TODO(dewittj): Replace changes_ with a deque.
160     changes_.weak_erase(iter);
161     // |message_center| is taking ownership of each element here.
162     switch (change->type()) {
163       case CHANGE_TYPE_ADD:
164         message_center->AddNotification(change->PassNotification());
165         break;
166       case CHANGE_TYPE_UPDATE:
167         message_center->UpdateNotification(change->notification_list_id(),
168                                            change->PassNotification());
169         break;
170       case CHANGE_TYPE_DELETE:
171         message_center->RemoveNotification(change->notification_list_id(),
172                                            change->by_user());
173         break;
174       default:
175         NOTREACHED();
176     }
177   }
178 }
179
180 void ChangeQueue::AddNotification(scoped_ptr<Notification> notification) {
181   std::string id = notification->id();
182
183   scoped_ptr<Change> change(
184       new Change(CHANGE_TYPE_ADD, id, notification.Pass()));
185   Replace(id, change.Pass());
186 }
187
188 void ChangeQueue::UpdateNotification(const std::string& old_id,
189                                      scoped_ptr<Notification> notification) {
190   std::string new_id = notification->id();
191   scoped_ptr<Change> change(
192       new Change(CHANGE_TYPE_UPDATE, new_id, notification.Pass()));
193   Replace(old_id, change.Pass());
194 }
195
196 void ChangeQueue::EraseNotification(const std::string& id, bool by_user) {
197   scoped_ptr<Change> change(
198       new Change(CHANGE_TYPE_DELETE, id, scoped_ptr<Notification>()));
199   change->set_by_user(by_user);
200   Replace(id, change.Pass());
201 }
202
203 bool ChangeQueue::Has(const std::string& id) const {
204   ScopedVector<Change>::const_iterator iter =
205       std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id));
206   return iter != changes_.end();
207 }
208
209 Notification* ChangeQueue::GetLatestNotification(const std::string& id) const {
210   ScopedVector<Change>::const_iterator iter =
211       std::find_if(changes_.begin(), changes_.end(), ChangeFinder(id));
212   if (iter == changes_.end())
213     return NULL;
214
215   return (*iter)->notification();
216 }
217
218 void ChangeQueue::Replace(const std::string& changed_id,
219                           scoped_ptr<Change> new_change) {
220   ScopedVector<Change>::iterator iter =
221       std::find_if(changes_.begin(), changes_.end(), ChangeFinder(changed_id));
222   if (iter != changes_.end()) {
223     Change* old_change = *iter;
224     new_change->set_notification_list_id(old_change->notification_list_id());
225     changes_.erase(iter);
226   } else {
227     new_change->set_notification_list_id(changed_id);
228   }
229
230   changes_.push_back(new_change.release());
231 }
232
233 ////////////////////////////////////////////////////////////////////////////////
234 // PopupTimer
235
236 PopupTimer::PopupTimer(const std::string& id,
237                        base::TimeDelta timeout,
238                        base::WeakPtr<PopupTimersController> controller)
239     : id_(id),
240       timeout_(timeout),
241       timer_controller_(controller),
242       timer_(new base::OneShotTimer<PopupTimersController>) {}
243
244 PopupTimer::~PopupTimer() {
245   if (!timer_)
246     return;
247
248   if (timer_->IsRunning())
249     timer_->Stop();
250 }
251
252 void PopupTimer::Start() {
253   if (timer_->IsRunning())
254     return;
255   base::TimeDelta timeout_to_close =
256       timeout_ <= passed_ ? base::TimeDelta() : timeout_ - passed_;
257   start_time_ = base::Time::Now();
258   timer_->Start(
259       FROM_HERE,
260       timeout_to_close,
261       base::Bind(
262           &PopupTimersController::TimerFinished, timer_controller_, id_));
263 }
264
265 void PopupTimer::Pause() {
266   if (!timer_.get() || !timer_->IsRunning())
267     return;
268
269   timer_->Stop();
270   passed_ += base::Time::Now() - start_time_;
271 }
272
273 void PopupTimer::Reset() {
274   if (timer_)
275     timer_->Stop();
276   passed_ = base::TimeDelta();
277 }
278
279 ////////////////////////////////////////////////////////////////////////////////
280 // PopupTimersController
281
282 PopupTimersController::PopupTimersController(MessageCenter* message_center)
283     : message_center_(message_center), popup_deleter_(&popup_timers_) {
284   message_center_->AddObserver(this);
285 }
286
287 PopupTimersController::~PopupTimersController() {
288   message_center_->RemoveObserver(this);
289 }
290
291 void PopupTimersController::StartTimer(const std::string& id,
292                                        const base::TimeDelta& timeout) {
293   PopupTimerCollection::iterator iter = popup_timers_.find(id);
294   if (iter != popup_timers_.end()) {
295     DCHECK(iter->second);
296     iter->second->Start();
297     return;
298   }
299
300   PopupTimer* timer = new PopupTimer(id, timeout, AsWeakPtr());
301
302   timer->Start();
303   popup_timers_[id] = timer;
304 }
305
306 void PopupTimersController::StartAll() {
307   std::map<std::string, PopupTimer*>::iterator iter;
308   for (iter = popup_timers_.begin(); iter != popup_timers_.end(); iter++) {
309     iter->second->Start();
310   }
311 }
312
313 void PopupTimersController::ResetTimer(const std::string& id,
314                                        const base::TimeDelta& timeout) {
315   CancelTimer(id);
316   StartTimer(id, timeout);
317 }
318
319 void PopupTimersController::PauseTimer(const std::string& id) {
320   PopupTimerCollection::iterator iter = popup_timers_.find(id);
321   if (iter == popup_timers_.end())
322     return;
323   iter->second->Pause();
324 }
325
326 void PopupTimersController::PauseAll() {
327   std::map<std::string, PopupTimer*>::iterator iter;
328   for (iter = popup_timers_.begin(); iter != popup_timers_.end(); iter++) {
329     iter->second->Pause();
330   }
331 }
332
333 void PopupTimersController::CancelTimer(const std::string& id) {
334   PopupTimerCollection::iterator iter = popup_timers_.find(id);
335   if (iter == popup_timers_.end())
336     return;
337
338   PopupTimer* timer = iter->second;
339   delete timer;
340
341   popup_timers_.erase(iter);
342 }
343
344 void PopupTimersController::CancelAll() {
345   STLDeleteValues(&popup_timers_);
346   popup_timers_.clear();
347 }
348
349 void PopupTimersController::TimerFinished(const std::string& id) {
350   PopupTimerCollection::iterator iter = popup_timers_.find(id);
351   if (iter == popup_timers_.end())
352     return;
353
354   CancelTimer(id);
355   message_center_->MarkSinglePopupAsShown(id, false);
356 }
357
358 void PopupTimersController::OnNotificationDisplayed(const std::string& id) {
359   OnNotificationUpdated(id);
360 }
361
362 void PopupTimersController::OnNotificationUpdated(const std::string& id) {
363   NotificationList::PopupNotifications popup_notifications =
364       message_center_->GetPopupNotifications();
365
366   if (!popup_notifications.size()) {
367     CancelAll();
368     return;
369   }
370
371   NotificationList::PopupNotifications::const_iterator iter =
372       popup_notifications.begin();
373   for (; iter != popup_notifications.end(); iter++) {
374     if ((*iter)->id() == id)
375       break;
376   }
377
378   if (iter == popup_notifications.end() || (*iter)->never_timeout()) {
379     CancelTimer(id);
380     return;
381   }
382
383   // Start the timer if not yet.
384   if (popup_timers_.find(id) == popup_timers_.end())
385     StartTimer(id, GetTimeoutForPriority((*iter)->priority()));
386 }
387
388 void PopupTimersController::OnNotificationRemoved(const std::string& id,
389                                                   bool by_user) {
390   CancelTimer(id);
391 }
392
393 }  // namespace internal
394
395 ////////////////////////////////////////////////////////////////////////////////
396 // MessageCenterImpl::NotificationCache
397
398 MessageCenterImpl::NotificationCache::NotificationCache()
399     : unread_count(0) {}
400
401 MessageCenterImpl::NotificationCache::~NotificationCache() {}
402
403 void MessageCenterImpl::NotificationCache::Rebuild(
404     const NotificationList::Notifications& notifications) {
405   visible_notifications = notifications;
406   RecountUnread();
407 }
408
409 void MessageCenterImpl::NotificationCache::RecountUnread() {
410   unread_count = 0;
411   for (NotificationList::Notifications::const_iterator iter =
412            visible_notifications.begin();
413        iter != visible_notifications.end(); ++iter) {
414     if (!(*iter)->IsRead())
415       ++unread_count;
416   }
417 }
418
419 ////////////////////////////////////////////////////////////////////////////////
420 // MessageCenterImpl
421
422 MessageCenterImpl::MessageCenterImpl()
423     : MessageCenter(),
424       popup_timers_controller_(new internal::PopupTimersController(this)),
425       settings_provider_(NULL) {
426   notification_list_.reset(new NotificationList());
427   notification_queue_.reset(new internal::ChangeQueue());
428 }
429
430 MessageCenterImpl::~MessageCenterImpl() {}
431
432 void MessageCenterImpl::AddObserver(MessageCenterObserver* observer) {
433   observer_list_.AddObserver(observer);
434 }
435
436 void MessageCenterImpl::RemoveObserver(MessageCenterObserver* observer) {
437   observer_list_.RemoveObserver(observer);
438 }
439
440 void MessageCenterImpl::AddNotificationBlocker(NotificationBlocker* blocker) {
441   if (std::find(blockers_.begin(), blockers_.end(), blocker) !=
442       blockers_.end()) {
443     return;
444   }
445   blocker->AddObserver(this);
446   blockers_.push_back(blocker);
447 }
448
449 void MessageCenterImpl::RemoveNotificationBlocker(
450     NotificationBlocker* blocker) {
451   std::vector<NotificationBlocker*>::iterator iter =
452       std::find(blockers_.begin(), blockers_.end(), blocker);
453   if (iter == blockers_.end())
454     return;
455   blocker->RemoveObserver(this);
456   blockers_.erase(iter);
457 }
458
459 void MessageCenterImpl::OnBlockingStateChanged(NotificationBlocker* blocker) {
460   std::list<std::string> blocked_ids;
461   NotificationList::PopupNotifications popups =
462       notification_list_->GetPopupNotifications(blockers_, &blocked_ids);
463
464   for (std::list<std::string>::const_iterator iter = blocked_ids.begin();
465        iter != blocked_ids.end(); ++iter) {
466     // Do not call MessageCenterImpl::MarkSinglePopupAsShown() directly here
467     // just for performance reason. MessageCenterImpl::MarkSinglePopupAsShown()
468     // calls NotificationList::MarkSinglePopupAsShown() and then updates the
469     // unread count, but the whole cache will be recreated below.
470     notification_list_->MarkSinglePopupAsShown((*iter), true);
471     FOR_EACH_OBSERVER(MessageCenterObserver,
472                       observer_list_,
473                       OnNotificationUpdated(*iter));
474   }
475   notification_cache_.Rebuild(
476       notification_list_->GetVisibleNotifications(blockers_));
477   FOR_EACH_OBSERVER(MessageCenterObserver,
478                     observer_list_,
479                     OnBlockingStateChanged(blocker));
480 }
481
482 void MessageCenterImpl::SetVisibility(Visibility visibility) {
483   std::set<std::string> updated_ids;
484   notification_list_->SetMessageCenterVisible(
485       (visibility == VISIBILITY_MESSAGE_CENTER), &updated_ids);
486   notification_cache_.RecountUnread();
487
488   for (std::set<std::string>::const_iterator iter = updated_ids.begin();
489        iter != updated_ids.end();
490        ++iter) {
491     FOR_EACH_OBSERVER(
492         MessageCenterObserver, observer_list_, OnNotificationUpdated(*iter));
493   }
494
495   if (visibility == VISIBILITY_TRANSIENT)
496     notification_queue_->ApplyChanges(this);
497
498   FOR_EACH_OBSERVER(MessageCenterObserver,
499                     observer_list_,
500                     OnCenterVisibilityChanged(visibility));
501 }
502
503 bool MessageCenterImpl::IsMessageCenterVisible() const {
504   return notification_list_->is_message_center_visible();
505 }
506
507 size_t MessageCenterImpl::NotificationCount() const {
508   return notification_cache_.visible_notifications.size();
509 }
510
511 size_t MessageCenterImpl::UnreadNotificationCount() const {
512   return notification_cache_.unread_count;
513 }
514
515 bool MessageCenterImpl::HasPopupNotifications() const {
516   return !IsMessageCenterVisible() &&
517       notification_list_->HasPopupNotifications(blockers_);
518 }
519
520 bool MessageCenterImpl::HasNotification(const std::string& id) {
521   // This will return true if the notification with |id| is hidden by the
522   // ChromeOS multi-profile feature. This would be harmless for now because
523   // this check will be used from the UI, so the |id| for hidden profile won't
524   // arrive here.
525   // TODO(mukai): fix this if necessary.
526   return notification_list_->HasNotification(id);
527 }
528
529 bool MessageCenterImpl::IsQuietMode() const {
530   return notification_list_->quiet_mode();
531 }
532
533 bool MessageCenterImpl::HasClickedListener(const std::string& id) {
534   scoped_refptr<NotificationDelegate> delegate =
535       notification_list_->GetNotificationDelegate(id);
536   return delegate.get() && delegate->HasClickedListener();
537 }
538
539 const NotificationList::Notifications&
540 MessageCenterImpl::GetVisibleNotifications() {
541   return notification_cache_.visible_notifications;
542 }
543
544 NotificationList::PopupNotifications
545     MessageCenterImpl::GetPopupNotifications() {
546   return notification_list_->GetPopupNotifications(blockers_, NULL);
547 }
548
549 //------------------------------------------------------------------------------
550 // Client code interface.
551 void MessageCenterImpl::AddNotification(scoped_ptr<Notification> notification) {
552   DCHECK(notification.get());
553   if (GetMessageCenterShowState() == MESSAGE_CENTER_SHOW_NEVER) {
554     notification->set_shown_as_popup(false);
555     notification->set_never_timeout(true);
556     notification->set_priority(message_center::DEFAULT_PRIORITY);
557   }
558
559   for (size_t i = 0; i < blockers_.size(); ++i)
560     blockers_[i]->CheckState();
561
562   if (notification_list_->is_message_center_visible()) {
563     notification_queue_->AddNotification(notification.Pass());
564     return;
565   }
566
567   // Sometimes the notification can be added with the same id and the
568   // |notification_list| will replace the notification instead of adding new.
569   // This is essentially an update rather than addition.
570   const std::string& id = notification->id();
571   bool already_exists = notification_list_->HasNotification(id);
572   notification_list_->AddNotification(notification.Pass());
573   notification_cache_.Rebuild(
574       notification_list_->GetVisibleNotifications(blockers_));
575
576   if (already_exists) {
577     FOR_EACH_OBSERVER(
578         MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
579   } else {
580     FOR_EACH_OBSERVER(
581         MessageCenterObserver, observer_list_, OnNotificationAdded(id));
582   }
583 }
584
585 void MessageCenterImpl::UpdateNotification(
586     const std::string& old_id,
587     scoped_ptr<Notification> new_notification) {
588   for (size_t i = 0; i < blockers_.size(); ++i)
589     blockers_[i]->CheckState();
590
591   if (notification_list_->is_message_center_visible()) {
592     // We will allow notifications that are progress types (and stay progress
593     // types) to be updated even if the message center is open.  There are 3
594     // requirements here:
595     //  * Notification of type PROGRESS exists with same ID in the center
596     //  * There are no queued updates for this notification (they imply a change
597     //    that violates the PROGRESS invariant
598     //  * The new notification is type PROGRESS.
599     // TODO(dewittj): Ensure this works when the ID is changed by the caller.
600     // This shouldn't be an issue in practice since only W3C notifications
601     // change the ID on update, and they don't have progress type notifications.
602     bool update_keeps_progress_type =
603         new_notification->type() == NOTIFICATION_TYPE_PROGRESS &&
604         !notification_queue_->Has(old_id) &&
605         notification_list_->HasNotificationOfType(old_id,
606                                                   NOTIFICATION_TYPE_PROGRESS);
607     if (!update_keeps_progress_type) {
608       // Updates are allowed only for progress notifications.
609       notification_queue_->UpdateNotification(old_id, new_notification.Pass());
610       return;
611     }
612   }
613
614   std::string new_id = new_notification->id();
615   notification_list_->UpdateNotificationMessage(old_id,
616                                                 new_notification.Pass());
617   notification_cache_.Rebuild(
618      notification_list_->GetVisibleNotifications(blockers_));
619   if (old_id == new_id) {
620     FOR_EACH_OBSERVER(
621         MessageCenterObserver, observer_list_, OnNotificationUpdated(new_id));
622   } else {
623     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
624                       OnNotificationRemoved(old_id, false));
625     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
626                       OnNotificationAdded(new_id));
627   }
628 }
629
630 void MessageCenterImpl::RemoveNotification(const std::string& id,
631                                            bool by_user) {
632   if (!by_user && notification_list_->is_message_center_visible()) {
633     notification_queue_->EraseNotification(id, by_user);
634     return;
635   }
636
637   if (!HasNotification(id))
638     return;
639
640   scoped_refptr<NotificationDelegate> delegate =
641       notification_list_->GetNotificationDelegate(id);
642   if (delegate.get())
643     delegate->Close(by_user);
644
645   // In many cases |id| is a reference to an existing notification instance
646   // but the instance can be destructed in RemoveNotification(). Hence
647   // copies the id explicitly here.
648   std::string copied_id(id);
649   notification_list_->RemoveNotification(copied_id);
650   notification_cache_.Rebuild(
651       notification_list_->GetVisibleNotifications(blockers_));
652   FOR_EACH_OBSERVER(MessageCenterObserver,
653                     observer_list_,
654                     OnNotificationRemoved(copied_id, by_user));
655 }
656
657 void MessageCenterImpl::RemoveAllNotifications(bool by_user) {
658   // Using not |blockers_| but an empty list since it wants to remove literally
659   // all notifications.
660   RemoveNotifications(by_user, NotificationBlockers());
661 }
662
663 void MessageCenterImpl::RemoveAllVisibleNotifications(bool by_user) {
664   RemoveNotifications(by_user, blockers_);
665 }
666
667 void MessageCenterImpl::RemoveNotifications(
668     bool by_user,
669     const NotificationBlockers& blockers) {
670   const NotificationList::Notifications notifications =
671       notification_list_->GetVisibleNotifications(blockers);
672   std::set<std::string> ids;
673   for (NotificationList::Notifications::const_iterator iter =
674            notifications.begin(); iter != notifications.end(); ++iter) {
675     ids.insert((*iter)->id());
676     scoped_refptr<NotificationDelegate> delegate = (*iter)->delegate();
677     if (delegate.get())
678       delegate->Close(by_user);
679     notification_list_->RemoveNotification((*iter)->id());
680   }
681
682   if (!ids.empty()) {
683     notification_cache_.Rebuild(
684         notification_list_->GetVisibleNotifications(blockers_));
685   }
686   for (std::set<std::string>::const_iterator iter = ids.begin();
687        iter != ids.end(); ++iter) {
688     FOR_EACH_OBSERVER(MessageCenterObserver,
689                       observer_list_,
690                       OnNotificationRemoved(*iter, by_user));
691   }
692 }
693
694 void MessageCenterImpl::SetNotificationIcon(const std::string& notification_id,
695                                         const gfx::Image& image) {
696   bool updated = false;
697   Notification* queue_notification = notification_queue_->GetLatestNotification(
698       notification_id);
699
700   if (queue_notification) {
701     queue_notification->set_icon(image);
702     updated = true;
703   } else {
704     updated = notification_list_->SetNotificationIcon(notification_id, image);
705   }
706
707   if (updated) {
708     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
709                       OnNotificationUpdated(notification_id));
710   }
711 }
712
713 void MessageCenterImpl::SetNotificationImage(const std::string& notification_id,
714                                          const gfx::Image& image) {
715   bool updated = false;
716   Notification* queue_notification = notification_queue_->GetLatestNotification(
717       notification_id);
718
719   if (queue_notification) {
720     queue_notification->set_image(image);
721     updated = true;
722   } else {
723     updated = notification_list_->SetNotificationImage(notification_id, image);
724   }
725
726   if (updated) {
727     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
728                       OnNotificationUpdated(notification_id));
729   }
730 }
731
732 void MessageCenterImpl::SetNotificationButtonIcon(
733     const std::string& notification_id, int button_index,
734     const gfx::Image& image) {
735   bool updated = false;
736   Notification* queue_notification = notification_queue_->GetLatestNotification(
737       notification_id);
738
739   if (queue_notification) {
740     queue_notification->SetButtonIcon(button_index, image);
741     updated = true;
742   } else {
743     updated = notification_list_->SetNotificationButtonIcon(
744         notification_id, button_index, image);
745   }
746
747   if (updated) {
748     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
749                       OnNotificationUpdated(notification_id));
750   }
751 }
752
753 void MessageCenterImpl::DisableNotificationsByNotifier(
754     const NotifierId& notifier_id) {
755   if (settings_provider_) {
756     // TODO(mukai): SetNotifierEnabled can just accept notifier_id?
757     Notifier notifier(notifier_id, base::string16(), true);
758     settings_provider_->SetNotifierEnabled(notifier, false);
759   }
760
761   NotificationList::Notifications notifications =
762       notification_list_->GetNotificationsByNotifierId(notifier_id);
763   for (NotificationList::Notifications::const_iterator iter =
764            notifications.begin(); iter != notifications.end();) {
765     std::string id = (*iter)->id();
766     iter++;
767     RemoveNotification(id, false);
768   }
769   if (!notifications.empty()) {
770     notification_cache_.Rebuild(
771         notification_list_->GetVisibleNotifications(blockers_));
772   }
773 }
774
775 void MessageCenterImpl::ClickOnNotification(const std::string& id) {
776   if (!HasNotification(id))
777     return;
778   if (HasPopupNotifications())
779     MarkSinglePopupAsShown(id, true);
780   scoped_refptr<NotificationDelegate> delegate =
781       notification_list_->GetNotificationDelegate(id);
782   if (delegate.get())
783     delegate->Click();
784   FOR_EACH_OBSERVER(
785       MessageCenterObserver, observer_list_, OnNotificationClicked(id));
786 }
787
788 void MessageCenterImpl::ClickOnNotificationButton(const std::string& id,
789                                               int button_index) {
790   if (!HasNotification(id))
791     return;
792   if (HasPopupNotifications())
793     MarkSinglePopupAsShown(id, true);
794   scoped_refptr<NotificationDelegate> delegate =
795       notification_list_->GetNotificationDelegate(id);
796   if (delegate.get())
797     delegate->ButtonClick(button_index);
798   FOR_EACH_OBSERVER(
799       MessageCenterObserver, observer_list_, OnNotificationButtonClicked(
800           id, button_index));
801 }
802
803 void MessageCenterImpl::MarkSinglePopupAsShown(const std::string& id,
804                                                bool mark_notification_as_read) {
805   if (!HasNotification(id))
806     return;
807   notification_list_->MarkSinglePopupAsShown(id, mark_notification_as_read);
808   notification_cache_.RecountUnread();
809   FOR_EACH_OBSERVER(
810       MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
811 }
812
813 void MessageCenterImpl::DisplayedNotification(const std::string& id) {
814   if (!HasNotification(id))
815     return;
816
817   if (HasPopupNotifications())
818     notification_list_->MarkSinglePopupAsDisplayed(id);
819   notification_cache_.RecountUnread();
820   scoped_refptr<NotificationDelegate> delegate =
821       notification_list_->GetNotificationDelegate(id);
822   if (delegate.get())
823     delegate->Display();
824   FOR_EACH_OBSERVER(
825       MessageCenterObserver, observer_list_, OnNotificationDisplayed(id));
826 }
827
828 void MessageCenterImpl::SetNotifierSettingsProvider(
829     NotifierSettingsProvider* provider) {
830   settings_provider_ = provider;
831 }
832
833 NotifierSettingsProvider* MessageCenterImpl::GetNotifierSettingsProvider() {
834   return settings_provider_;
835 }
836
837 void MessageCenterImpl::SetQuietMode(bool in_quiet_mode) {
838   if (in_quiet_mode != notification_list_->quiet_mode()) {
839     notification_list_->SetQuietMode(in_quiet_mode);
840     FOR_EACH_OBSERVER(MessageCenterObserver,
841                       observer_list_,
842                       OnQuietModeChanged(in_quiet_mode));
843   }
844   quiet_mode_timer_.reset();
845 }
846
847 void MessageCenterImpl::EnterQuietModeWithExpire(
848     const base::TimeDelta& expires_in) {
849   if (quiet_mode_timer_.get()) {
850     // Note that the capital Reset() is the method to restart the timer, not
851     // scoped_ptr::reset().
852     quiet_mode_timer_->Reset();
853   } else {
854     notification_list_->SetQuietMode(true);
855     FOR_EACH_OBSERVER(
856         MessageCenterObserver, observer_list_, OnQuietModeChanged(true));
857
858     quiet_mode_timer_.reset(new base::OneShotTimer<MessageCenterImpl>);
859     quiet_mode_timer_->Start(
860         FROM_HERE,
861         expires_in,
862         base::Bind(
863             &MessageCenterImpl::SetQuietMode, base::Unretained(this), false));
864   }
865 }
866
867 void MessageCenterImpl::RestartPopupTimers() {
868   if (popup_timers_controller_.get())
869     popup_timers_controller_->StartAll();
870 }
871
872 void MessageCenterImpl::PausePopupTimers() {
873   if (popup_timers_controller_.get())
874     popup_timers_controller_->PauseAll();
875 }
876
877 void MessageCenterImpl::DisableTimersForTest() {
878   popup_timers_controller_.reset();
879 }
880
881 }  // namespace message_center