OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "chrome/browser/notifications/balloon_notification_ui_manager.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/prefs/pref_service.h" | |
10 #include "base/stl_util.h" | |
11 #include "chrome/browser/browser_process.h" | |
12 #include "chrome/browser/chrome_notification_types.h" | |
13 #include "chrome/browser/fullscreen.h" | |
14 #include "chrome/browser/idle.h" | |
15 #include "chrome/browser/notifications/balloon_collection.h" | |
16 #include "chrome/browser/notifications/notification.h" | |
17 #include "chrome/browser/profiles/profile.h" | |
18 #include "chrome/common/pref_names.h" | |
19 #include "content/public/browser/notification_service.h" | |
20 | |
21 // A class which represents a notification waiting to be shown. | |
22 class QueuedNotification { | |
23 public: | |
24 QueuedNotification(const Notification& notification, Profile* profile) | |
25 : notification_(notification), | |
26 profile_(profile) { | |
27 } | |
28 | |
29 const Notification& notification() const { return notification_; } | |
30 Profile* profile() const { return profile_; } | |
31 | |
32 void Replace(const Notification& new_notification) { | |
33 notification_ = new_notification; | |
34 } | |
35 | |
36 private: | |
37 // The notification to be shown. | |
38 Notification notification_; | |
39 | |
40 // Non owned pointer to the user's profile. | |
41 Profile* profile_; | |
42 | |
43 DISALLOW_COPY_AND_ASSIGN(QueuedNotification); | |
44 }; | |
45 | |
46 BalloonNotificationUIManager::BalloonNotificationUIManager( | |
47 PrefService* local_state) | |
48 : NotificationPrefsManager(local_state), | |
49 // Passes NULL to blockers since |message_center| is not used from balloon | |
50 // notifications. | |
51 screen_lock_blocker_(NULL), | |
52 fullscreen_blocker_(NULL), | |
53 system_observer_(this) { | |
54 position_pref_.Init( | |
55 prefs::kDesktopNotificationPosition, | |
56 local_state, | |
57 base::Bind( | |
58 &BalloonNotificationUIManager::OnDesktopNotificationPositionChanged, | |
59 base::Unretained(this))); | |
60 } | |
61 | |
62 BalloonNotificationUIManager::~BalloonNotificationUIManager() { | |
63 } | |
64 | |
65 void BalloonNotificationUIManager::SetBalloonCollection( | |
66 BalloonCollection* balloon_collection) { | |
67 DCHECK(!balloon_collection_.get() || | |
68 balloon_collection_->GetActiveBalloons().size() == 0); | |
69 DCHECK(balloon_collection); | |
70 balloon_collection_.reset(balloon_collection); | |
71 balloon_collection_->SetPositionPreference( | |
72 static_cast<BalloonCollection::PositionPreference>( | |
73 position_pref_.GetValue())); | |
74 balloon_collection_->set_space_change_listener(this); | |
75 } | |
76 | |
77 void BalloonNotificationUIManager::Add(const Notification& notification, | |
78 Profile* profile) { | |
79 if (Update(notification, profile)) { | |
80 return; | |
81 } | |
82 | |
83 VLOG(1) << "Added notification. URL: " | |
84 << notification.content_url().spec(); | |
85 show_queue_.push_back(linked_ptr<QueuedNotification>( | |
86 new QueuedNotification(notification, profile))); | |
87 CheckAndShowNotifications(); | |
88 } | |
89 | |
90 bool BalloonNotificationUIManager::Update(const Notification& notification, | |
91 Profile* profile) { | |
92 const GURL& origin = notification.origin_url(); | |
93 const base::string16& replace_id = notification.replace_id(); | |
94 | |
95 if (replace_id.empty()) | |
96 return false; | |
97 | |
98 // First check the queue of pending notifications for replacement. | |
99 // Then check the list of notifications already being shown. | |
100 for (NotificationDeque::const_iterator iter = show_queue_.begin(); | |
101 iter != show_queue_.end(); ++iter) { | |
102 if (profile == (*iter)->profile() && | |
103 origin == (*iter)->notification().origin_url() && | |
104 replace_id == (*iter)->notification().replace_id()) { | |
105 (*iter)->Replace(notification); | |
106 return true; | |
107 } | |
108 } | |
109 | |
110 return UpdateNotification(notification, profile); | |
111 } | |
112 | |
113 const Notification* BalloonNotificationUIManager::FindById( | |
114 const std::string& id) const { | |
115 for (NotificationDeque::const_iterator iter = show_queue_.begin(); | |
116 iter != show_queue_.end(); ++iter) { | |
117 if ((*iter)->notification().notification_id() == id) { | |
118 return &((*iter)->notification()); | |
119 } | |
120 } | |
121 return balloon_collection_->FindById(id); | |
122 } | |
123 | |
124 bool BalloonNotificationUIManager::CancelById(const std::string& id) { | |
125 // See if this ID hasn't been shown yet. | |
126 for (NotificationDeque::iterator iter = show_queue_.begin(); | |
127 iter != show_queue_.end(); ++iter) { | |
128 if ((*iter)->notification().notification_id() == id) { | |
129 show_queue_.erase(iter); | |
130 return true; | |
131 } | |
132 } | |
133 // If it has been shown, remove it from the balloon collections. | |
134 return balloon_collection_->RemoveById(id); | |
135 } | |
136 | |
137 std::set<std::string> | |
138 BalloonNotificationUIManager::GetAllIdsByProfileAndSourceOrigin( | |
139 Profile* profile, | |
140 const GURL& source) { | |
141 std::set<std::string> notification_ids; | |
142 for (NotificationDeque::iterator iter = show_queue_.begin(); | |
143 iter != show_queue_.end(); iter++) { | |
144 if ((*iter)->notification().origin_url() == source && | |
145 profile->IsSameProfile((*iter)->profile())) { | |
146 notification_ids.insert((*iter)->notification().notification_id()); | |
147 } | |
148 } | |
149 | |
150 const BalloonCollection::Balloons& balloons = | |
151 balloon_collection_->GetActiveBalloons(); | |
152 for (BalloonCollection::Balloons::const_iterator iter = balloons.begin(); | |
153 iter != balloons.end(); ++iter) { | |
154 if (profile->IsSameProfile((*iter)->profile()) && | |
155 source == (*iter)->notification().origin_url()) { | |
156 notification_ids.insert((*iter)->notification().notification_id()); | |
157 } | |
158 } | |
159 return notification_ids; | |
160 } | |
161 | |
162 bool BalloonNotificationUIManager::CancelAllBySourceOrigin(const GURL& source) { | |
163 // Same pattern as CancelById, but more complicated than the above | |
164 // because there may be multiple notifications from the same source. | |
165 bool removed = false; | |
166 for (NotificationDeque::iterator loopiter = show_queue_.begin(); | |
167 loopiter != show_queue_.end(); ) { | |
168 if ((*loopiter)->notification().origin_url() != source) { | |
169 ++loopiter; | |
170 continue; | |
171 } | |
172 | |
173 loopiter = show_queue_.erase(loopiter); | |
174 removed = true; | |
175 } | |
176 return balloon_collection_->RemoveBySourceOrigin(source) || removed; | |
177 } | |
178 | |
179 bool BalloonNotificationUIManager::CancelAllByProfile(Profile* profile) { | |
180 // Same pattern as CancelAllBySourceOrigin. | |
181 bool removed = false; | |
182 for (NotificationDeque::iterator loopiter = show_queue_.begin(); | |
183 loopiter != show_queue_.end(); ) { | |
184 if ((*loopiter)->profile() != profile) { | |
185 ++loopiter; | |
186 continue; | |
187 } | |
188 | |
189 loopiter = show_queue_.erase(loopiter); | |
190 removed = true; | |
191 } | |
192 return balloon_collection_->RemoveByProfile(profile) || removed; | |
193 } | |
194 | |
195 void BalloonNotificationUIManager::CancelAll() { | |
196 balloon_collection_->RemoveAll(); | |
197 } | |
198 | |
199 BalloonCollection* BalloonNotificationUIManager::balloon_collection() { | |
200 return balloon_collection_.get(); | |
201 } | |
202 | |
203 NotificationPrefsManager* BalloonNotificationUIManager::prefs_manager() { | |
204 return this; | |
205 } | |
206 | |
207 bool BalloonNotificationUIManager::ShowNotification( | |
208 const Notification& notification, | |
209 Profile* profile) { | |
210 if (!balloon_collection_->HasSpace()) | |
211 return false; | |
212 balloon_collection_->Add(notification, profile); | |
213 return true; | |
214 } | |
215 | |
216 void BalloonNotificationUIManager::OnBalloonSpaceChanged() { | |
217 CheckAndShowNotifications(); | |
218 } | |
219 | |
220 void BalloonNotificationUIManager::OnBlockingStateChanged( | |
221 message_center::NotificationBlocker* blocker) { | |
222 CheckAndShowNotifications(); | |
223 } | |
224 | |
225 bool BalloonNotificationUIManager::UpdateNotification( | |
226 const Notification& notification, | |
227 Profile* profile) { | |
228 const GURL& origin = notification.origin_url(); | |
229 const base::string16& replace_id = notification.replace_id(); | |
230 | |
231 DCHECK(!replace_id.empty()); | |
232 | |
233 const BalloonCollection::Balloons& balloons = | |
234 balloon_collection_->GetActiveBalloons(); | |
235 for (BalloonCollection::Balloons::const_iterator iter = balloons.begin(); | |
236 iter != balloons.end(); ++iter) { | |
237 if (profile == (*iter)->profile() && | |
238 origin == (*iter)->notification().origin_url() && | |
239 replace_id == (*iter)->notification().replace_id()) { | |
240 (*iter)->Update(notification); | |
241 return true; | |
242 } | |
243 } | |
244 | |
245 return false; | |
246 } | |
247 | |
248 BalloonCollection::PositionPreference | |
249 BalloonNotificationUIManager::GetPositionPreference() const { | |
250 return static_cast<BalloonCollection::PositionPreference>( | |
251 position_pref_.GetValue()); | |
252 } | |
253 | |
254 void BalloonNotificationUIManager::SetPositionPreference( | |
255 BalloonCollection::PositionPreference preference) { | |
256 position_pref_.SetValue(static_cast<int>(preference)); | |
257 balloon_collection_->SetPositionPreference(preference); | |
258 } | |
259 | |
260 void BalloonNotificationUIManager::CheckAndShowNotifications() { | |
261 screen_lock_blocker_.CheckState(); | |
262 fullscreen_blocker_.CheckState(); | |
263 if (screen_lock_blocker_.is_locked() || | |
264 fullscreen_blocker_.is_fullscreen_mode()) { | |
265 return; | |
266 } | |
267 ShowNotifications(); | |
268 } | |
269 | |
270 void BalloonNotificationUIManager::OnDesktopNotificationPositionChanged() { | |
271 balloon_collection_->SetPositionPreference( | |
272 static_cast<BalloonCollection::PositionPreference>( | |
273 position_pref_.GetValue())); | |
274 } | |
275 | |
276 void BalloonNotificationUIManager::ShowNotifications() { | |
277 while (!show_queue_.empty()) { | |
278 linked_ptr<QueuedNotification> queued_notification(show_queue_.front()); | |
279 show_queue_.pop_front(); | |
280 if (!ShowNotification(queued_notification->notification(), | |
281 queued_notification->profile())) { | |
282 show_queue_.push_front(queued_notification); | |
283 return; | |
284 } | |
285 } | |
286 } | |
287 | |
288 // static | |
289 BalloonNotificationUIManager* | |
290 BalloonNotificationUIManager::GetInstanceForTesting() { | |
291 if (NotificationUIManager::DelegatesToMessageCenter()) { | |
292 LOG(ERROR) << "Attempt to run a test that requires " | |
293 << "BalloonNotificationUIManager while delegating to a " | |
294 << "native MessageCenter. Test will fail. Ask dimich@"; | |
295 return NULL; | |
296 } | |
297 return static_cast<BalloonNotificationUIManager*>( | |
298 g_browser_process->notification_ui_manager()); | |
299 } | |
300 | |
301 void BalloonNotificationUIManager::GetQueuedNotificationsForTesting( | |
302 std::vector<const Notification*>* notifications) { | |
303 for (NotificationDeque::const_iterator iter = show_queue_.begin(); | |
304 iter != show_queue_.end(); ++iter) { | |
305 notifications->push_back(&(*iter)->notification()); | |
306 } | |
307 } | |
OLD | NEW |