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