1 // Copyright 2016 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/popup_timers_controller.h"
6 
7 #include <algorithm>
8 
9 #include "base/stl_util.h"
10 #include "ui/message_center/public/cpp/message_center_constants.h"
11 
12 namespace message_center {
13 
14 namespace {
15 
UseHighPriorityDelay(Notification * notification)16 bool UseHighPriorityDelay(Notification* notification) {
17 // Web Notifications are given a longer on-screen time on non-Chrome OS
18 // platforms as there is no notification center to dismiss them to.
19 #if defined(OS_CHROMEOS)
20   const bool use_high_priority_delay =
21       notification->priority() > DEFAULT_PRIORITY;
22 #else
23   const bool use_high_priority_delay =
24       notification->priority() > DEFAULT_PRIORITY ||
25       notification->notifier_id().type == NotifierType::WEB_PAGE;
26 #endif
27 
28   return use_high_priority_delay;
29 }
30 
31 }  // namespace
32 
33 // Timeout values used to dismiss notifications automatically after they are
34 // shown.
35 int notification_timeout_default_seconds_ = kAutocloseDefaultDelaySeconds;
36 int notification_timeout_high_priority_seconds_ =
37     kAutocloseHighPriorityDelaySeconds;
38 
PopupTimersController(MessageCenter * message_center)39 PopupTimersController::PopupTimersController(MessageCenter* message_center)
40     : message_center_(message_center) {
41   message_center_->AddObserver(this);
42 }
43 
~PopupTimersController()44 PopupTimersController::~PopupTimersController() {
45   message_center_->RemoveObserver(this);
46 }
47 
StartTimer(const std::string & id,const base::TimeDelta & timeout)48 void PopupTimersController::StartTimer(const std::string& id,
49                                        const base::TimeDelta& timeout) {
50   PopupTimerCollection::const_iterator iter = popup_timers_.find(id);
51   if (iter != popup_timers_.end()) {
52     DCHECK(iter->second);
53     iter->second->Start();
54     return;
55   }
56 
57   std::unique_ptr<PopupTimer> timer(new PopupTimer(id, timeout, AsWeakPtr()));
58 
59   timer->Start();
60   popup_timers_.emplace(id, std::move(timer));
61 }
62 
StartAll()63 void PopupTimersController::StartAll() {
64   for (const auto& iter : popup_timers_)
65     iter.second->Start();
66 }
67 
PauseAll()68 void PopupTimersController::PauseAll() {
69   for (const auto& iter : popup_timers_)
70     iter.second->Pause();
71 }
72 
CancelTimer(const std::string & id)73 void PopupTimersController::CancelTimer(const std::string& id) {
74   popup_timers_.erase(id);
75 }
76 
SetNotificationTimeouts(int default_timeout,int high_priority_timeout)77 void PopupTimersController::SetNotificationTimeouts(int default_timeout,
78                                                     int high_priority_timeout) {
79   notification_timeout_default_seconds_ = default_timeout;
80   notification_timeout_high_priority_seconds_ = high_priority_timeout;
81 }
82 
CancelAll()83 void PopupTimersController::CancelAll() {
84   popup_timers_.clear();
85 }
86 
TimerFinished(const std::string & id)87 void PopupTimersController::TimerFinished(const std::string& id) {
88   if (!base::Contains(popup_timers_, id))
89     return;
90 
91   CancelTimer(id);
92   message_center_->MarkSinglePopupAsShown(id, false);
93 }
94 
GetTimeoutForNotification(Notification * notification)95 base::TimeDelta PopupTimersController::GetTimeoutForNotification(
96     Notification* notification) {
97   return base::TimeDelta::FromSeconds(
98       UseHighPriorityDelay(notification)
99           ? notification_timeout_high_priority_seconds_
100           : notification_timeout_default_seconds_);
101 }
102 
GetNotificationTimeoutDefault()103 int PopupTimersController::GetNotificationTimeoutDefault() {
104   return notification_timeout_default_seconds_;
105 }
106 
OnNotificationDisplayed(const std::string & id,const DisplaySource source)107 void PopupTimersController::OnNotificationDisplayed(
108     const std::string& id,
109     const DisplaySource source) {
110   OnNotificationUpdated(id);
111 }
112 
OnNotificationUpdated(const std::string & id)113 void PopupTimersController::OnNotificationUpdated(const std::string& id) {
114   NotificationList::PopupNotifications popup_notifications =
115       message_center_->GetPopupNotifications();
116 
117   if (popup_notifications.empty()) {
118     CancelAll();
119     return;
120   }
121 
122   auto iter = popup_notifications.begin();
123   for (; iter != popup_notifications.end(); ++iter) {
124     if ((*iter)->id() == id)
125       break;
126   }
127 
128   if (iter == popup_notifications.end() || (*iter)->never_timeout()) {
129     CancelTimer(id);
130     return;
131   }
132 
133   auto timer = popup_timers_.find(id);
134   // The timer must already have been started and not be running. Relies on
135   // the invariant that |popup_timers_| only contains timers that have been
136   // started.
137   bool was_paused = timer != popup_timers_.end() && !timer->second->IsRunning();
138   CancelTimer(id);
139   StartTimer(id, GetTimeoutForNotification(*iter));
140 
141   // If a timer was paused before, pause it afterwards as well.
142   // See crbug.com/710298
143   if (was_paused) {
144     auto timer = popup_timers_.find(id);
145     timer->second->Pause();
146   }
147 }
148 
OnNotificationRemoved(const std::string & id,bool by_user)149 void PopupTimersController::OnNotificationRemoved(const std::string& id,
150                                                   bool by_user) {
151   CancelTimer(id);
152 }
153 
154 }  // namespace message_center
155