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