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