blob: 85fe53d6464e97f430a4ad600c2bd25235b74a5f [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/devtools/devtools_settings.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/scoped_user_pref_update.h"
const char DevToolsSettings::kSyncDevToolsPreferencesFrontendName[] =
"sync-preferences";
const bool DevToolsSettings::kSyncDevToolsPreferencesDefault = false;
DevToolsSettings::DevToolsSettings(Profile* profile) : profile_(profile) {
pref_change_registrar_.Init(profile_->GetPrefs());
pref_change_registrar_.Add(
prefs::kDevToolsSyncPreferences,
base::BindRepeating(&DevToolsSettings::DevToolsSyncPreferencesChanged,
base::Unretained(this)));
}
DevToolsSettings::~DevToolsSettings() = default;
void DevToolsSettings::Register(const std::string& name,
const RegisterOptions& options) {
// kSyncDevToolsPreferenceFrontendName is not stored in any of the relevant
// dictionaries. Skip registration.
if (name == kSyncDevToolsPreferencesFrontendName)
return;
if (options.sync_mode == RegisterOptions::SyncMode::kSync) {
synced_setting_names_.insert(name);
}
// Setting might have had a different sync status in the past. Move the
// setting to the correct dictionary.
PrefService* prefs = profile_->GetPrefs();
const char* dictionary_to_remove_from =
options.sync_mode == RegisterOptions::SyncMode::kSync
? prefs::kDevToolsPreferences
: GetDictionaryNameForSyncedPrefs();
const std::string* settings_value =
prefs->GetDict(dictionary_to_remove_from).FindString(name);
if (!settings_value) {
return;
}
const char* dictionary_to_insert_into =
GetDictionaryNameForSettingsName(name);
// Settings already moved to the synced dictionary on a different device have
// precedence.
const std::string* already_synced_value =
prefs->GetDict(dictionary_to_insert_into).FindString(name);
if (dictionary_to_insert_into == prefs::kDevToolsPreferences ||
!already_synced_value) {
ScopedDictPrefUpdate insert_update(profile_->GetPrefs(),
dictionary_to_insert_into);
insert_update->Set(name, *settings_value);
}
ScopedDictPrefUpdate remove_update(profile_->GetPrefs(),
dictionary_to_remove_from);
remove_update->Remove(name);
}
base::Value::Dict DevToolsSettings::Get() {
base::Value::Dict settings;
PrefService* prefs = profile_->GetPrefs();
// DevTools expects any kind of preference to be a string. Parsing is
// happening on the frontend.
settings.Set(
kSyncDevToolsPreferencesFrontendName,
prefs->GetBoolean(prefs::kDevToolsSyncPreferences) ? "true" : "false");
settings.Merge(prefs->GetDict(prefs::kDevToolsPreferences).Clone());
settings.Merge(prefs->GetDict(GetDictionaryNameForSyncedPrefs()).Clone());
return settings;
}
std::optional<base::Value> DevToolsSettings::Get(const std::string& name) {
PrefService* prefs = profile_->GetPrefs();
if (name == kSyncDevToolsPreferencesFrontendName) {
// DevTools expects any kind of preference to be a string. Parsing is
// happening on the frontend.
bool result = prefs->GetBoolean(prefs::kDevToolsSyncPreferences);
return base::Value(result ? "true" : "false");
}
const char* dict_name = GetDictionaryNameForSettingsName(name);
const base::Value::Dict& dict = prefs->GetDict(dict_name);
const base::Value* value = dict.Find(name);
return value ? std::optional<base::Value>(value->Clone()) : std::nullopt;
}
void DevToolsSettings::Set(const std::string& name, const std::string& value) {
if (name == kSyncDevToolsPreferencesFrontendName) {
profile_->GetPrefs()->SetBoolean(prefs::kDevToolsSyncPreferences,
value == "true");
return;
}
ScopedDictPrefUpdate update(profile_->GetPrefs(),
GetDictionaryNameForSettingsName(name));
update->Set(name, value);
}
void DevToolsSettings::Remove(const std::string& name) {
if (name == kSyncDevToolsPreferencesFrontendName) {
profile_->GetPrefs()->SetBoolean(prefs::kDevToolsSyncPreferences,
kSyncDevToolsPreferencesDefault);
return;
}
PrefService* prefs = profile_->GetPrefs();
for (auto* dict_name :
{GetDictionaryNameForSyncedPrefs(), prefs::kDevToolsPreferences}) {
const base::Value::Dict& dict = prefs->GetDict(dict_name);
if (dict.Find(name)) {
ScopedDictPrefUpdate update(profile_->GetPrefs(), dict_name);
update->Remove(name);
}
}
}
void DevToolsSettings::Clear() {
profile_->GetPrefs()->SetBoolean(prefs::kDevToolsSyncPreferences,
kSyncDevToolsPreferencesDefault);
profile_->GetPrefs()->SetDict(prefs::kDevToolsPreferences,
base::Value::Dict());
profile_->GetPrefs()->SetDict(prefs::kDevToolsSyncedPreferencesSyncEnabled,
base::Value::Dict());
profile_->GetPrefs()->SetDict(prefs::kDevToolsSyncedPreferencesSyncDisabled,
base::Value::Dict());
}
const char* DevToolsSettings::GetDictionaryNameForSettingsName(
const std::string& name) const {
return synced_setting_names_.contains(name)
? GetDictionaryNameForSyncedPrefs()
: prefs::kDevToolsPreferences;
}
const char* DevToolsSettings::GetDictionaryNameForSyncedPrefs() const {
const bool isDevToolsSyncEnabled =
profile_->GetPrefs()->GetBoolean(prefs::kDevToolsSyncPreferences);
return isDevToolsSyncEnabled ? prefs::kDevToolsSyncedPreferencesSyncEnabled
: prefs::kDevToolsSyncedPreferencesSyncDisabled;
}
void DevToolsSettings::DevToolsSyncPreferencesChanged() {
// There are two cases to handle:
//
// Sync was enabled: We assume this was triggered by the user in the local
// DevTools session as opposed to synced from a different device. As such, the
// local settings have precedence when merging. The unsynced dictonary is
// cleared.
//
// Sync was disabled: As kDevToolsSyncPreferences is synced itself we can
// clear the synced dictionary after copying to the unsynced one. The unsynced
// dictionary is empty.
//
// Considering the points above, the implementation between both cases can be
// shared modulo the source/target dictionary.
const bool sync_enabled =
profile_->GetPrefs()->GetBoolean(prefs::kDevToolsSyncPreferences);
const char* target_dictionary =
sync_enabled ? prefs::kDevToolsSyncedPreferencesSyncEnabled
: prefs::kDevToolsSyncedPreferencesSyncDisabled;
const char* source_dictionary =
sync_enabled ? prefs::kDevToolsSyncedPreferencesSyncDisabled
: prefs::kDevToolsSyncedPreferencesSyncEnabled;
ScopedDictPrefUpdate source_update(profile_->GetPrefs(), source_dictionary);
ScopedDictPrefUpdate target_update(profile_->GetPrefs(), target_dictionary);
base::Value::Dict source_dict;
std::swap(source_dict, *source_update);
target_update->Merge(std::move(source_dict));
}