blob: 566173424653be5d5af52272e26a278e4ab1adeb [file] [log] [blame]
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +00001// 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 Murdoch2385ea32013-08-06 11:01:04 +010010#include "chrome/browser/chrome_notification_types.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010011#include "chrome/browser/extensions/extension_info_map.h"
12#include "chrome/browser/extensions/extension_system.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000013#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 Murdoch2385ea32013-08-06 11:01:04 +010023#include "content/public/browser/notification_service.h"
24#include "content/public/browser/user_metrics.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000025#include "content/public/browser/web_contents.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010026#include "content/public/common/url_constants.h"
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010027#include "ui/message_center/message_center_style.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000028#include "ui/message_center/message_center_tray.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010029#include "ui/message_center/notifier_settings.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000030
Ben Murdocheb525c52013-07-10 11:40:50 +010031namespace {
32// The first-run balloon will be shown |kFirstRunIdleDelaySeconds| after all
33// popups go away and the user has notifications in the message center.
34const int kFirstRunIdleDelaySeconds = 1;
35} // namespace
36
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000037MessageCenterNotificationManager::MessageCenterNotificationManager(
Ben Murdocheb525c52013-07-10 11:40:50 +010038 message_center::MessageCenter* message_center,
Ben Murdochbb1529c2013-08-08 10:24:53 +010039 PrefService* local_state,
40 scoped_ptr<message_center::NotifierSettingsProvider> settings_provider)
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010041 : message_center_(message_center),
Ben Murdocheb525c52013-07-10 11:40:50 +010042#if defined(OS_WIN)
43 first_run_idle_timeout_(
44 base::TimeDelta::FromSeconds(kFirstRunIdleDelaySeconds)),
45 weak_factory_(this),
46#endif
Ben Murdochbb1529c2013-08-08 10:24:53 +010047 settings_provider_(settings_provider.Pass()) {
Ben Murdocheb525c52013-07-10 11:40:50 +010048#if defined(OS_WIN)
49 first_run_pref_.Init(prefs::kMessageCenterShowedFirstRunBalloon, local_state);
50#endif
51
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000052 message_center_->SetDelegate(this);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010053 message_center_->AddObserver(this);
Ben Murdochbb1529c2013-08-08 10:24:53 +010054 message_center_->SetNotifierSettingsProvider(settings_provider_.get());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000055
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010056#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)2a99a7e2013-03-28 15:31:22 +000060 tray_.reset(message_center::CreateMessageCenterTray());
61#endif
Ben Murdoch2385ea32013-08-06 11:01:04 +010062 registrar_.Add(this,
63 chrome::NOTIFICATION_FULLSCREEN_CHANGED,
64 content::NotificationService::AllSources());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000065}
66
67MessageCenterNotificationManager::~MessageCenterNotificationManager() {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010068 message_center_->RemoveObserver(this);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000069}
70
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000071////////////////////////////////////////////////////////////////////////////////
72// NotificationUIManager
73
Ben Murdoch558790d2013-07-30 15:19:42 +010074const 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)2a99a7e2013-03-28 15:31:22 +000080 if (iter == profile_notifications_.end())
Ben Murdoch558790d2013-07-30 15:19:42 +010081 return NULL;
82 return &(iter->second->notification());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000083}
84
85bool 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)c2e0dbd2013-05-09 18:35:53 +010095 message_center_->RemoveNotification(id, /* by_user */ false);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000096 return true;
97}
98
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010099std::set<std::string>
100MessageCenterNotificationManager::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 Murdocheb525c52013-07-10 11:40:50 +0100111 profile == (*iter).second->profile()) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100112 notification_ids.insert(iter->first);
113 }
114 }
115 return notification_ids;
116}
117
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000118bool 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)c2e0dbd2013-05-09 18:35:53 +0100128 message_center_->RemoveNotification(curiter->first, /* by_user */ false);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000129 removed = true;
130 }
131 }
132 return removed;
133}
134
135bool 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 Murdocheb525c52013-07-10 11:40:50 +0100142 if (profile == (*curiter).second->profile()) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100143 message_center_->RemoveNotification(curiter->first, /* by_user */ false);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000144 removed = true;
145 }
146 }
147 return removed;
148}
149
150void MessageCenterNotificationManager::CancelAll() {
151 NotificationUIManagerImpl::CancelAll();
152
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100153 message_center_->RemoveAllNotifications(/* by_user */ false);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000154}
155
156////////////////////////////////////////////////////////////////////////////////
157// NotificationUIManagerImpl
158
159bool MessageCenterNotificationManager::ShowNotification(
160 const Notification& notification, Profile* profile) {
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100161 if (message_center_->IsMessageCenterVisible())
162 return false;
163
164 if (UpdateNotification(notification, profile))
165 return true;
166
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000167 AddProfileNotification(
168 new ProfileNotification(profile, notification, message_center_));
169 return true;
170}
171
172bool MessageCenterNotificationManager::UpdateNotification(
173 const Notification& notification, Profile* profile) {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100174 // 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)868fa2f2013-06-11 10:57:03 +0100180 return false;
181
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000182 const string16& replace_id = notification.replace_id();
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100183 if (replace_id.empty())
184 return false;
185
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000186 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 Murdocheb525c52013-07-10 11:40:50 +0100197 old_notification->profile() == profile) {
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100198 // 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)2a99a7e2013-03-28 15:31:22 +0000206 std::string old_id =
207 old_notification->notification().notification_id();
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100208 DCHECK(message_center_->HasNotification(old_id));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000209
210 // Add/remove notification in the local list but just update the same
211 // one in MessageCenter.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000212 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)868fa2f2013-06-11 10:57:03 +0100217
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)2a99a7e2013-03-28 15:31:22 +0000223 message_center_->UpdateNotification(old_id,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100224 message_center_notification.Pass());
225
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000226 new_notification->StartDownloads();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000227 return true;
228 }
229 }
230 return false;
231}
232
233////////////////////////////////////////////////////////////////////////////////
234// MessageCenter::Delegate
235
236void MessageCenterNotificationManager::DisableExtension(
237 const std::string& notification_id) {
238 ProfileNotification* profile_notification =
239 FindProfileNotification(notification_id);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100240 if (!profile_notification)
241 return;
242
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000243 std::string extension_id = profile_notification->GetExtensionId();
244 DCHECK(!extension_id.empty()); // or UI should not have enabled the command.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100245 DesktopNotificationService* service =
246 DesktopNotificationServiceFactory::GetForProfile(
247 profile_notification->profile());
Ben Murdocheb525c52013-07-10 11:40:50 +0100248 message_center::NotifierId notifier_id(
249 message_center::NotifierId::APPLICATION, extension_id);
250 service->SetNotifierEnabled(notifier_id, false);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000251}
252
253void MessageCenterNotificationManager::DisableNotificationsFromSource(
254 const std::string& notification_id) {
255 ProfileNotification* profile_notification =
256 FindProfileNotification(notification_id);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100257 if (!profile_notification)
258 return;
259
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000260 // 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)c2e0dbd2013-05-09 18:35:53 +0100265 if (profile_notification->notification().origin_url().scheme() ==
266 chrome::kChromeUIScheme) {
267 const std::string name =
268 profile_notification->notification().origin_url().host();
Ben Murdocheb525c52013-07-10 11:40:50 +0100269 message_center::NotifierId notifier_id(
270 message_center::ParseSystemComponentName(name));
271 service->SetNotifierEnabled(notifier_id, false);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100272 } else {
273 service->DenyPermission(profile_notification->notification().origin_url());
274 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000275}
276
277void 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)c2e0dbd2013-05-09 18:35:53 +0100287 if (!profile_notification)
288 return;
289
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000290 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)c2e0dbd2013-05-09 18:35:53 +0100299////////////////////////////////////////////////////////////////////////////////
300// MessageCenter::Observer
301void 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 Murdocheb525c52013-07-10 11:40:50 +0100311
312#if defined(OS_WIN)
313 CheckFirstRunTimer();
314#endif
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000315}
316
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100317void 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 Murdocheb525c52013-07-10 11:40:50 +0100321#if defined(OS_WIN)
322 CheckFirstRunTimer();
323#endif
324}
325
326void MessageCenterNotificationManager::OnNotificationUpdated(
327 const std::string& notification_id) {
328#if defined(OS_WIN)
329 CheckFirstRunTimer();
330#endif
331}
332
333void MessageCenterNotificationManager::SetMessageCenterTrayDelegateForTest(
334 message_center::MessageCenterTrayDelegate* delegate) {
335 tray_.reset(delegate);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100336}
337
Ben Murdoch2385ea32013-08-06 11:01:04 +0100338void 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)2a99a7e2013-03-28 15:31:22 +0000352////////////////////////////////////////////////////////////////////////////////
353// ImageDownloads
354
355MessageCenterNotificationManager::ImageDownloads::ImageDownloads(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100356 message_center::MessageCenter* message_center,
357 ImageDownloadsObserver* observer)
358 : message_center_(message_center),
359 pending_downloads_(0),
360 observer_(observer) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000361}
362
363MessageCenterNotificationManager::ImageDownloads::~ImageDownloads() { }
364
365void MessageCenterNotificationManager::ImageDownloads::StartDownloads(
366 const Notification& notification) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100367 // In case all downloads are synchronous, assume a pending download.
368 AddPendingDownload();
369
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000370 // Notification primary icon.
371 StartDownloadWithImage(
372 notification,
373 &notification.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)868fa2f2013-06-11 10:57:03 +0100381 StartDownloadWithImage(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000382 notification,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100383 NULL,
384 notification.image_url(),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000385 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)868fa2f2013-06-11 10:57:03 +0100391 StartDownloadWithImage(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000392 notification,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100393 NULL,
394 notification.button_one_icon_url(),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000395 message_center::kNotificationButtonIconSize,
396 base::Bind(&message_center::MessageCenter::SetNotificationButtonIcon,
397 base::Unretained(message_center_),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100398 notification.notification_id(),
399 0));
400 StartDownloadWithImage(
401 notification,
402 NULL,
403 notification.button_two_icon_url(),
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000404 message_center::kNotificationButtonIconSize,
405 base::Bind(&message_center::MessageCenter::SetNotificationButtonIcon,
406 base::Unretained(message_center_),
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100407 notification.notification_id(),
408 1));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100409
410 // This should tell the observer we're done if everything was synchronous.
411 PendingDownloadCompleted();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000412}
413
414void 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)c2e0dbd2013-05-09 18:35:53 +0100443 AddPendingDownload();
444
445 contents->DownloadImage(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000446 url,
Ben Murdocheb525c52013-07-10 11:40:50 +0100447 false, // Not a favicon
448 size, // Preferred size
449 0, // No maximum size
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000450 base::Bind(
451 &MessageCenterNotificationManager::ImageDownloads::DownloadComplete,
452 AsWeakPtr(),
453 callback));
454}
455
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000456void MessageCenterNotificationManager::ImageDownloads::DownloadComplete(
457 const SetImageCallback& callback,
458 int download_id,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100459 int http_status_code,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000460 const GURL& image_url,
461 int requested_size,
462 const std::vector<SkBitmap>& bitmaps) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100463 PendingDownloadCompleted();
464
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000465 if (bitmaps.empty())
466 return;
467 gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmaps[0]);
468 callback.Run(image);
469}
470
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100471// Private methods.
472
473void MessageCenterNotificationManager::ImageDownloads::AddPendingDownload() {
474 ++pending_downloads_;
475}
476
477void
478MessageCenterNotificationManager::ImageDownloads::PendingDownloadCompleted() {
479 DCHECK(pending_downloads_ > 0);
480 if (--pending_downloads_ == 0 && observer_)
481 observer_->OnDownloadsCompleted();
482}
483
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000484////////////////////////////////////////////////////////////////////////////////
485// ProfileNotification
486
487MessageCenterNotificationManager::ProfileNotification::ProfileNotification(
488 Profile* profile,
489 const Notification& notification,
490 message_center::MessageCenter* message_center)
491 : profile_(profile),
492 notification_(notification),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100493 downloads_(new ImageDownloads(message_center, this)) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000494 DCHECK(profile);
495}
496
497MessageCenterNotificationManager::ProfileNotification::~ProfileNotification() {
498}
499
500void MessageCenterNotificationManager::ProfileNotification::StartDownloads() {
501 downloads_->StartDownloads(notification_);
502}
503
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100504void
505MessageCenterNotificationManager::ProfileNotification::OnDownloadsCompleted() {
506 notification_.DoneRendering();
507}
508
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000509std::string
510 MessageCenterNotificationManager::ProfileNotification::GetExtensionId() {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100511 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 Murdocheb525c52013-07-10 11:40:50 +0100522 if (desktop_service->IsNotifierEnabled(message_center::NotifierId(
523 message_center::NotifierId::APPLICATION, (*iter)->id()))) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100524 return (*iter)->id();
Ben Murdocheb525c52013-07-10 11:40:50 +0100525 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100526 }
527 return std::string();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000528}
529
530////////////////////////////////////////////////////////////////////////////////
531// private
532
533void 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)868fa2f2013-06-11 10:57:03 +0100541 // 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)2a99a7e2013-03-28 15:31:22 +0000548 profile_notification->StartDownloads();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000549}
550
551void 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)2a99a7e2013-03-28 15:31:22 +0000556 profile_notifications_.erase(id);
557 delete profile_notification;
558}
559
560MessageCenterNotificationManager::ProfileNotification*
561 MessageCenterNotificationManager::FindProfileNotification(
562 const std::string& id) const {
563 NotificationMap::const_iterator iter = profile_notifications_.find(id);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100564 if (iter == profile_notifications_.end())
565 return NULL;
566
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000567 return (*iter).second;
568}