Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(674)

Unified Diff: components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc

Issue 1110833002: [autofill] Sync server card and address metadata. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Work Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698