1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/prefs/pref_service_syncable.h"
6
7#include "base/bind.h"
8#include "base/files/file_path.h"
9#include "base/prefs/default_pref_store.h"
10#include "base/prefs/overlay_user_pref_store.h"
11#include "base/prefs/pref_notifier_impl.h"
12#include "base/prefs/pref_registry.h"
13#include "base/prefs/pref_value_store.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/value_conversions.h"
16#include "chrome/browser/prefs/pref_model_associator.h"
17#include "chrome/browser/prefs/pref_service_syncable_observer.h"
18#include "chrome/browser/profiles/profile.h"
19#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
20#include "components/pref_registry/pref_registry_syncable.h"
21
22// static
23PrefServiceSyncable* PrefServiceSyncable::FromProfile(Profile* profile) {
24  return static_cast<PrefServiceSyncable*>(profile->GetPrefs());
25}
26
27// static
28PrefServiceSyncable* PrefServiceSyncable::IncognitoFromProfile(
29    Profile* profile) {
30  return static_cast<PrefServiceSyncable*>(profile->GetOffTheRecordPrefs());
31}
32
33PrefServiceSyncable::PrefServiceSyncable(
34    PrefNotifierImpl* pref_notifier,
35    PrefValueStore* pref_value_store,
36    PersistentPrefStore* user_prefs,
37    user_prefs::PrefRegistrySyncable* pref_registry,
38    base::Callback<void(PersistentPrefStore::PrefReadError)>
39        read_error_callback,
40    bool async)
41  : PrefService(pref_notifier,
42                pref_value_store,
43                user_prefs,
44                pref_registry,
45                read_error_callback,
46                async),
47    pref_sync_associator_(syncer::PREFERENCES),
48    priority_pref_sync_associator_(syncer::PRIORITY_PREFERENCES) {
49  pref_sync_associator_.SetPrefService(this);
50  priority_pref_sync_associator_.SetPrefService(this);
51
52  // Let PrefModelAssociators know about changes to preference values.
53  pref_value_store->set_callback(
54      base::Bind(&PrefServiceSyncable::ProcessPrefChange,
55                 base::Unretained(this)));
56
57  // Add already-registered syncable preferences to PrefModelAssociator.
58  const user_prefs::PrefRegistrySyncable::PrefToStatus& syncable_preferences =
59      pref_registry->syncable_preferences();
60  for (user_prefs::PrefRegistrySyncable::PrefToStatus::const_iterator it =
61           syncable_preferences.begin();
62       it != syncable_preferences.end();
63       ++it) {
64    AddRegisteredSyncablePreference(it->first.c_str(), it->second);
65  }
66
67  // Watch for syncable preferences registered after this point.
68  pref_registry->SetSyncableRegistrationCallback(
69      base::Bind(&PrefServiceSyncable::AddRegisteredSyncablePreference,
70                 base::Unretained(this)));
71}
72
73PrefServiceSyncable::~PrefServiceSyncable() {
74  // Remove our callback from the registry, since it may outlive us.
75  user_prefs::PrefRegistrySyncable* registry =
76      static_cast<user_prefs::PrefRegistrySyncable*>(pref_registry_.get());
77  registry->SetSyncableRegistrationCallback(
78      user_prefs::PrefRegistrySyncable::SyncableRegistrationCallback());
79}
80
81PrefServiceSyncable* PrefServiceSyncable::CreateIncognitoPrefService(
82    PrefStore* incognito_extension_prefs) {
83  pref_service_forked_ = true;
84  PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
85  OverlayUserPrefStore* incognito_pref_store =
86      new OverlayUserPrefStore(user_pref_store_.get());
87  PrefsTabHelper::InitIncognitoUserPrefStore(incognito_pref_store);
88
89  scoped_refptr<user_prefs::PrefRegistrySyncable> forked_registry =
90      static_cast<user_prefs::PrefRegistrySyncable*>(
91          pref_registry_.get())->ForkForIncognito();
92  PrefServiceSyncable* incognito_service = new PrefServiceSyncable(
93      pref_notifier,
94      pref_value_store_->CloneAndSpecialize(NULL,  // managed
95                                            NULL,  // supervised_user
96                                            incognito_extension_prefs,
97                                            NULL,  // command_line_prefs
98                                            incognito_pref_store,
99                                            NULL,  // recommended
100                                            forked_registry->defaults().get(),
101                                            pref_notifier),
102      incognito_pref_store,
103      forked_registry.get(),
104      read_error_callback_,
105      false);
106  return incognito_service;
107}
108
109bool PrefServiceSyncable::IsSyncing() {
110  return pref_sync_associator_.models_associated();
111}
112
113bool PrefServiceSyncable::IsPrioritySyncing() {
114  return priority_pref_sync_associator_.models_associated();
115}
116
117bool PrefServiceSyncable::IsPrefSynced(const std::string& name) const {
118  return pref_sync_associator_.IsPrefSynced(name) ||
119         priority_pref_sync_associator_.IsPrefSynced(name);
120}
121
122void PrefServiceSyncable::AddObserver(PrefServiceSyncableObserver* observer) {
123  observer_list_.AddObserver(observer);
124}
125
126void PrefServiceSyncable::RemoveObserver(
127    PrefServiceSyncableObserver* observer) {
128  observer_list_.RemoveObserver(observer);
129}
130
131syncer::SyncableService* PrefServiceSyncable::GetSyncableService(
132    const syncer::ModelType& type) {
133  if (type == syncer::PREFERENCES) {
134    return &pref_sync_associator_;
135  } else if (type == syncer::PRIORITY_PREFERENCES) {
136    return &priority_pref_sync_associator_;
137  } else {
138    NOTREACHED() << "invalid model type: " << type;
139    return NULL;
140  }
141}
142
143void PrefServiceSyncable::UpdateCommandLinePrefStore(
144    PrefStore* cmd_line_store) {
145  // If |pref_service_forked_| is true, then this PrefService and the forked
146  // copies will be out of sync.
147  DCHECK(!pref_service_forked_);
148  PrefService::UpdateCommandLinePrefStore(cmd_line_store);
149}
150
151void PrefServiceSyncable::AddSyncedPrefObserver(
152    const std::string& name,
153    SyncedPrefObserver* observer) {
154  pref_sync_associator_.AddSyncedPrefObserver(name, observer);
155  priority_pref_sync_associator_.AddSyncedPrefObserver(name, observer);
156}
157
158void PrefServiceSyncable::RemoveSyncedPrefObserver(
159    const std::string& name,
160    SyncedPrefObserver* observer) {
161  pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
162  priority_pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
163}
164
165void PrefServiceSyncable::AddRegisteredSyncablePreference(
166    const char* path,
167    const user_prefs::PrefRegistrySyncable::PrefSyncStatus sync_status) {
168  DCHECK(FindPreference(path));
169  if (sync_status == user_prefs::PrefRegistrySyncable::SYNCABLE_PREF) {
170    pref_sync_associator_.RegisterPref(path);
171  } else if (sync_status ==
172             user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF) {
173    priority_pref_sync_associator_.RegisterPref(path);
174  } else {
175    NOTREACHED() << "invalid sync_status: " << sync_status;
176  }
177}
178
179void PrefServiceSyncable::OnIsSyncingChanged() {
180  FOR_EACH_OBSERVER(PrefServiceSyncableObserver, observer_list_,
181                    OnIsSyncingChanged());
182}
183
184void PrefServiceSyncable::ProcessPrefChange(const std::string& name) {
185  pref_sync_associator_.ProcessPrefChange(name);
186  priority_pref_sync_associator_.ProcessPrefChange(name);
187}
188