15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prefs/pref_model_associator.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/auto_reset.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_string_value_serializer.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
134311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch#include "base/stl_util.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/prefs/pref_service_syncable.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/api/sync_change.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/api/sync_error_factory.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/preference_specifics.pb.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/sync.pb.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncer::PREFERENCES;
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using syncer::PRIORITY_PREFERENCES;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const sync_pb::PreferenceSpecifics& GetSpecifics(const syncer::SyncData& pref) {
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(pref.GetDataType() == syncer::PREFERENCES ||
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         pref.GetDataType() == syncer::PRIORITY_PREFERENCES);
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (pref.GetDataType() == syncer::PRIORITY_PREFERENCES) {
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return pref.GetSpecifics().priority_preference().preference();
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return pref.GetSpecifics().preference();
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)sync_pb::PreferenceSpecifics* GetMutableSpecifics(
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const syncer::ModelType type,
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    sync_pb::EntitySpecifics* specifics) {
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (type == syncer::PRIORITY_PREFERENCES) {
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(!specifics->has_preference());
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return specifics->mutable_priority_preference()->mutable_preference();
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(!specifics->has_priority_preference());
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return specifics->mutable_preference();
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)PrefModelAssociator::PrefModelAssociator(syncer::ModelType type)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : models_associated_(false),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      processing_syncer_changes_(false),
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pref_service_(NULL),
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      type_(type) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(type_ == PREFERENCES || type_ == PRIORITY_PREFERENCES);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PrefModelAssociator::~PrefModelAssociator() {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_service_ = NULL;
654311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
664311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  STLDeleteContainerPairSecondPointers(synced_pref_observers_.begin(),
674311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch                                       synced_pref_observers_.end());
684311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  synced_pref_observers_.clear();
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrefModelAssociator::InitPrefAndAssociate(
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncer::SyncData& sync_pref,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& pref_name,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncChangeList* sync_changes) {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Value* user_pref_value = pref_service_->GetUserPrefValue(
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pref_name.c_str());
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Associating preference " << pref_name;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sync_pref.IsValid()) {
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const sync_pb::PreferenceSpecifics& preference = GetSpecifics(sync_pref);
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(pref_name, preference.name());
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::JSONReader reader;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<Value> sync_value(reader.ReadToValue(preference.value()));
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!sync_value.get()) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to deserialize preference value: "
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << reader.GetErrorMessage();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (user_pref_value) {
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // We have both server and local values. Merge them.
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scoped_ptr<Value> new_value(
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          MergePreference(pref_name, *user_pref_value, *sync_value));
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Update the local preference based on what we got from the
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // sync server. Note: this only updates the user value store, which is
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // ignored if the preference is policy controlled.
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (new_value->IsType(Value::TYPE_NULL)) {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        pref_service_->ClearPref(pref_name.c_str());
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (!new_value->IsType(user_pref_value->GetType())) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(WARNING) << "Synced value for " << preference.name()
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     << " is of type " << new_value->GetType()
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     << " which doesn't match pref type "
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     << user_pref_value->GetType();
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (!user_pref_value->Equals(new_value.get())) {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        pref_service_->Set(pref_name.c_str(), *new_value);
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If the merge resulted in an updated value, inform the syncer.
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!sync_value->Equals(new_value.get())) {
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        syncer::SyncData sync_data;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (!CreatePrefSyncData(pref_name, *new_value, &sync_data)) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          LOG(ERROR) << "Failed to update preference.";
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        sync_changes->push_back(
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            syncer::SyncChange(FROM_HERE,
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               syncer::SyncChange::ACTION_UPDATE,
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               sync_data));
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else if (!sync_value->IsType(Value::TYPE_NULL)) {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Only a server value exists. Just set the local user value.
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pref_service_->Set(pref_name.c_str(), *sync_value);
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (user_pref_value) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The server does not know about this preference and should be added
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to the syncer's database.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncData sync_data;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!CreatePrefSyncData(pref_name, *user_pref_value, &sync_data)) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to update preference.";
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_changes->push_back(
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        syncer::SyncChange(FROM_HERE,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           syncer::SyncChange::ACTION_ADD,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           sync_data));
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This pref does not have a sync value but also does not have a user
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // controlled value (either it's a default value or it's policy controlled,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // either way it's not interesting). We can ignore it. Once it gets changed,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we'll send the new user controlled value to the syncer.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we add it to our list of synced preferences so we know what
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the server is aware of.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  synced_preferences_.insert(pref_name);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::ModelType type,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncer::SyncDataList& initial_sync_data,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(type_, type);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pref_service_);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!sync_processor_.get());
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sync_processor.get());
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sync_error_factory.get());
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::SyncMergeResult merge_result(type);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_processor_ = sync_processor.Pass();
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_error_factory_ = sync_error_factory.Pass();
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncChangeList new_changes;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<std::string> remaining_preferences = registered_preferences_;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Go through and check for all preferences we care about that sync already
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // knows about.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (syncer::SyncDataList::const_iterator sync_iter =
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           initial_sync_data.begin();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       sync_iter != initial_sync_data.end();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++sync_iter) {
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_EQ(type_, sync_iter->GetDataType());
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const sync_pb::PreferenceSpecifics& preference = GetSpecifics(*sync_iter);
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& sync_pref_name = preference.name();
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (remaining_preferences.count(sync_pref_name) == 0) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We're not syncing this preference locally, ignore the sync data.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(zea): Eventually we want to be able to have the syncable service
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // reconstruct all sync data for it's datatype (therefore having
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // GetAllSyncData be a complete representation). We should store this data
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // somewhere, even if we don't use it.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remaining_preferences.erase(sync_pref_name);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Go through and build sync data for any remaining preferences.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<std::string>::iterator pref_name_iter =
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          remaining_preferences.begin();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       pref_name_iter != remaining_preferences.end();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++pref_name_iter) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Push updates to sync.
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  merge_result.set_error(
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (merge_result.error().IsSet())
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return merge_result;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  models_associated_ = true;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_service_->OnIsSyncingChanged();
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return merge_result;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrefModelAssociator::StopSyncing(syncer::ModelType type) {
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(type_, type);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  models_associated_ = false;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_processor_.reset();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_error_factory_.reset();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_service_->OnIsSyncingChanged();
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<Value> PrefModelAssociator::MergePreference(
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& name,
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Value& local_value,
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value& server_value) {
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (name == prefs::kURLsToRestoreOnStartup) {
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<Value>(MergeListValues(local_value, server_value)).Pass();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (name == prefs::kContentSettingsPatternPairs) {
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<Value>(
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        MergeDictionaryValues(local_value, server_value)).Pass();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If this is not a specially handled preference, server wins.
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return scoped_ptr<Value>(server_value.DeepCopy()).Pass();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PrefModelAssociator::CreatePrefSyncData(
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value& value,
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    syncer::SyncData* sync_data) const {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (value.IsType(Value::TYPE_NULL)) {
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Attempting to sync a null pref value for " << name;
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string serialized;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(zea): consider JSONWriter::Write since you don't have to check
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // failures to deserialize.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JSONStringValueSerializer json(&serialized);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!json.Serialize(value)) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Failed to serialize preference value.";
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_pb::EntitySpecifics specifics;
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  sync_pb::PreferenceSpecifics* pref_specifics =
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GetMutableSpecifics(type_, &specifics);
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_specifics->set_name(name);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_specifics->set_value(serialized);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *sync_data = syncer::SyncData::CreateLocalData(name, name, specifics);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Value* PrefModelAssociator::MergeListValues(const Value& from_value,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            const Value& to_value) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_value.GetType() == Value::TYPE_NULL)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return to_value.DeepCopy();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (to_value.GetType() == Value::TYPE_NULL)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return from_value.DeepCopy();
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(from_value.GetType() == Value::TYPE_LIST);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(to_value.GetType() == Value::TYPE_LIST);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ListValue& from_list_value = static_cast<const ListValue&>(from_value);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ListValue& to_list_value = static_cast<const ListValue&>(to_value);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ListValue* result = to_list_value.DeepCopy();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ListValue::const_iterator i = from_list_value.begin();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != from_list_value.end(); ++i) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Value* value = (*i)->DeepCopy();
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->AppendIfNotPresent(value);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Value* PrefModelAssociator::MergeDictionaryValues(
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value& from_value,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Value& to_value) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_value.GetType() == Value::TYPE_NULL)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return to_value.DeepCopy();
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (to_value.GetType() == Value::TYPE_NULL)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return from_value.DeepCopy();
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(from_value.GetType(), Value::TYPE_DICTIONARY);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(to_value.GetType(), Value::TYPE_DICTIONARY);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DictionaryValue& from_dict_value =
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<const DictionaryValue&>(from_value);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DictionaryValue& to_dict_value =
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<const DictionaryValue&>(to_value);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DictionaryValue* result = to_dict_value.DeepCopy();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (DictionaryValue::Iterator it(from_dict_value); !it.IsAtEnd();
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it.Advance()) {
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Value* from_value = &it.value();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Value* to_key_value;
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (result->GetWithoutPathExpansion(it.key(), &to_key_value)) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (to_key_value->GetType() == Value::TYPE_DICTIONARY) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Value* merged_value = MergeDictionaryValues(*from_value, *to_key_value);
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result->SetWithoutPathExpansion(it.key(), merged_value);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note that for all other types we want to preserve the "to"
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // values so we do nothing here.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      result->SetWithoutPathExpansion(it.key(), from_value->DeepCopy());
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: This will build a model of all preferences registered as syncable
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with user controlled data. We do not track any information for preferences
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// not registered locally as syncable and do not inform the syncer of
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// non-user controlled preferences.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncDataList PrefModelAssociator::GetAllSyncData(
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::ModelType type)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const {
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(type_, type);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncDataList current_data;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (PreferenceSet::const_iterator iter = synced_preferences_.begin();
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != synced_preferences_.end();
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++iter) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string name = *iter;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PrefService::Preference* pref =
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pref_service_->FindPreference(name.c_str());
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(pref);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!pref->IsUserControlled() || pref->IsDefaultValue())
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // This is not data we care about.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(zea): plumb a way to read the user controlled value.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncData sync_data;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!CreatePrefSyncData(name, *pref->GetValue(), &sync_data))
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_data.push_back(sync_data);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return current_data;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncError PrefModelAssociator::ProcessSyncChanges(
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& from_here,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncer::SyncChangeList& change_list) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!models_associated_) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncError error(FROM_HERE,
356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            syncer::SyncError::DATATYPE_ERROR,
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            "Models not yet associated.",
358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            PREFERENCES);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return error;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncChangeList::const_iterator iter;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (iter = change_list.begin(); iter != change_list.end(); ++iter) {
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK_EQ(type_, iter->sync_data().GetDataType());
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string name;
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const sync_pb::PreferenceSpecifics& pref_specifics =
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        GetSpecifics(iter->sync_data());
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<Value> value(ReadPreferenceSpecifics(pref_specifics,
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    &name));
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We never delete preferences.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Attempted to process sync delete change for " << name
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << ". Skipping.";
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip values we can't deserialize.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(zea): consider taking some further action such as erasing the bad
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // data.
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.get())
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // It is possible that we may receive a change to a preference we do not
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // want to sync. For example if the user is syncing a Mac client and a
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Windows client, the Windows client does not support
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // kConfirmToQuitEnabled. Ignore updates from these preferences.
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* pref_name = name.c_str();
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsPrefRegistered(pref_name))
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const PrefService::Preference* pref =
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pref_service_->FindPreference(pref_name);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(pref);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This will only modify the user controlled value store, which takes
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // priority over the default value but is ignored if the preference is
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // policy controlled.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pref_service_->Set(pref_name, *value);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4034311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    NotifySyncedPrefObservers(name, true /*from_sync*/);
4044311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Keep track of any newly synced preferences.
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (iter->change_type() == syncer::SyncChange::ACTION_ADD) {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      synced_preferences_.insert(name);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return syncer::SyncError();
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Value* PrefModelAssociator::ReadPreferenceSpecifics(
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::PreferenceSpecifics& preference,
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* name) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::JSONReader reader;
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<Value> value(reader.ReadToValue(preference.value()));
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value.get()) {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string err = "Failed to deserialize preference value: " +
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reader.GetErrorMessage();
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << err;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *name = preference.name();
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value.release();
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool PrefModelAssociator::IsPrefSynced(const std::string& name) const {
42990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return synced_preferences_.find(name) != synced_preferences_.end();
43090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
43190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4324311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdochvoid PrefModelAssociator::AddSyncedPrefObserver(const std::string& name,
4334311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    SyncedPrefObserver* observer) {
4344311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  SyncedPrefObserverList* observers = synced_pref_observers_[name];
4354311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  if (observers == NULL) {
4364311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    observers = new SyncedPrefObserverList;
4374311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    synced_pref_observers_[name] = observers;
4384311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  }
4394311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  observers->AddObserver(observer);
4404311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch}
4414311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
4424311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdochvoid PrefModelAssociator::RemoveSyncedPrefObserver(const std::string& name,
4434311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    SyncedPrefObserver* observer) {
4444311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  SyncedPrefObserverMap::iterator observer_iter =
4454311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      synced_pref_observers_.find(name);
4464311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  if (observer_iter == synced_pref_observers_.end())
4474311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    return;
4484311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  SyncedPrefObserverList* observers = observer_iter->second;
4494311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  observers->RemoveObserver(observer);
4504311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch}
4514311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::set<std::string> PrefModelAssociator::registered_preferences() const {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return registered_preferences_;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrefModelAssociator::RegisterPref(const char* name) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!models_associated_ && registered_preferences_.count(name) == 0);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registered_preferences_.insert(name);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PrefModelAssociator::IsPrefRegistered(const char* name) {
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return registered_preferences_.count(name) > 0;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (processing_syncer_changes_)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // These are changes originating from us, ignore.
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only process changes if we've already associated models.
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!models_associated_)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PrefService::Preference* preference =
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pref_service_->FindPreference(name.c_str());
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!preference)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsPrefRegistered(name.c_str()))
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // We are not syncing this preference.
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncChangeList changes;
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!preference->IsUserModifiable()) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the preference is no longer user modifiable, it must now be controlled
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // by policy, whose values we do not sync. Just return. If the preference
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // stops being controlled by policy, it will revert back to the user value
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (which we continue to update with sync changes).
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4934311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  NotifySyncedPrefObservers(name, false /*from_sync*/);
4944311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (synced_preferences_.count(name) == 0) {
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Not in synced_preferences_ means no synced data. InitPrefAndAssociate(..)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will determine if we care about its data (e.g. if it has a default value
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and hasn't been changed yet we don't) and take care syncing any new data.
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitPrefAndAssociate(syncer::SyncData(), name, &changes);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We are already syncing this preference, just update it's sync node.
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncer::SyncData sync_data;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to update preference.";
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changes.push_back(
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        syncer::SyncChange(FROM_HERE,
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           syncer::SyncChange::ACTION_UPDATE,
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           sync_data));
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::SyncError error =
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pref_service_ == NULL);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pref_service_ = pref_service;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5214311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
5224311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdochvoid PrefModelAssociator::NotifySyncedPrefObservers(const std::string& path,
5234311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch                                                    bool from_sync) const {
5244311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  SyncedPrefObserverMap::const_iterator observer_iter =
5254311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      synced_pref_observers_.find(path);
5264311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  if (observer_iter == synced_pref_observers_.end())
5274311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    return;
5284311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  SyncedPrefObserverList* observers = observer_iter->second;
5294311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  FOR_EACH_OBSERVER(SyncedPrefObserver, *observers,
5304311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch                    OnSyncedPrefChanged(path, from_sync));
5314311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch}
532