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