blob: fc45d393289dc7bd12d140920a9bb7e5cf1646f2 [file] [log] [blame]
// Copyright 2021 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/ash/crosapi/prefs_ash.h"
#include <utility>
#include "ash/public/cpp/ash_pref_names.h"
#include "base/bind.h"
#include "base/check.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chromeos/crosapi/mojom/prefs.mojom.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user_manager.h"
namespace crosapi {
namespace {
// On non login case, ProfileManager::GetPrimaryUserProfile() returns
// a Profile instance which is different from logged in user profile.
Profile* GetPrimaryLoggedInUserProfile() {
// Check login state first.
if (!user_manager::UserManager::IsInitialized() ||
!user_manager::UserManager::Get()->IsUserLoggedIn()) {
return nullptr;
}
return ProfileManager::GetPrimaryUserProfile();
}
} // namespace
PrefsAsh::PrefsAsh(ProfileManager* profile_manager, PrefService* local_state)
: profile_manager_(profile_manager), local_state_(local_state) {
DCHECK(profile_manager_);
DCHECK(local_state_);
profile_manager_->AddObserver(this);
local_state_registrar_.Init(local_state_);
Profile* primary_profile = GetPrimaryLoggedInUserProfile();
if (primary_profile)
OnPrimaryProfileReady(primary_profile);
}
PrefsAsh::~PrefsAsh() {
// Remove this observer, in case Primary logged in profile is not yet created.
profile_manager_->RemoveObserver(this);
}
void PrefsAsh::BindReceiver(mojo::PendingReceiver<mojom::Prefs> receiver) {
receivers_.Add(this, std::move(receiver));
}
void PrefsAsh::GetPref(mojom::PrefPath path, GetPrefCallback callback) {
auto state = GetState(path);
const base::Value* value =
state ? state->pref_service->Get(state->path) : nullptr;
std::move(callback).Run(value ? base::Optional<base::Value>(value->Clone())
: base::nullopt);
}
void PrefsAsh::SetPref(mojom::PrefPath path,
base::Value value,
SetPrefCallback callback) {
auto state = GetState(path);
if (state) {
state->pref_service->Set(state->path, value);
}
std::move(callback).Run();
}
void PrefsAsh::AddObserver(mojom::PrefPath path,
mojo::PendingRemote<mojom::PrefObserver> observer) {
auto state = GetState(path);
const base::Value* value =
state ? state->pref_service->Get(state->path) : nullptr;
if (!value) {
return;
}
// Fire the observer with the initial value.
mojo::Remote<mojom::PrefObserver> remote(std::move(observer));
remote->OnPrefChanged(value->Clone());
if (!state->registrar->IsObserved(state->path)) {
// Unretained() is safe since PrefChangeRegistrar and RemoteSet within
// observers_ are owned by this and wont invoke if PrefsAsh is destroyed.
state->registrar->Add(state->path,
base::BindRepeating(&PrefsAsh::OnPrefChanged,
base::Unretained(this), path));
observers_[path].set_disconnect_handler(base::BindRepeating(
&PrefsAsh::OnDisconnect, base::Unretained(this), path));
}
observers_[path].Add(std::move(remote));
}
void PrefsAsh::OnProfileAdded(Profile* profile) {
Profile* primary_profile = GetPrimaryLoggedInUserProfile();
if (!primary_profile) {
// Primary profile is not yet available. Wait for another invocation
// to capture its creation.
return;
}
OnPrimaryProfileReady(primary_profile);
}
base::Optional<PrefsAsh::State> PrefsAsh::GetState(mojom::PrefPath path) {
switch (path) {
case mojom::PrefPath::kMetricsReportingEnabled:
return State{local_state_, &local_state_registrar_,
metrics::prefs::kMetricsReportingEnabled};
case mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled:
if (!profile_prefs_) {
LOG(WARNING) << "Primary profile is not yet initialized";
return base::nullopt;
}
return State{profile_prefs_, &profile_prefs_registrar_,
ash::prefs::kAccessibilitySpokenFeedbackEnabled};
default:
LOG(WARNING) << "Unknown pref path: " << path;
return base::nullopt;
}
}
void PrefsAsh::OnPrefChanged(mojom::PrefPath path) {
auto state = GetState(path);
const base::Value* value =
state ? state->pref_service->Get(state->path) : nullptr;
if (value) {
for (auto& observer : observers_[path]) {
observer->OnPrefChanged(value->Clone());
}
}
}
void PrefsAsh::OnDisconnect(mojom::PrefPath path, mojo::RemoteSetElementId id) {
const auto& it = observers_.find(path);
if (it != observers_.end() && it->second.empty()) {
if (auto state = GetState(path)) {
state->registrar->Remove(state->path);
}
observers_.erase(it);
}
}
void PrefsAsh::OnPrimaryProfileReady(Profile* profile) {
profile_manager_->RemoveObserver(this);
profile_prefs_ = profile->GetPrefs();
profile_prefs_registrar_.Init(profile_prefs_);
}
} // namespace crosapi