Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / notifications / message_center_notification_manager.cc
blob85a4dfe57788098eb6249f49ad6710a30bf37110
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.
5 #include "chrome/browser/notifications/message_center_notification_manager.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/prefs/pref_registry_simple.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/notifications/desktop_notification_service.h"
13 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
14 #include "chrome/browser/notifications/fullscreen_notification_blocker.h"
15 #include "chrome/browser/notifications/message_center_settings_controller.h"
16 #include "chrome/browser/notifications/notification.h"
17 #include "chrome/browser/notifications/screen_lock_notification_blocker.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/browser_finder.h"
20 #include "chrome/browser/ui/chrome_pages.h"
21 #include "chrome/browser/ui/host_desktop.h"
22 #include "chrome/common/pref_names.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/common/url_constants.h"
26 #include "extensions/browser/extension_system.h"
27 #include "extensions/browser/info_map.h"
28 #include "extensions/common/extension_set.h"
29 #include "ui/gfx/image/image_skia.h"
30 #include "ui/message_center/message_center_style.h"
31 #include "ui/message_center/message_center_tray.h"
32 #include "ui/message_center/message_center_types.h"
33 #include "ui/message_center/notifier_settings.h"
35 #if defined(OS_CHROMEOS)
36 #include "chrome/browser/notifications/login_state_notification_blocker_chromeos.h"
37 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
38 #endif
40 #if defined(USE_ASH)
41 #include "ash/shell.h"
42 #include "ash/system/web_notification/web_notification_tray.h"
43 #endif
45 #if defined(OS_WIN)
46 // The first-run balloon will be shown |kFirstRunIdleDelaySeconds| after all
47 // popups go away and the user has notifications in the message center.
48 const int kFirstRunIdleDelaySeconds = 1;
49 #endif
51 MessageCenterNotificationManager::MessageCenterNotificationManager(
52 message_center::MessageCenter* message_center,
53 PrefService* local_state,
54 scoped_ptr<message_center::NotifierSettingsProvider> settings_provider)
55 : message_center_(message_center),
56 #if defined(OS_WIN)
57 first_run_idle_timeout_(
58 base::TimeDelta::FromSeconds(kFirstRunIdleDelaySeconds)),
59 weak_factory_(this),
60 #endif
61 settings_provider_(settings_provider.Pass()),
62 system_observer_(this),
63 stats_collector_(message_center) {
64 #if defined(OS_WIN)
65 first_run_pref_.Init(prefs::kMessageCenterShowedFirstRunBalloon, local_state);
66 #endif
68 message_center_->AddObserver(this);
69 message_center_->SetNotifierSettingsProvider(settings_provider_.get());
71 #if defined(OS_CHROMEOS)
72 blockers_.push_back(
73 new LoginStateNotificationBlockerChromeOS(message_center));
74 #else
75 blockers_.push_back(new ScreenLockNotificationBlocker(message_center));
76 #endif
77 blockers_.push_back(new FullscreenNotificationBlocker(message_center));
79 #if defined(OS_WIN) || defined(OS_MACOSX) \
80 || (defined(USE_AURA) && !defined(USE_ASH))
81 // On Windows, Linux and Mac, the notification manager owns the tray icon and
82 // views.Other platforms have global ownership and Create will return NULL.
83 tray_.reset(message_center::CreateMessageCenterTray());
84 #endif
85 registrar_.Add(this,
86 chrome::NOTIFICATION_FULLSCREEN_CHANGED,
87 content::NotificationService::AllSources());
90 MessageCenterNotificationManager::~MessageCenterNotificationManager() {
91 message_center_->RemoveObserver(this);
94 void MessageCenterNotificationManager::RegisterPrefs(
95 PrefRegistrySimple* registry) {
96 registry->RegisterBooleanPref(prefs::kMessageCenterShowedFirstRunBalloon,
97 false);
98 registry->RegisterBooleanPref(prefs::kMessageCenterShowIcon, true);
99 registry->RegisterBooleanPref(prefs::kMessageCenterForcedOnTaskbar, false);
102 ////////////////////////////////////////////////////////////////////////////////
103 // NotificationUIManager
105 void MessageCenterNotificationManager::Add(const Notification& notification,
106 Profile* profile) {
107 if (Update(notification, profile))
108 return;
110 DesktopNotificationServiceFactory::GetForProfile(profile)->
111 ShowWelcomeNotificationIfNecessary(notification);
113 AddProfileNotification(
114 new ProfileNotification(profile, notification, message_center_));
117 bool MessageCenterNotificationManager::Update(const Notification& notification,
118 Profile* profile) {
119 const base::string16& replace_id = notification.replace_id();
120 if (replace_id.empty())
121 return false;
123 const GURL origin_url = notification.origin_url();
124 DCHECK(origin_url.is_valid());
126 // Since replace_id is provided by arbitrary JS, we need to use origin_url
127 // (which is an app url in case of app/extension) to scope the replace ids
128 // in the given profile.
129 for (NotificationMap::iterator iter = profile_notifications_.begin();
130 iter != profile_notifications_.end(); ++iter) {
131 ProfileNotification* old_notification = (*iter).second;
132 if (old_notification->notification().replace_id() == replace_id &&
133 old_notification->notification().origin_url() == origin_url &&
134 old_notification->profile() == profile) {
135 // Changing the type from non-progress to progress does not count towards
136 // the immediate update allowed in the message center.
137 std::string old_id =
138 old_notification->notification().notification_id();
139 DCHECK(message_center_->HasNotification(old_id));
141 // Add/remove notification in the local list but just update the same
142 // one in MessageCenter.
143 delete old_notification;
144 profile_notifications_.erase(old_id);
145 ProfileNotification* new_notification =
146 new ProfileNotification(profile, notification, message_center_);
147 profile_notifications_[notification.notification_id()] = new_notification;
149 // Now pass a copy to message center.
150 scoped_ptr<message_center::Notification> message_center_notification(
151 make_scoped_ptr(new message_center::Notification(notification)));
152 message_center_->UpdateNotification(old_id,
153 message_center_notification.Pass());
155 new_notification->StartDownloads();
156 return true;
159 return false;
162 const Notification* MessageCenterNotificationManager::FindById(
163 const std::string& id) const {
164 NotificationMap::const_iterator iter = profile_notifications_.find(id);
165 if (iter == profile_notifications_.end())
166 return NULL;
167 return &(iter->second->notification());
170 bool MessageCenterNotificationManager::CancelById(const std::string& id) {
171 // See if this ID hasn't been shown yet.
172 // If it has been shown, remove it.
173 NotificationMap::iterator iter = profile_notifications_.find(id);
174 if (iter == profile_notifications_.end())
175 return false;
177 RemoveProfileNotification(iter->second);
178 message_center_->RemoveNotification(id, /* by_user */ false);
179 return true;
182 std::set<std::string>
183 MessageCenterNotificationManager::GetAllIdsByProfileAndSourceOrigin(
184 Profile* profile,
185 const GURL& source) {
187 std::set<std::string> notification_ids;
188 for (NotificationMap::iterator iter = profile_notifications_.begin();
189 iter != profile_notifications_.end(); iter++) {
190 if ((*iter).second->notification().origin_url() == source &&
191 profile == (*iter).second->profile()) {
192 notification_ids.insert(iter->first);
195 return notification_ids;
198 bool MessageCenterNotificationManager::CancelAllBySourceOrigin(
199 const GURL& source) {
200 // Same pattern as CancelById, but more complicated than the above
201 // because there may be multiple notifications from the same source.
202 bool removed = false;
204 for (NotificationMap::iterator loopiter = profile_notifications_.begin();
205 loopiter != profile_notifications_.end(); ) {
206 NotificationMap::iterator curiter = loopiter++;
207 if ((*curiter).second->notification().origin_url() == source) {
208 const std::string id = curiter->first;
209 RemoveProfileNotification(curiter->second);
210 message_center_->RemoveNotification(id, /* by_user */ false);
211 removed = true;
214 return removed;
217 bool MessageCenterNotificationManager::CancelAllByProfile(Profile* profile) {
218 // Same pattern as CancelAllBySourceOrigin.
219 bool removed = false;
221 for (NotificationMap::iterator loopiter = profile_notifications_.begin();
222 loopiter != profile_notifications_.end(); ) {
223 NotificationMap::iterator curiter = loopiter++;
224 if (profile == (*curiter).second->profile()) {
225 const std::string id = curiter->first;
226 RemoveProfileNotification(curiter->second);
227 message_center_->RemoveNotification(id, /* by_user */ false);
228 removed = true;
231 return removed;
234 void MessageCenterNotificationManager::CancelAll() {
235 message_center_->RemoveAllNotifications(/* by_user */ false);
238 ////////////////////////////////////////////////////////////////////////////////
239 // MessageCenter::Observer
240 void MessageCenterNotificationManager::OnNotificationRemoved(
241 const std::string& notification_id,
242 bool by_user) {
243 NotificationMap::const_iterator iter =
244 profile_notifications_.find(notification_id);
245 if (iter != profile_notifications_.end())
246 RemoveProfileNotification(iter->second);
248 #if defined(OS_WIN)
249 CheckFirstRunTimer();
250 #endif
253 void MessageCenterNotificationManager::OnCenterVisibilityChanged(
254 message_center::Visibility visibility) {
255 #if defined(OS_WIN)
256 if (visibility == message_center::VISIBILITY_TRANSIENT)
257 CheckFirstRunTimer();
258 #endif
261 void MessageCenterNotificationManager::OnNotificationUpdated(
262 const std::string& notification_id) {
263 #if defined(OS_WIN)
264 CheckFirstRunTimer();
265 #endif
268 void MessageCenterNotificationManager::EnsureMessageCenterClosed() {
269 if (tray_.get())
270 tray_->GetMessageCenterTray()->HideMessageCenterBubble();
272 #if defined(USE_ASH)
273 if (ash::Shell::HasInstance()) {
274 ash::WebNotificationTray* tray =
275 ash::Shell::GetInstance()->GetWebNotificationTray();
276 if (tray)
277 tray->GetMessageCenterTray()->HideMessageCenterBubble();
279 #endif
282 void MessageCenterNotificationManager::SetMessageCenterTrayDelegateForTest(
283 message_center::MessageCenterTrayDelegate* delegate) {
284 tray_.reset(delegate);
287 void MessageCenterNotificationManager::Observe(
288 int type,
289 const content::NotificationSource& source,
290 const content::NotificationDetails& details) {
291 if (type == chrome::NOTIFICATION_FULLSCREEN_CHANGED) {
292 const bool is_fullscreen = *content::Details<bool>(details).ptr();
294 if (is_fullscreen && tray_.get() && tray_->GetMessageCenterTray())
295 tray_->GetMessageCenterTray()->HidePopupBubble();
299 ////////////////////////////////////////////////////////////////////////////////
300 // ImageDownloads
302 MessageCenterNotificationManager::ImageDownloads::ImageDownloads(
303 message_center::MessageCenter* message_center,
304 ImageDownloadsObserver* observer)
305 : message_center_(message_center),
306 pending_downloads_(0),
307 observer_(observer) {
310 MessageCenterNotificationManager::ImageDownloads::~ImageDownloads() { }
312 void MessageCenterNotificationManager::ImageDownloads::StartDownloads(
313 const Notification& notification) {
314 // In case all downloads are synchronous, assume a pending download.
315 AddPendingDownload();
317 // Notification primary icon.
318 StartDownloadWithImage(
319 notification,
320 &notification.icon(),
321 notification.icon_url(),
322 base::Bind(&message_center::MessageCenter::SetNotificationIcon,
323 base::Unretained(message_center_),
324 notification.notification_id()));
326 // Notification image.
327 StartDownloadWithImage(
328 notification,
329 NULL,
330 notification.image_url(),
331 base::Bind(&message_center::MessageCenter::SetNotificationImage,
332 base::Unretained(message_center_),
333 notification.notification_id()));
335 // Notification button icons.
336 StartDownloadWithImage(
337 notification,
338 NULL,
339 notification.button_one_icon_url(),
340 base::Bind(&message_center::MessageCenter::SetNotificationButtonIcon,
341 base::Unretained(message_center_),
342 notification.notification_id(),
343 0));
344 StartDownloadWithImage(
345 notification,
346 NULL,
347 notification.button_two_icon_url(),
348 base::Bind(&message_center::MessageCenter::SetNotificationButtonIcon,
349 base::Unretained(message_center_),
350 notification.notification_id(),
351 1));
353 // This should tell the observer we're done if everything was synchronous.
354 PendingDownloadCompleted();
357 void MessageCenterNotificationManager::ImageDownloads::StartDownloadWithImage(
358 const Notification& notification,
359 const gfx::Image* image,
360 const GURL& url,
361 const SetImageCallback& callback) {
362 // Set the image directly if we have it.
363 if (image && !image->IsEmpty()) {
364 callback.Run(*image);
365 return;
368 // Leave the image null if there's no URL.
369 if (url.is_empty())
370 return;
372 content::WebContents* contents = notification.GetWebContents();
373 if (!contents) {
374 LOG(WARNING) << "Notification needs an image but has no WebContents";
375 return;
378 AddPendingDownload();
380 contents->DownloadImage(
381 url,
382 false, // Not a favicon
383 0, // No maximum size
384 base::Bind(
385 &MessageCenterNotificationManager::ImageDownloads::DownloadComplete,
386 AsWeakPtr(),
387 callback));
390 void MessageCenterNotificationManager::ImageDownloads::DownloadComplete(
391 const SetImageCallback& callback,
392 int download_id,
393 int http_status_code,
394 const GURL& image_url,
395 const std::vector<SkBitmap>& bitmaps,
396 const std::vector<gfx::Size>& original_bitmap_sizes) {
397 PendingDownloadCompleted();
399 if (bitmaps.empty())
400 return;
401 gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmaps[0]);
402 callback.Run(image);
405 // Private methods.
407 void MessageCenterNotificationManager::ImageDownloads::AddPendingDownload() {
408 ++pending_downloads_;
411 void
412 MessageCenterNotificationManager::ImageDownloads::PendingDownloadCompleted() {
413 DCHECK(pending_downloads_ > 0);
414 if (--pending_downloads_ == 0 && observer_)
415 observer_->OnDownloadsCompleted();
418 ////////////////////////////////////////////////////////////////////////////////
419 // ProfileNotification
421 MessageCenterNotificationManager::ProfileNotification::ProfileNotification(
422 Profile* profile,
423 const Notification& notification,
424 message_center::MessageCenter* message_center)
425 : profile_(profile),
426 notification_(notification),
427 downloads_(new ImageDownloads(message_center, this)) {
428 DCHECK(profile);
429 #if defined(OS_CHROMEOS)
430 notification_.set_profile_id(multi_user_util::GetUserIDFromProfile(profile));
431 #endif
434 MessageCenterNotificationManager::ProfileNotification::~ProfileNotification() {
437 void MessageCenterNotificationManager::ProfileNotification::StartDownloads() {
438 downloads_->StartDownloads(notification_);
441 void
442 MessageCenterNotificationManager::ProfileNotification::OnDownloadsCompleted() {
443 notification_.DoneRendering();
446 std::string
447 MessageCenterNotificationManager::ProfileNotification::GetExtensionId() {
448 extensions::InfoMap* extension_info_map =
449 extensions::ExtensionSystem::Get(profile())->info_map();
450 extensions::ExtensionSet extensions;
451 extension_info_map->GetExtensionsWithAPIPermissionForSecurityOrigin(
452 notification().origin_url(), notification().process_id(),
453 extensions::APIPermission::kNotification, &extensions);
455 DesktopNotificationService* desktop_service =
456 DesktopNotificationServiceFactory::GetForProfile(profile());
457 for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
458 iter != extensions.end(); ++iter) {
459 if (desktop_service->IsNotifierEnabled(message_center::NotifierId(
460 message_center::NotifierId::APPLICATION, (*iter)->id()))) {
461 return (*iter)->id();
464 return std::string();
467 ////////////////////////////////////////////////////////////////////////////////
468 // private
470 void MessageCenterNotificationManager::AddProfileNotification(
471 ProfileNotification* profile_notification) {
472 const Notification& notification = profile_notification->notification();
473 std::string id = notification.notification_id();
474 // Notification ids should be unique.
475 DCHECK(profile_notifications_.find(id) == profile_notifications_.end());
476 profile_notifications_[id] = profile_notification;
478 // Create the copy for message center, and ensure the extension ID is correct.
479 scoped_ptr<message_center::Notification> message_center_notification(
480 new message_center::Notification(notification));
481 message_center_->AddNotification(message_center_notification.Pass());
483 profile_notification->StartDownloads();
486 void MessageCenterNotificationManager::RemoveProfileNotification(
487 ProfileNotification* profile_notification) {
488 std::string id = profile_notification->notification().notification_id();
489 profile_notifications_.erase(id);
490 delete profile_notification;
493 MessageCenterNotificationManager::ProfileNotification*
494 MessageCenterNotificationManager::FindProfileNotification(
495 const std::string& id) const {
496 NotificationMap::const_iterator iter = profile_notifications_.find(id);
497 if (iter == profile_notifications_.end())
498 return NULL;
500 return (*iter).second;