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