blob: c6804a179b1622d455ca68cd85a46bb0ecc5fff8 [file] [log] [blame]
// Copyright 2015 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/extensions/api/settings_private/settings_private_event_router.h"
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/settings_private/generated_prefs.h"
#include "chrome/browser/extensions/api/settings_private/generated_prefs_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/settings_private.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_context.h"
namespace extensions {
SettingsPrivateEventRouter::SettingsPrivateEventRouter(
content::BrowserContext* context)
: context_(context), listening_(false), weak_ptr_factory_(this) {
// Register with the event router so we know when renderers are listening to
// our events. We first check and see if there *is* an event router, because
// some unit tests try to create all context services, but don't initialize
// the event router first.
EventRouter* event_router = EventRouter::Get(context_);
if (event_router) {
event_router->RegisterObserver(
this, api::settings_private::OnPrefsChanged::kEventName);
StartOrStopListeningForPrefsChanges();
}
Profile* profile = Profile::FromBrowserContext(context_);
prefs_util_.reset(new PrefsUtil(profile));
user_prefs_registrar_.Init(profile->GetPrefs());
local_state_registrar_.Init(g_browser_process->local_state());
}
SettingsPrivateEventRouter::~SettingsPrivateEventRouter() {
DCHECK(!listening_);
}
void SettingsPrivateEventRouter::OnGeneratedPrefChanged(
const std::string& pref_name) {
OnPreferenceChanged(pref_name);
}
void SettingsPrivateEventRouter::Shutdown() {
// Unregister with the event router. We first check and see if there *is* an
// event router, because some unit tests try to shutdown all context services,
// but didn't initialize the event router first.
EventRouter* event_router = EventRouter::Get(context_);
if (event_router)
event_router->UnregisterObserver(this);
if (listening_) {
cros_settings_subscription_map_.clear();
const PrefsUtil::TypedPrefMap& keys = prefs_util_->GetWhitelistedKeys();
settings_private::GeneratedPrefs* generated_prefs =
settings_private::GeneratedPrefsFactory::GetForBrowserContext(context_);
for (const auto& it : keys) {
if (generated_prefs && generated_prefs->HasPref(it.first))
generated_prefs->RemoveObserver(it.first, this);
else if (!prefs_util_->IsCrosSetting(it.first))
FindRegistrarForPref(it.first)->Remove(it.first);
}
}
listening_ = false;
}
void SettingsPrivateEventRouter::OnListenerAdded(
const EventListenerInfo& details) {
// Start listening to events from the PrefChangeRegistrars.
StartOrStopListeningForPrefsChanges();
}
void SettingsPrivateEventRouter::OnListenerRemoved(
const EventListenerInfo& details) {
// Stop listening to events from the PrefChangeRegistrars if there are no
// more listeners.
StartOrStopListeningForPrefsChanges();
}
PrefChangeRegistrar* SettingsPrivateEventRouter::FindRegistrarForPref(
const std::string& pref_name) {
Profile* profile = Profile::FromBrowserContext(context_);
if (prefs_util_->FindServiceForPref(pref_name) == profile->GetPrefs()) {
return &user_prefs_registrar_;
}
return &local_state_registrar_;
}
void SettingsPrivateEventRouter::StartOrStopListeningForPrefsChanges() {
EventRouter* event_router = EventRouter::Get(context_);
bool should_listen = event_router->HasEventListener(
api::settings_private::OnPrefsChanged::kEventName);
settings_private::GeneratedPrefs* generated_prefs =
settings_private::GeneratedPrefsFactory::GetForBrowserContext(context_);
if (should_listen && !listening_) {
const PrefsUtil::TypedPrefMap& keys = prefs_util_->GetWhitelistedKeys();
for (const auto& it : keys) {
std::string pref_name = it.first;
if (prefs_util_->IsCrosSetting(pref_name)) {
#if defined(OS_CHROMEOS)
std::unique_ptr<chromeos::CrosSettings::ObserverSubscription>
subscription = chromeos::CrosSettings::Get()->AddSettingsObserver(
pref_name.c_str(),
base::Bind(&SettingsPrivateEventRouter::OnPreferenceChanged,
base::Unretained(this), pref_name));
cros_settings_subscription_map_.insert(
make_pair(pref_name, std::move(subscription)));
#endif
} else if (generated_prefs && generated_prefs->HasPref(pref_name)) {
generated_prefs->AddObserver(pref_name, this);
} else {
FindRegistrarForPref(it.first)
->Add(pref_name,
base::Bind(&SettingsPrivateEventRouter::OnPreferenceChanged,
base::Unretained(this)));
}
}
} else if (!should_listen && listening_) {
const PrefsUtil::TypedPrefMap& keys = prefs_util_->GetWhitelistedKeys();
for (const auto& it : keys) {
if (prefs_util_->IsCrosSetting(it.first))
cros_settings_subscription_map_.erase(it.first);
else if (generated_prefs && generated_prefs->HasPref(it.first))
generated_prefs->RemoveObserver(it.first, this);
else
FindRegistrarForPref(it.first)->Remove(it.first);
}
}
listening_ = should_listen;
}
void SettingsPrivateEventRouter::OnPreferenceChanged(
const std::string& pref_name) {
// This posts an asynchronous task to ensure that all pref stores are updated,
// as |prefs_util_->GetPref()| relies on this information to determine if a
// preference is controlled by e.g. extensions.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&SettingsPrivateEventRouter::SendPrefChange,
weak_ptr_factory_.GetWeakPtr(), pref_name));
}
void SettingsPrivateEventRouter::SendPrefChange(const std::string& pref_name) {
EventRouter* event_router = EventRouter::Get(context_);
if (!event_router->HasEventListener(
api::settings_private::OnPrefsChanged::kEventName)) {
return;
}
std::unique_ptr<api::settings_private::PrefObject> pref_object =
prefs_util_->GetPref(pref_name);
std::vector<api::settings_private::PrefObject> prefs;
if (pref_object)
prefs.push_back(std::move(*pref_object));
std::unique_ptr<base::ListValue> args(
api::settings_private::OnPrefsChanged::Create(prefs));
std::unique_ptr<Event> extension_event(new Event(
events::SETTINGS_PRIVATE_ON_PREFS_CHANGED,
api::settings_private::OnPrefsChanged::kEventName, std::move(args)));
event_router->BroadcastEvent(std::move(extension_event));
}
SettingsPrivateEventRouter* SettingsPrivateEventRouter::Create(
content::BrowserContext* context) {
return new SettingsPrivateEventRouter(context);
}
} // namespace extensions