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 |