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 |