• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetTimeoutForPriority(int priority)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 
notification() const60     Notification* notification() const { return notification_.get(); }
id() const61     const std::string& id() const { return id_; }
type() const62     ChangeType type() const { return type_; }
by_user() const63     bool by_user() const { return by_user_; }
set_by_user(bool by_user)64     void set_by_user(bool by_user) { by_user_ = by_user; }
notification_list_id() const65     const std::string& notification_list_id() const {
66       return notification_list_id_;
67     }
set_notification_list_id(const std::string & id)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 {
ChangeFindermessage_center::internal::ChangeFinder119   explicit ChangeFinder(const std::string& id) : id(id) {}
operator ()message_center::internal::ChangeFinder120   bool operator()(ChangeQueue::Change* change) { return change->id() == id; }
121 
122   std::string id;
123 };
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 // ChangeQueue::Change
127 
Change(ChangeType type,const std::string & id,scoped_ptr<Notification> notification)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 
~Change()140 ChangeQueue::Change::~Change() {}
141 
PassNotification()142 scoped_ptr<Notification> ChangeQueue::Change::PassNotification() {
143   return notification_.Pass();
144 }
145 
146 ////////////////////////////////////////////////////////////////////////////////
147 // ChangeQueue
148 
ChangeQueue()149 ChangeQueue::ChangeQueue() {}
150 
~ChangeQueue()151 ChangeQueue::~ChangeQueue() {}
152 
ApplyChanges(MessageCenter * message_center)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 
AddNotification(scoped_ptr<Notification> notification)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 
UpdateNotification(const std::string & old_id,scoped_ptr<Notification> notification)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 
EraseNotification(const std::string & id,bool by_user)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 
Has(const std::string & id) const202 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 
GetLatestNotification(const std::string & id) const208 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 
Replace(const std::string & changed_id,scoped_ptr<Change> new_change)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 
PopupTimer(const std::string & id,base::TimeDelta timeout,base::WeakPtr<PopupTimersController> controller)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 
~PopupTimer()243 PopupTimer::~PopupTimer() {
244   if (!timer_)
245     return;
246 
247   if (timer_->IsRunning())
248     timer_->Stop();
249 }
250 
Start()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 
Pause()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 
Reset()272 void PopupTimer::Reset() {
273   if (timer_)
274     timer_->Stop();
275   passed_ = base::TimeDelta();
276 }
277 
278 ////////////////////////////////////////////////////////////////////////////////
279 // PopupTimersController
280 
PopupTimersController(MessageCenter * message_center)281 PopupTimersController::PopupTimersController(MessageCenter* message_center)
282     : message_center_(message_center), popup_deleter_(&popup_timers_) {
283   message_center_->AddObserver(this);
284 }
285 
~PopupTimersController()286 PopupTimersController::~PopupTimersController() {
287   message_center_->RemoveObserver(this);
288 }
289 
StartTimer(const std::string & id,const base::TimeDelta & timeout)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 
StartAll()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 
ResetTimer(const std::string & id,const base::TimeDelta & timeout)312 void PopupTimersController::ResetTimer(const std::string& id,
313                                        const base::TimeDelta& timeout) {
314   CancelTimer(id);
315   StartTimer(id, timeout);
316 }
317 
PauseTimer(const std::string & id)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 
PauseAll()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 
CancelTimer(const std::string & id)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 
CancelAll()343 void PopupTimersController::CancelAll() {
344   STLDeleteValues(&popup_timers_);
345   popup_timers_.clear();
346 }
347 
TimerFinished(const std::string & id)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 
OnNotificationDisplayed(const std::string & id,const DisplaySource source)357 void PopupTimersController::OnNotificationDisplayed(
358     const std::string& id,
359     const DisplaySource source) {
360   OnNotificationUpdated(id);
361 }
362 
OnNotificationUpdated(const std::string & id)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 
OnNotificationRemoved(const std::string & id,bool by_user)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 
NotificationCache()399 MessageCenterImpl::NotificationCache::NotificationCache()
400     : unread_count(0) {}
401 
~NotificationCache()402 MessageCenterImpl::NotificationCache::~NotificationCache() {}
403 
Rebuild(const NotificationList::Notifications & notifications)404 void MessageCenterImpl::NotificationCache::Rebuild(
405     const NotificationList::Notifications& notifications) {
406   visible_notifications = notifications;
407   RecountUnread();
408 }
409 
RecountUnread()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 
MessageCenterImpl()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 
~MessageCenterImpl()431 MessageCenterImpl::~MessageCenterImpl() {
432   SetNotifierSettingsProvider(NULL);
433 }
434 
AddObserver(MessageCenterObserver * observer)435 void MessageCenterImpl::AddObserver(MessageCenterObserver* observer) {
436   observer_list_.AddObserver(observer);
437 }
438 
RemoveObserver(MessageCenterObserver * observer)439 void MessageCenterImpl::RemoveObserver(MessageCenterObserver* observer) {
440   observer_list_.RemoveObserver(observer);
441 }
442 
AddNotificationBlocker(NotificationBlocker * blocker)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 
RemoveNotificationBlocker(NotificationBlocker * blocker)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 
OnBlockingStateChanged(NotificationBlocker * blocker)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 
UpdateIconImage(const NotifierId & notifier_id,const gfx::Image & icon)485 void MessageCenterImpl::UpdateIconImage(
486   const NotifierId& notifier_id,const gfx::Image& icon) {}
487 
NotifierGroupChanged()488 void MessageCenterImpl::NotifierGroupChanged() {}
489 
NotifierEnabledChanged(const NotifierId & notifier_id,bool enabled)490 void MessageCenterImpl::NotifierEnabledChanged(
491   const NotifierId& notifier_id, bool enabled) {
492   if (!enabled) {
493     RemoveNotificationsForNotifierId(notifier_id);
494   }
495 }
496 
SetVisibility(Visibility visibility)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 
IsMessageCenterVisible() const518 bool MessageCenterImpl::IsMessageCenterVisible() const {
519   return notification_list_->is_message_center_visible();
520 }
521 
NotificationCount() const522 size_t MessageCenterImpl::NotificationCount() const {
523   return notification_cache_.visible_notifications.size();
524 }
525 
UnreadNotificationCount() const526 size_t MessageCenterImpl::UnreadNotificationCount() const {
527   return notification_cache_.unread_count;
528 }
529 
HasPopupNotifications() const530 bool MessageCenterImpl::HasPopupNotifications() const {
531   return !IsMessageCenterVisible() &&
532       notification_list_->HasPopupNotifications(blockers_);
533 }
534 
IsQuietMode() const535 bool MessageCenterImpl::IsQuietMode() const {
536   return notification_list_->quiet_mode();
537 }
538 
HasClickedListener(const std::string & id)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 
FindVisibleNotificationById(const std::string & id)545 message_center::Notification* MessageCenterImpl::FindVisibleNotificationById(
546     const std::string& id) {
547   return notification_list_->GetNotificationById(id);
548 }
549 
550 const NotificationList::Notifications&
GetVisibleNotifications()551 MessageCenterImpl::GetVisibleNotifications() {
552   return notification_cache_.visible_notifications;
553 }
554 
555 NotificationList::PopupNotifications
GetPopupNotifications()556     MessageCenterImpl::GetPopupNotifications() {
557   return notification_list_->GetPopupNotifications(blockers_, NULL);
558 }
559 
560 //------------------------------------------------------------------------------
561 // Client code interface.
AddNotification(scoped_ptr<Notification> notification)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 
UpdateNotification(const std::string & old_id,scoped_ptr<Notification> new_notification)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 
RemoveNotification(const std::string & id,bool by_user)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 
RemoveNotificationsForNotifierId(const NotifierId & notifier_id)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 
RemoveAllNotifications(bool by_user)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 
RemoveAllVisibleNotifications(bool by_user)683 void MessageCenterImpl::RemoveAllVisibleNotifications(bool by_user) {
684   RemoveNotifications(by_user, blockers_);
685 }
686 
RemoveNotifications(bool by_user,const NotificationBlockers & blockers)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 
SetNotificationIcon(const std::string & notification_id,const gfx::Image & image)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 
SetNotificationImage(const std::string & notification_id,const gfx::Image & image)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 
SetNotificationButtonIcon(const std::string & notification_id,int button_index,const gfx::Image & image)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 
DisableNotificationsByNotifier(const NotifierId & notifier_id)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 
ClickOnNotification(const std::string & id)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 
ClickOnNotificationButton(const std::string & id,int button_index)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 
MarkSinglePopupAsShown(const std::string & id,bool mark_notification_as_read)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 
DisplayedNotification(const std::string & id,const DisplaySource source)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 
SetNotifierSettingsProvider(NotifierSettingsProvider * provider)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 
GetNotifierSettingsProvider()854 NotifierSettingsProvider* MessageCenterImpl::GetNotifierSettingsProvider() {
855   return settings_provider_;
856 }
857 
SetQuietMode(bool in_quiet_mode)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 
EnterQuietModeWithExpire(const base::TimeDelta & expires_in)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 
RestartPopupTimers()888 void MessageCenterImpl::RestartPopupTimers() {
889   if (popup_timers_controller_.get())
890     popup_timers_controller_->StartAll();
891 }
892 
PausePopupTimers()893 void MessageCenterImpl::PausePopupTimers() {
894   if (popup_timers_controller_.get())
895     popup_timers_controller_->PauseAll();
896 }
897 
DisableTimersForTest()898 void MessageCenterImpl::DisableTimersForTest() {
899   popup_timers_controller_.reset();
900 }
901 
902 }  // namespace message_center
903