| 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 |