Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / message_center / message_center_impl.cc
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
433 void MessageCenterImpl::AddObserver(MessageCenterObserver* observer) {
434   observer_list_.AddObserver(observer);
435 }
436
437 void MessageCenterImpl::RemoveObserver(MessageCenterObserver* observer) {
438   observer_list_.RemoveObserver(observer);
439 }
440
441 void MessageCenterImpl::AddNotificationBlocker(NotificationBlocker* blocker) {
442   if (std::find(blockers_.begin(), blockers_.end(), blocker) !=
443       blockers_.end()) {
444     return;
445   }
446   blocker->AddObserver(this);
447   blockers_.push_back(blocker);
448 }
449
450 void MessageCenterImpl::RemoveNotificationBlocker(
451     NotificationBlocker* blocker) {
452   std::vector<NotificationBlocker*>::iterator iter =
453       std::find(blockers_.begin(), blockers_.end(), blocker);
454   if (iter == blockers_.end())
455     return;
456   blocker->RemoveObserver(this);
457   blockers_.erase(iter);
458 }
459
460 void MessageCenterImpl::OnBlockingStateChanged(NotificationBlocker* blocker) {
461   std::list<std::string> blocked_ids;
462   NotificationList::PopupNotifications popups =
463       notification_list_->GetPopupNotifications(blockers_, &blocked_ids);
464
465   for (std::list<std::string>::const_iterator iter = blocked_ids.begin();
466        iter != blocked_ids.end(); ++iter) {
467     // Do not call MessageCenterImpl::MarkSinglePopupAsShown() directly here
468     // just for performance reason. MessageCenterImpl::MarkSinglePopupAsShown()
469     // calls NotificationList::MarkSinglePopupAsShown() and then updates the
470     // unread count, but the whole cache will be recreated below.
471     notification_list_->MarkSinglePopupAsShown((*iter), true);
472     FOR_EACH_OBSERVER(MessageCenterObserver,
473                       observer_list_,
474                       OnNotificationUpdated(*iter));
475   }
476   notification_cache_.Rebuild(
477       notification_list_->GetVisibleNotifications(blockers_));
478   FOR_EACH_OBSERVER(MessageCenterObserver,
479                     observer_list_,
480                     OnBlockingStateChanged(blocker));
481 }
482
483 void MessageCenterImpl::SetVisibility(Visibility visibility) {
484   std::set<std::string> updated_ids;
485   notification_list_->SetMessageCenterVisible(
486       (visibility == VISIBILITY_MESSAGE_CENTER), &updated_ids);
487   notification_cache_.RecountUnread();
488
489   for (std::set<std::string>::const_iterator iter = updated_ids.begin();
490        iter != updated_ids.end();
491        ++iter) {
492     FOR_EACH_OBSERVER(
493         MessageCenterObserver, observer_list_, OnNotificationUpdated(*iter));
494   }
495
496   if (visibility == VISIBILITY_TRANSIENT)
497     notification_queue_->ApplyChanges(this);
498
499   FOR_EACH_OBSERVER(MessageCenterObserver,
500                     observer_list_,
501                     OnCenterVisibilityChanged(visibility));
502 }
503
504 bool MessageCenterImpl::IsMessageCenterVisible() const {
505   return notification_list_->is_message_center_visible();
506 }
507
508 size_t MessageCenterImpl::NotificationCount() const {
509   return notification_cache_.visible_notifications.size();
510 }
511
512 size_t MessageCenterImpl::UnreadNotificationCount() const {
513   return notification_cache_.unread_count;
514 }
515
516 bool MessageCenterImpl::HasPopupNotifications() const {
517   return !IsMessageCenterVisible() &&
518       notification_list_->HasPopupNotifications(blockers_);
519 }
520
521 bool MessageCenterImpl::HasNotification(const std::string& id) {
522   // This will return true if the notification with |id| is hidden by the
523   // ChromeOS multi-profile feature. This would be harmless for now because
524   // this check will be used from the UI, so the |id| for hidden profile won't
525   // arrive here.
526   // TODO(mukai): fix this if necessary.
527   return notification_list_->HasNotification(id);
528 }
529
530 bool MessageCenterImpl::IsQuietMode() const {
531   return notification_list_->quiet_mode();
532 }
533
534 bool MessageCenterImpl::HasClickedListener(const std::string& id) {
535   scoped_refptr<NotificationDelegate> delegate =
536       notification_list_->GetNotificationDelegate(id);
537   return delegate.get() && delegate->HasClickedListener();
538 }
539
540 const NotificationList::Notifications&
541 MessageCenterImpl::GetVisibleNotifications() {
542   return notification_cache_.visible_notifications;
543 }
544
545 NotificationList::PopupNotifications
546     MessageCenterImpl::GetPopupNotifications() {
547   return notification_list_->GetPopupNotifications(blockers_, NULL);
548 }
549
550 //------------------------------------------------------------------------------
551 // Client code interface.
552 void MessageCenterImpl::AddNotification(scoped_ptr<Notification> notification) {
553   DCHECK(notification.get());
554   const std::string id = notification->id();
555   for (size_t i = 0; i < blockers_.size(); ++i)
556     blockers_[i]->CheckState();
557
558   if (notification_list_->is_message_center_visible()) {
559     notification_queue_->AddNotification(notification.Pass());
560     return;
561   }
562
563   // Sometimes the notification can be added with the same id and the
564   // |notification_list| will replace the notification instead of adding new.
565   // This is essentially an update rather than addition.
566   bool already_exists = notification_list_->HasNotification(id);
567   notification_list_->AddNotification(notification.Pass());
568   notification_cache_.Rebuild(
569       notification_list_->GetVisibleNotifications(blockers_));
570
571   if (already_exists) {
572     FOR_EACH_OBSERVER(
573         MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
574   } else {
575     FOR_EACH_OBSERVER(
576         MessageCenterObserver, observer_list_, OnNotificationAdded(id));
577   }
578 }
579
580 void MessageCenterImpl::UpdateNotification(
581     const std::string& old_id,
582     scoped_ptr<Notification> new_notification) {
583   for (size_t i = 0; i < blockers_.size(); ++i)
584     blockers_[i]->CheckState();
585
586   if (notification_list_->is_message_center_visible()) {
587     // We will allow notifications that are progress types (and stay progress
588     // types) to be updated even if the message center is open.  There are 3
589     // requirements here:
590     //  * Notification of type PROGRESS exists with same ID in the center
591     //  * There are no queued updates for this notification (they imply a change
592     //    that violates the PROGRESS invariant
593     //  * The new notification is type PROGRESS.
594     // TODO(dewittj): Ensure this works when the ID is changed by the caller.
595     // This shouldn't be an issue in practice since only W3C notifications
596     // change the ID on update, and they don't have progress type notifications.
597     bool update_keeps_progress_type =
598         new_notification->type() == NOTIFICATION_TYPE_PROGRESS &&
599         !notification_queue_->Has(old_id) &&
600         notification_list_->HasNotificationOfType(old_id,
601                                                   NOTIFICATION_TYPE_PROGRESS);
602     if (!update_keeps_progress_type) {
603       // Updates are allowed only for progress notifications.
604       notification_queue_->UpdateNotification(old_id, new_notification.Pass());
605       return;
606     }
607   }
608
609   std::string new_id = new_notification->id();
610   notification_list_->UpdateNotificationMessage(old_id,
611                                                 new_notification.Pass());
612   notification_cache_.Rebuild(
613      notification_list_->GetVisibleNotifications(blockers_));
614   if (old_id == new_id) {
615     FOR_EACH_OBSERVER(
616         MessageCenterObserver, observer_list_, OnNotificationUpdated(new_id));
617   } else {
618     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
619                       OnNotificationRemoved(old_id, false));
620     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
621                       OnNotificationAdded(new_id));
622   }
623 }
624
625 void MessageCenterImpl::RemoveNotification(const std::string& id,
626                                            bool by_user) {
627   if (!by_user && notification_list_->is_message_center_visible()) {
628     notification_queue_->EraseNotification(id, by_user);
629     return;
630   }
631
632   if (!HasNotification(id))
633     return;
634
635   // In many cases |id| is a reference to an existing notification instance
636   // but the instance can be destructed in RemoveNotification(). Hence
637   // copies the id explicitly here.
638   std::string copied_id(id);
639
640   scoped_refptr<NotificationDelegate> delegate =
641       notification_list_->GetNotificationDelegate(copied_id);
642   if (delegate.get())
643     delegate->Close(by_user);
644
645   notification_list_->RemoveNotification(copied_id);
646   notification_cache_.Rebuild(
647       notification_list_->GetVisibleNotifications(blockers_));
648   FOR_EACH_OBSERVER(MessageCenterObserver,
649                     observer_list_,
650                     OnNotificationRemoved(copied_id, by_user));
651 }
652
653 void MessageCenterImpl::RemoveAllNotifications(bool by_user) {
654   // Using not |blockers_| but an empty list since it wants to remove literally
655   // all notifications.
656   RemoveNotifications(by_user, NotificationBlockers());
657 }
658
659 void MessageCenterImpl::RemoveAllVisibleNotifications(bool by_user) {
660   RemoveNotifications(by_user, blockers_);
661 }
662
663 void MessageCenterImpl::RemoveNotifications(
664     bool by_user,
665     const NotificationBlockers& blockers) {
666   const NotificationList::Notifications notifications =
667       notification_list_->GetVisibleNotifications(blockers);
668   std::set<std::string> ids;
669   for (NotificationList::Notifications::const_iterator iter =
670            notifications.begin(); iter != notifications.end(); ++iter) {
671     ids.insert((*iter)->id());
672     scoped_refptr<NotificationDelegate> delegate = (*iter)->delegate();
673     if (delegate.get())
674       delegate->Close(by_user);
675     notification_list_->RemoveNotification((*iter)->id());
676   }
677
678   if (!ids.empty()) {
679     notification_cache_.Rebuild(
680         notification_list_->GetVisibleNotifications(blockers_));
681   }
682   for (std::set<std::string>::const_iterator iter = ids.begin();
683        iter != ids.end(); ++iter) {
684     FOR_EACH_OBSERVER(MessageCenterObserver,
685                       observer_list_,
686                       OnNotificationRemoved(*iter, by_user));
687   }
688 }
689
690 void MessageCenterImpl::SetNotificationIcon(const std::string& notification_id,
691                                         const gfx::Image& image) {
692   bool updated = false;
693   Notification* queue_notification = notification_queue_->GetLatestNotification(
694       notification_id);
695
696   if (queue_notification) {
697     queue_notification->set_icon(image);
698     updated = true;
699   } else {
700     updated = notification_list_->SetNotificationIcon(notification_id, image);
701   }
702
703   if (updated) {
704     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
705                       OnNotificationUpdated(notification_id));
706   }
707 }
708
709 void MessageCenterImpl::SetNotificationImage(const std::string& notification_id,
710                                          const gfx::Image& image) {
711   bool updated = false;
712   Notification* queue_notification = notification_queue_->GetLatestNotification(
713       notification_id);
714
715   if (queue_notification) {
716     queue_notification->set_image(image);
717     updated = true;
718   } else {
719     updated = notification_list_->SetNotificationImage(notification_id, image);
720   }
721
722   if (updated) {
723     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
724                       OnNotificationUpdated(notification_id));
725   }
726 }
727
728 void MessageCenterImpl::SetNotificationButtonIcon(
729     const std::string& notification_id, int button_index,
730     const gfx::Image& image) {
731   bool updated = false;
732   Notification* queue_notification = notification_queue_->GetLatestNotification(
733       notification_id);
734
735   if (queue_notification) {
736     queue_notification->SetButtonIcon(button_index, image);
737     updated = true;
738   } else {
739     updated = notification_list_->SetNotificationButtonIcon(
740         notification_id, button_index, image);
741   }
742
743   if (updated) {
744     FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_,
745                       OnNotificationUpdated(notification_id));
746   }
747 }
748
749 void MessageCenterImpl::DisableNotificationsByNotifier(
750     const NotifierId& notifier_id) {
751   if (settings_provider_) {
752     // TODO(mukai): SetNotifierEnabled can just accept notifier_id?
753     Notifier notifier(notifier_id, base::string16(), true);
754     settings_provider_->SetNotifierEnabled(notifier, false);
755   }
756
757   NotificationList::Notifications notifications =
758       notification_list_->GetNotificationsByNotifierId(notifier_id);
759   for (NotificationList::Notifications::const_iterator iter =
760            notifications.begin(); iter != notifications.end();) {
761     std::string id = (*iter)->id();
762     iter++;
763     RemoveNotification(id, false);
764   }
765   if (!notifications.empty()) {
766     notification_cache_.Rebuild(
767         notification_list_->GetVisibleNotifications(blockers_));
768   }
769 }
770
771 void MessageCenterImpl::ClickOnNotification(const std::string& id) {
772   if (!HasNotification(id))
773     return;
774   if (HasPopupNotifications())
775     MarkSinglePopupAsShown(id, true);
776   scoped_refptr<NotificationDelegate> delegate =
777       notification_list_->GetNotificationDelegate(id);
778   if (delegate.get())
779     delegate->Click();
780   FOR_EACH_OBSERVER(
781       MessageCenterObserver, observer_list_, OnNotificationClicked(id));
782 }
783
784 void MessageCenterImpl::ClickOnNotificationButton(const std::string& id,
785                                               int button_index) {
786   if (!HasNotification(id))
787     return;
788   if (HasPopupNotifications())
789     MarkSinglePopupAsShown(id, true);
790   scoped_refptr<NotificationDelegate> delegate =
791       notification_list_->GetNotificationDelegate(id);
792   if (delegate.get())
793     delegate->ButtonClick(button_index);
794   FOR_EACH_OBSERVER(
795       MessageCenterObserver, observer_list_, OnNotificationButtonClicked(
796           id, button_index));
797 }
798
799 void MessageCenterImpl::MarkSinglePopupAsShown(const std::string& id,
800                                                bool mark_notification_as_read) {
801   if (!HasNotification(id))
802     return;
803   notification_list_->MarkSinglePopupAsShown(id, mark_notification_as_read);
804   notification_cache_.RecountUnread();
805   FOR_EACH_OBSERVER(
806       MessageCenterObserver, observer_list_, OnNotificationUpdated(id));
807 }
808
809 void MessageCenterImpl::DisplayedNotification(
810     const std::string& id,
811     const DisplaySource source) {
812   if (!HasNotification(id))
813     return;
814
815   if (HasPopupNotifications())
816     notification_list_->MarkSinglePopupAsDisplayed(id);
817   notification_cache_.RecountUnread();
818   scoped_refptr<NotificationDelegate> delegate =
819       notification_list_->GetNotificationDelegate(id);
820   if (delegate.get())
821     delegate->Display();
822   FOR_EACH_OBSERVER(
823       MessageCenterObserver,
824       observer_list_,
825       OnNotificationDisplayed(id, source));
826 }
827
828 void MessageCenterImpl::SetNotifierSettingsProvider(
829     NotifierSettingsProvider* provider) {
830   settings_provider_ = provider;
831 }
832
833 NotifierSettingsProvider* MessageCenterImpl::GetNotifierSettingsProvider() {
834   return settings_provider_;
835 }
836
837 void MessageCenterImpl::SetQuietMode(bool in_quiet_mode) {
838   if (in_quiet_mode != notification_list_->quiet_mode()) {
839     notification_list_->SetQuietMode(in_quiet_mode);
840     FOR_EACH_OBSERVER(MessageCenterObserver,
841                       observer_list_,
842                       OnQuietModeChanged(in_quiet_mode));
843   }
844   quiet_mode_timer_.reset();
845 }
846
847 void MessageCenterImpl::EnterQuietModeWithExpire(
848     const base::TimeDelta& expires_in) {
849   if (quiet_mode_timer_.get()) {
850     // Note that the capital Reset() is the method to restart the timer, not
851     // scoped_ptr::reset().
852     quiet_mode_timer_->Reset();
853   } else {
854     notification_list_->SetQuietMode(true);
855     FOR_EACH_OBSERVER(
856         MessageCenterObserver, observer_list_, OnQuietModeChanged(true));
857
858     quiet_mode_timer_.reset(new base::OneShotTimer<MessageCenterImpl>);
859     quiet_mode_timer_->Start(
860         FROM_HERE,
861         expires_in,
862         base::Bind(
863             &MessageCenterImpl::SetQuietMode, base::Unretained(this), false));
864   }
865 }
866
867 void MessageCenterImpl::RestartPopupTimers() {
868   if (popup_timers_controller_.get())
869     popup_timers_controller_->StartAll();
870 }
871
872 void MessageCenterImpl::PausePopupTimers() {
873   if (popup_timers_controller_.get())
874     popup_timers_controller_->PauseAll();
875 }
876
877 void MessageCenterImpl::DisableTimersForTest() {
878   popup_timers_controller_.reset();
879 }
880
881 }  // namespace message_center