Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 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/message_center_notification_manager.h" |
| 6 | |
| 7 | #include "base/logging.h" |
| 8 | #include "base/memory/scoped_ptr.h" |
| 9 | #include "base/prefs/pref_service.h" |
Ben Murdoch | 2385ea3 | 2013-08-06 11:01:04 +0100 | [diff] [blame] | 10 | #include "chrome/browser/chrome_notification_types.h" |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 11 | #include "chrome/browser/extensions/extension_info_map.h" |
| 12 | #include "chrome/browser/extensions/extension_system.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 13 | #include "chrome/browser/notifications/desktop_notification_service.h" |
| 14 | #include "chrome/browser/notifications/desktop_notification_service_factory.h" |
| 15 | #include "chrome/browser/notifications/message_center_settings_controller.h" |
| 16 | #include "chrome/browser/notifications/notification.h" |
| 17 | #include "chrome/browser/profiles/profile.h" |
| 18 | #include "chrome/browser/ui/browser_finder.h" |
| 19 | #include "chrome/browser/ui/chrome_pages.h" |
| 20 | #include "chrome/browser/ui/host_desktop.h" |
| 21 | #include "chrome/common/extensions/extension_set.h" |
| 22 | #include "chrome/common/pref_names.h" |
Ben Murdoch | 2385ea3 | 2013-08-06 11:01:04 +0100 | [diff] [blame] | 23 | #include "content/public/browser/notification_service.h" |
| 24 | #include "content/public/browser/user_metrics.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 25 | #include "content/public/browser/web_contents.h" |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 26 | #include "content/public/common/url_constants.h" |
Torne (Richard Coles) | 90dce4d | 2013-05-29 14:40:03 +0100 | [diff] [blame] | 27 | #include "ui/message_center/message_center_style.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 28 | #include "ui/message_center/message_center_tray.h" |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 29 | #include "ui/message_center/notifier_settings.h" |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 30 | |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 31 | namespace { |
| 32 | // The first-run balloon will be shown |kFirstRunIdleDelaySeconds| after all |
| 33 | // popups go away and the user has notifications in the message center. |
| 34 | const int kFirstRunIdleDelaySeconds = 1; |
| 35 | } // namespace |
| 36 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 37 | MessageCenterNotificationManager::MessageCenterNotificationManager( |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 38 | message_center::MessageCenter* message_center, |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 39 | PrefService* local_state, |
| 40 | scoped_ptr<message_center::NotifierSettingsProvider> settings_provider) |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 41 | : message_center_(message_center), |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 42 | #if defined(OS_WIN) |
| 43 | first_run_idle_timeout_( |
| 44 | base::TimeDelta::FromSeconds(kFirstRunIdleDelaySeconds)), |
| 45 | weak_factory_(this), |
| 46 | #endif |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 47 | settings_provider_(settings_provider.Pass()) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 48 | #if defined(OS_WIN) |
| 49 | first_run_pref_.Init(prefs::kMessageCenterShowedFirstRunBalloon, local_state); |
| 50 | #endif |
| 51 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 52 | message_center_->SetDelegate(this); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 53 | message_center_->AddObserver(this); |
Ben Murdoch | bb1529c | 2013-08-08 10:24:53 +0100 | [diff] [blame^] | 54 | message_center_->SetNotifierSettingsProvider(settings_provider_.get()); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 55 | |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 56 | #if defined(OS_WIN) || defined(OS_MACOSX) \ |
| 57 | || (defined(USE_AURA) && !defined(USE_ASH)) |
| 58 | // On Windows, Linux and Mac, the notification manager owns the tray icon and |
| 59 | // views.Other platforms have global ownership and Create will return NULL. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 60 | tray_.reset(message_center::CreateMessageCenterTray()); |
| 61 | #endif |
Ben Murdoch | 2385ea3 | 2013-08-06 11:01:04 +0100 | [diff] [blame] | 62 | registrar_.Add(this, |
| 63 | chrome::NOTIFICATION_FULLSCREEN_CHANGED, |
| 64 | content::NotificationService::AllSources()); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | MessageCenterNotificationManager::~MessageCenterNotificationManager() { |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 68 | message_center_->RemoveObserver(this); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 69 | } |
| 70 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 71 | //////////////////////////////////////////////////////////////////////////////// |
| 72 | // NotificationUIManager |
| 73 | |
Ben Murdoch | 558790d | 2013-07-30 15:19:42 +0100 | [diff] [blame] | 74 | const Notification* MessageCenterNotificationManager::FindById( |
| 75 | const std::string& id) const { |
| 76 | const Notification* notification = NotificationUIManagerImpl::FindById(id); |
| 77 | if (notification) |
| 78 | return notification; |
| 79 | NotificationMap::const_iterator iter = profile_notifications_.find(id); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 80 | if (iter == profile_notifications_.end()) |
Ben Murdoch | 558790d | 2013-07-30 15:19:42 +0100 | [diff] [blame] | 81 | return NULL; |
| 82 | return &(iter->second->notification()); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | bool MessageCenterNotificationManager::CancelById(const std::string& id) { |
| 86 | // See if this ID hasn't been shown yet. |
| 87 | if (NotificationUIManagerImpl::CancelById(id)) |
| 88 | return true; |
| 89 | |
| 90 | // If it has been shown, remove it. |
| 91 | NotificationMap::iterator iter = profile_notifications_.find(id); |
| 92 | if (iter == profile_notifications_.end()) |
| 93 | return false; |
| 94 | |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 95 | message_center_->RemoveNotification(id, /* by_user */ false); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 96 | return true; |
| 97 | } |
| 98 | |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 99 | std::set<std::string> |
| 100 | MessageCenterNotificationManager::GetAllIdsByProfileAndSourceOrigin( |
| 101 | Profile* profile, |
| 102 | const GURL& source) { |
| 103 | |
| 104 | std::set<std::string> notification_ids = |
| 105 | NotificationUIManagerImpl::GetAllIdsByProfileAndSourceOrigin(profile, |
| 106 | source); |
| 107 | |
| 108 | for (NotificationMap::iterator iter = profile_notifications_.begin(); |
| 109 | iter != profile_notifications_.end(); iter++) { |
| 110 | if ((*iter).second->notification().origin_url() == source && |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 111 | profile == (*iter).second->profile()) { |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 112 | notification_ids.insert(iter->first); |
| 113 | } |
| 114 | } |
| 115 | return notification_ids; |
| 116 | } |
| 117 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 118 | bool MessageCenterNotificationManager::CancelAllBySourceOrigin( |
| 119 | const GURL& source) { |
| 120 | // Same pattern as CancelById, but more complicated than the above |
| 121 | // because there may be multiple notifications from the same source. |
| 122 | bool removed = NotificationUIManagerImpl::CancelAllBySourceOrigin(source); |
| 123 | |
| 124 | for (NotificationMap::iterator loopiter = profile_notifications_.begin(); |
| 125 | loopiter != profile_notifications_.end(); ) { |
| 126 | NotificationMap::iterator curiter = loopiter++; |
| 127 | if ((*curiter).second->notification().origin_url() == source) { |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 128 | message_center_->RemoveNotification(curiter->first, /* by_user */ false); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 129 | removed = true; |
| 130 | } |
| 131 | } |
| 132 | return removed; |
| 133 | } |
| 134 | |
| 135 | bool MessageCenterNotificationManager::CancelAllByProfile(Profile* profile) { |
| 136 | // Same pattern as CancelAllBySourceOrigin. |
| 137 | bool removed = NotificationUIManagerImpl::CancelAllByProfile(profile); |
| 138 | |
| 139 | for (NotificationMap::iterator loopiter = profile_notifications_.begin(); |
| 140 | loopiter != profile_notifications_.end(); ) { |
| 141 | NotificationMap::iterator curiter = loopiter++; |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 142 | if (profile == (*curiter).second->profile()) { |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 143 | message_center_->RemoveNotification(curiter->first, /* by_user */ false); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 144 | removed = true; |
| 145 | } |
| 146 | } |
| 147 | return removed; |
| 148 | } |
| 149 | |
| 150 | void MessageCenterNotificationManager::CancelAll() { |
| 151 | NotificationUIManagerImpl::CancelAll(); |
| 152 | |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 153 | message_center_->RemoveAllNotifications(/* by_user */ false); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 154 | } |
| 155 | |
| 156 | //////////////////////////////////////////////////////////////////////////////// |
| 157 | // NotificationUIManagerImpl |
| 158 | |
| 159 | bool MessageCenterNotificationManager::ShowNotification( |
| 160 | const Notification& notification, Profile* profile) { |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 161 | if (message_center_->IsMessageCenterVisible()) |
| 162 | return false; |
| 163 | |
| 164 | if (UpdateNotification(notification, profile)) |
| 165 | return true; |
| 166 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 167 | AddProfileNotification( |
| 168 | new ProfileNotification(profile, notification, message_center_)); |
| 169 | return true; |
| 170 | } |
| 171 | |
| 172 | bool MessageCenterNotificationManager::UpdateNotification( |
| 173 | const Notification& notification, Profile* profile) { |
Torne (Richard Coles) | a36e592 | 2013-08-05 13:57:33 +0100 | [diff] [blame] | 174 | // Only progress notification update can be reflected immediately in the |
| 175 | // message center. |
| 176 | bool update_progress_notification = |
| 177 | notification.type() == message_center::NOTIFICATION_TYPE_PROGRESS; |
| 178 | bool is_message_center_visible = message_center_->IsMessageCenterVisible(); |
| 179 | if (!update_progress_notification && is_message_center_visible) |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 180 | return false; |
| 181 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 182 | const string16& replace_id = notification.replace_id(); |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 183 | if (replace_id.empty()) |
| 184 | return false; |
| 185 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 186 | const GURL origin_url = notification.origin_url(); |
| 187 | DCHECK(origin_url.is_valid()); |
| 188 | |
| 189 | // Since replace_id is provided by arbitrary JS, we need to use origin_url |
| 190 | // (which is an app url in case of app/extension) to scope the replace ids |
| 191 | // in the given profile. |
| 192 | for (NotificationMap::iterator iter = profile_notifications_.begin(); |
| 193 | iter != profile_notifications_.end(); ++iter) { |
| 194 | ProfileNotification* old_notification = (*iter).second; |
| 195 | if (old_notification->notification().replace_id() == replace_id && |
| 196 | old_notification->notification().origin_url() == origin_url && |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 197 | old_notification->profile() == profile) { |
Torne (Richard Coles) | a36e592 | 2013-08-05 13:57:33 +0100 | [diff] [blame] | 198 | // Changing the type from non-progress to progress does not count towards |
| 199 | // the immediate update allowed in the message center. |
| 200 | if (update_progress_notification && is_message_center_visible && |
| 201 | old_notification->notification().type() != |
| 202 | message_center::NOTIFICATION_TYPE_PROGRESS) { |
| 203 | return false; |
| 204 | } |
| 205 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 206 | std::string old_id = |
| 207 | old_notification->notification().notification_id(); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 208 | DCHECK(message_center_->HasNotification(old_id)); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 209 | |
| 210 | // Add/remove notification in the local list but just update the same |
| 211 | // one in MessageCenter. |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 212 | delete old_notification; |
| 213 | profile_notifications_.erase(old_id); |
| 214 | ProfileNotification* new_notification = |
| 215 | new ProfileNotification(profile, notification, message_center_); |
| 216 | profile_notifications_[notification.notification_id()] = new_notification; |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 217 | |
| 218 | // Now pass a copy to message center. |
| 219 | scoped_ptr<message_center::Notification> message_center_notification( |
| 220 | make_scoped_ptr(new message_center::Notification(notification))); |
| 221 | message_center_notification->set_extension_id( |
| 222 | new_notification->GetExtensionId()); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 223 | message_center_->UpdateNotification(old_id, |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 224 | message_center_notification.Pass()); |
| 225 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 226 | new_notification->StartDownloads(); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 227 | return true; |
| 228 | } |
| 229 | } |
| 230 | return false; |
| 231 | } |
| 232 | |
| 233 | //////////////////////////////////////////////////////////////////////////////// |
| 234 | // MessageCenter::Delegate |
| 235 | |
| 236 | void MessageCenterNotificationManager::DisableExtension( |
| 237 | const std::string& notification_id) { |
| 238 | ProfileNotification* profile_notification = |
| 239 | FindProfileNotification(notification_id); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 240 | if (!profile_notification) |
| 241 | return; |
| 242 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 243 | std::string extension_id = profile_notification->GetExtensionId(); |
| 244 | DCHECK(!extension_id.empty()); // or UI should not have enabled the command. |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 245 | DesktopNotificationService* service = |
| 246 | DesktopNotificationServiceFactory::GetForProfile( |
| 247 | profile_notification->profile()); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 248 | message_center::NotifierId notifier_id( |
| 249 | message_center::NotifierId::APPLICATION, extension_id); |
| 250 | service->SetNotifierEnabled(notifier_id, false); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 251 | } |
| 252 | |
| 253 | void MessageCenterNotificationManager::DisableNotificationsFromSource( |
| 254 | const std::string& notification_id) { |
| 255 | ProfileNotification* profile_notification = |
| 256 | FindProfileNotification(notification_id); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 257 | if (!profile_notification) |
| 258 | return; |
| 259 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 260 | // UI should not have enabled the command if there is no valid source. |
| 261 | DCHECK(profile_notification->notification().origin_url().is_valid()); |
| 262 | DesktopNotificationService* service = |
| 263 | DesktopNotificationServiceFactory::GetForProfile( |
| 264 | profile_notification->profile()); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 265 | if (profile_notification->notification().origin_url().scheme() == |
| 266 | chrome::kChromeUIScheme) { |
| 267 | const std::string name = |
| 268 | profile_notification->notification().origin_url().host(); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 269 | message_center::NotifierId notifier_id( |
| 270 | message_center::ParseSystemComponentName(name)); |
| 271 | service->SetNotifierEnabled(notifier_id, false); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 272 | } else { |
| 273 | service->DenyPermission(profile_notification->notification().origin_url()); |
| 274 | } |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 275 | } |
| 276 | |
| 277 | void MessageCenterNotificationManager::ShowSettings( |
| 278 | const std::string& notification_id) { |
| 279 | // The per-message-center Settings button passes an empty string. |
| 280 | if (notification_id.empty()) { |
| 281 | NOTIMPLEMENTED(); |
| 282 | return; |
| 283 | } |
| 284 | |
| 285 | ProfileNotification* profile_notification = |
| 286 | FindProfileNotification(notification_id); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 287 | if (!profile_notification) |
| 288 | return; |
| 289 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 290 | Browser* browser = |
| 291 | chrome::FindOrCreateTabbedBrowser(profile_notification->profile(), |
| 292 | chrome::HOST_DESKTOP_TYPE_NATIVE); |
| 293 | if (profile_notification->GetExtensionId().empty()) |
| 294 | chrome::ShowContentSettings(browser, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); |
| 295 | else |
| 296 | chrome::ShowExtensions(browser, std::string()); |
| 297 | } |
| 298 | |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 299 | //////////////////////////////////////////////////////////////////////////////// |
| 300 | // MessageCenter::Observer |
| 301 | void MessageCenterNotificationManager::OnNotificationRemoved( |
| 302 | const std::string& notification_id, |
| 303 | bool by_user) { |
| 304 | // Do not call FindProfileNotification(). Some tests create notifications |
| 305 | // directly to MessageCenter, but this method will be called for the removals |
| 306 | // of such notifications. |
| 307 | NotificationMap::const_iterator iter = |
| 308 | profile_notifications_.find(notification_id); |
| 309 | if (iter != profile_notifications_.end()) |
| 310 | RemoveProfileNotification(iter->second, by_user); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 311 | |
| 312 | #if defined(OS_WIN) |
| 313 | CheckFirstRunTimer(); |
| 314 | #endif |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 315 | } |
| 316 | |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 317 | void MessageCenterNotificationManager::OnNotificationCenterClosed() { |
| 318 | // When the center is open it halts all notifications, so we need to listen |
| 319 | // for events indicating it's been closed. |
| 320 | CheckAndShowNotifications(); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 321 | #if defined(OS_WIN) |
| 322 | CheckFirstRunTimer(); |
| 323 | #endif |
| 324 | } |
| 325 | |
| 326 | void MessageCenterNotificationManager::OnNotificationUpdated( |
| 327 | const std::string& notification_id) { |
| 328 | #if defined(OS_WIN) |
| 329 | CheckFirstRunTimer(); |
| 330 | #endif |
| 331 | } |
| 332 | |
| 333 | void MessageCenterNotificationManager::SetMessageCenterTrayDelegateForTest( |
| 334 | message_center::MessageCenterTrayDelegate* delegate) { |
| 335 | tray_.reset(delegate); |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 336 | } |
| 337 | |
Ben Murdoch | 2385ea3 | 2013-08-06 11:01:04 +0100 | [diff] [blame] | 338 | void MessageCenterNotificationManager::Observe( |
| 339 | int type, |
| 340 | const content::NotificationSource& source, |
| 341 | const content::NotificationDetails& details) { |
| 342 | if (type == chrome::NOTIFICATION_FULLSCREEN_CHANGED) { |
| 343 | const bool is_fullscreen = *content::Details<bool>(details).ptr(); |
| 344 | |
| 345 | if (is_fullscreen && tray_.get() && tray_->GetMessageCenterTray()) |
| 346 | tray_->GetMessageCenterTray()->HidePopupBubble(); |
| 347 | } else { |
| 348 | NotificationUIManagerImpl::Observe(type, source, details); |
| 349 | } |
| 350 | } |
| 351 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 352 | //////////////////////////////////////////////////////////////////////////////// |
| 353 | // ImageDownloads |
| 354 | |
| 355 | MessageCenterNotificationManager::ImageDownloads::ImageDownloads( |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 356 | message_center::MessageCenter* message_center, |
| 357 | ImageDownloadsObserver* observer) |
| 358 | : message_center_(message_center), |
| 359 | pending_downloads_(0), |
| 360 | observer_(observer) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 361 | } |
| 362 | |
| 363 | MessageCenterNotificationManager::ImageDownloads::~ImageDownloads() { } |
| 364 | |
| 365 | void MessageCenterNotificationManager::ImageDownloads::StartDownloads( |
| 366 | const Notification& notification) { |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 367 | // In case all downloads are synchronous, assume a pending download. |
| 368 | AddPendingDownload(); |
| 369 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 370 | // Notification primary icon. |
| 371 | StartDownloadWithImage( |
| 372 | notification, |
| 373 | ¬ification.icon(), |
| 374 | notification.icon_url(), |
| 375 | message_center::kNotificationIconSize, |
| 376 | base::Bind(&message_center::MessageCenter::SetNotificationIcon, |
| 377 | base::Unretained(message_center_), |
| 378 | notification.notification_id())); |
| 379 | |
| 380 | // Notification image. |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 381 | StartDownloadWithImage( |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 382 | notification, |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 383 | NULL, |
| 384 | notification.image_url(), |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 385 | message_center::kNotificationPreferredImageSize, |
| 386 | base::Bind(&message_center::MessageCenter::SetNotificationImage, |
| 387 | base::Unretained(message_center_), |
| 388 | notification.notification_id())); |
| 389 | |
| 390 | // Notification button icons. |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 391 | StartDownloadWithImage( |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 392 | notification, |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 393 | NULL, |
| 394 | notification.button_one_icon_url(), |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 395 | message_center::kNotificationButtonIconSize, |
| 396 | base::Bind(&message_center::MessageCenter::SetNotificationButtonIcon, |
| 397 | base::Unretained(message_center_), |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 398 | notification.notification_id(), |
| 399 | 0)); |
| 400 | StartDownloadWithImage( |
| 401 | notification, |
| 402 | NULL, |
| 403 | notification.button_two_icon_url(), |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 404 | message_center::kNotificationButtonIconSize, |
| 405 | base::Bind(&message_center::MessageCenter::SetNotificationButtonIcon, |
| 406 | base::Unretained(message_center_), |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 407 | notification.notification_id(), |
| 408 | 1)); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 409 | |
| 410 | // This should tell the observer we're done if everything was synchronous. |
| 411 | PendingDownloadCompleted(); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 412 | } |
| 413 | |
| 414 | void MessageCenterNotificationManager::ImageDownloads::StartDownloadWithImage( |
| 415 | const Notification& notification, |
| 416 | const gfx::Image* image, |
| 417 | const GURL& url, |
| 418 | int size, |
| 419 | const SetImageCallback& callback) { |
| 420 | // Set the image directly if we have it. |
| 421 | if (image && !image->IsEmpty()) { |
| 422 | callback.Run(*image); |
| 423 | return; |
| 424 | } |
| 425 | |
| 426 | // Leave the image null if there's no URL. |
| 427 | if (url.is_empty()) |
| 428 | return; |
| 429 | |
| 430 | content::RenderViewHost* host = notification.GetRenderViewHost(); |
| 431 | if (!host) { |
| 432 | LOG(WARNING) << "Notification needs an image but has no RenderViewHost"; |
| 433 | return; |
| 434 | } |
| 435 | |
| 436 | content::WebContents* contents = |
| 437 | content::WebContents::FromRenderViewHost(host); |
| 438 | if (!contents) { |
| 439 | LOG(WARNING) << "Notification needs an image but has no WebContents"; |
| 440 | return; |
| 441 | } |
| 442 | |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 443 | AddPendingDownload(); |
| 444 | |
| 445 | contents->DownloadImage( |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 446 | url, |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 447 | false, // Not a favicon |
| 448 | size, // Preferred size |
| 449 | 0, // No maximum size |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 450 | base::Bind( |
| 451 | &MessageCenterNotificationManager::ImageDownloads::DownloadComplete, |
| 452 | AsWeakPtr(), |
| 453 | callback)); |
| 454 | } |
| 455 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 456 | void MessageCenterNotificationManager::ImageDownloads::DownloadComplete( |
| 457 | const SetImageCallback& callback, |
| 458 | int download_id, |
Torne (Richard Coles) | 90dce4d | 2013-05-29 14:40:03 +0100 | [diff] [blame] | 459 | int http_status_code, |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 460 | const GURL& image_url, |
| 461 | int requested_size, |
| 462 | const std::vector<SkBitmap>& bitmaps) { |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 463 | PendingDownloadCompleted(); |
| 464 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 465 | if (bitmaps.empty()) |
| 466 | return; |
| 467 | gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmaps[0]); |
| 468 | callback.Run(image); |
| 469 | } |
| 470 | |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 471 | // Private methods. |
| 472 | |
| 473 | void MessageCenterNotificationManager::ImageDownloads::AddPendingDownload() { |
| 474 | ++pending_downloads_; |
| 475 | } |
| 476 | |
| 477 | void |
| 478 | MessageCenterNotificationManager::ImageDownloads::PendingDownloadCompleted() { |
| 479 | DCHECK(pending_downloads_ > 0); |
| 480 | if (--pending_downloads_ == 0 && observer_) |
| 481 | observer_->OnDownloadsCompleted(); |
| 482 | } |
| 483 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 484 | //////////////////////////////////////////////////////////////////////////////// |
| 485 | // ProfileNotification |
| 486 | |
| 487 | MessageCenterNotificationManager::ProfileNotification::ProfileNotification( |
| 488 | Profile* profile, |
| 489 | const Notification& notification, |
| 490 | message_center::MessageCenter* message_center) |
| 491 | : profile_(profile), |
| 492 | notification_(notification), |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 493 | downloads_(new ImageDownloads(message_center, this)) { |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 494 | DCHECK(profile); |
| 495 | } |
| 496 | |
| 497 | MessageCenterNotificationManager::ProfileNotification::~ProfileNotification() { |
| 498 | } |
| 499 | |
| 500 | void MessageCenterNotificationManager::ProfileNotification::StartDownloads() { |
| 501 | downloads_->StartDownloads(notification_); |
| 502 | } |
| 503 | |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 504 | void |
| 505 | MessageCenterNotificationManager::ProfileNotification::OnDownloadsCompleted() { |
| 506 | notification_.DoneRendering(); |
| 507 | } |
| 508 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 509 | std::string |
| 510 | MessageCenterNotificationManager::ProfileNotification::GetExtensionId() { |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 511 | ExtensionInfoMap* extension_info_map = |
| 512 | extensions::ExtensionSystem::Get(profile())->info_map(); |
| 513 | ExtensionSet extensions; |
| 514 | extension_info_map->GetExtensionsWithAPIPermissionForSecurityOrigin( |
| 515 | notification().origin_url(), notification().process_id(), |
| 516 | extensions::APIPermission::kNotification, &extensions); |
| 517 | |
| 518 | DesktopNotificationService* desktop_service = |
| 519 | DesktopNotificationServiceFactory::GetForProfile(profile()); |
| 520 | for (ExtensionSet::const_iterator iter = extensions.begin(); |
| 521 | iter != extensions.end(); ++iter) { |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 522 | if (desktop_service->IsNotifierEnabled(message_center::NotifierId( |
| 523 | message_center::NotifierId::APPLICATION, (*iter)->id()))) { |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 524 | return (*iter)->id(); |
Ben Murdoch | eb525c5 | 2013-07-10 11:40:50 +0100 | [diff] [blame] | 525 | } |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 526 | } |
| 527 | return std::string(); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 528 | } |
| 529 | |
| 530 | //////////////////////////////////////////////////////////////////////////////// |
| 531 | // private |
| 532 | |
| 533 | void MessageCenterNotificationManager::AddProfileNotification( |
| 534 | ProfileNotification* profile_notification) { |
| 535 | const Notification& notification = profile_notification->notification(); |
| 536 | std::string id = notification.notification_id(); |
| 537 | // Notification ids should be unique. |
| 538 | DCHECK(profile_notifications_.find(id) == profile_notifications_.end()); |
| 539 | profile_notifications_[id] = profile_notification; |
| 540 | |
Torne (Richard Coles) | 868fa2f | 2013-06-11 10:57:03 +0100 | [diff] [blame] | 541 | // Create the copy for message center, and ensure the extension ID is correct. |
| 542 | scoped_ptr<message_center::Notification> message_center_notification( |
| 543 | new message_center::Notification(notification)); |
| 544 | message_center_notification->set_extension_id( |
| 545 | profile_notification->GetExtensionId()); |
| 546 | message_center_->AddNotification(message_center_notification.Pass()); |
| 547 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 548 | profile_notification->StartDownloads(); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 549 | } |
| 550 | |
| 551 | void MessageCenterNotificationManager::RemoveProfileNotification( |
| 552 | ProfileNotification* profile_notification, |
| 553 | bool by_user) { |
| 554 | profile_notification->notification().Close(by_user); |
| 555 | std::string id = profile_notification->notification().notification_id(); |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 556 | profile_notifications_.erase(id); |
| 557 | delete profile_notification; |
| 558 | } |
| 559 | |
| 560 | MessageCenterNotificationManager::ProfileNotification* |
| 561 | MessageCenterNotificationManager::FindProfileNotification( |
| 562 | const std::string& id) const { |
| 563 | NotificationMap::const_iterator iter = profile_notifications_.find(id); |
Torne (Richard Coles) | c2e0dbd | 2013-05-09 18:35:53 +0100 | [diff] [blame] | 564 | if (iter == profile_notifications_.end()) |
| 565 | return NULL; |
| 566 | |
Torne (Richard Coles) | 2a99a7e | 2013-03-28 15:31:22 +0000 | [diff] [blame] | 567 | return (*iter).second; |
| 568 | } |