1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "components/prefs/pref_member.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <utility>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/json/values_util.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/task/sequenced_task_runner.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
15*6777b538SAndroid Build Coastguard Worker #include "components/prefs/pref_service.h"
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker using base::SequencedTaskRunner;
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker namespace subtle {
20*6777b538SAndroid Build Coastguard Worker
PrefMemberBase()21*6777b538SAndroid Build Coastguard Worker PrefMemberBase::PrefMemberBase() : prefs_(nullptr), setting_value_(false) {}
22*6777b538SAndroid Build Coastguard Worker
~PrefMemberBase()23*6777b538SAndroid Build Coastguard Worker PrefMemberBase::~PrefMemberBase() {
24*6777b538SAndroid Build Coastguard Worker Destroy();
25*6777b538SAndroid Build Coastguard Worker }
26*6777b538SAndroid Build Coastguard Worker
Init(const std::string & pref_name,PrefService * prefs,const NamedChangeCallback & observer)27*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::Init(const std::string& pref_name,
28*6777b538SAndroid Build Coastguard Worker PrefService* prefs,
29*6777b538SAndroid Build Coastguard Worker const NamedChangeCallback& observer) {
30*6777b538SAndroid Build Coastguard Worker observer_ = observer;
31*6777b538SAndroid Build Coastguard Worker Init(pref_name, prefs);
32*6777b538SAndroid Build Coastguard Worker }
33*6777b538SAndroid Build Coastguard Worker
Init(const std::string & pref_name,PrefService * prefs)34*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::Init(const std::string& pref_name, PrefService* prefs) {
35*6777b538SAndroid Build Coastguard Worker DCHECK(prefs);
36*6777b538SAndroid Build Coastguard Worker DCHECK(pref_name_.empty()); // Check that Init is only called once.
37*6777b538SAndroid Build Coastguard Worker prefs_ = prefs;
38*6777b538SAndroid Build Coastguard Worker pref_name_ = pref_name;
39*6777b538SAndroid Build Coastguard Worker // Check that the preference is registered.
40*6777b538SAndroid Build Coastguard Worker DCHECK(prefs_->FindPreference(pref_name_)) << pref_name << " not registered.";
41*6777b538SAndroid Build Coastguard Worker
42*6777b538SAndroid Build Coastguard Worker // Add ourselves as a pref observer so we can keep our local value in sync.
43*6777b538SAndroid Build Coastguard Worker prefs_->AddPrefObserver(pref_name, this);
44*6777b538SAndroid Build Coastguard Worker }
45*6777b538SAndroid Build Coastguard Worker
Destroy()46*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::Destroy() {
47*6777b538SAndroid Build Coastguard Worker if (prefs_ && !pref_name_.empty()) {
48*6777b538SAndroid Build Coastguard Worker prefs_->RemovePrefObserver(pref_name_, this);
49*6777b538SAndroid Build Coastguard Worker }
50*6777b538SAndroid Build Coastguard Worker prefs_ = nullptr;
51*6777b538SAndroid Build Coastguard Worker }
52*6777b538SAndroid Build Coastguard Worker
MoveToSequence(scoped_refptr<SequencedTaskRunner> task_runner)53*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::MoveToSequence(
54*6777b538SAndroid Build Coastguard Worker scoped_refptr<SequencedTaskRunner> task_runner) {
55*6777b538SAndroid Build Coastguard Worker VerifyValuePrefName();
56*6777b538SAndroid Build Coastguard Worker // Load the value from preferences if it hasn't been loaded so far.
57*6777b538SAndroid Build Coastguard Worker if (!internal())
58*6777b538SAndroid Build Coastguard Worker UpdateValueFromPref(base::OnceClosure());
59*6777b538SAndroid Build Coastguard Worker internal()->MoveToSequence(std::move(task_runner));
60*6777b538SAndroid Build Coastguard Worker }
61*6777b538SAndroid Build Coastguard Worker
OnPreferenceChanged(PrefService * service,const std::string & pref_name)62*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::OnPreferenceChanged(PrefService* service,
63*6777b538SAndroid Build Coastguard Worker const std::string& pref_name) {
64*6777b538SAndroid Build Coastguard Worker VerifyValuePrefName();
65*6777b538SAndroid Build Coastguard Worker UpdateValueFromPref((!setting_value_ && !observer_.is_null())
66*6777b538SAndroid Build Coastguard Worker ? base::BindOnce(observer_, pref_name)
67*6777b538SAndroid Build Coastguard Worker : base::OnceClosure());
68*6777b538SAndroid Build Coastguard Worker }
69*6777b538SAndroid Build Coastguard Worker
UpdateValueFromPref(base::OnceClosure callback) const70*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::UpdateValueFromPref(base::OnceClosure callback) const {
71*6777b538SAndroid Build Coastguard Worker VerifyValuePrefName();
72*6777b538SAndroid Build Coastguard Worker const PrefService::Preference* pref = prefs_->FindPreference(pref_name_);
73*6777b538SAndroid Build Coastguard Worker DCHECK(pref);
74*6777b538SAndroid Build Coastguard Worker if (!internal())
75*6777b538SAndroid Build Coastguard Worker CreateInternal();
76*6777b538SAndroid Build Coastguard Worker internal()->UpdateValue(
77*6777b538SAndroid Build Coastguard Worker base::Value::ToUniquePtrValue(pref->GetValue()->Clone()).release(),
78*6777b538SAndroid Build Coastguard Worker pref->IsManaged(), pref->IsUserModifiable(), pref->IsDefaultValue(),
79*6777b538SAndroid Build Coastguard Worker std::move(callback));
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker
VerifyPref() const82*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::VerifyPref() const {
83*6777b538SAndroid Build Coastguard Worker VerifyValuePrefName();
84*6777b538SAndroid Build Coastguard Worker if (!internal())
85*6777b538SAndroid Build Coastguard Worker UpdateValueFromPref(base::OnceClosure());
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker
InvokeUnnamedCallback(const base::RepeatingClosure & callback,const std::string & pref_name)88*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::InvokeUnnamedCallback(
89*6777b538SAndroid Build Coastguard Worker const base::RepeatingClosure& callback,
90*6777b538SAndroid Build Coastguard Worker const std::string& pref_name) {
91*6777b538SAndroid Build Coastguard Worker callback.Run();
92*6777b538SAndroid Build Coastguard Worker }
93*6777b538SAndroid Build Coastguard Worker
Internal()94*6777b538SAndroid Build Coastguard Worker PrefMemberBase::Internal::Internal()
95*6777b538SAndroid Build Coastguard Worker : owning_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {}
96*6777b538SAndroid Build Coastguard Worker PrefMemberBase::Internal::~Internal() = default;
97*6777b538SAndroid Build Coastguard Worker
IsOnCorrectSequence() const98*6777b538SAndroid Build Coastguard Worker bool PrefMemberBase::Internal::IsOnCorrectSequence() const {
99*6777b538SAndroid Build Coastguard Worker return owning_task_runner_->RunsTasksInCurrentSequence();
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker
UpdateValue(base::Value * v,bool is_managed,bool is_user_modifiable,bool is_default_value,base::OnceClosure callback) const102*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::Internal::UpdateValue(base::Value* v,
103*6777b538SAndroid Build Coastguard Worker bool is_managed,
104*6777b538SAndroid Build Coastguard Worker bool is_user_modifiable,
105*6777b538SAndroid Build Coastguard Worker bool is_default_value,
106*6777b538SAndroid Build Coastguard Worker base::OnceClosure callback) const {
107*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::Value> value(v);
108*6777b538SAndroid Build Coastguard Worker base::ScopedClosureRunner closure_runner(std::move(callback));
109*6777b538SAndroid Build Coastguard Worker if (IsOnCorrectSequence()) {
110*6777b538SAndroid Build Coastguard Worker bool rv = UpdateValueInternal(*value);
111*6777b538SAndroid Build Coastguard Worker DCHECK(rv);
112*6777b538SAndroid Build Coastguard Worker is_managed_ = is_managed;
113*6777b538SAndroid Build Coastguard Worker is_user_modifiable_ = is_user_modifiable;
114*6777b538SAndroid Build Coastguard Worker is_default_value_ = is_default_value;
115*6777b538SAndroid Build Coastguard Worker } else {
116*6777b538SAndroid Build Coastguard Worker bool may_run = owning_task_runner_->PostTask(
117*6777b538SAndroid Build Coastguard Worker FROM_HERE,
118*6777b538SAndroid Build Coastguard Worker base::BindOnce(&PrefMemberBase::Internal::UpdateValue, this,
119*6777b538SAndroid Build Coastguard Worker value.release(), is_managed, is_user_modifiable,
120*6777b538SAndroid Build Coastguard Worker is_default_value, closure_runner.Release()));
121*6777b538SAndroid Build Coastguard Worker DCHECK(may_run);
122*6777b538SAndroid Build Coastguard Worker }
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker
MoveToSequence(scoped_refptr<SequencedTaskRunner> task_runner)125*6777b538SAndroid Build Coastguard Worker void PrefMemberBase::Internal::MoveToSequence(
126*6777b538SAndroid Build Coastguard Worker scoped_refptr<SequencedTaskRunner> task_runner) {
127*6777b538SAndroid Build Coastguard Worker CheckOnCorrectSequence();
128*6777b538SAndroid Build Coastguard Worker owning_task_runner_ = std::move(task_runner);
129*6777b538SAndroid Build Coastguard Worker }
130*6777b538SAndroid Build Coastguard Worker
PrefMemberVectorStringUpdate(const base::Value & value,std::vector<std::string> * string_vector)131*6777b538SAndroid Build Coastguard Worker bool PrefMemberVectorStringUpdate(const base::Value& value,
132*6777b538SAndroid Build Coastguard Worker std::vector<std::string>* string_vector) {
133*6777b538SAndroid Build Coastguard Worker if (!value.is_list())
134*6777b538SAndroid Build Coastguard Worker return false;
135*6777b538SAndroid Build Coastguard Worker
136*6777b538SAndroid Build Coastguard Worker std::vector<std::string> local_vector;
137*6777b538SAndroid Build Coastguard Worker for (const auto& item : value.GetList()) {
138*6777b538SAndroid Build Coastguard Worker if (!item.is_string())
139*6777b538SAndroid Build Coastguard Worker return false;
140*6777b538SAndroid Build Coastguard Worker local_vector.push_back(item.GetString());
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker
143*6777b538SAndroid Build Coastguard Worker string_vector->swap(local_vector);
144*6777b538SAndroid Build Coastguard Worker return true;
145*6777b538SAndroid Build Coastguard Worker }
146*6777b538SAndroid Build Coastguard Worker
147*6777b538SAndroid Build Coastguard Worker } // namespace subtle
148*6777b538SAndroid Build Coastguard Worker
149*6777b538SAndroid Build Coastguard Worker template <>
UpdatePref(const bool & value)150*6777b538SAndroid Build Coastguard Worker void PrefMember<bool>::UpdatePref(const bool& value) {
151*6777b538SAndroid Build Coastguard Worker prefs()->SetBoolean(pref_name(), value);
152*6777b538SAndroid Build Coastguard Worker }
153*6777b538SAndroid Build Coastguard Worker
154*6777b538SAndroid Build Coastguard Worker template <>
UpdateValueInternal(const base::Value & value) const155*6777b538SAndroid Build Coastguard Worker bool PrefMember<bool>::Internal::UpdateValueInternal(
156*6777b538SAndroid Build Coastguard Worker const base::Value& value) const {
157*6777b538SAndroid Build Coastguard Worker if (value.is_bool())
158*6777b538SAndroid Build Coastguard Worker value_ = value.GetBool();
159*6777b538SAndroid Build Coastguard Worker return value.is_bool();
160*6777b538SAndroid Build Coastguard Worker }
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker template <>
UpdatePref(const int & value)163*6777b538SAndroid Build Coastguard Worker void PrefMember<int>::UpdatePref(const int& value) {
164*6777b538SAndroid Build Coastguard Worker prefs()->SetInteger(pref_name(), value);
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard Worker template <>
UpdateValueInternal(const base::Value & value) const168*6777b538SAndroid Build Coastguard Worker bool PrefMember<int>::Internal::UpdateValueInternal(
169*6777b538SAndroid Build Coastguard Worker const base::Value& value) const {
170*6777b538SAndroid Build Coastguard Worker if (value.is_int())
171*6777b538SAndroid Build Coastguard Worker value_ = value.GetInt();
172*6777b538SAndroid Build Coastguard Worker return value.is_int();
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Worker template <>
UpdatePref(const double & value)176*6777b538SAndroid Build Coastguard Worker void PrefMember<double>::UpdatePref(const double& value) {
177*6777b538SAndroid Build Coastguard Worker prefs()->SetDouble(pref_name(), value);
178*6777b538SAndroid Build Coastguard Worker }
179*6777b538SAndroid Build Coastguard Worker
180*6777b538SAndroid Build Coastguard Worker template <>
UpdateValueInternal(const base::Value & value) const181*6777b538SAndroid Build Coastguard Worker bool PrefMember<double>::Internal::UpdateValueInternal(const base::Value& value)
182*6777b538SAndroid Build Coastguard Worker const {
183*6777b538SAndroid Build Coastguard Worker if (value.is_double() || value.is_int())
184*6777b538SAndroid Build Coastguard Worker value_ = value.GetDouble();
185*6777b538SAndroid Build Coastguard Worker return value.is_double() || value.is_int();
186*6777b538SAndroid Build Coastguard Worker }
187*6777b538SAndroid Build Coastguard Worker
188*6777b538SAndroid Build Coastguard Worker template <>
UpdatePref(const std::string & value)189*6777b538SAndroid Build Coastguard Worker void PrefMember<std::string>::UpdatePref(const std::string& value) {
190*6777b538SAndroid Build Coastguard Worker prefs()->SetString(pref_name(), value);
191*6777b538SAndroid Build Coastguard Worker }
192*6777b538SAndroid Build Coastguard Worker
193*6777b538SAndroid Build Coastguard Worker template <>
UpdateValueInternal(const base::Value & value) const194*6777b538SAndroid Build Coastguard Worker bool PrefMember<std::string>::Internal::UpdateValueInternal(
195*6777b538SAndroid Build Coastguard Worker const base::Value& value)
196*6777b538SAndroid Build Coastguard Worker const {
197*6777b538SAndroid Build Coastguard Worker if (value.is_string())
198*6777b538SAndroid Build Coastguard Worker value_ = value.GetString();
199*6777b538SAndroid Build Coastguard Worker return value.is_string();
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker
202*6777b538SAndroid Build Coastguard Worker template <>
UpdatePref(const base::FilePath & value)203*6777b538SAndroid Build Coastguard Worker void PrefMember<base::FilePath>::UpdatePref(const base::FilePath& value) {
204*6777b538SAndroid Build Coastguard Worker prefs()->SetFilePath(pref_name(), value);
205*6777b538SAndroid Build Coastguard Worker }
206*6777b538SAndroid Build Coastguard Worker
207*6777b538SAndroid Build Coastguard Worker template <>
UpdateValueInternal(const base::Value & value) const208*6777b538SAndroid Build Coastguard Worker bool PrefMember<base::FilePath>::Internal::UpdateValueInternal(
209*6777b538SAndroid Build Coastguard Worker const base::Value& value)
210*6777b538SAndroid Build Coastguard Worker const {
211*6777b538SAndroid Build Coastguard Worker std::optional<base::FilePath> path = base::ValueToFilePath(value);
212*6777b538SAndroid Build Coastguard Worker if (!path)
213*6777b538SAndroid Build Coastguard Worker return false;
214*6777b538SAndroid Build Coastguard Worker value_ = *path;
215*6777b538SAndroid Build Coastguard Worker return true;
216*6777b538SAndroid Build Coastguard Worker }
217*6777b538SAndroid Build Coastguard Worker
218*6777b538SAndroid Build Coastguard Worker template <>
UpdatePref(const std::vector<std::string> & value)219*6777b538SAndroid Build Coastguard Worker void PrefMember<std::vector<std::string> >::UpdatePref(
220*6777b538SAndroid Build Coastguard Worker const std::vector<std::string>& value) {
221*6777b538SAndroid Build Coastguard Worker base::Value::List list_value;
222*6777b538SAndroid Build Coastguard Worker for (const std::string& val : value)
223*6777b538SAndroid Build Coastguard Worker list_value.Append(val);
224*6777b538SAndroid Build Coastguard Worker
225*6777b538SAndroid Build Coastguard Worker prefs()->SetList(pref_name(), std::move(list_value));
226*6777b538SAndroid Build Coastguard Worker }
227*6777b538SAndroid Build Coastguard Worker
228*6777b538SAndroid Build Coastguard Worker template <>
UpdateValueInternal(const base::Value & value) const229*6777b538SAndroid Build Coastguard Worker bool PrefMember<std::vector<std::string> >::Internal::UpdateValueInternal(
230*6777b538SAndroid Build Coastguard Worker const base::Value& value) const {
231*6777b538SAndroid Build Coastguard Worker return subtle::PrefMemberVectorStringUpdate(value, &value_);
232*6777b538SAndroid Build Coastguard Worker }
233