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 "base/observer_list.h"
      8 #include "ui/message_center/message_center_style.h"
      9 #include "ui/message_center/notification.h"
     10 #include "ui/message_center/notification_list.h"
     11 #include "ui/message_center/notification_types.h"
     12 
     13 namespace {
     14 
     15 base::TimeDelta GetTimeoutForPriority(int priority) {
     16   if (priority > message_center::DEFAULT_PRIORITY) {
     17     return base::TimeDelta::FromSeconds(
     18         message_center::kAutocloseHighPriorityDelaySeconds);
     19   }
     20   return base::TimeDelta::FromSeconds(
     21       message_center::kAutocloseDefaultDelaySeconds);
     22 }
     23 
     24 }  // namespace
     25 
     26 namespace message_center {
     27 namespace internal {
     28 
     29 ////////////////////////////////////////////////////////////////////////////////
     30 // PopupTimer
     31 
     32 PopupTimer::PopupTimer(const std::string& id,
     33                        base::TimeDelta timeout,
     34                        base::WeakPtr<PopupTimersController> controller)
     35     : id_(id),
     36       timeout_(timeout),
     37       timer_controller_(controller),
     38       timer_(new base::OneShotTimer<PopupTimersController>) {}
     39 
     40 PopupTimer::~PopupTimer() {
     41   if (!timer_)
     42     return;
     43 
     44   if (timer_->IsRunning())
     45     timer_->Stop();
     46 }
     47 
     48 void PopupTimer::Start() {
     49   if (timer_->IsRunning())
     50     return;
     51   base::TimeDelta timeout_to_close =
     52       timeout_ <= passed_ ? base::TimeDelta() : timeout_ - passed_;
     53   start_time_ = base::Time::Now();
     54   timer_->Start(
     55       FROM_HERE,
     56       timeout_to_close,
     57       base::Bind(
     58           &PopupTimersController::TimerFinished, timer_controller_, id_));
     59 }
     60 
     61 void PopupTimer::Pause() {
     62   if (!timer_.get() || !timer_->IsRunning())
     63     return;
     64 
     65   timer_->Stop();
     66   passed_ += base::Time::Now() - start_time_;
     67 }
     68 
     69 void PopupTimer::Reset() {
     70   if (timer_)
     71     timer_->Stop();
     72   passed_ = base::TimeDelta();
     73 }
     74 
     75 ////////////////////////////////////////////////////////////////////////////////
     76 // PopupTimersController
     77 
     78 PopupTimersController::PopupTimersController(MessageCenter* message_center)
     79     : message_center_(message_center), popup_deleter_(&popup_timers_) {
     80   message_center_->AddObserver(this);
     81 }
     82 
     83 PopupTimersController::~PopupTimersController() {
     84   message_center_->RemoveObserver(this);
     85 }
     86 
     87 void PopupTimersController::StartTimer(const std::string& id,
     88                                        const base::TimeDelta& timeout) {
     89   PopupTimerCollection::iterator iter = popup_timers_.find(id);
     90   if (iter != popup_timers_.end()) {
     91     DCHECK(iter->second);
     92     iter->second->Start();
     93     return;
     94   }
     95 
     96   PopupTimer* timer = new PopupTimer(id, timeout, AsWeakPtr());
     97 
     98   timer->Start();
     99   popup_timers_[id] = timer;
    100 }
    101 
    102 void PopupTimersController::StartAll() {
    103   std::map<std::string, PopupTimer*>::iterator iter;
    104   for (iter = popup_timers_.begin(); iter != popup_timers_.end(); iter++) {
    105     iter->second->Start();
    106   }
    107 }
    108 
    109 void PopupTimersController::ResetTimer(const std::string& id,
    110                                        const base::TimeDelta& timeout) {
    111   CancelTimer(id);
    112   StartTimer(id, timeout);
    113 }
    114 
    115 void PopupTimersController::PauseTimer(const std::string& id) {
    116   PopupTimerCollection::iterator iter = popup_timers_.find(id);
    117   if (iter == popup_timers_.end())
    118     return;
    119   iter->second->Pause();
    120 }
    121 
    122 void PopupTimersController::PauseAll() {
    123   std::map<std::string, PopupTimer*>::iterator iter;
    124   for (iter = popup_timers_.begin(); iter != popup_timers_.end(); iter++) {
    125     iter->second->Pause();
    126   }
    127 }
    128 
    129 void PopupTimersController::CancelTimer(const std::string& id) {
    130   PopupTimerCollection::iterator iter = popup_timers_.find(id);
    131   if (iter == popup_timers_.end())
    132     return;
    133 
    134   PopupTimer* timer = iter->second;
    135   delete timer;
    136 
    137   popup_timers_.erase(iter);
    138 }
    139 
    140 void PopupTimersController::CancelAll() {
    141   STLDeleteValues(&popup_timers_);
    142   popup_timers_.clear();
    143 }
    144 
    145 void PopupTimersController::TimerFinished(const std::string& id) {
    146   PopupTimerCollection::iterator iter = popup_timers_.find(id);
    147   if (iter == popup_timers_.end())
    148     return;
    149 
    150   CancelTimer(id);
    151   message_center_->MarkSinglePopupAsShown(id, false);
    152 }
    153 
    154 void PopupTimersController::OnNotificationDisplayed(const std::string& id) {
    155   OnNotificationUpdated(id);
    156 }
    157 
    158 void PopupTimersController::OnNotificationUpdated(const std::string& id) {
    159   NotificationList::PopupNotifications popup_notifications =
    160       message_center_->GetPopupNotifications();
    161 
    162   if (!popup_notifications.size()) {
    163     CancelAll();
    164     return;
    165   }
    166 
    167   NotificationList::PopupNotifications::const_iterator iter =
    168       popup_notifications.begin();
    169   for (; iter != popup_notifications.end(); iter++) {
    170     if ((*iter)->id() == id)
    171       break;
    172   }
    173 
    174   if (iter == popup_notifications.end() || (*iter)->never_timeout()) {
    175     CancelTimer(id);
    176     return;
    177   }
    178 
    179   // Start the timer if not yet.
    180   if (popup_timers_.find(id) == popup_timers_.end())
    181     StartTimer(id, GetTimeoutForPriority((*iter)->priority()));
    182 }
    183 
    184 void PopupTimersController::OnNotificationRemoved(const std::string& id,
    185                                                   bool by_user) {
    186   CancelTimer(id);
    187 }
    188 
    189 }  // namespace internal
    190 
    191 ////////////////////////////////////////////////////////////////////////////////
    192 // MessageCenterImpl
    193 
    194 MessageCenterImpl::MessageCenterImpl()
    195     : MessageCenter(),
    196       popup_timers_controller_(new internal::PopupTimersController(this)),
    197       delegate_(NULL),
    198       settings_provider_(NULL) {
    199   notification_list_.reset(new NotificationList());
    200 }
    201 
    202 MessageCenterImpl::~MessageCenterImpl() {
    203   notification_list_.reset();
    204 }
    205 
    206 void MessageCenterImpl::AddObserver(MessageCenterObserver* observer) {
    207   observer_list_.AddObserver(observer);
    208 }
    209 
    210 void MessageCenterImpl::RemoveObserver(MessageCenterObserver* observer) {
    211   observer_list_.RemoveObserver(observer);
    212 }
    213 
    214 void MessageCenterImpl::SetDelegate(Delegate* delegate) {
    215   delegate_ = delegate;
    216 }
    217 
    218 void MessageCenterImpl::SetMessageCenterVisible(bool visible) {
    219   std::set<std::string> updated_ids;
    220   notification_list_->SetMessageCenterVisible(visible, &updated_ids);
    221   for (std::set<std::string>::const_iterator iter = updated_ids.begin();
    222        iter != updated_ids.end();
    223        ++iter) {
    224     FOR_EACH_OBSERVER(
    225         MessageCenterObserver, observer_list_, OnNotificationUpdated(*iter));
    226   }
    227 
    228   if (!visible) {
    229     FOR_EACH_OBSERVER(
    230         MessageCenterObserver, observer_list_, OnNotificationCenterClosed());
    231   }
    232 }
    233 
    234 bool MessageCenterImpl::IsMessageCenterVisible() {
    235   return notification_list_->is_message_center_visible();
    236 }
    237 
    238 size_t MessageCenterImpl::NotificationCount() const {
    239   return notification_list_->NotificationCount();
    240 }
    241 
    242 size_t MessageCenterImpl::UnreadNotificationCount() const {
    243   return notification_list_->unread_count();
    244 }
    245 
    246 bool MessageCenterImpl::HasPopupNotifications() const {
    247   return notification_list_->HasPopupNotifications();
    248 }
    249 
    250 bool MessageCenterImpl::HasNotification(const std::string& id) {
    251   return notification_list_->HasNotification(id);
    252 }
    253 
    254 bool MessageCenterImpl::IsQuietMode() const {
    255   return notification_list_->quiet_mode();
    256 }
    257 
    258 bool MessageCenterImpl::HasClickedListener(const std::string& id) {
    259   NotificationDelegate* delegate =
    260       notification_list_->GetNotificationDelegate(id);
    261   return delegate && delegate->HasClickedListener();
    262 }
    263 
    264 const NotificationList::Notifications& MessageCenterImpl::GetNotifications() {
    265   return notification_list_->GetNotifications();
    266 }
    267 
    268 NotificationList::PopupNotifications
    269     MessageCenterImpl::GetPopupNotifications() {
    270   return notification_list_->GetPopupNotifications();
    271 }
    272 
    273 //------------------------------------------------------------------------------
    274 // Client code interface.
    275 void MessageCenterImpl::AddNotification(scoped_ptr<Notification> notification) {
    276   DCHECK(notification.get());
    277 
    278   // Sometimes the notification can be added with the same id and the
    279   // |notification_list| will replace the notification instead of adding new.
    280   // This is essentially an update rather than addition.
    281   const std::string& id = notification->id();
    282   bool already_exists = notification_list_->HasNotification(id);
    283   notification_list_->AddNotification(notification.Pass());
    284 
    285   if (already_exists) {
    286     FOR_EACH_OBSERVER(
    287         MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
    288   } else {
    289     FOR_EACH_OBSERVER(
    290         MessageCenterObserver, observer_list_, OnNotificationAdded(id));
    291   }
    292 }
    293 
    294 void MessageCenterImpl::UpdateNotification(
    295     const std::string& old_id,
    296     scoped_ptr<Notification> new_notification) {
    297   std::string new_id = new_notification->id();
    298   notification_list_->UpdateNotificationMessage(old_id,
    299                                                 new_notification.Pass());
    300   if (old_id == new_id) {
    301     FOR_EACH_OBSERVER(
    302         MessageCenterObserver, observer_list_, OnNotificationUpdated(new_id));
    303   } else {
    304     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
    305                       OnNotificationRemoved(old_id, false));
    306     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
    307                       OnNotificationAdded(new_id));
    308   }
    309 }
    310 
    311 void MessageCenterImpl::RemoveNotification(const std::string& id,
    312                                            bool by_user) {
    313   if (!HasNotification(id))
    314     return;
    315 
    316   NotificationDelegate* delegate =
    317       notification_list_->GetNotificationDelegate(id);
    318   if (delegate)
    319     delegate->Close(by_user);
    320 
    321   // In many cases |id| is a reference to an existing notification instance
    322   // but the instance can be destructed in RemoveNotification(). Hence
    323   // copies the id explicitly here.
    324   std::string copied_id(id);
    325   notification_list_->RemoveNotification(copied_id);
    326   FOR_EACH_OBSERVER(MessageCenterObserver,
    327                     observer_list_,
    328                     OnNotificationRemoved(copied_id, by_user));
    329 }
    330 
    331 void MessageCenterImpl::RemoveAllNotifications(bool by_user) {
    332   const NotificationList::Notifications& notifications =
    333       notification_list_->GetNotifications();
    334   std::set<std::string> ids;
    335   for (NotificationList::Notifications::const_iterator iter =
    336            notifications.begin(); iter != notifications.end(); ++iter) {
    337     ids.insert((*iter)->id());
    338   }
    339   notification_list_->RemoveAllNotifications();
    340 
    341   for (std::set<std::string>::const_iterator iter = ids.begin();
    342        iter != ids.end(); ++iter) {
    343     FOR_EACH_OBSERVER(MessageCenterObserver,
    344                       observer_list_,
    345                       OnNotificationRemoved(*iter, by_user));
    346   }
    347 }
    348 
    349 void MessageCenterImpl::SetNotificationIcon(const std::string& notification_id,
    350                                         const gfx::Image& image) {
    351   if (notification_list_->SetNotificationIcon(notification_id, image)) {
    352     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
    353                       OnNotificationUpdated(notification_id));
    354   }
    355 }
    356 
    357 void MessageCenterImpl::SetNotificationImage(const std::string& notification_id,
    358                                          const gfx::Image& image) {
    359   if (notification_list_->SetNotificationImage(notification_id, image)) {
    360     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
    361                       OnNotificationUpdated(notification_id));
    362   }
    363 }
    364 
    365 void MessageCenterImpl::SetNotificationButtonIcon(
    366     const std::string& notification_id, int button_index,
    367     const gfx::Image& image) {
    368   if (!HasNotification(notification_id))
    369     return;
    370   if (notification_list_->SetNotificationButtonIcon(notification_id,
    371                                                     button_index, image)) {
    372     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
    373                       OnNotificationUpdated(notification_id));
    374   }
    375 }
    376 
    377 void MessageCenterImpl::DisableNotificationsByExtension(
    378     const std::string& id) {
    379   if (delegate_)
    380     delegate_->DisableExtension(id);
    381 
    382   NotificationList::Notifications notifications =
    383       notification_list_->GetNotificationsByExtension(id);
    384   for (NotificationList::Notifications::const_iterator iter =
    385            notifications.begin(); iter != notifications.end();) {
    386     std::string id = (*iter)->id();
    387     iter++;
    388     RemoveNotification(id, false);
    389   }
    390 }
    391 
    392 void MessageCenterImpl::DisableNotificationsByUrl(const std::string& id) {
    393   if (delegate_)
    394     delegate_->DisableNotificationsFromSource(id);
    395 
    396   NotificationList::Notifications notifications =
    397       notification_list_->GetNotificationsBySource(id);
    398   for (NotificationList::Notifications::const_iterator iter =
    399            notifications.begin(); iter != notifications.end();) {
    400     std::string id = (*iter)->id();
    401     iter++;
    402     RemoveNotification(id, false);
    403   }
    404 }
    405 
    406 void MessageCenterImpl::ShowNotificationSettings(const std::string& id) {
    407   if (delegate_)
    408     delegate_->ShowSettings(id);
    409 }
    410 
    411 void MessageCenterImpl::ExpandNotification(const std::string& id) {
    412   if (!HasNotification(id))
    413     return;
    414   notification_list_->MarkNotificationAsExpanded(id);
    415   FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
    416                     OnNotificationUpdated(id));
    417 }
    418 
    419 void MessageCenterImpl::ClickOnNotification(const std::string& id) {
    420   if (!HasNotification(id))
    421     return;
    422   if (HasPopupNotifications())
    423     MarkSinglePopupAsShown(id, true);
    424   NotificationDelegate* delegate =
    425       notification_list_->GetNotificationDelegate(id);
    426   if (delegate)
    427     delegate->Click();
    428   FOR_EACH_OBSERVER(
    429       MessageCenterObserver, observer_list_, OnNotificationClicked(id));
    430 }
    431 
    432 void MessageCenterImpl::ClickOnNotificationButton(const std::string& id,
    433                                               int button_index) {
    434   if (!HasNotification(id))
    435     return;
    436   if (HasPopupNotifications())
    437     MarkSinglePopupAsShown(id, true);
    438   NotificationDelegate* delegate =
    439       notification_list_->GetNotificationDelegate(id);
    440   if (delegate)
    441     delegate->ButtonClick(button_index);
    442   FOR_EACH_OBSERVER(
    443       MessageCenterObserver, observer_list_, OnNotificationButtonClicked(
    444           id, button_index));
    445 }
    446 
    447 void MessageCenterImpl::MarkSinglePopupAsShown(const std::string& id,
    448                                                bool mark_notification_as_read) {
    449   if (!HasNotification(id))
    450     return;
    451   notification_list_->MarkSinglePopupAsShown(id, mark_notification_as_read);
    452   FOR_EACH_OBSERVER(
    453       MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
    454 }
    455 
    456 void MessageCenterImpl::DisplayedNotification(const std::string& id) {
    457   if (!HasNotification(id))
    458     return;
    459 
    460   if (HasPopupNotifications())
    461     notification_list_->MarkSinglePopupAsDisplayed(id);
    462   NotificationDelegate* delegate =
    463       notification_list_->GetNotificationDelegate(id);
    464   if (delegate)
    465     delegate->Display();
    466   FOR_EACH_OBSERVER(
    467       MessageCenterObserver, observer_list_, OnNotificationDisplayed(id));
    468 }
    469 
    470 void MessageCenterImpl::SetNotifierSettingsProvider(
    471     NotifierSettingsProvider* provider) {
    472   settings_provider_ = provider;
    473 }
    474 
    475 NotifierSettingsProvider* MessageCenterImpl::GetNotifierSettingsProvider() {
    476   return settings_provider_;
    477 }
    478 
    479 void MessageCenterImpl::SetQuietMode(bool in_quiet_mode) {
    480   notification_list_->SetQuietMode(in_quiet_mode);
    481 }
    482 
    483 void MessageCenterImpl::EnterQuietModeWithExpire(
    484     const base::TimeDelta& expires_in) {
    485   notification_list_->EnterQuietModeWithExpire(expires_in);
    486 }
    487 
    488 void MessageCenterImpl::RestartPopupTimers() {
    489   if (popup_timers_controller_.get())
    490     popup_timers_controller_->StartAll();
    491 }
    492 
    493 void MessageCenterImpl::PausePopupTimers() {
    494   if (popup_timers_controller_.get())
    495     popup_timers_controller_->PauseAll();
    496 }
    497 
    498 void MessageCenterImpl::DisableTimersForTest() {
    499   popup_timers_controller_.reset();
    500 }
    501 
    502 }  // namespace message_center
    503