| Index: components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
|
| diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f104f8d9a3973a4bd4bb34035671753dca77c29b
|
| --- /dev/null
|
| +++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
|
| @@ -0,0 +1,393 @@
|
| +// Copyright 2015 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 "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
|
| +
|
| +#include <utility>
|
| +
|
| +#include "components/autofill/core/browser/autofill_profile.h"
|
| +#include "components/autofill/core/browser/credit_card.h"
|
| +#include "components/autofill/core/browser/webdata/autofill_table.h"
|
| +#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
|
| +#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
|
| +#include "sync/api/sync_change.h"
|
| +#include "sync/api/sync_error_factory.h"
|
| +#include "sync/protocol/autofill_specifics.pb.h"
|
| +#include "sync/protocol/sync.pb.h"
|
| +
|
| +namespace autofill {
|
| +
|
| +namespace {
|
| +
|
| +void* UserDataKey() {
|
| + // Use the address of a static so that COMDAT folding won't ever fold
|
| + // with something else.
|
| + static int user_data_key = 0;
|
| + return reinterpret_cast<void*>(&user_data_key);
|
| +}
|
| +
|
| +// Returns sync data of the given |type|, built from |local|.
|
| +syncer::SyncData CreateSyncData(const AutofillDataModel& local,
|
| + sync_pb::WalletMetadataSpecifics::Type type) {
|
| + sync_pb::EntitySpecifics entity;
|
| + sync_pb::WalletMetadataSpecifics* metadata = entity.mutable_wallet_metadata();
|
| + metadata->set_type(type);
|
| + metadata->set_id(local.server_id());
|
| + metadata->set_use_count(local.use_count());
|
| + metadata->set_use_date(local.use_date().ToInternalValue());
|
| + return syncer::SyncData::CreateLocalData(local.server_id(), local.server_id(),
|
| + entity);
|
| +}
|
| +
|
| +// Updates |local| usage stats from |remote_use_count| and |remote_use_date| if
|
| +// necessary. Returns true if |local| is modified.
|
| +bool UpdateLocalStats(size_t remote_use_count,
|
| + const base::Time& remote_use_date,
|
| + AutofillDataModel* local) {
|
| + bool modified = false;
|
| + if (local->use_count() < remote_use_count) {
|
| + local->set_use_count(remote_use_count);
|
| + modified = true;
|
| + }
|
| +
|
| + if (local->use_date() < remote_use_date) {
|
| + local->set_use_date(remote_use_date);
|
| + modified = true;
|
| + }
|
| +
|
| + return modified;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +AutofillWalletMetadataSyncableService::
|
| + ~AutofillWalletMetadataSyncableService() {
|
| +}
|
| +
|
| +syncer::SyncMergeResult
|
| +AutofillWalletMetadataSyncableService::MergeDataAndStartSyncing(
|
| + syncer::ModelType type,
|
| + const syncer::SyncDataList& initial_sync_data,
|
| + scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
|
| + scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!sync_processor_);
|
| + DCHECK(!sync_error_factory_);
|
| + DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
|
| +
|
| + sync_processor_ = sync_processor.Pass();
|
| + sync_error_factory_ = sync_error_factory.Pass();
|
| +
|
| + syncer::SyncMergeResult result(syncer::AUTOFILL_WALLET_METADATA);
|
| + result.set_error(Reconcile(initial_sync_data));
|
| +
|
| + return result;
|
| +}
|
| +
|
| +void AutofillWalletMetadataSyncableService::StopSyncing(
|
| + syncer::ModelType type) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
|
| + sync_processor_.reset();
|
| + sync_error_factory_.reset();
|
| +}
|
| +
|
| +syncer::SyncDataList AutofillWalletMetadataSyncableService::GetAllSyncData(
|
| + syncer::ModelType type) const {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
|
| +
|
| + syncer::SyncDataList data_list;
|
| + std::vector<AutofillProfile*> profiles;
|
| + if (GetServerProfiles(&profiles)) {
|
| + for (auto it = profiles.begin(); it != profiles.end(); ++it) {
|
| + data_list.push_back(
|
| + CreateSyncData(**it, sync_pb::WalletMetadataSpecifics::ADDRESS));
|
| + }
|
| + }
|
| +
|
| + std::vector<CreditCard*> credit_cards;
|
| + if (GetServerCreditCards(&credit_cards)) {
|
| + for (auto it = credit_cards.begin(); it != credit_cards.end(); ++it) {
|
| + data_list.push_back(
|
| + CreateSyncData(**it, sync_pb::WalletMetadataSpecifics::CARD));
|
| + }
|
| + }
|
| +
|
| + return data_list;
|
| +}
|
| +
|
| +syncer::SyncError AutofillWalletMetadataSyncableService::ProcessSyncChanges(
|
| + const tracked_objects::Location& from_here,
|
| + const syncer::SyncChangeList& change_list) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + std::map<std::string, AutofillProfile*> profiles;
|
| + std::map<std::string, CreditCard*> cards;
|
| + GetServerData(&profiles, &cards);
|
| +
|
| + for (auto it = change_list.begin(); it != change_list.end(); ++it) {
|
| + // Add and update behave the same. Delete is ignored, because metadata is
|
| + // deleted along with the corresponding Wallet data.
|
| + if (it->change_type() == syncer::SyncChange::ACTION_ADD ||
|
| + it->change_type() == syncer::SyncChange::ACTION_UPDATE) {
|
| + const sync_pb::WalletMetadataSpecifics& metadata =
|
| + it->sync_data().GetSpecifics().wallet_metadata();
|
| +
|
| + switch (metadata.type()) {
|
| + case sync_pb::WalletMetadataSpecifics::ADDRESS: {
|
| + if (profiles.find(metadata.id()) == profiles.end())
|
| + break;
|
| +
|
| + AutofillProfile profile(AutofillProfile::SERVER_PROFILE,
|
| + metadata.id());
|
| + profile.set_use_count(metadata.use_count());
|
| + profile.set_use_date(
|
| + base::Time::FromInternalValue(metadata.use_date()));
|
| + UpdateServerAddressUsageStats(profile);
|
| + break;
|
| + }
|
| +
|
| + case sync_pb::WalletMetadataSpecifics::CARD: {
|
| + if (cards.find(metadata.id()) == cards.end())
|
| + break;
|
| +
|
| + // Does not matter whether MASKED_SERVER_CARD or FULL_SERVER_CARD is
|
| + // specified, because UpdateServerCardUsageStats does not use this
|
| + // value.
|
| + CreditCard card(CreditCard::MASKED_SERVER_CARD, metadata.id());
|
| + card.set_use_count(metadata.use_count());
|
| + card.set_use_date(base::Time::FromInternalValue(metadata.use_date()));
|
| + UpdateServerCardUsageStats(card);
|
| + break;
|
| + }
|
| +
|
| + case sync_pb::WalletMetadataSpecifics::UNKNOWN:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + return syncer::SyncError();
|
| +}
|
| +
|
| +void AutofillWalletMetadataSyncableService::AutofillProfileChanged(
|
| + const AutofillProfileChange& change) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + // Handle only metadata updates while syncing. Addition and deletion are
|
| + // handled in AutofillMultipleChanged.
|
| + if (!sync_processor_ || change.type() != AutofillProfileChange::UPDATE ||
|
| + change.profile()->record_type() != AutofillProfile::SERVER_PROFILE) {
|
| + return;
|
| + }
|
| +
|
| + syncer::SyncError error = sync_processor_->ProcessSyncChanges(
|
| + FROM_HERE,
|
| + syncer::SyncChangeList(
|
| + 1, syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
|
| + CreateSyncData(*change.profile(),
|
| + sync_pb::WalletMetadataSpecifics::ADDRESS))));
|
| +
|
| + if (error.IsSet())
|
| + sync_error_factory_->CreateAndUploadError(FROM_HERE, error.ToString());
|
| +}
|
| +
|
| +void AutofillWalletMetadataSyncableService::CreditCardChanged(
|
| + const CreditCardChange& change) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + // Handle only metadata updates while syncing. Addition and deletion are
|
| + // handled in AutofillMultipleChanged.
|
| + if (!sync_processor_ || change.type() != CreditCardChange::UPDATE ||
|
| + change.card()->record_type() == CreditCard::LOCAL_CARD) {
|
| + return;
|
| + }
|
| +
|
| + syncer::SyncError error = sync_processor_->ProcessSyncChanges(
|
| + FROM_HERE,
|
| + syncer::SyncChangeList(
|
| + 1, syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
|
| + CreateSyncData(*change.card(),
|
| + sync_pb::WalletMetadataSpecifics::CARD))));
|
| +
|
| + if (error.IsSet())
|
| + sync_error_factory_->CreateAndUploadError(FROM_HERE, error.ToString());
|
| +}
|
| +
|
| +void AutofillWalletMetadataSyncableService::AutofillMultipleChanged() {
|
| + if (!sync_processor_)
|
| + return;
|
| +
|
| + syncer::SyncError error = Reconcile(
|
| + sync_processor_->GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA));
|
| + if (error.IsSet())
|
| + sync_error_factory_->CreateAndUploadError(FROM_HERE, error.ToString());
|
| +}
|
| +
|
| +// static
|
| +void AutofillWalletMetadataSyncableService::CreateForWebDataServiceAndBackend(
|
| + AutofillWebDataService* web_data_service,
|
| + AutofillWebDataBackend* webdata_backend,
|
| + const std::string& app_locale) {
|
| + web_data_service->GetDBUserData()->SetUserData(
|
| + UserDataKey(),
|
| + new AutofillWalletMetadataSyncableService(webdata_backend, app_locale));
|
| +}
|
| +
|
| +// static
|
| +AutofillWalletMetadataSyncableService*
|
| +AutofillWalletMetadataSyncableService::FromWebDataService(
|
| + AutofillWebDataService* web_data_service) {
|
| + return static_cast<AutofillWalletMetadataSyncableService*>(
|
| + web_data_service->GetDBUserData()->GetUserData(UserDataKey()));
|
| +}
|
| +
|
| +AutofillWalletMetadataSyncableService::AutofillWalletMetadataSyncableService(
|
| + AutofillWebDataBackend* webdata_backend,
|
| + const std::string& app_locale)
|
| + : webdata_backend_(webdata_backend), scoped_observer_(this) {
|
| + // No webdata in tests.
|
| + if (webdata_backend_)
|
| + scoped_observer_.Add(webdata_backend_);
|
| +}
|
| +
|
| +bool AutofillWalletMetadataSyncableService::GetServerProfiles(
|
| + std::vector<AutofillProfile*>* profiles) const {
|
| + return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
|
| + ->GetServerProfiles(profiles);
|
| +}
|
| +
|
| +bool AutofillWalletMetadataSyncableService::GetServerCreditCards(
|
| + std::vector<CreditCard*>* credit_cards) const {
|
| + return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
|
| + ->GetServerCreditCards(credit_cards);
|
| +}
|
| +
|
| +bool AutofillWalletMetadataSyncableService::UpdateServerAddressUsageStats(
|
| + const AutofillProfile& profile) {
|
| + return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
|
| + ->UpdateServerAddressUsageStats(profile);
|
| +}
|
| +
|
| +bool AutofillWalletMetadataSyncableService::UpdateServerCardUsageStats(
|
| + const CreditCard& credit_card) {
|
| + return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
|
| + ->UpdateServerCardUsageStats(credit_card);
|
| +}
|
| +
|
| +syncer::SyncError AutofillWalletMetadataSyncableService::Reconcile(
|
| + const syncer::SyncDataList& sync_data) {
|
| + DCHECK(sync_processor_);
|
| +
|
| + std::map<std::string, AutofillProfile*> profiles;
|
| + std::map<std::string, CreditCard*> cards;
|
| + GetServerData(&profiles, &cards);
|
| +
|
| + syncer::SyncChangeList remote_changes;
|
| + for (auto it = sync_data.begin(); it != sync_data.end(); ++it) {
|
| + const sync_pb::WalletMetadataSpecifics& remote =
|
| + it->GetSpecifics().wallet_metadata();
|
| + size_t remote_use_count = static_cast<size_t>(remote.use_count());
|
| + base::Time remote_use_date =
|
| + base::Time::FromInternalValue(remote.use_date());
|
| +
|
| + switch (remote.type()) {
|
| + case sync_pb::WalletMetadataSpecifics::ADDRESS: {
|
| + auto profile_it = profiles.find(remote.id());
|
| + if (profile_it == profiles.end()) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_DELETE, *it));
|
| + break;
|
| + }
|
| +
|
| + AutofillProfile* local = profile_it->second;
|
| + profiles.erase(profile_it);
|
| + bool local_modified =
|
| + UpdateLocalStats(remote_use_count, remote_use_date, local);
|
| +
|
| + if (local->use_count() > remote_use_count ||
|
| + local->use_date() > remote_use_date) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
|
| + CreateSyncData(*local,
|
| + sync_pb::WalletMetadataSpecifics::ADDRESS)));
|
| + }
|
| +
|
| + // Save the stats last, because this clears values in |local|.
|
| + if (local_modified)
|
| + UpdateServerAddressUsageStats(*local);
|
| +
|
| + break;
|
| + }
|
| +
|
| + case sync_pb::WalletMetadataSpecifics::CARD: {
|
| + auto card_it = cards.find(remote.id());
|
| + if (card_it == cards.end()) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_DELETE, *it));
|
| + break;
|
| + }
|
| +
|
| + CreditCard* local = card_it->second;
|
| + cards.erase(card_it);
|
| + bool local_modified =
|
| + UpdateLocalStats(remote_use_count, remote_use_date, local);
|
| +
|
| + if (local->use_count() > remote_use_count ||
|
| + local->use_date() > remote_use_date) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
|
| + CreateSyncData(*local, sync_pb::WalletMetadataSpecifics::CARD)));
|
| + }
|
| +
|
| + // Save the stats last, because this clears values in |local|.
|
| + if (local_modified)
|
| + UpdateServerCardUsageStats(*local);
|
| +
|
| + break;
|
| + }
|
| +
|
| + case sync_pb::WalletMetadataSpecifics::UNKNOWN:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + for (auto it = profiles.begin(); it != profiles.end(); ++it) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_ADD,
|
| + CreateSyncData(*it->second,
|
| + sync_pb::WalletMetadataSpecifics::ADDRESS)));
|
| + }
|
| +
|
| + for (auto it = cards.begin(); it != cards.end(); ++it) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_ADD,
|
| + CreateSyncData(*it->second, sync_pb::WalletMetadataSpecifics::CARD)));
|
| + }
|
| +
|
| + return sync_processor_->ProcessSyncChanges(FROM_HERE, remote_changes);
|
| +}
|
| +
|
| +bool AutofillWalletMetadataSyncableService::GetServerData(
|
| + std::map<std::string, AutofillProfile*>* profiles,
|
| + std::map<std::string, CreditCard*>* cards) {
|
| + std::vector<AutofillProfile*> profile_list;
|
| + bool success = GetServerProfiles(&profile_list);
|
| + for (auto it = profile_list.begin(); it != profile_list.end(); ++it)
|
| + profiles->insert(std::make_pair((*it)->server_id(), *it));
|
| +
|
| + std::vector<CreditCard*> card_list;
|
| + success &= GetServerCreditCards(&card_list);
|
| + for (auto it = card_list.begin(); it != card_list.end(); ++it)
|
| + cards->insert(std::make_pair((*it)->server_id(), *it));
|
| +
|
| + return success;
|
| +}
|
| +
|
| +} // namespace autofill
|
|
|