Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / notifications / balloon_notification_ui_manager.cc
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 }