Refactor MessageCenterSettingsController.

The CL does refactoring for MessageCenterSettingsController to get rid
of #ifdef macros for CHROME_OS.

1. Define NotifierSource abstract class that provides a list of specific
   type of notifiers.
2. Define subclass for each notifier type (APPLICATION, WEB_PAGE,
   SYSTEM_COMPONENT, ARC_APPLICATION).
3. Let MessageCenterSettingsController delegate to each source.

BUG=620184
TEST=None

Review-Url: https://codereview.chromium.org/2064363002
Cr-Commit-Position: refs/heads/master@{#400867}
diff --git a/chrome/browser/notifications/application_notifier_source.cc b/chrome/browser/notifications/application_notifier_source.cc
new file mode 100644
index 0000000..132b0f23
--- /dev/null
+++ b/chrome/browser/notifications/application_notifier_source.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/notifications/application_notifier_source.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/notifications/notifier_state_tracker.h"
+#include "chrome/browser/notifications/notifier_state_tracker_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension_set.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "ui/message_center/notifier_settings.h"
+
+ApplicationNotifierSource::ApplicationNotifierSource(Observer* observer)
+    : observer_(observer) {}
+
+ApplicationNotifierSource::~ApplicationNotifierSource() {}
+
+std::vector<std::unique_ptr<message_center::Notifier>>
+ApplicationNotifierSource::GetNotifierList(Profile* profile) {
+  std::vector<std::unique_ptr<message_center::Notifier>> notifiers;
+  const extensions::ExtensionSet& extension_set =
+      extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
+  // The extension icon size has to be 32x32 at least to load bigger icons if
+  // the icon doesn't exist for the specified size, and in that case it falls
+  // back to the default icon. The fetched icon will be resized in the
+  // settings dialog. See chrome/browser/extensions/extension_icon_image.cc
+  // and crbug.com/222931
+  app_icon_loader_.reset(new extensions::ExtensionAppIconLoader(
+      profile, extension_misc::EXTENSION_ICON_SMALL, this));
+  for (extensions::ExtensionSet::const_iterator iter = extension_set.begin();
+       iter != extension_set.end(); ++iter) {
+    const extensions::Extension* extension = iter->get();
+    if (!extension->permissions_data()->HasAPIPermission(
+            extensions::APIPermission::kNotifications)) {
+      continue;
+    }
+
+    // Hosted apps are no longer able to affect the notifications permission
+    // state for web notifications.
+    // TODO(dewittj): Deprecate the 'notifications' permission for hosted
+    // apps.
+    if (extension->is_hosted_app())
+      continue;
+
+    message_center::NotifierId notifier_id(
+        message_center::NotifierId::APPLICATION, extension->id());
+    NotifierStateTracker* const notifier_state_tracker =
+        NotifierStateTrackerFactory::GetForProfile(profile);
+    notifiers.emplace_back(new message_center::Notifier(
+        notifier_id, base::UTF8ToUTF16(extension->name()),
+        notifier_state_tracker->IsNotifierEnabled(notifier_id)));
+    app_icon_loader_->FetchImage(extension->id());
+  }
+
+  return notifiers;
+}
+
+void ApplicationNotifierSource::SetNotifierEnabled(
+    Profile* profile,
+    const message_center::Notifier& notifier,
+    bool enabled) {
+  NotifierStateTrackerFactory::GetForProfile(profile)->SetNotifierEnabled(
+      notifier.notifier_id, enabled);
+  observer_->OnNotifierEnabledChanged(notifier.notifier_id, enabled);
+}
+
+message_center::NotifierId::NotifierType
+ApplicationNotifierSource::GetNotifierType() {
+  return message_center::NotifierId::APPLICATION;
+}
+
+void ApplicationNotifierSource::OnAppImageUpdated(const std::string& id,
+                                                  const gfx::ImageSkia& image) {
+  observer_->OnIconImageUpdated(
+      message_center::NotifierId(message_center::NotifierId::APPLICATION, id),
+      gfx::Image(image));
+}
diff --git a/chrome/browser/notifications/application_notifier_source.h b/chrome/browser/notifications/application_notifier_source.h
new file mode 100644
index 0000000..a3604ba
--- /dev/null
+++ b/chrome/browser/notifications/application_notifier_source.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NOTIFICATIONS_APPLICATION_NOTIFIER_SOURCE_H_
+#define CHROME_BROWSER_NOTIFICATIONS_APPLICATION_NOTIFIER_SOURCE_H_
+
+#include "chrome/browser/extensions/extension_app_icon_loader.h"
+#include "chrome/browser/notifications/notifier_source.h"
+
+class ApplicationNotifierSource : public NotifierSource,
+                                  public AppIconLoaderDelegate {
+ public:
+  explicit ApplicationNotifierSource(Observer* observer);
+  ~ApplicationNotifierSource() override;
+
+  std::vector<std::unique_ptr<message_center::Notifier>> GetNotifierList(
+      Profile* profile) override;
+
+  void SetNotifierEnabled(Profile* profile,
+                          const message_center::Notifier& notifier,
+                          bool enabled) override;
+
+  message_center::NotifierId::NotifierType GetNotifierType() override;
+
+ private:
+  // Overridden from AppIconLoaderDelegate.
+  void OnAppImageUpdated(const std::string& id,
+                         const gfx::ImageSkia& image) override;
+
+  std::unique_ptr<AppIconLoader> app_icon_loader_;
+
+  // Lifetime of parent must be longer than the source.
+  Observer* observer_;
+};
+
+#endif  // CHROME_BROWSER_NOTIFICATIONS_APPLICATION_NOTIFIER_SOURCE_H_
diff --git a/chrome/browser/notifications/arc_application_notifier_source_chromeos.cc b/chrome/browser/notifications/arc_application_notifier_source_chromeos.cc
new file mode 100644
index 0000000..171268e
--- /dev/null
+++ b/chrome/browser/notifications/arc_application_notifier_source_chromeos.cc
@@ -0,0 +1,69 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/notifications/arc_application_notifier_source_chromeos.h"
+
+#include <set>
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "ui/message_center/notifier_settings.h"
+
+namespace arc {
+
+namespace {
+constexpr int kSetNotificationsEnabledMinVersion = 6;
+}  // namespace
+
+ArcApplicationNotifierSourceChromeOS::ArcApplicationNotifierSourceChromeOS(
+    Observer* observer)
+    : observer_(observer) {}
+
+std::vector<std::unique_ptr<message_center::Notifier>>
+ArcApplicationNotifierSourceChromeOS::GetNotifierList(Profile* profile) {
+  const ArcAppListPrefs* const app_list = ArcAppListPrefs::Get(profile);
+  const std::vector<std::string>& app_ids = app_list->GetAppIds();
+  std::set<std::string> added_packages;
+  std::vector<std::unique_ptr<message_center::Notifier>> results;
+
+  for (const std::string& app_id : app_ids) {
+    const auto app = app_list->GetApp(app_id);
+    if (!app)
+      continue;
+    // Handle packages having multiple launcher activities.
+    if (added_packages.count(app->package_name))
+      continue;
+
+    added_packages.insert(app->package_name);
+    message_center::NotifierId notifier_id(
+        message_center::NotifierId::ARC_APPLICATION, app->package_name);
+    results.emplace_back(
+        new message_center::Notifier(notifier_id, base::ASCIIToUTF16(app->name),
+                                     app->notifications_enabled));
+  }
+
+  return results;
+}
+
+void ArcApplicationNotifierSourceChromeOS::SetNotifierEnabled(
+    Profile* profile,
+    const message_center::Notifier& notifier,
+    bool enabled) {
+  auto* const service = arc::ArcBridgeService::Get();
+  if (service) {
+    if (service->app_version() >= kSetNotificationsEnabledMinVersion) {
+      service->app_instance()->SetNotificationsEnabled(notifier.notifier_id.id,
+                                                       enabled);
+      observer_->OnNotifierEnabledChanged(notifier.notifier_id, enabled);
+    }
+  }
+}
+
+message_center::NotifierId::NotifierType
+ArcApplicationNotifierSourceChromeOS::GetNotifierType() {
+  return message_center::NotifierId::ARC_APPLICATION;
+}
+
+}  // namespace arc
diff --git a/chrome/browser/notifications/arc_application_notifier_source_chromeos.h b/chrome/browser/notifications/arc_application_notifier_source_chromeos.h
new file mode 100644
index 0000000..35232f6
--- /dev/null
+++ b/chrome/browser/notifications/arc_application_notifier_source_chromeos.h
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NOTIFICATIONS_ARC_APPLICATION_NOTIFIER_SOURCE_CHROMEOS_H_
+#define CHROME_BROWSER_NOTIFICATIONS_ARC_APPLICATION_NOTIFIER_SOURCE_CHROMEOS_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "chrome/browser/notifications/notifier_source.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace message_center {
+struct Notifier;
+}
+
+namespace arc {
+
+// TODO(hirono): Observe enabled flag change and notify it to message center.
+class ArcApplicationNotifierSourceChromeOS : public NotifierSource {
+ public:
+  explicit ArcApplicationNotifierSourceChromeOS(Observer* observer);
+
+  // TODO(hirono): Rewrite the function with new API to fetch package list.
+  std::vector<std::unique_ptr<message_center::Notifier>> GetNotifierList(
+      Profile* profile) override;
+  void SetNotifierEnabled(Profile* profile,
+                          const message_center::Notifier& notifier,
+                          bool enabled) override;
+  message_center::NotifierId::NotifierType GetNotifierType() override;
+
+ private:
+  Observer* observer_;
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_NOTIFICATIONS_ARC_APPLICATION_NOTIFIER_SOURCE_CHROMEOS_H_
diff --git a/chrome/browser/notifications/arc_notifier_manager.cc b/chrome/browser/notifications/arc_notifier_manager.cc
deleted file mode 100644
index d6f96b8..0000000
--- a/chrome/browser/notifications/arc_notifier_manager.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/notifications/arc_notifier_manager.h"
-
-#include <set>
-
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
-#include "ui/message_center/notifier_settings.h"
-
-namespace arc {
-
-namespace {
-constexpr int kSetNotificationsEnabledMinVersion = 6;
-}  // namespace
-
-std::vector<std::unique_ptr<message_center::Notifier>>
-ArcNotifierManager::GetNotifiers(content::BrowserContext* profile) {
-  const ArcAppListPrefs* const app_list = ArcAppListPrefs::Get(profile);
-  const std::vector<std::string>& app_ids = app_list->GetAppIds();
-  std::set<std::string> added_packages;
-  std::vector<std::unique_ptr<message_center::Notifier>> results;
-
-  for (const std::string& app_id : app_ids) {
-    const auto app = app_list->GetApp(app_id);
-    if (!app)
-      continue;
-    // Handle packages having multiple launcher activities.
-    if (added_packages.count(app->package_name))
-      continue;
-
-    added_packages.insert(app->package_name);
-    message_center::NotifierId notifier_id(
-        message_center::NotifierId::ARC_APPLICATION, app->package_name);
-    results.emplace_back(new message_center::Notifier(
-        notifier_id,
-        base::ASCIIToUTF16(app->name),
-        app->notifications_enabled));
-  }
-
-  return results;
-}
-
-void ArcNotifierManager::SetNotifierEnabled(const std::string& package,
-                                            bool enabled) {
-  auto* const service = arc::ArcBridgeService::Get();
-  if (service) {
-    if (service->app_version() >= kSetNotificationsEnabledMinVersion) {
-      service->app_instance()->SetNotificationsEnabled(package, enabled);
-    }
-  }
-}
-
-}  // namespace arc
diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc
index 8de630e..03c8a32 100644
--- a/chrome/browser/notifications/message_center_settings_controller.cc
+++ b/chrome/browser/notifications/message_center_settings_controller.cc
@@ -11,46 +11,26 @@
 #include "base/command_line.h"
 #include "base/i18n/string_compare.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/task/cancelable_task_tracker.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/extensions/extension_app_icon_loader.h"
-#include "chrome/browser/favicon/favicon_service_factory.h"
-#include "chrome/browser/notifications/desktop_notification_profile_util.h"
-#include "chrome/browser/notifications/notifier_state_tracker.h"
-#include "chrome/browser/notifications/notifier_state_tracker_factory.h"
+#include "chrome/browser/notifications/application_notifier_source.h"
+#include "chrome/browser/notifications/web_page_notifier_source.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/extensions/api/notifications.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/favicon/core/favicon_service.h"
-#include "components/favicon_base/favicon_types.h"
-#include "components/history/core/browser/history_types.h"
 #include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
 #include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/common/constants.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/permissions/permissions_data.h"
-#include "grit/theme_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 #include "ui/message_center/message_center_style.h"
-#include "ui/strings/grit/ui_strings.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/common/system/system_notifier.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/notifications/arc_notifier_manager.h"
-#include "components/arc/arc_bridge_service.h"
+#include "chrome/browser/notifications/arc_application_notifier_source_chromeos.h"
+#include "chrome/browser/notifications/system_component_notifier_source_chromeos.h"
 #endif
 
 using message_center::Notifier;
@@ -98,6 +78,7 @@
 }  // namespace message_center
 
 namespace {
+
 class NotifierComparator {
  public:
   explicit NotifierComparator(icu::Collator* collator) : collator_(collator) {}
@@ -139,13 +120,26 @@
   profile_attributes_storage_.AddObserver(this);
   RebuildNotifierGroups(false);
 
+  sources_.insert(std::make_pair(
+      NotifierId::APPLICATION,
+      std::unique_ptr<NotifierSource>(new ApplicationNotifierSource(this))));
+  sources_.insert(std::make_pair(
+      NotifierId::WEB_PAGE,
+      std::unique_ptr<NotifierSource>(new WebPageNotifiereSource(this))));
+
 #if defined(OS_CHROMEOS)
   // UserManager may not exist in some tests.
   if (user_manager::UserManager::IsInitialized())
     user_manager::UserManager::Get()->AddSessionStateObserver(this);
-  // Check if ARC is enabled.
-  if (arc::ArcBridgeService::Get())
-    arc_notifier_manager_.reset(new arc::ArcNotifierManager());
+  // For system components.
+  sources_.insert(
+      std::make_pair(NotifierId::SYSTEM_COMPONENT,
+                     std::unique_ptr<NotifierSource>(
+                         new SystemComponentNotifierSourceChromeOS(this))));
+  sources_.insert(
+      std::make_pair(NotifierId::ARC_APPLICATION,
+                     std::unique_ptr<NotifierSource>(
+                         new arc::ArcApplicationNotifierSourceChromeOS(this))));
 #endif
 }
 
@@ -195,9 +189,7 @@
     return;
 
   current_notifier_group_ = index;
-  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
-                    observers_,
-                    NotifierGroupChanged());
+  DispatchNotifierGroupChanged();
 }
 
 void MessageCenterSettingsController::GetNotifierList(
@@ -209,101 +201,13 @@
   // the default profile is not loaded.
   Profile* profile = notifier_groups_[current_notifier_group_]->profile();
 
-  NotifierStateTracker* notifier_state_tracker =
-      NotifierStateTrackerFactory::GetForProfile(profile);
-
-  const extensions::ExtensionSet& extension_set =
-      extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
-  // The extension icon size has to be 32x32 at least to load bigger icons if
-  // the icon doesn't exist for the specified size, and in that case it falls
-  // back to the default icon. The fetched icon will be resized in the settings
-  // dialog. See chrome/browser/extensions/extension_icon_image.cc and
-  // crbug.com/222931
-  app_icon_loader_.reset(new extensions::ExtensionAppIconLoader(
-      profile, extension_misc::EXTENSION_ICON_SMALL, this));
-  for (extensions::ExtensionSet::const_iterator iter = extension_set.begin();
-       iter != extension_set.end();
-       ++iter) {
-    const extensions::Extension* extension = iter->get();
-    if (!extension->permissions_data()->HasAPIPermission(
-            extensions::APIPermission::kNotifications)) {
-      continue;
-    }
-
-    // Hosted apps are no longer able to affect the notifications permission
-    // state for web notifications.
-    // TODO(dewittj): Deprecate the 'notifications' permission for hosted apps.
-    if (extension->is_hosted_app())
-      continue;
-
-    NotifierId notifier_id(NotifierId::APPLICATION, extension->id());
-    notifiers->push_back(new Notifier(
-        notifier_id,
-        base::UTF8ToUTF16(extension->name()),
-        notifier_state_tracker->IsNotifierEnabled(notifier_id)));
-    app_icon_loader_->FetchImage(extension->id());
-  }
-
-  ContentSettingsForOneType settings;
-  DesktopNotificationProfileUtil::GetNotificationsSettings(profile, &settings);
-
-  favicon::FaviconService* favicon_service =
-      FaviconServiceFactory::GetForProfile(profile,
-                                           ServiceAccessType::EXPLICIT_ACCESS);
-  favicon_tracker_.reset(new base::CancelableTaskTracker());
-  patterns_.clear();
-  for (ContentSettingsForOneType::const_iterator iter = settings.begin();
-       iter != settings.end(); ++iter) {
-    if (iter->primary_pattern == ContentSettingsPattern::Wildcard() &&
-        iter->secondary_pattern == ContentSettingsPattern::Wildcard() &&
-        iter->source != "preference") {
-      continue;
-    }
-
-    std::string url_pattern = iter->primary_pattern.ToString();
-    base::string16 name = base::UTF8ToUTF16(url_pattern);
-    GURL url(url_pattern);
-    NotifierId notifier_id(url);
-    notifiers->push_back(new Notifier(
-        notifier_id,
-        name,
-        notifier_state_tracker->IsNotifierEnabled(notifier_id)));
-    patterns_[name] = iter->primary_pattern;
-    // Note that favicon service obtains the favicon from history. This means
-    // that it will fail to obtain the image if there are no history data for
-    // that URL.
-    favicon_service->GetFaviconImageForPageURL(
-        url,
-        base::Bind(&MessageCenterSettingsController::OnFaviconLoaded,
-                   base::Unretained(this),
-                   url),
-        favicon_tracker_.get());
-  }
-
-#if defined(OS_CHROMEOS)
-  // Add ARC++ apps.
-  if (arc_notifier_manager_) {
-    auto list = arc_notifier_manager_->GetNotifiers(profile);
-    for (auto& notifier : list) {
+  for (auto& source : sources_) {
+    auto source_notifiers = source.second->GetNotifierList(profile);
+    for (auto& notifier : source_notifiers) {
       notifiers->push_back(notifier.release());
     }
   }
 
-  // Screenshot notification feature is only for ChromeOS. See crbug.com/238358
-  const base::string16& screenshot_name =
-      l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_NOTIFIER_SCREENSHOT_NAME);
-  NotifierId screenshot_notifier_id(
-      NotifierId::SYSTEM_COMPONENT, ash::system_notifier::kNotifierScreenshot);
-  Notifier* const screenshot_notifier = new Notifier(
-      screenshot_notifier_id,
-      screenshot_name,
-      notifier_state_tracker->IsNotifierEnabled(screenshot_notifier_id));
-  screenshot_notifier->icon =
-      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-          IDR_SCREENSHOT_NOTIFICATION_ICON);
-  notifiers->push_back(screenshot_notifier);
-#endif
-
   UErrorCode error = U_ZERO_ERROR;
   std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
   std::unique_ptr<NotifierComparator> comparator(
@@ -318,96 +222,19 @@
   DCHECK_LT(current_notifier_group_, notifier_groups_.size());
   Profile* profile = notifier_groups_[current_notifier_group_]->profile();
 
-  switch (notifier.notifier_id.type) {
-    case NotifierId::WEB_PAGE: {
-      // WEB_PAGE notifier cannot handle in DesktopNotificationService
-      // since it has the exact URL pattern.
-      // TODO(mukai): fix this.
-      ContentSetting default_setting =
-          HostContentSettingsMapFactory::GetForProfile(profile)
-              ->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-                                         NULL);
-
-      DCHECK(default_setting == CONTENT_SETTING_ALLOW ||
-             default_setting == CONTENT_SETTING_BLOCK ||
-             default_setting == CONTENT_SETTING_ASK);
-
-      // The content setting for notifications needs to clear when it changes to
-      // the default value or get explicitly set when it differs from the
-      // default.
-      bool differs_from_default_value =
-          (default_setting != CONTENT_SETTING_ALLOW && enabled) ||
-          (default_setting == CONTENT_SETTING_ALLOW && !enabled);
-
-      if (differs_from_default_value) {
-        if (notifier.notifier_id.url.is_valid()) {
-          if (enabled) {
-            DesktopNotificationProfileUtil::GrantPermission(
-                profile, notifier.notifier_id.url);
-          } else {
-            DesktopNotificationProfileUtil::DenyPermission(
-                profile, notifier.notifier_id.url);
-          }
-        } else {
-          LOG(ERROR) << "Invalid url pattern: "
-                     << notifier.notifier_id.url.spec();
-        }
-      } else {
-        ContentSettingsPattern pattern;
-
-        const auto& iter = patterns_.find(notifier.name);
-        if (iter != patterns_.end()) {
-          pattern = iter->second;
-        } else if (notifier.notifier_id.url.is_valid()) {
-          pattern = ContentSettingsPattern::FromURLNoWildcard(
-              notifier.notifier_id.url);
-        } else {
-          LOG(ERROR) << "Invalid url pattern: "
-                     << notifier.notifier_id.url.spec();
-        }
-
-        if (pattern.IsValid()) {
-          // Note that we don't use
-          // DesktopNotificationProfileUtil::ClearSetting()
-          // here because pattern might be from user manual input and not match
-          // the default one used by ClearSetting().
-          HostContentSettingsMapFactory::GetForProfile(profile)
-              ->SetContentSettingCustomScope(
-                  pattern, ContentSettingsPattern::Wildcard(),
-                  CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-                  content_settings::ResourceIdentifier(),
-                  CONTENT_SETTING_DEFAULT);
-        }
-      }
-      break;
-    }
-    case NotifierId::APPLICATION:
-    case NotifierId::SYSTEM_COMPONENT: {
-      NotifierStateTrackerFactory::GetForProfile(profile)->SetNotifierEnabled(
-          notifier.notifier_id, enabled);
-      break;
-    }
-    case NotifierId::ARC_APPLICATION: {
-#if defined(OS_CHROMEOS)
-      if (arc_notifier_manager_) {
-        arc_notifier_manager_->SetNotifierEnabled(notifier.notifier_id.id,
-                                                  enabled);
-      }
-#else
-      NOTREACHED();
-#endif
-      break;
-    }
+  if (!sources_.count(notifier.notifier_id.type)) {
+    NOTREACHED();
+    return;
   }
-  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
-                    observers_,
-                    NotifierEnabledChanged(notifier.notifier_id, enabled));
+
+  sources_[notifier.notifier_id.type]->SetNotifierEnabled(profile, notifier,
+                                                          enabled);
 }
 
 void MessageCenterSettingsController::OnNotifierSettingsClosing() {
-  DCHECK(favicon_tracker_.get());
-  favicon_tracker_->TryCancelAll();
-  patterns_.clear();
+  for (auto& source : sources_) {
+    source.second->OnNotifierSettingsClosing();
+  }
 }
 
 bool MessageCenterSettingsController::NotifierHasAdvancedSettings(
@@ -453,15 +280,6 @@
   event_router->DispatchEventToExtension(extension_id, std::move(event));
 }
 
-void MessageCenterSettingsController::OnFaviconLoaded(
-    const GURL& url,
-    const favicon_base::FaviconImageResult& favicon_result) {
-  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
-                    observers_,
-                    UpdateIconImage(NotifierId(url), favicon_result.image));
-}
-
-
 #if defined(OS_CHROMEOS)
 void MessageCenterSettingsController::ActiveUserChanged(
     const user_manager::User* active_user) {
@@ -469,14 +287,6 @@
 }
 #endif
 
-void MessageCenterSettingsController::OnAppImageUpdated(
-    const std::string& id, const gfx::ImageSkia& image) {
-  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
-                    observers_,
-                    UpdateIconImage(NotifierId(NotifierId::APPLICATION, id),
-                                    gfx::Image(image)));
-}
-
 void MessageCenterSettingsController::Observe(
     int type,
     const content::NotificationSource& source,
@@ -510,6 +320,25 @@
   RebuildNotifierGroups(true);
 }
 
+void MessageCenterSettingsController::OnIconImageUpdated(
+    const message_center::NotifierId& id,
+    const gfx::Image& image) {
+  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver, observers_,
+                    UpdateIconImage(id, image));
+}
+
+void MessageCenterSettingsController::OnNotifierEnabledChanged(
+    const message_center::NotifierId& id,
+    bool enabled) {
+  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver, observers_,
+                    NotifierEnabledChanged(id, enabled));
+}
+
+void MessageCenterSettingsController::DispatchNotifierGroupChanged() {
+  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver, observers_,
+                    NotifierGroupChanged());
+}
+
 #if defined(OS_CHROMEOS)
 void MessageCenterSettingsController::CreateNotifierGroupForGuestLogin() {
   // Already created.
@@ -532,10 +361,7 @@
           user->GetDisplayName(), profile));
 
   notifier_groups_.push_back(std::move(group));
-
-  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
-                    observers_,
-                    NotifierGroupChanged());
+  DispatchNotifierGroupChanged();
 }
 #endif
 
@@ -595,9 +421,6 @@
   }
 #endif
 
-  if (notify) {
-    FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
-                      observers_,
-                      NotifierGroupChanged());
-  }
+  if (notify)
+    DispatchNotifierGroupChanged();
 }
diff --git a/chrome/browser/notifications/message_center_settings_controller.h b/chrome/browser/notifications/message_center_settings_controller.h
index d25c240..d1cbbc6 100644
--- a/chrome/browser/notifications/message_center_settings_controller.h
+++ b/chrome/browser/notifications/message_center_settings_controller.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "build/build_config.h"
+#include "chrome/browser/notifications/notifier_source.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/ui/app_icon_loader.h"
 #include "components/content_settings/core/common/content_settings.h"
@@ -30,12 +31,7 @@
 #endif
 
 class Profile;
-
-#if defined(OS_CHROMEOS)
-namespace arc {
-class ArcNotifierManager;
-}
-#endif
+class NotifierSource;
 
 namespace base {
 class CancelableTaskTracker;
@@ -58,7 +54,7 @@
 #if defined(OS_CHROMEOS)
       public user_manager::UserManager::UserSessionStateObserver,
 #endif
-      public AppIconLoaderDelegate {
+      public NotifierSource::Observer {
  public:
   explicit MessageCenterSettingsController(
       ProfileAttributesStorage& profile_attributes_storage);
@@ -90,17 +86,13 @@
   void ActiveUserChanged(const user_manager::User* active_user) override;
 #endif
 
-  // Overridden from AppIconLoaderDelegate.
-  void OnAppImageUpdated(const std::string& id,
-                         const gfx::ImageSkia& image) override;
-
  private:
   // Overridden from content::NotificationObserver.
   void Observe(int type,
                const content::NotificationSource& source,
                const content::NotificationDetails& details) override;
 
-  // ProfileAttributesStorage::Observer:
+  // Overridden from ProfileAttributesStorage::Observer.
   void OnProfileAdded(const base::FilePath& profile_path) override;
   void OnProfileWasRemoved(const base::FilePath& profile_path,
       const base::string16& profile_name) override;
@@ -108,8 +100,13 @@
       const base::string16& old_profile_name) override;
   void OnProfileAuthInfoChanged(const base::FilePath& profile_path) override;
 
-  void OnFaviconLoaded(const GURL& url,
-                       const favicon_base::FaviconImageResult& favicon_result);
+  // Overridden from NotifierSource::Observer.
+  void OnIconImageUpdated(const message_center::NotifierId&,
+                          const gfx::Image&) override;
+  void OnNotifierEnabledChanged(const message_center::NotifierId&,
+                                bool) override;
+
+  void DispatchNotifierGroupChanged();
 
 #if defined(OS_CHROMEOS)
   // Sets up the notifier group for the guest session. This needs to be
@@ -126,23 +123,17 @@
   // The views displaying notifier settings.
   base::ObserverList<message_center::NotifierSettingsObserver> observers_;
 
-  // The task tracker for loading favicons.
-  std::unique_ptr<base::CancelableTaskTracker> favicon_tracker_;
-
-  std::unique_ptr<AppIconLoader> app_icon_loader_;
-
-#if defined(OS_CHROMEOS)
-  std::unique_ptr<arc::ArcNotifierManager> arc_notifier_manager_;
-#endif
-
-  std::map<base::string16, ContentSettingsPattern> patterns_;
-
   // The list of all configurable notifier groups. This is each profile that is
   // loaded (and in the ProfileAttributesStorage - so no incognito profiles go
   // here).
   std::vector<std::unique_ptr<message_center::ProfileNotifierGroup>>
       notifier_groups_;
 
+  // Notifier source for each notifier type.
+  std::map<message_center::NotifierId::NotifierType,
+           std::unique_ptr<NotifierSource>>
+      sources_;
+
   size_t current_notifier_group_;
 
   content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/notifications/notifier_source.h b/chrome/browser/notifications/notifier_source.h
new file mode 100644
index 0000000..7c9f4f2e7
--- /dev/null
+++ b/chrome/browser/notifications/notifier_source.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFIER_SOURCE_H_
+#define CHROME_BROWSER_NOTIFICATIONS_NOTIFIER_SOURCE_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "ui/message_center/notifier_settings.h"
+
+class Profile;
+
+namespace message_center {
+struct Notifier;
+class NotifierSettingsObserver;
+}
+
+class NotifierSource {
+ public:
+  class Observer {
+   public:
+    virtual void OnIconImageUpdated(const message_center::NotifierId& id,
+                                    const gfx::Image& image) = 0;
+    virtual void OnNotifierEnabledChanged(const message_center::NotifierId& id,
+                                          bool enabled) = 0;
+  };
+
+  NotifierSource() = default;
+  virtual ~NotifierSource() = default;
+
+  // Returns notifiers.
+  // If the source starts loading for icon images, it needs to call
+  // Observer::OnIconImageUpdated after the icon is loaded.
+  virtual std::vector<std::unique_ptr<message_center::Notifier>>
+  GetNotifierList(Profile* profile) = 0;
+
+  // Set notifier enabled. |notifier| must have notifier type that can be
+  // handled by the source. It has responsibility to invoke
+  // Observer::OnNotifierEnabledChanged.
+  virtual void SetNotifierEnabled(Profile* profile,
+                                  const message_center::Notifier& notifier,
+                                  bool enabled) = 0;
+
+  // Release temporary resouces tagged with notifier list that is returned last
+  // time.
+  virtual void OnNotifierSettingsClosing() {}
+
+  // Notifier type provided by the source.
+  virtual message_center::NotifierId::NotifierType GetNotifierType() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NotifierSource);
+};
+
+#endif  // CHROME_BROWSER_NOTIFICATIONS_NOTIFIER_SOURCE_H_
diff --git a/chrome/browser/notifications/system_component_notifier_source_chromeos.cc b/chrome/browser/notifications/system_component_notifier_source_chromeos.cc
new file mode 100644
index 0000000..03d3eed
--- /dev/null
+++ b/chrome/browser/notifications/system_component_notifier_source_chromeos.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/notifications/system_component_notifier_source_chromeos.h"
+
+#include "ash/common/system/system_notifier.h"
+#include "chrome/browser/notifications/notifier_state_tracker.h"
+#include "chrome/browser/notifications/notifier_state_tracker_factory.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/notifier_settings.h"
+#include "ui/strings/grit/ui_strings.h"
+
+SystemComponentNotifierSourceChromeOS::SystemComponentNotifierSourceChromeOS(
+    Observer* observer)
+    : observer_(observer) {}
+
+std::vector<std::unique_ptr<message_center::Notifier>>
+SystemComponentNotifierSourceChromeOS::GetNotifierList(Profile* profile) {
+  std::vector<std::unique_ptr<message_center::Notifier>> notifiers;
+  NotifierStateTracker* const notifier_state_tracker =
+      NotifierStateTrackerFactory::GetForProfile(profile);
+
+  // Screenshot notification feature is only for ChromeOS. See
+  // crbug.com/238358
+  const base::string16& screenshot_name =
+      l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_NOTIFIER_SCREENSHOT_NAME);
+  message_center::NotifierId screenshot_notifier_id(
+      message_center::NotifierId::SYSTEM_COMPONENT,
+      ash::system_notifier::kNotifierScreenshot);
+  message_center::Notifier* const screenshot_notifier =
+      new message_center::Notifier(
+          screenshot_notifier_id, screenshot_name,
+          notifier_state_tracker->IsNotifierEnabled(screenshot_notifier_id));
+  screenshot_notifier->icon =
+      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+          IDR_SCREENSHOT_NOTIFICATION_ICON);
+  notifiers.emplace_back(screenshot_notifier);
+  return notifiers;
+}
+
+void SystemComponentNotifierSourceChromeOS::SetNotifierEnabled(
+    Profile* profile,
+    const message_center::Notifier& notifier,
+    bool enabled) {
+  NotifierStateTrackerFactory::GetForProfile(profile)->SetNotifierEnabled(
+      notifier.notifier_id, enabled);
+  observer_->OnNotifierEnabledChanged(notifier.notifier_id, enabled);
+}
+
+message_center::NotifierId::NotifierType
+SystemComponentNotifierSourceChromeOS::GetNotifierType() {
+  return message_center::NotifierId::SYSTEM_COMPONENT;
+}
diff --git a/chrome/browser/notifications/system_component_notifier_source_chromeos.h b/chrome/browser/notifications/system_component_notifier_source_chromeos.h
new file mode 100644
index 0000000..31250de9
--- /dev/null
+++ b/chrome/browser/notifications/system_component_notifier_source_chromeos.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NOTIFICATIONS_SYSTEM_COMPONENT_NOTIFIER_SOURCE_CHROMEOS_H_
+#define CHROME_BROWSER_NOTIFICATIONS_SYSTEM_COMPONENT_NOTIFIER_SOURCE_CHROMEOS_H_
+
+#include "chrome/browser/notifications/notifier_source.h"
+
+class SystemComponentNotifierSourceChromeOS : public NotifierSource {
+ public:
+  explicit SystemComponentNotifierSourceChromeOS(Observer* observer);
+  std::vector<std::unique_ptr<message_center::Notifier>> GetNotifierList(
+      Profile* profile) override;
+  void SetNotifierEnabled(Profile* profile,
+                          const message_center::Notifier& notifier,
+                          bool enabled) override;
+  message_center::NotifierId::NotifierType GetNotifierType() override;
+
+ private:
+  // Lifetime of parent must be longer than the source.
+  Observer* observer_;
+};
+
+#endif  // CHROME_BROWSER_NOTIFICATIONS_SYSTEM_COMPONENT_NOTIFIER_SOURCE_CHROMEOS_H_
diff --git a/chrome/browser/notifications/web_page_notifier_source.cc b/chrome/browser/notifications/web_page_notifier_source.cc
new file mode 100644
index 0000000..74b54cd
--- /dev/null
+++ b/chrome/browser/notifications/web_page_notifier_source.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/notifications/web_page_notifier_source.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
+#include "chrome/browser/notifications/desktop_notification_profile_util.h"
+#include "chrome/browser/notifications/notifier_state_tracker.h"
+#include "chrome/browser/notifications/notifier_state_tracker_factory.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/favicon/core/favicon_service.h"
+
+WebPageNotifiereSource::WebPageNotifiereSource(Observer* observer)
+    : observer_(observer) {}
+
+WebPageNotifiereSource::~WebPageNotifiereSource() {}
+
+std::vector<std::unique_ptr<message_center::Notifier>>
+WebPageNotifiereSource::GetNotifierList(Profile* profile) {
+  std::vector<std::unique_ptr<message_center::Notifier>> notifiers;
+
+  ContentSettingsForOneType settings;
+  DesktopNotificationProfileUtil::GetNotificationsSettings(profile, &settings);
+
+  favicon::FaviconService* const favicon_service =
+      FaviconServiceFactory::GetForProfile(profile,
+                                           ServiceAccessType::EXPLICIT_ACCESS);
+  favicon_tracker_.reset(new base::CancelableTaskTracker());
+  patterns_.clear();
+  for (ContentSettingsForOneType::const_iterator iter = settings.begin();
+       iter != settings.end(); ++iter) {
+    if (iter->primary_pattern == ContentSettingsPattern::Wildcard() &&
+        iter->secondary_pattern == ContentSettingsPattern::Wildcard() &&
+        iter->source != "preference") {
+      continue;
+    }
+
+    std::string url_pattern = iter->primary_pattern.ToString();
+    base::string16 name = base::UTF8ToUTF16(url_pattern);
+    GURL url(url_pattern);
+    message_center::NotifierId notifier_id(url);
+    NotifierStateTracker* const notifier_state_tracker =
+        NotifierStateTrackerFactory::GetForProfile(profile);
+    notifiers.emplace_back(new message_center::Notifier(
+        notifier_id, name,
+        notifier_state_tracker->IsNotifierEnabled(notifier_id)));
+    patterns_[name] = iter->primary_pattern;
+    // Note that favicon service obtains the favicon from history. This means
+    // that it will fail to obtain the image if there are no history data for
+    // that URL.
+    favicon_service->GetFaviconImageForPageURL(
+        url, base::Bind(&WebPageNotifiereSource::OnFaviconLoaded,
+                        base::Unretained(this), url),
+        favicon_tracker_.get());
+  }
+
+  return notifiers;
+}
+
+void WebPageNotifiereSource::SetNotifierEnabled(
+    Profile* profile,
+    const message_center::Notifier& notifier,
+    bool enabled) {
+  // WEB_PAGE notifier cannot handle in DesktopNotificationService
+  // since it has the exact URL pattern.
+  // TODO(mukai): fix this.
+  ContentSetting default_setting =
+      HostContentSettingsMapFactory::GetForProfile(profile)
+          ->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, NULL);
+
+  DCHECK(default_setting == CONTENT_SETTING_ALLOW ||
+         default_setting == CONTENT_SETTING_BLOCK ||
+         default_setting == CONTENT_SETTING_ASK);
+
+  // The content setting for notifications needs to clear when it changes to
+  // the default value or get explicitly set when it differs from the
+  // default.
+  bool differs_from_default_value =
+      (default_setting != CONTENT_SETTING_ALLOW && enabled) ||
+      (default_setting == CONTENT_SETTING_ALLOW && !enabled);
+
+  if (differs_from_default_value) {
+    if (notifier.notifier_id.url.is_valid()) {
+      if (enabled) {
+        DesktopNotificationProfileUtil::GrantPermission(
+            profile, notifier.notifier_id.url);
+      } else {
+        DesktopNotificationProfileUtil::DenyPermission(
+            profile, notifier.notifier_id.url);
+      }
+    } else {
+      LOG(ERROR) << "Invalid url pattern: " << notifier.notifier_id.url.spec();
+    }
+  } else {
+    ContentSettingsPattern pattern;
+
+    const auto& iter = patterns_.find(notifier.name);
+    if (iter != patterns_.end()) {
+      pattern = iter->second;
+    } else if (notifier.notifier_id.url.is_valid()) {
+      pattern =
+          ContentSettingsPattern::FromURLNoWildcard(notifier.notifier_id.url);
+    } else {
+      LOG(ERROR) << "Invalid url pattern: " << notifier.notifier_id.url.spec();
+    }
+
+    if (pattern.IsValid()) {
+      // Note that we don't use
+      // DesktopNotificationProfileUtil::ClearSetting()
+      // here because pattern might be from user manual input and not match
+      // the default one used by ClearSetting().
+      HostContentSettingsMapFactory::GetForProfile(profile)
+          ->SetContentSettingCustomScope(
+              pattern, ContentSettingsPattern::Wildcard(),
+              CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+              content_settings::ResourceIdentifier(), CONTENT_SETTING_DEFAULT);
+    }
+  }
+
+  observer_->OnNotifierEnabledChanged(notifier.notifier_id, enabled);
+}
+
+void WebPageNotifiereSource::OnNotifierSettingsClosing() {
+  DCHECK(favicon_tracker_.get());
+  favicon_tracker_->TryCancelAll();
+  patterns_.clear();
+}
+
+message_center::NotifierId::NotifierType
+WebPageNotifiereSource::GetNotifierType() {
+  return message_center::NotifierId::WEB_PAGE;
+}
+
+void WebPageNotifiereSource::OnFaviconLoaded(
+    const GURL& url,
+    const favicon_base::FaviconImageResult& favicon_result) {
+  observer_->OnIconImageUpdated(message_center::NotifierId(url),
+                                favicon_result.image);
+}
diff --git a/chrome/browser/notifications/web_page_notifier_source.h b/chrome/browser/notifications/web_page_notifier_source.h
new file mode 100644
index 0000000..2b9fe38
--- /dev/null
+++ b/chrome/browser/notifications/web_page_notifier_source.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NOTIFICATIONS_WEB_PAGE_NOTIFIER_SOURCE_H_
+#define CHROME_BROWSER_NOTIFICATIONS_WEB_PAGE_NOTIFIER_SOURCE_H_
+
+#include "chrome/browser/notifications/notifier_source.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
+
+namespace base {
+class CancelableTaskTracker;
+}
+
+namespace favicon_base {
+struct FaviconImageResult;
+}
+
+class WebPageNotifiereSource : public NotifierSource {
+ public:
+  explicit WebPageNotifiereSource(Observer* observer);
+  ~WebPageNotifiereSource() override;
+
+  std::vector<std::unique_ptr<message_center::Notifier>> GetNotifierList(
+      Profile* profile) override;
+
+  void SetNotifierEnabled(Profile* profile,
+                          const message_center::Notifier& notifier,
+                          bool enabled) override;
+
+  void OnNotifierSettingsClosing() override;
+
+  message_center::NotifierId::NotifierType GetNotifierType() override;
+
+ private:
+  void OnFaviconLoaded(const GURL& url,
+                       const favicon_base::FaviconImageResult& favicon_result);
+
+  std::map<base::string16, ContentSettingsPattern> patterns_;
+
+  // The task tracker for loading favicons.
+  std::unique_ptr<base::CancelableTaskTracker> favicon_tracker_;
+
+  // Lifetime of parent must be longer than the source.
+  Observer* observer_;
+};
+
+#endif  // CHROME_BROWSER_NOTIFICATIONS_WEB_PAGE_NOTIFIER_SOURCE_H_