// Copyright (c) 2012 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/prefs/pref_service_syncable.h" #include "base/bind.h" #include "base/files/file_path.h" #include "base/prefs/default_pref_store.h" #include "base/prefs/overlay_user_pref_store.h" #include "base/prefs/pref_notifier_impl.h" #include "base/prefs/pref_registry.h" #include "base/prefs/pref_value_store.h" #include "base/strings/string_number_conversions.h" #include "base/value_conversions.h" #include "chrome/browser/prefs/pref_model_associator.h" #include "chrome/browser/prefs/pref_service_syncable_observer.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/prefs/prefs_tab_helper.h" #include "components/pref_registry/pref_registry_syncable.h" // static PrefServiceSyncable* PrefServiceSyncable::FromProfile(Profile* profile) { return static_cast(profile->GetPrefs()); } // static PrefServiceSyncable* PrefServiceSyncable::IncognitoFromProfile( Profile* profile) { return static_cast(profile->GetOffTheRecordPrefs()); } PrefServiceSyncable::PrefServiceSyncable( PrefNotifierImpl* pref_notifier, PrefValueStore* pref_value_store, PersistentPrefStore* user_prefs, user_prefs::PrefRegistrySyncable* pref_registry, base::Callback read_error_callback, bool async) : PrefService(pref_notifier, pref_value_store, user_prefs, pref_registry, read_error_callback, async), pref_sync_associator_(syncer::PREFERENCES), priority_pref_sync_associator_(syncer::PRIORITY_PREFERENCES) { pref_sync_associator_.SetPrefService(this); priority_pref_sync_associator_.SetPrefService(this); // Let PrefModelAssociators know about changes to preference values. pref_value_store->set_callback( base::Bind(&PrefServiceSyncable::ProcessPrefChange, base::Unretained(this))); // Add already-registered syncable preferences to PrefModelAssociator. const user_prefs::PrefRegistrySyncable::PrefToStatus& syncable_preferences = pref_registry->syncable_preferences(); for (user_prefs::PrefRegistrySyncable::PrefToStatus::const_iterator it = syncable_preferences.begin(); it != syncable_preferences.end(); ++it) { AddRegisteredSyncablePreference(it->first.c_str(), it->second); } // Watch for syncable preferences registered after this point. pref_registry->SetSyncableRegistrationCallback( base::Bind(&PrefServiceSyncable::AddRegisteredSyncablePreference, base::Unretained(this))); } PrefServiceSyncable::~PrefServiceSyncable() { // Remove our callback from the registry, since it may outlive us. user_prefs::PrefRegistrySyncable* registry = static_cast(pref_registry_.get()); registry->SetSyncableRegistrationCallback( user_prefs::PrefRegistrySyncable::SyncableRegistrationCallback()); } PrefServiceSyncable* PrefServiceSyncable::CreateIncognitoPrefService( PrefStore* incognito_extension_prefs) { pref_service_forked_ = true; PrefNotifierImpl* pref_notifier = new PrefNotifierImpl(); OverlayUserPrefStore* incognito_pref_store = new OverlayUserPrefStore(user_pref_store_.get()); PrefsTabHelper::InitIncognitoUserPrefStore(incognito_pref_store); scoped_refptr forked_registry = static_cast( pref_registry_.get())->ForkForIncognito(); PrefServiceSyncable* incognito_service = new PrefServiceSyncable( pref_notifier, pref_value_store_->CloneAndSpecialize(NULL, // managed NULL, // supervised_user incognito_extension_prefs, NULL, // command_line_prefs incognito_pref_store, NULL, // recommended forked_registry->defaults().get(), pref_notifier), incognito_pref_store, forked_registry.get(), read_error_callback_, false); return incognito_service; } bool PrefServiceSyncable::IsSyncing() { return pref_sync_associator_.models_associated(); } bool PrefServiceSyncable::IsPrioritySyncing() { return priority_pref_sync_associator_.models_associated(); } bool PrefServiceSyncable::IsPrefSynced(const std::string& name) const { return pref_sync_associator_.IsPrefSynced(name) || priority_pref_sync_associator_.IsPrefSynced(name); } void PrefServiceSyncable::AddObserver(PrefServiceSyncableObserver* observer) { observer_list_.AddObserver(observer); } void PrefServiceSyncable::RemoveObserver( PrefServiceSyncableObserver* observer) { observer_list_.RemoveObserver(observer); } syncer::SyncableService* PrefServiceSyncable::GetSyncableService( const syncer::ModelType& type) { if (type == syncer::PREFERENCES) { return &pref_sync_associator_; } else if (type == syncer::PRIORITY_PREFERENCES) { return &priority_pref_sync_associator_; } else { NOTREACHED() << "invalid model type: " << type; return NULL; } } void PrefServiceSyncable::UpdateCommandLinePrefStore( PrefStore* cmd_line_store) { // If |pref_service_forked_| is true, then this PrefService and the forked // copies will be out of sync. DCHECK(!pref_service_forked_); PrefService::UpdateCommandLinePrefStore(cmd_line_store); } void PrefServiceSyncable::AddSyncedPrefObserver( const std::string& name, SyncedPrefObserver* observer) { pref_sync_associator_.AddSyncedPrefObserver(name, observer); priority_pref_sync_associator_.AddSyncedPrefObserver(name, observer); } void PrefServiceSyncable::RemoveSyncedPrefObserver( const std::string& name, SyncedPrefObserver* observer) { pref_sync_associator_.RemoveSyncedPrefObserver(name, observer); priority_pref_sync_associator_.RemoveSyncedPrefObserver(name, observer); } void PrefServiceSyncable::AddRegisteredSyncablePreference( const char* path, const user_prefs::PrefRegistrySyncable::PrefSyncStatus sync_status) { DCHECK(FindPreference(path)); if (sync_status == user_prefs::PrefRegistrySyncable::SYNCABLE_PREF) { pref_sync_associator_.RegisterPref(path); } else if (sync_status == user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF) { priority_pref_sync_associator_.RegisterPref(path); } else { NOTREACHED() << "invalid sync_status: " << sync_status; } } void PrefServiceSyncable::OnIsSyncingChanged() { FOR_EACH_OBSERVER(PrefServiceSyncableObserver, observer_list_, OnIsSyncingChanged()); } void PrefServiceSyncable::ProcessPrefChange(const std::string& name) { pref_sync_associator_.ProcessPrefChange(name); priority_pref_sync_associator_.ProcessPrefChange(name); }