• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 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_settings_controller.h"
6 
7 #include <algorithm>
8 
9 #include "base/command_line.h"
10 #include "base/i18n/string_compare.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/task/cancelable_task_tracker.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/extensions/app_icon_loader_impl.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/extension_util.h"
19 #include "chrome/browser/favicon/favicon_service.h"
20 #include "chrome/browser/favicon/favicon_service_factory.h"
21 #include "chrome/browser/history/history_types.h"
22 #include "chrome/browser/notifications/desktop_notification_service.h"
23 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
24 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
25 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/profiles/profile_info_cache.h"
28 #include "chrome/browser/profiles/profile_manager.h"
29 #include "chrome/common/extensions/api/notifications.h"
30 #include "chrome/common/extensions/extension_constants.h"
31 #include "components/favicon_base/favicon_types.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/notification_source.h"
34 #include "extensions/browser/event_router.h"
35 #include "extensions/browser/extension_system.h"
36 #include "extensions/browser/extension_util.h"
37 #include "extensions/common/constants.h"
38 #include "extensions/common/extension.h"
39 #include "extensions/common/permissions/permissions_data.h"
40 #include "grit/theme_resources.h"
41 #include "grit/ui_strings.h"
42 #include "ui/base/l10n/l10n_util.h"
43 #include "ui/base/resource/resource_bundle.h"
44 #include "ui/gfx/image/image.h"
45 #include "ui/message_center/message_center_style.h"
46 
47 #if defined(OS_CHROMEOS)
48 #include "ash/system/system_notifier.h"
49 #include "chrome/browser/chromeos/profiles/profile_helper.h"
50 #endif
51 
52 using message_center::Notifier;
53 using message_center::NotifierId;
54 
55 namespace message_center {
56 
57 class ProfileNotifierGroup : public message_center::NotifierGroup {
58  public:
59   ProfileNotifierGroup(const gfx::Image& icon,
60                        const base::string16& display_name,
61                        const base::string16& login_info,
62                        size_t index,
63                        const base::FilePath& profile_path);
64   ProfileNotifierGroup(const gfx::Image& icon,
65                        const base::string16& display_name,
66                        const base::string16& login_info,
67                        size_t index,
68                        Profile* profile);
~ProfileNotifierGroup()69   virtual ~ProfileNotifierGroup() {}
70 
profile() const71   Profile* profile() const { return profile_; }
72 
73  private:
74   Profile* profile_;
75 };
76 
ProfileNotifierGroup(const gfx::Image & icon,const base::string16 & display_name,const base::string16 & login_info,size_t index,const base::FilePath & profile_path)77 ProfileNotifierGroup::ProfileNotifierGroup(const gfx::Image& icon,
78                                            const base::string16& display_name,
79                                            const base::string16& login_info,
80                                            size_t index,
81                                            const base::FilePath& profile_path)
82     : message_center::NotifierGroup(icon, display_name, login_info, index),
83       profile_(NULL) {
84   // Try to get the profile
85   profile_ =
86       g_browser_process->profile_manager()->GetProfileByPath(profile_path);
87 }
88 
ProfileNotifierGroup(const gfx::Image & icon,const base::string16 & display_name,const base::string16 & login_info,size_t index,Profile * profile)89 ProfileNotifierGroup::ProfileNotifierGroup(const gfx::Image& icon,
90                                            const base::string16& display_name,
91                                            const base::string16& login_info,
92                                            size_t index,
93                                            Profile* profile)
94     : message_center::NotifierGroup(icon, display_name, login_info, index),
95       profile_(profile) {
96 }
97 
98 }  // namespace message_center
99 
100 namespace {
101 class NotifierComparator {
102  public:
NotifierComparator(icu::Collator * collator)103   explicit NotifierComparator(icu::Collator* collator) : collator_(collator) {}
104 
operator ()(Notifier * n1,Notifier * n2)105   bool operator() (Notifier* n1, Notifier* n2) {
106     return base::i18n::CompareString16WithCollator(
107         collator_, n1->name, n2->name) == UCOL_LESS;
108   }
109 
110  private:
111   icu::Collator* collator_;
112 };
113 
SimpleCompareNotifiers(Notifier * n1,Notifier * n2)114 bool SimpleCompareNotifiers(Notifier* n1, Notifier* n2) {
115   return n1->name < n2->name;
116 }
117 
118 }  // namespace
119 
MessageCenterSettingsController(ProfileInfoCache * profile_info_cache)120 MessageCenterSettingsController::MessageCenterSettingsController(
121     ProfileInfoCache* profile_info_cache)
122     : current_notifier_group_(0),
123       profile_info_cache_(profile_info_cache),
124       weak_factory_(this) {
125   DCHECK(profile_info_cache_);
126   // The following events all represent changes that may need to be reflected in
127   // the profile selector context menu, so listen for them all.  We'll just
128   // rebuild the list when we get any of them.
129   registrar_.Add(this,
130                  chrome::NOTIFICATION_PROFILE_CREATED,
131                  content::NotificationService::AllBrowserContextsAndSources());
132   registrar_.Add(this,
133                  chrome::NOTIFICATION_PROFILE_ADDED,
134                  content::NotificationService::AllBrowserContextsAndSources());
135   registrar_.Add(this,
136                  chrome::NOTIFICATION_PROFILE_DESTROYED,
137                  content::NotificationService::AllBrowserContextsAndSources());
138   registrar_.Add(this,
139                  chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
140                  content::NotificationService::AllBrowserContextsAndSources());
141   RebuildNotifierGroups();
142 
143 #if defined(OS_CHROMEOS)
144   // UserManager may not exist in some tests.
145   if (chromeos::UserManager::IsInitialized())
146     chromeos::UserManager::Get()->AddSessionStateObserver(this);
147 #endif
148 }
149 
~MessageCenterSettingsController()150 MessageCenterSettingsController::~MessageCenterSettingsController() {
151 #if defined(OS_CHROMEOS)
152   // UserManager may not exist in some tests.
153   if (chromeos::UserManager::IsInitialized())
154     chromeos::UserManager::Get()->RemoveSessionStateObserver(this);
155 #endif
156 }
157 
AddObserver(message_center::NotifierSettingsObserver * observer)158 void MessageCenterSettingsController::AddObserver(
159     message_center::NotifierSettingsObserver* observer) {
160   observers_.AddObserver(observer);
161 }
162 
RemoveObserver(message_center::NotifierSettingsObserver * observer)163 void MessageCenterSettingsController::RemoveObserver(
164     message_center::NotifierSettingsObserver* observer) {
165   observers_.RemoveObserver(observer);
166 }
167 
GetNotifierGroupCount() const168 size_t MessageCenterSettingsController::GetNotifierGroupCount() const {
169   return notifier_groups_.size();
170 }
171 
172 const message_center::NotifierGroup&
GetNotifierGroupAt(size_t index) const173 MessageCenterSettingsController::GetNotifierGroupAt(size_t index) const {
174   DCHECK_LT(index, notifier_groups_.size());
175   return *(notifier_groups_[index]);
176 }
177 
IsNotifierGroupActiveAt(size_t index) const178 bool MessageCenterSettingsController::IsNotifierGroupActiveAt(
179     size_t index) const {
180   return current_notifier_group_ == index;
181 }
182 
183 const message_center::NotifierGroup&
GetActiveNotifierGroup() const184 MessageCenterSettingsController::GetActiveNotifierGroup() const {
185   DCHECK_LT(current_notifier_group_, notifier_groups_.size());
186   return *(notifier_groups_[current_notifier_group_]);
187 }
188 
SwitchToNotifierGroup(size_t index)189 void MessageCenterSettingsController::SwitchToNotifierGroup(size_t index) {
190   DCHECK_LT(index, notifier_groups_.size());
191   if (current_notifier_group_ == index)
192     return;
193 
194   current_notifier_group_ = index;
195   FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
196                     observers_,
197                     NotifierGroupChanged());
198 }
199 
GetNotifierList(std::vector<Notifier * > * notifiers)200 void MessageCenterSettingsController::GetNotifierList(
201     std::vector<Notifier*>* notifiers) {
202   DCHECK(notifiers);
203   if (notifier_groups_.size() <= current_notifier_group_)
204     return;
205   // Temporarily use the last used profile to prevent chrome from crashing when
206   // the default profile is not loaded.
207   Profile* profile = notifier_groups_[current_notifier_group_]->profile();
208 
209   DesktopNotificationService* notification_service =
210       DesktopNotificationServiceFactory::GetForProfile(profile);
211 
212   UErrorCode error = U_ZERO_ERROR;
213   scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
214   scoped_ptr<NotifierComparator> comparator;
215   if (!U_FAILURE(error))
216     comparator.reset(new NotifierComparator(collator.get()));
217 
218   ExtensionService* extension_service = profile->GetExtensionService();
219   const extensions::ExtensionSet* extension_set =
220       extension_service->extensions();
221   // The extension icon size has to be 32x32 at least to load bigger icons if
222   // the icon doesn't exist for the specified size, and in that case it falls
223   // back to the default icon. The fetched icon will be resized in the settings
224   // dialog. See chrome/browser/extensions/extension_icon_image.cc and
225   // crbug.com/222931
226   app_icon_loader_.reset(new extensions::AppIconLoaderImpl(
227       profile, extension_misc::EXTENSION_ICON_SMALL, this));
228   for (extensions::ExtensionSet::const_iterator iter = extension_set->begin();
229        iter != extension_set->end();
230        ++iter) {
231     const extensions::Extension* extension = iter->get();
232     if (!extension->permissions_data()->HasAPIPermission(
233             extensions::APIPermission::kNotification)) {
234       continue;
235     }
236 
237     // Exclude cached ephemeral apps that are not currently running.
238     if (extensions::util::IsEphemeralApp(extension->id(), profile) &&
239         extensions::util::IsExtensionIdle(extension->id(), profile)) {
240       continue;
241     }
242 
243     NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
244     notifiers->push_back(new Notifier(
245         notifier_id,
246         base::UTF8ToUTF16(extension->name()),
247         notification_service->IsNotifierEnabled(notifier_id)));
248     app_icon_loader_->FetchImage(extension->id());
249   }
250 
251   if (notifier::ChromeNotifierServiceFactory::UseSyncedNotifications(
252           CommandLine::ForCurrentProcess())) {
253     notifier::ChromeNotifierService* sync_notifier_service =
254         notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile(
255             profile, Profile::EXPLICIT_ACCESS);
256     if (sync_notifier_service) {
257       sync_notifier_service->GetSyncedNotificationServices(notifiers);
258 
259       if (comparator)
260         std::sort(notifiers->begin(), notifiers->end(), *comparator);
261       else
262         std::sort(notifiers->begin(), notifiers->end(), SimpleCompareNotifiers);
263     }
264   }
265 
266   int app_count = notifiers->size();
267 
268   ContentSettingsForOneType settings;
269   notification_service->GetNotificationsSettings(&settings);
270   FaviconService* favicon_service =
271       FaviconServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
272   favicon_tracker_.reset(new base::CancelableTaskTracker());
273   patterns_.clear();
274   for (ContentSettingsForOneType::const_iterator iter = settings.begin();
275        iter != settings.end(); ++iter) {
276     if (iter->primary_pattern == ContentSettingsPattern::Wildcard() &&
277         iter->secondary_pattern == ContentSettingsPattern::Wildcard() &&
278         iter->source != "preference") {
279       continue;
280     }
281 
282     std::string url_pattern = iter->primary_pattern.ToString();
283     base::string16 name = base::UTF8ToUTF16(url_pattern);
284     GURL url(url_pattern);
285     NotifierId notifier_id(url);
286     notifiers->push_back(new Notifier(
287         notifier_id,
288         name,
289         notification_service->IsNotifierEnabled(notifier_id)));
290     patterns_[name] = iter->primary_pattern;
291     FaviconService::FaviconForPageURLParams favicon_params(
292         url,
293         favicon_base::FAVICON | favicon_base::TOUCH_ICON,
294         message_center::kSettingsIconSize);
295     // Note that favicon service obtains the favicon from history. This means
296     // that it will fail to obtain the image if there are no history data for
297     // that URL.
298     favicon_service->GetFaviconImageForPageURL(
299         favicon_params,
300         base::Bind(&MessageCenterSettingsController::OnFaviconLoaded,
301                    base::Unretained(this),
302                    url),
303         favicon_tracker_.get());
304   }
305 
306   // Screenshot notification feature is only for ChromeOS. See crbug.com/238358
307 #if defined(OS_CHROMEOS)
308   const base::string16 screenshot_name =
309       l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_NOTIFIER_SCREENSHOT_NAME);
310   NotifierId screenshot_notifier_id(
311       NotifierId::SYSTEM_COMPONENT, ash::system_notifier::kNotifierScreenshot);
312   Notifier* const screenshot_notifier = new Notifier(
313       screenshot_notifier_id,
314       screenshot_name,
315       notification_service->IsNotifierEnabled(screenshot_notifier_id));
316   screenshot_notifier->icon =
317       ui::ResourceBundle::GetSharedInstance().GetImageNamed(
318           IDR_SCREENSHOT_NOTIFICATION_ICON);
319   notifiers->push_back(screenshot_notifier);
320 #endif
321 
322   if (comparator) {
323     std::sort(notifiers->begin() + app_count, notifiers->end(), *comparator);
324   } else {
325     std::sort(notifiers->begin() + app_count, notifiers->end(),
326               SimpleCompareNotifiers);
327   }
328 }
329 
SetNotifierEnabled(const Notifier & notifier,bool enabled)330 void MessageCenterSettingsController::SetNotifierEnabled(
331     const Notifier& notifier,
332     bool enabled) {
333   DCHECK_LT(current_notifier_group_, notifier_groups_.size());
334   Profile* profile = notifier_groups_[current_notifier_group_]->profile();
335 
336   DesktopNotificationService* notification_service =
337       DesktopNotificationServiceFactory::GetForProfile(profile);
338 
339   if (notifier.notifier_id.type == NotifierId::WEB_PAGE) {
340     // WEB_PAGE notifier cannot handle in DesktopNotificationService
341     // since it has the exact URL pattern.
342     // TODO(mukai): fix this.
343     ContentSetting default_setting =
344         notification_service->GetDefaultContentSetting(NULL);
345     DCHECK(default_setting == CONTENT_SETTING_ALLOW ||
346            default_setting == CONTENT_SETTING_BLOCK ||
347            default_setting == CONTENT_SETTING_ASK);
348     if ((enabled && default_setting != CONTENT_SETTING_ALLOW) ||
349         (!enabled && default_setting == CONTENT_SETTING_ALLOW)) {
350       if (notifier.notifier_id.url.is_valid()) {
351         if (enabled)
352           notification_service->GrantPermission(notifier.notifier_id.url);
353         else
354           notification_service->DenyPermission(notifier.notifier_id.url);
355       } else {
356         LOG(ERROR) << "Invalid url pattern: "
357                    << notifier.notifier_id.url.spec();
358       }
359     } else {
360       std::map<base::string16, ContentSettingsPattern>::const_iterator iter =
361           patterns_.find(notifier.name);
362       if (iter != patterns_.end()) {
363         notification_service->ClearSetting(iter->second);
364       } else {
365         LOG(ERROR) << "Invalid url pattern: "
366                    << notifier.notifier_id.url.spec();
367       }
368     }
369   } else {
370     notification_service->SetNotifierEnabled(notifier.notifier_id, enabled);
371     if (notifier.notifier_id.type == NotifierId::SYNCED_NOTIFICATION_SERVICE) {
372       notifier::ChromeNotifierService* notifier_service =
373           notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile(
374               profile, Profile::EXPLICIT_ACCESS);
375       notifier_service->OnSyncedNotificationServiceEnabled(
376           notifier.notifier_id.id, enabled);
377     }
378   }
379   FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
380                     observers_,
381                     NotifierEnabledChanged(notifier.notifier_id, enabled));
382 }
383 
OnNotifierSettingsClosing()384 void MessageCenterSettingsController::OnNotifierSettingsClosing() {
385   DCHECK(favicon_tracker_.get());
386   favicon_tracker_->TryCancelAll();
387   patterns_.clear();
388 }
389 
NotifierHasAdvancedSettings(const NotifierId & notifier_id) const390 bool MessageCenterSettingsController::NotifierHasAdvancedSettings(
391     const NotifierId& notifier_id) const {
392   // TODO(dewittj): Refactor this so that notifiers have a delegate that can
393   // handle this in a more appropriate location.
394   if (notifier_id.type != NotifierId::APPLICATION)
395     return false;
396 
397   const std::string& extension_id = notifier_id.id;
398 
399   if (notifier_groups_.size() < current_notifier_group_)
400     return false;
401   Profile* profile = notifier_groups_[current_notifier_group_]->profile();
402 
403   extensions::EventRouter* event_router = extensions::EventRouter::Get(profile);
404 
405   return event_router->ExtensionHasEventListener(
406       extension_id, extensions::api::notifications::OnShowSettings::kEventName);
407 }
408 
OnNotifierAdvancedSettingsRequested(const NotifierId & notifier_id,const std::string * notification_id)409 void MessageCenterSettingsController::OnNotifierAdvancedSettingsRequested(
410     const NotifierId& notifier_id,
411     const std::string* notification_id) {
412   // TODO(dewittj): Refactor this so that notifiers have a delegate that can
413   // handle this in a more appropriate location.
414   if (notifier_id.type != NotifierId::APPLICATION)
415     return;
416 
417   const std::string& extension_id = notifier_id.id;
418 
419   if (notifier_groups_.size() < current_notifier_group_)
420     return;
421   Profile* profile = notifier_groups_[current_notifier_group_]->profile();
422 
423   extensions::EventRouter* event_router = extensions::EventRouter::Get(profile);
424   scoped_ptr<base::ListValue> args(new base::ListValue());
425 
426   scoped_ptr<extensions::Event> event(new extensions::Event(
427       extensions::api::notifications::OnShowSettings::kEventName, args.Pass()));
428   event_router->DispatchEventToExtension(extension_id, event.Pass());
429 }
430 
OnFaviconLoaded(const GURL & url,const favicon_base::FaviconImageResult & favicon_result)431 void MessageCenterSettingsController::OnFaviconLoaded(
432     const GURL& url,
433     const favicon_base::FaviconImageResult& favicon_result) {
434   FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
435                     observers_,
436                     UpdateIconImage(NotifierId(url), favicon_result.image));
437 }
438 
439 
440 #if defined(OS_CHROMEOS)
ActiveUserChanged(const chromeos::User * active_user)441 void MessageCenterSettingsController::ActiveUserChanged(
442     const chromeos::User* active_user) {
443   RebuildNotifierGroups();
444 }
445 #endif
446 
SetAppImage(const std::string & id,const gfx::ImageSkia & image)447 void MessageCenterSettingsController::SetAppImage(const std::string& id,
448                                                   const gfx::ImageSkia& image) {
449   FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
450                     observers_,
451                     UpdateIconImage(NotifierId(NotifierId::APPLICATION, id),
452                                     gfx::Image(image)));
453 }
454 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)455 void MessageCenterSettingsController::Observe(
456     int type,
457     const content::NotificationSource& source,
458     const content::NotificationDetails& details) {
459   // GetOffTheRecordProfile() may create a new off-the-record profile, but that
460   // doesn't need to rebuild the groups.
461   if (type == chrome::NOTIFICATION_PROFILE_CREATED &&
462       content::Source<Profile>(source).ptr()->IsOffTheRecord()) {
463     return;
464   }
465 
466   RebuildNotifierGroups();
467   FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
468                     observers_,
469                     NotifierGroupChanged());
470 }
471 
472 #if defined(OS_CHROMEOS)
CreateNotifierGroupForGuestLogin()473 void MessageCenterSettingsController::CreateNotifierGroupForGuestLogin() {
474   // Already created.
475   if (!notifier_groups_.empty())
476     return;
477 
478   chromeos::UserManager* user_manager = chromeos::UserManager::Get();
479   // |notifier_groups_| can be empty in login screen too.
480   if (!user_manager->IsLoggedInAsGuest())
481     return;
482 
483   chromeos::User* user = user_manager->GetActiveUser();
484   Profile* profile = user_manager->GetProfileByUser(user);
485   DCHECK(profile);
486   notifier_groups_.push_back(
487       new message_center::ProfileNotifierGroup(gfx::Image(user->GetImage()),
488                                                user->GetDisplayName(),
489                                                user->GetDisplayName(),
490                                                0,
491                                                profile));
492 
493   FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
494                     observers_,
495                     NotifierGroupChanged());
496 }
497 #endif
498 
RebuildNotifierGroups()499 void MessageCenterSettingsController::RebuildNotifierGroups() {
500   notifier_groups_.clear();
501   current_notifier_group_ = 0;
502 
503   const size_t count = profile_info_cache_->GetNumberOfProfiles();
504 
505   for (size_t i = 0; i < count; ++i) {
506     scoped_ptr<message_center::ProfileNotifierGroup> group(
507         new message_center::ProfileNotifierGroup(
508             profile_info_cache_->GetAvatarIconOfProfileAtIndex(i),
509             profile_info_cache_->GetNameOfProfileAtIndex(i),
510             profile_info_cache_->GetUserNameOfProfileAtIndex(i),
511             i,
512             profile_info_cache_->GetPathOfProfileAtIndex(i)));
513     if (group->profile() == NULL)
514       continue;
515 
516 #if defined(OS_CHROMEOS)
517     // Allows the active user only.
518     // UserManager may not exist in some tests.
519     if (chromeos::UserManager::IsInitialized()) {
520       chromeos::UserManager* user_manager = chromeos::UserManager::Get();
521       if (user_manager->GetUserByProfile(group->profile()) !=
522           user_manager->GetActiveUser()) {
523         continue;
524       }
525     }
526 
527     // In ChromeOS, the login screen first creates a dummy profile which is not
528     // actually used, and then the real profile for the user is created when
529     // login (or turns into kiosk mode). This profile should be skipped.
530     if (chromeos::ProfileHelper::IsSigninProfile(group->profile()))
531       continue;
532 #endif
533     notifier_groups_.push_back(group.release());
534   }
535 
536 #if defined(OS_CHROMEOS)
537   // ChromeOS guest login cannot get the profile from the for-loop above, so
538   // get the group here.
539   if (notifier_groups_.empty() && chromeos::UserManager::IsInitialized() &&
540       chromeos::UserManager::Get()->IsLoggedInAsGuest()) {
541     // Do not invoke CreateNotifierGroupForGuestLogin() directly. In some tests,
542     // this method may be called before the primary profile is created, which
543     // means user_manager->GetProfileByUser() will create a new primary profile.
544     // But creating a primary profile causes an Observe() before registreing it
545     // as the primary one, which causes this method which causes another
546     // creating a primary profile, and causes an infinite loop.
547     // Thus, it would be better to delay creating group for guest login.
548     base::MessageLoopProxy::current()->PostTask(
549         FROM_HERE,
550         base::Bind(
551             &MessageCenterSettingsController::CreateNotifierGroupForGuestLogin,
552             weak_factory_.GetWeakPtr()));
553   }
554 #endif
555 }
556