| 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..49f1bec32f2565d002cb6621e08ec48a27d08d15
|
| --- /dev/null
|
| +++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
|
| @@ -0,0 +1,410 @@
|
| +// 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 syncable metadata for the |local| profile or credit card.
|
| +syncer::SyncData CreateSyncData(const AutofillDataModel& local,
|
| + const std::string& server_id,
|
| + sync_pb::WalletMetadataSpecifics::Type type) {
|
| + sync_pb::EntitySpecifics entity;
|
| + sync_pb::WalletMetadataSpecifics* metadata = entity.mutable_wallet_metadata();
|
| + metadata->set_type(type);
|
| + metadata->set_id(server_id);
|
| + metadata->set_use_count(local.use_count());
|
| + metadata->set_use_date(local.use_date().ToInternalValue());
|
| +
|
| + std::string sync_tag;
|
| + switch (type) {
|
| + case sync_pb::WalletMetadataSpecifics::ADDRESS:
|
| + sync_tag = "address-" + server_id;
|
| + break;
|
| + case sync_pb::WalletMetadataSpecifics::CARD:
|
| + sync_tag = "card-" + server_id;
|
| + break;
|
| + case sync_pb::WalletMetadataSpecifics::UNKNOWN:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| +
|
| + return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, 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 (const AutofillProfile* profile : profiles) {
|
| + data_list.push_back(
|
| + CreateSyncData(*profile, profile->server_id(),
|
| + sync_pb::WalletMetadataSpecifics::ADDRESS));
|
| + }
|
| + }
|
| +
|
| + std::vector<CreditCard*> credit_cards;
|
| + if (GetServerCreditCards(&credit_cards)) {
|
| + for (const CreditCard* credit_card : credit_cards) {
|
| + data_list.push_back(
|
| + CreateSyncData(*credit_card, credit_card->server_id(),
|
| + 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 (const syncer::SyncChange& change : change_list) {
|
| + // Add and update behave the same. Delete is ignored, because metadata is
|
| + // deleted along with the corresponding Wallet data.
|
| + if (change.change_type() == syncer::SyncChange::ACTION_ADD ||
|
| + change.change_type() == syncer::SyncChange::ACTION_UPDATE) {
|
| + const sync_pb::WalletMetadataSpecifics& metadata =
|
| + change.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(), change.profile()->server_id(),
|
| + 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(), change.card()->server_id(),
|
| + 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 (const syncer::SyncData& datum : sync_data) {
|
| + const sync_pb::WalletMetadataSpecifics& remote =
|
| + datum.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 it = profiles.find(remote.id());
|
| + if (it == profiles.end()) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_DELETE, datum));
|
| + break;
|
| + }
|
| +
|
| + AutofillProfile* local = it->second;
|
| + profiles.erase(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, local->server_id(),
|
| + 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 it = cards.find(remote.id());
|
| + if (it == cards.end()) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_DELETE, datum));
|
| + break;
|
| + }
|
| +
|
| + CreditCard* local = it->second;
|
| + cards.erase(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, local->server_id(),
|
| + 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 (const auto& id_profile_pair : profiles) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_ADD,
|
| + CreateSyncData(*id_profile_pair.second, id_profile_pair.first,
|
| + sync_pb::WalletMetadataSpecifics::ADDRESS)));
|
| + }
|
| +
|
| + for (const auto& id_card_pair : cards) {
|
| + remote_changes.push_back(syncer::SyncChange(
|
| + FROM_HERE, syncer::SyncChange::ACTION_ADD,
|
| + CreateSyncData(*id_card_pair.second, id_card_pair.first,
|
| + 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 (AutofillProfile* profile : profile_list)
|
| + profiles->insert(std::make_pair(profile->server_id(), profile));
|
| +
|
| + std::vector<CreditCard*> card_list;
|
| + success &= GetServerCreditCards(&card_list);
|
| + for (CreditCard* card : card_list)
|
| + cards->insert(std::make_pair(card->server_id(), card));
|
| +
|
| + return success;
|
| +}
|
| +
|
| +} // namespace autofill
|
|
|