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 "components/sync_driver/sync_prefs.h"
6
7#include "base/logging.h"
8#include "base/prefs/pref_member.h"
9#include "base/prefs/pref_service.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/values.h"
12#include "build/build_config.h"
13#include "components/pref_registry/pref_registry_syncable.h"
14#include "components/sync_driver/pref_names.h"
15
16namespace sync_driver {
17
18SyncPrefObserver::~SyncPrefObserver() {}
19
20SyncPrefs::SyncPrefs(PrefService* pref_service) : pref_service_(pref_service) {
21  DCHECK(pref_service);
22  RegisterPrefGroups();
23  // Watch the preference that indicates sync is managed so we can take
24  // appropriate action.
25  pref_sync_managed_.Init(
26      prefs::kSyncManaged,
27      pref_service_,
28      base::Bind(&SyncPrefs::OnSyncManagedPrefChanged, base::Unretained(this)));
29}
30
31SyncPrefs::SyncPrefs() : pref_service_(NULL) {}
32
33SyncPrefs::~SyncPrefs() { DCHECK(CalledOnValidThread()); }
34
35// static
36void SyncPrefs::RegisterProfilePrefs(
37    user_prefs::PrefRegistrySyncable* registry) {
38  registry->RegisterBooleanPref(
39      prefs::kSyncHasSetupCompleted,
40      false,
41      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
42  registry->RegisterBooleanPref(
43      prefs::kSyncSuppressStart,
44      false,
45      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
46  registry->RegisterInt64Pref(
47      prefs::kSyncLastSyncedTime,
48      0,
49      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
50  registry->RegisterInt64Pref(
51      prefs::kSyncFirstSyncTime,
52      0,
53      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
54
55  // All datatypes are on by default, but this gets set explicitly
56  // when you configure sync (when turning it on), in
57  // ProfileSyncService::OnUserChoseDatatypes.
58  registry->RegisterBooleanPref(
59      prefs::kSyncKeepEverythingSynced,
60      true,
61      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
62
63  syncer::ModelTypeSet user_types = syncer::UserTypes();
64
65  // Include proxy types as well, as they can be individually selected,
66  // although they don't have sync representations.
67  user_types.PutAll(syncer::ProxyTypes());
68
69  // Treat bookmarks and device info specially.
70  RegisterDataTypePreferredPref(registry, syncer::BOOKMARKS, true);
71  RegisterDataTypePreferredPref(registry, syncer::DEVICE_INFO, true);
72  user_types.Remove(syncer::BOOKMARKS);
73  user_types.Remove(syncer::DEVICE_INFO);
74
75  // These two prefs are set from sync experiment to enable enhanced bookmarks.
76  registry->RegisterIntegerPref(
77      prefs::kEnhancedBookmarksExperimentEnabled,
78      0,
79      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
80
81  registry->RegisterStringPref(
82      prefs::kEnhancedBookmarksExtensionId,
83      std::string(),
84      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
85
86  // All types are set to off by default, which forces a configuration to
87  // explicitly enable them. GetPreferredTypes() will ensure that any new
88  // implicit types are enabled when their pref group is, or via
89  // KeepEverythingSynced.
90  for (syncer::ModelTypeSet::Iterator it = user_types.First(); it.Good();
91       it.Inc()) {
92    RegisterDataTypePreferredPref(registry, it.Get(), false);
93  }
94
95  registry->RegisterBooleanPref(
96      prefs::kSyncManaged,
97      false,
98      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
99  registry->RegisterStringPref(
100      prefs::kSyncEncryptionBootstrapToken,
101      std::string(),
102      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
103  registry->RegisterStringPref(
104      prefs::kSyncKeystoreEncryptionBootstrapToken,
105      std::string(),
106      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
107#if defined(OS_CHROMEOS)
108  registry->RegisterStringPref(
109      prefs::kSyncSpareBootstrapToken,
110      "",
111      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
112#endif
113
114  registry->RegisterBooleanPref(
115      prefs::kSyncHasAuthError,
116      false,
117      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
118
119  registry->RegisterStringPref(
120      prefs::kSyncSessionsGUID,
121      std::string(),
122      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
123
124  // We will start prompting people about new data types after the launch of
125  // SESSIONS - all previously launched data types are treated as if they are
126  // already acknowledged.
127  syncer::ModelTypeSet model_set;
128  model_set.Put(syncer::BOOKMARKS);
129  model_set.Put(syncer::PREFERENCES);
130  model_set.Put(syncer::PASSWORDS);
131  model_set.Put(syncer::AUTOFILL_PROFILE);
132  model_set.Put(syncer::AUTOFILL);
133  model_set.Put(syncer::THEMES);
134  model_set.Put(syncer::EXTENSIONS);
135  model_set.Put(syncer::NIGORI);
136  model_set.Put(syncer::SEARCH_ENGINES);
137  model_set.Put(syncer::APPS);
138  model_set.Put(syncer::APP_LIST);
139  model_set.Put(syncer::TYPED_URLS);
140  model_set.Put(syncer::SESSIONS);
141  model_set.Put(syncer::ARTICLES);
142  registry->RegisterListPref(prefs::kSyncAcknowledgedSyncTypes,
143                             syncer::ModelTypeSetToValue(model_set),
144                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
145
146  registry->RegisterIntegerPref(
147      prefs::kSyncRemainingRollbackTries, 0,
148      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
149}
150
151void SyncPrefs::AddSyncPrefObserver(SyncPrefObserver* sync_pref_observer) {
152  DCHECK(CalledOnValidThread());
153  sync_pref_observers_.AddObserver(sync_pref_observer);
154}
155
156void SyncPrefs::RemoveSyncPrefObserver(SyncPrefObserver* sync_pref_observer) {
157  DCHECK(CalledOnValidThread());
158  sync_pref_observers_.RemoveObserver(sync_pref_observer);
159}
160
161void SyncPrefs::ClearPreferences() {
162  DCHECK(CalledOnValidThread());
163  pref_service_->ClearPref(prefs::kSyncLastSyncedTime);
164  pref_service_->ClearPref(prefs::kSyncHasSetupCompleted);
165  pref_service_->ClearPref(prefs::kSyncEncryptionBootstrapToken);
166  pref_service_->ClearPref(prefs::kSyncKeystoreEncryptionBootstrapToken);
167
168  // TODO(nick): The current behavior does not clear
169  // e.g. prefs::kSyncBookmarks.  Is that really what we want?
170}
171
172bool SyncPrefs::HasSyncSetupCompleted() const {
173  DCHECK(CalledOnValidThread());
174  return pref_service_->GetBoolean(prefs::kSyncHasSetupCompleted);
175}
176
177void SyncPrefs::SetSyncSetupCompleted() {
178  DCHECK(CalledOnValidThread());
179  pref_service_->SetBoolean(prefs::kSyncHasSetupCompleted, true);
180  SetStartSuppressed(false);
181}
182
183bool SyncPrefs::SyncHasAuthError() const {
184  DCHECK(CalledOnValidThread());
185  return pref_service_->GetBoolean(prefs::kSyncHasAuthError);
186}
187
188void SyncPrefs::SetSyncAuthError(bool error) {
189  DCHECK(CalledOnValidThread());
190  pref_service_->SetBoolean(prefs::kSyncHasAuthError, error);
191}
192
193bool SyncPrefs::IsStartSuppressed() const {
194  DCHECK(CalledOnValidThread());
195  return pref_service_->GetBoolean(prefs::kSyncSuppressStart);
196}
197
198void SyncPrefs::SetStartSuppressed(bool is_suppressed) {
199  DCHECK(CalledOnValidThread());
200  pref_service_->SetBoolean(prefs::kSyncSuppressStart, is_suppressed);
201}
202
203base::Time SyncPrefs::GetLastSyncedTime() const {
204  DCHECK(CalledOnValidThread());
205  return base::Time::FromInternalValue(
206      pref_service_->GetInt64(prefs::kSyncLastSyncedTime));
207}
208
209void SyncPrefs::SetLastSyncedTime(base::Time time) {
210  DCHECK(CalledOnValidThread());
211  pref_service_->SetInt64(prefs::kSyncLastSyncedTime, time.ToInternalValue());
212}
213
214bool SyncPrefs::HasKeepEverythingSynced() const {
215  DCHECK(CalledOnValidThread());
216  return pref_service_->GetBoolean(prefs::kSyncKeepEverythingSynced);
217}
218
219void SyncPrefs::SetKeepEverythingSynced(bool keep_everything_synced) {
220  DCHECK(CalledOnValidThread());
221  pref_service_->SetBoolean(prefs::kSyncKeepEverythingSynced,
222                            keep_everything_synced);
223}
224
225syncer::ModelTypeSet SyncPrefs::GetPreferredDataTypes(
226    syncer::ModelTypeSet registered_types) const {
227  DCHECK(CalledOnValidThread());
228
229  if (pref_service_->GetBoolean(prefs::kSyncKeepEverythingSynced)) {
230    return registered_types;
231  }
232
233  syncer::ModelTypeSet preferred_types;
234  for (syncer::ModelTypeSet::Iterator it = registered_types.First(); it.Good();
235       it.Inc()) {
236    if (GetDataTypePreferred(it.Get())) {
237      preferred_types.Put(it.Get());
238    }
239  }
240  return ResolvePrefGroups(registered_types, preferred_types);
241}
242
243void SyncPrefs::SetPreferredDataTypes(syncer::ModelTypeSet registered_types,
244                                      syncer::ModelTypeSet preferred_types) {
245  DCHECK(CalledOnValidThread());
246  DCHECK(registered_types.HasAll(preferred_types));
247  preferred_types = ResolvePrefGroups(registered_types, preferred_types);
248  for (syncer::ModelTypeSet::Iterator i = registered_types.First(); i.Good();
249       i.Inc()) {
250    SetDataTypePreferred(i.Get(), preferred_types.Has(i.Get()));
251  }
252}
253
254bool SyncPrefs::IsManaged() const {
255  DCHECK(CalledOnValidThread());
256  return pref_service_->GetBoolean(prefs::kSyncManaged);
257}
258
259std::string SyncPrefs::GetEncryptionBootstrapToken() const {
260  DCHECK(CalledOnValidThread());
261  return pref_service_->GetString(prefs::kSyncEncryptionBootstrapToken);
262}
263
264void SyncPrefs::SetEncryptionBootstrapToken(const std::string& token) {
265  DCHECK(CalledOnValidThread());
266  pref_service_->SetString(prefs::kSyncEncryptionBootstrapToken, token);
267}
268
269std::string SyncPrefs::GetKeystoreEncryptionBootstrapToken() const {
270  DCHECK(CalledOnValidThread());
271  return pref_service_->GetString(prefs::kSyncKeystoreEncryptionBootstrapToken);
272}
273
274void SyncPrefs::SetKeystoreEncryptionBootstrapToken(const std::string& token) {
275  DCHECK(CalledOnValidThread());
276  pref_service_->SetString(prefs::kSyncKeystoreEncryptionBootstrapToken, token);
277}
278
279std::string SyncPrefs::GetSyncSessionsGUID() const {
280  DCHECK(CalledOnValidThread());
281  return pref_service_->GetString(prefs::kSyncSessionsGUID);
282}
283
284void SyncPrefs::SetSyncSessionsGUID(const std::string& guid) {
285  DCHECK(CalledOnValidThread());
286  pref_service_->SetString(prefs::kSyncSessionsGUID, guid);
287}
288
289// static
290const char* SyncPrefs::GetPrefNameForDataType(syncer::ModelType data_type) {
291  switch (data_type) {
292    case syncer::BOOKMARKS:
293      return prefs::kSyncBookmarks;
294    case syncer::PASSWORDS:
295      return prefs::kSyncPasswords;
296    case syncer::PREFERENCES:
297      return prefs::kSyncPreferences;
298    case syncer::AUTOFILL:
299      return prefs::kSyncAutofill;
300    case syncer::AUTOFILL_PROFILE:
301      return prefs::kSyncAutofillProfile;
302    case syncer::THEMES:
303      return prefs::kSyncThemes;
304    case syncer::TYPED_URLS:
305      return prefs::kSyncTypedUrls;
306    case syncer::EXTENSION_SETTINGS:
307      return prefs::kSyncExtensionSettings;
308    case syncer::EXTENSIONS:
309      return prefs::kSyncExtensions;
310    case syncer::APP_LIST:
311      return prefs::kSyncAppList;
312    case syncer::APP_SETTINGS:
313      return prefs::kSyncAppSettings;
314    case syncer::APPS:
315      return prefs::kSyncApps;
316    case syncer::SEARCH_ENGINES:
317      return prefs::kSyncSearchEngines;
318    case syncer::SESSIONS:
319      return prefs::kSyncSessions;
320    case syncer::APP_NOTIFICATIONS:
321      return prefs::kSyncAppNotifications;
322    case syncer::HISTORY_DELETE_DIRECTIVES:
323      return prefs::kSyncHistoryDeleteDirectives;
324    case syncer::SYNCED_NOTIFICATIONS:
325      return prefs::kSyncSyncedNotifications;
326    case syncer::SYNCED_NOTIFICATION_APP_INFO:
327      return prefs::kSyncSyncedNotificationAppInfo;
328    case syncer::DICTIONARY:
329      return prefs::kSyncDictionary;
330    case syncer::FAVICON_IMAGES:
331      return prefs::kSyncFaviconImages;
332    case syncer::FAVICON_TRACKING:
333      return prefs::kSyncFaviconTracking;
334    case syncer::SUPERVISED_USER_SETTINGS:
335      return prefs::kSyncSupervisedUserSettings;
336    case syncer::PROXY_TABS:
337      return prefs::kSyncTabs;
338    case syncer::PRIORITY_PREFERENCES:
339      return prefs::kSyncPriorityPreferences;
340    case syncer::SUPERVISED_USERS:
341      return prefs::kSyncSupervisedUsers;
342    case syncer::ARTICLES:
343      return prefs::kSyncArticles;
344    case syncer::SUPERVISED_USER_SHARED_SETTINGS:
345      return prefs::kSyncSupervisedUserSharedSettings;
346    case syncer::DEVICE_INFO:
347      return prefs::kSyncDeviceInfo;
348    default:
349      break;
350  }
351  NOTREACHED() << "Type is " << data_type;
352  return NULL;
353}
354
355#if defined(OS_CHROMEOS)
356std::string SyncPrefs::GetSpareBootstrapToken() const {
357  DCHECK(CalledOnValidThread());
358  return pref_service_->GetString(prefs::kSyncSpareBootstrapToken);
359}
360
361void SyncPrefs::SetSpareBootstrapToken(const std::string& token) {
362  DCHECK(CalledOnValidThread());
363  pref_service_->SetString(prefs::kSyncSpareBootstrapToken, token);
364}
365#endif
366
367void SyncPrefs::AcknowledgeSyncedTypes(syncer::ModelTypeSet types) {
368  DCHECK(CalledOnValidThread());
369  // Add the types to the current set of acknowledged
370  // types, and then store the resulting set in prefs.
371  const syncer::ModelTypeSet acknowledged_types =
372      Union(types,
373            syncer::ModelTypeSetFromValue(
374                *pref_service_->GetList(prefs::kSyncAcknowledgedSyncTypes)));
375
376  scoped_ptr<base::ListValue> value(
377      syncer::ModelTypeSetToValue(acknowledged_types));
378  pref_service_->Set(prefs::kSyncAcknowledgedSyncTypes, *value);
379}
380
381int SyncPrefs::GetRemainingRollbackTries() const {
382  return pref_service_->GetInteger(prefs::kSyncRemainingRollbackTries);
383}
384
385void SyncPrefs::SetRemainingRollbackTries(int times) {
386  pref_service_->SetInteger(prefs::kSyncRemainingRollbackTries, times);
387}
388
389void SyncPrefs::OnSyncManagedPrefChanged() {
390  DCHECK(CalledOnValidThread());
391  FOR_EACH_OBSERVER(SyncPrefObserver,
392                    sync_pref_observers_,
393                    OnSyncManagedPrefChange(*pref_sync_managed_));
394}
395
396void SyncPrefs::SetManagedForTest(bool is_managed) {
397  DCHECK(CalledOnValidThread());
398  pref_service_->SetBoolean(prefs::kSyncManaged, is_managed);
399}
400
401syncer::ModelTypeSet SyncPrefs::GetAcknowledgeSyncedTypesForTest() const {
402  DCHECK(CalledOnValidThread());
403  return syncer::ModelTypeSetFromValue(
404      *pref_service_->GetList(prefs::kSyncAcknowledgedSyncTypes));
405}
406
407void SyncPrefs::RegisterPrefGroups() {
408  pref_groups_[syncer::APPS].Put(syncer::APP_NOTIFICATIONS);
409  pref_groups_[syncer::APPS].Put(syncer::APP_SETTINGS);
410  pref_groups_[syncer::APPS].Put(syncer::APP_LIST);
411
412  pref_groups_[syncer::AUTOFILL].Put(syncer::AUTOFILL_PROFILE);
413
414  pref_groups_[syncer::EXTENSIONS].Put(syncer::EXTENSION_SETTINGS);
415
416  pref_groups_[syncer::PREFERENCES].Put(syncer::DICTIONARY);
417  pref_groups_[syncer::PREFERENCES].Put(syncer::PRIORITY_PREFERENCES);
418  pref_groups_[syncer::PREFERENCES].Put(syncer::SEARCH_ENGINES);
419
420  pref_groups_[syncer::TYPED_URLS].Put(syncer::HISTORY_DELETE_DIRECTIVES);
421  pref_groups_[syncer::TYPED_URLS].Put(syncer::SESSIONS);
422  pref_groups_[syncer::TYPED_URLS].Put(syncer::FAVICON_IMAGES);
423  pref_groups_[syncer::TYPED_URLS].Put(syncer::FAVICON_TRACKING);
424
425  pref_groups_[syncer::PROXY_TABS].Put(syncer::SESSIONS);
426  pref_groups_[syncer::PROXY_TABS].Put(syncer::FAVICON_IMAGES);
427  pref_groups_[syncer::PROXY_TABS].Put(syncer::FAVICON_TRACKING);
428
429  // TODO(zea): put favicons in the bookmarks group as well once it handles
430  // those favicons.
431}
432
433// static
434void SyncPrefs::RegisterDataTypePreferredPref(
435    user_prefs::PrefRegistrySyncable* registry,
436    syncer::ModelType type,
437    bool is_preferred) {
438  const char* pref_name = GetPrefNameForDataType(type);
439  if (!pref_name) {
440    NOTREACHED();
441    return;
442  }
443  registry->RegisterBooleanPref(
444      pref_name,
445      is_preferred,
446      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
447}
448
449bool SyncPrefs::GetDataTypePreferred(syncer::ModelType type) const {
450  DCHECK(CalledOnValidThread());
451  const char* pref_name = GetPrefNameForDataType(type);
452  if (!pref_name) {
453    NOTREACHED();
454    return false;
455  }
456
457  // Device info is always enabled.
458  if (pref_name == prefs::kSyncDeviceInfo)
459    return true;
460
461  if (type == syncer::PROXY_TABS &&
462      pref_service_->GetUserPrefValue(pref_name) == NULL &&
463      pref_service_->IsUserModifiablePreference(pref_name)) {
464    // If there is no tab sync preference yet (i.e. newly enabled type),
465    // default to the session sync preference value.
466    pref_name = GetPrefNameForDataType(syncer::SESSIONS);
467  }
468
469  return pref_service_->GetBoolean(pref_name);
470}
471
472void SyncPrefs::SetDataTypePreferred(syncer::ModelType type,
473                                     bool is_preferred) {
474  DCHECK(CalledOnValidThread());
475  const char* pref_name = GetPrefNameForDataType(type);
476  if (!pref_name) {
477    NOTREACHED();
478    return;
479  }
480
481  // Device info is always preferred.
482  if (type == syncer::DEVICE_INFO)
483    return;
484
485  pref_service_->SetBoolean(pref_name, is_preferred);
486}
487
488syncer::ModelTypeSet SyncPrefs::ResolvePrefGroups(
489    syncer::ModelTypeSet registered_types,
490    syncer::ModelTypeSet types) const {
491  DCHECK(registered_types.HasAll(types));
492  syncer::ModelTypeSet types_with_groups = types;
493  for (PrefGroupsMap::const_iterator i = pref_groups_.begin();
494       i != pref_groups_.end();
495       ++i) {
496    if (types.Has(i->first))
497      types_with_groups.PutAll(i->second);
498  }
499  types_with_groups.RetainAll(registered_types);
500  return types_with_groups;
501}
502
503base::Time SyncPrefs::GetFirstSyncTime() const {
504  return base::Time::FromInternalValue(
505      pref_service_->GetInt64(prefs::kSyncFirstSyncTime));
506}
507
508void SyncPrefs::SetFirstSyncTime(base::Time time) {
509  pref_service_->SetInt64(prefs::kSyncFirstSyncTime, time.ToInternalValue());
510}
511
512void SyncPrefs::ClearFirstSyncTime() {
513  pref_service_->ClearPref(prefs::kSyncFirstSyncTime);
514}
515
516}  // namespace sync_driver
517