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