// Copyright (c) 2012 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/browser/personal_data_manager.h" #include #include #include #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/prefs/pref_service.h" #include "base/strings/string_number_conversions.h" #include "base/utf_string_conversions.h" #include "components/autofill/browser/autofill_country.h" #include "components/autofill/browser/autofill-inl.h" #include "components/autofill/browser/autofill_field.h" #include "components/autofill/browser/autofill_metrics.h" #include "components/autofill/browser/form_group.h" #include "components/autofill/browser/form_structure.h" #include "components/autofill/browser/personal_data_manager_observer.h" #include "components/autofill/browser/phone_number.h" #include "components/autofill/browser/phone_number_i18n.h" #include "components/autofill/browser/validation.h" #include "components/autofill/common/autofill_pref_names.h" #include "components/user_prefs/user_prefs.h" #include "components/webdata/autofill/autofill_webdata_service.h" #include "content/public/browser/browser_context.h" using content::BrowserContext; namespace { const string16::value_type kCreditCardPrefix[] = {'*', 0}; template class FormGroupMatchesByGUIDFunctor { public: explicit FormGroupMatchesByGUIDFunctor(const std::string& guid) : guid_(guid) { } bool operator()(const T& form_group) { return form_group.guid() == guid_; } bool operator()(const T* form_group) { return form_group->guid() == guid_; } private: std::string guid_; }; template bool FindByGUID(const C& container, const std::string& guid) { return std::find_if( container.begin(), container.end(), FormGroupMatchesByGUIDFunctor(guid)) != container.end(); } template class DereferenceFunctor { public: template const T& operator()(const T_Iterator& iterator) { return *iterator; } }; template T* address_of(T& v) { return &v; } // Returns true if minimum requirements for import of a given |profile| have // been met. An address submitted via a form must have at least the fields // required as determined by its country code. // No verification of validity of the contents is preformed. This is an // existence check only. bool IsMinimumAddress(const AutofillProfile& profile, const std::string& app_locale) { // All countries require at least one address line. if (profile.GetRawInfo(ADDRESS_HOME_LINE1).empty()) return false; std::string country_code = UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)); if (country_code.empty()) country_code = AutofillCountry::CountryCodeForLocale(app_locale); AutofillCountry country(country_code, app_locale); if (country.requires_city() && profile.GetRawInfo(ADDRESS_HOME_CITY).empty()) return false; if (country.requires_state() && profile.GetRawInfo(ADDRESS_HOME_STATE).empty()) return false; if (country.requires_zip() && profile.GetRawInfo(ADDRESS_HOME_ZIP).empty()) return false; return true; } // Return true if the |field_type| and |value| are valid within the context // of importing a form. bool IsValidFieldTypeAndValue(const std::set& types_seen, AutofillFieldType field_type, const string16& value) { // Abandon the import if two fields of the same type are encountered. // This indicates ambiguous data or miscategorization of types. // Make an exception for PHONE_HOME_NUMBER however as both prefix and // suffix are stored against this type. if (types_seen.count(field_type) && field_type != PHONE_HOME_NUMBER) return false; // Abandon the import if an email address value shows up in a field that is // not an email address. if (field_type != EMAIL_ADDRESS && autofill::IsValidEmailAddress(value)) return false; return true; } } // namespace PersonalDataManager::PersonalDataManager(const std::string& app_locale) : browser_context_(NULL), is_data_loaded_(false), pending_profiles_query_(0), pending_creditcards_query_(0), app_locale_(app_locale), metric_logger_(new AutofillMetrics), has_logged_profile_count_(false) {} void PersonalDataManager::Init(BrowserContext* browser_context) { browser_context_ = browser_context; metric_logger_->LogIsAutofillEnabledAtStartup(IsAutofillEnabled()); scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); // WebDataService may not be available in tests. if (!autofill_data.get()) return; LoadProfiles(); LoadCreditCards(); autofill_data->AddObserver(this); } PersonalDataManager::~PersonalDataManager() { CancelPendingQuery(&pending_profiles_query_); CancelPendingQuery(&pending_creditcards_query_); if (!browser_context_) return; scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (autofill_data.get()) autofill_data->RemoveObserver(this); } void PersonalDataManager::OnWebDataServiceRequestDone( WebDataServiceBase::Handle h, const WDTypedResult* result) { DCHECK(pending_profiles_query_ || pending_creditcards_query_); if (!result) { // Error from the web database. if (h == pending_creditcards_query_) pending_creditcards_query_ = 0; else if (h == pending_profiles_query_) pending_profiles_query_ = 0; return; } DCHECK(result->GetType() == AUTOFILL_PROFILES_RESULT || result->GetType() == AUTOFILL_CREDITCARDS_RESULT); switch (result->GetType()) { case AUTOFILL_PROFILES_RESULT: ReceiveLoadedProfiles(h, result); break; case AUTOFILL_CREDITCARDS_RESULT: ReceiveLoadedCreditCards(h, result); break; default: NOTREACHED(); } // If both requests have responded, then all personal data is loaded. if (pending_profiles_query_ == 0 && pending_creditcards_query_ == 0) { is_data_loaded_ = true; std::vector profile_pointers(web_profiles_.size()); std::copy(web_profiles_.begin(), web_profiles_.end(), profile_pointers.begin()); AutofillProfile::AdjustInferredLabels(&profile_pointers); FOR_EACH_OBSERVER(PersonalDataManagerObserver, observers_, OnPersonalDataChanged()); } } void PersonalDataManager::AutofillMultipleChanged() { Refresh(); } void PersonalDataManager::AddObserver(PersonalDataManagerObserver* observer) { observers_.AddObserver(observer); } void PersonalDataManager::RemoveObserver( PersonalDataManagerObserver* observer) { observers_.RemoveObserver(observer); } bool PersonalDataManager::ImportFormData( const FormStructure& form, const CreditCard** imported_credit_card) { scoped_ptr imported_profile(new AutofillProfile); scoped_ptr local_imported_credit_card(new CreditCard); // Parse the form and construct a profile based on the information that is // possible to import. int importable_credit_card_fields = 0; // Detect and discard forms with multiple fields of the same type. std::set types_seen; // We only set complete phone, so aggregate phone parts in these vars and set // complete at the end. PhoneNumber::PhoneCombineHelper home; for (size_t i = 0; i < form.field_count(); ++i) { const AutofillField* field = form.field(i); string16 value = CollapseWhitespace(field->value, false); // If we don't know the type of the field, or the user hasn't entered any // information into the field, then skip it. if (!field->IsFieldFillable() || value.empty()) continue; AutofillFieldType field_type = field->type(); FieldTypeGroup group(AutofillType(field_type).group()); // If the |field_type| and |value| don't pass basic validity checks then // abandon the import. if (!IsValidFieldTypeAndValue(types_seen, field_type, value)) { imported_profile.reset(); local_imported_credit_card.reset(); break; } types_seen.insert(field_type); if (group == AutofillType::CREDIT_CARD) { if (LowerCaseEqualsASCII(field->form_control_type, "month")) { DCHECK_EQ(CREDIT_CARD_EXP_MONTH, field_type); local_imported_credit_card->SetInfoForMonthInputType(value); } else { local_imported_credit_card->SetInfo(field_type, value, app_locale_); } ++importable_credit_card_fields; } else { // We need to store phone data in the variables, before building the whole // number at the end. The rest of the fields are set "as is". // If the fields are not the phone fields in question home.SetInfo() is // going to return false. if (!home.SetInfo(field_type, value)) imported_profile->SetInfo(field_type, value, app_locale_); // Reject profiles with invalid country information. if (field_type == ADDRESS_HOME_COUNTRY && !value.empty() && imported_profile->GetRawInfo(ADDRESS_HOME_COUNTRY).empty()) { imported_profile.reset(); break; } } } // Construct the phone number. Reject the profile if the number is invalid. if (imported_profile.get() && !home.IsEmpty()) { string16 constructed_number; if (!home.ParseNumber(*imported_profile, app_locale_, &constructed_number) || !imported_profile->SetInfo(PHONE_HOME_WHOLE_NUMBER, constructed_number, app_locale_)) { imported_profile.reset(); } } // Reject the profile if minimum address and validation requirements are not // met. if (imported_profile.get() && !IsValidLearnableProfile(*imported_profile, app_locale_)) imported_profile.reset(); // Reject the credit card if we did not detect enough filled credit card // fields or if the credit card number does not seem to be valid. if (local_imported_credit_card.get() && !local_imported_credit_card->IsComplete()) { local_imported_credit_card.reset(); } // Don't import if we already have this info. // Don't present an infobar if we have already saved this card number. bool merged_credit_card = false; if (local_imported_credit_card.get()) { for (std::vector::const_iterator iter = credit_cards_.begin(); iter != credit_cards_.end(); ++iter) { if ((*iter)->UpdateFromImportedCard(*local_imported_credit_card.get(), app_locale_)) { merged_credit_card = true; UpdateCreditCard(**iter); local_imported_credit_card.reset(); break; } } } if (imported_profile.get()) { // We always save imported profiles. SaveImportedProfile(*imported_profile); } *imported_credit_card = local_imported_credit_card.release(); if (imported_profile.get() || *imported_credit_card || merged_credit_card) { return true; } else { FOR_EACH_OBSERVER(PersonalDataManagerObserver, observers_, OnInsufficientFormData()); return false; } } void PersonalDataManager::AddProfile(const AutofillProfile& profile) { if (browser_context_->IsOffTheRecord()) return; if (profile.IsEmpty(app_locale_)) return; // Don't add an existing profile. if (FindByGUID(web_profiles_, profile.guid())) return; scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) return; // Don't add a duplicate. if (FindByContents(web_profiles_, profile)) return; // Add the new profile to the web database. autofill_data->AddAutofillProfile(profile); // Refresh our local cache and send notifications to observers. Refresh(); } void PersonalDataManager::UpdateProfile(const AutofillProfile& profile) { if (browser_context_->IsOffTheRecord()) return; if (!FindByGUID(web_profiles_, profile.guid())) return; if (profile.IsEmpty(app_locale_)) { RemoveByGUID(profile.guid()); return; } scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) return; // Make the update. autofill_data->UpdateAutofillProfile(profile); // Refresh our local cache and send notifications to observers. Refresh(); } AutofillProfile* PersonalDataManager::GetProfileByGUID( const std::string& guid) { const std::vector& profiles = GetProfiles(); for (std::vector::const_iterator iter = profiles.begin(); iter != profiles.end(); ++iter) { if ((*iter)->guid() == guid) return *iter; } return NULL; } void PersonalDataManager::AddCreditCard(const CreditCard& credit_card) { if (browser_context_->IsOffTheRecord()) return; if (credit_card.IsEmpty(app_locale_)) return; if (FindByGUID(credit_cards_, credit_card.guid())) return; scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) return; // Don't add a duplicate. if (FindByContents(credit_cards_, credit_card)) return; // Add the new credit card to the web database. autofill_data->AddCreditCard(credit_card); // Refresh our local cache and send notifications to observers. Refresh(); } void PersonalDataManager::UpdateCreditCard(const CreditCard& credit_card) { if (browser_context_->IsOffTheRecord()) return; if (!FindByGUID(credit_cards_, credit_card.guid())) return; if (credit_card.IsEmpty(app_locale_)) { RemoveByGUID(credit_card.guid()); return; } scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) return; // Make the update. autofill_data->UpdateCreditCard(credit_card); // Refresh our local cache and send notifications to observers. Refresh(); } void PersonalDataManager::RemoveByGUID(const std::string& guid) { if (browser_context_->IsOffTheRecord()) return; bool is_credit_card = FindByGUID(credit_cards_, guid); bool is_profile = !is_credit_card && FindByGUID(web_profiles_, guid); if (!is_credit_card && !is_profile) return; scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) return; if (is_credit_card) autofill_data->RemoveCreditCard(guid); else autofill_data->RemoveAutofillProfile(guid); // Refresh our local cache and send notifications to observers. Refresh(); } CreditCard* PersonalDataManager::GetCreditCardByGUID(const std::string& guid) { for (std::vector::iterator iter = credit_cards_.begin(); iter != credit_cards_.end(); ++iter) { if ((*iter)->guid() == guid) return *iter; } return NULL; } void PersonalDataManager::GetNonEmptyTypes( FieldTypeSet* non_empty_types) { const std::vector& profiles = GetProfiles(); for (std::vector::const_iterator iter = profiles.begin(); iter != profiles.end(); ++iter) { (*iter)->GetNonEmptyTypes(app_locale_, non_empty_types); } for (ScopedVector::const_iterator iter = credit_cards_.begin(); iter != credit_cards_.end(); ++iter) { (*iter)->GetNonEmptyTypes(app_locale_, non_empty_types); } } bool PersonalDataManager::IsDataLoaded() const { return is_data_loaded_; } const std::vector& PersonalDataManager::GetProfiles() { if (!components::UserPrefs::Get(browser_context_)->GetBoolean( prefs::kAutofillAuxiliaryProfilesEnabled)) { return web_profiles(); } profiles_.clear(); // Populates |auxiliary_profiles_|. LoadAuxiliaryProfiles(); profiles_.insert(profiles_.end(), web_profiles_.begin(), web_profiles_.end()); profiles_.insert(profiles_.end(), auxiliary_profiles_.begin(), auxiliary_profiles_.end()); return profiles_; } const std::vector& PersonalDataManager::web_profiles() const { return web_profiles_.get(); } const std::vector& PersonalDataManager::credit_cards() const { return credit_cards_.get(); } void PersonalDataManager::Refresh() { LoadProfiles(); LoadCreditCards(); } void PersonalDataManager::GetProfileSuggestions( AutofillFieldType type, const string16& field_contents, bool field_is_autofilled, std::vector other_field_types, std::vector* values, std::vector* labels, std::vector* icons, std::vector* guid_pairs) { values->clear(); labels->clear(); icons->clear(); guid_pairs->clear(); const std::vector& profiles = GetProfiles(); std::vector matched_profiles; for (std::vector::const_iterator iter = profiles.begin(); iter != profiles.end(); ++iter) { AutofillProfile* profile = *iter; // The value of the stored data for this field type in the |profile|. std::vector multi_values; profile->GetMultiInfo(type, app_locale_, &multi_values); for (size_t i = 0; i < multi_values.size(); ++i) { if (!field_is_autofilled) { // Suggest data that starts with what the user has typed. if (!multi_values[i].empty() && StartsWith(multi_values[i], field_contents, false)) { matched_profiles.push_back(profile); values->push_back(multi_values[i]); guid_pairs->push_back(GUIDPair(profile->guid(), i)); } } else { if (multi_values[i].empty()) continue; string16 profile_value_lower_case( StringToLowerASCII(multi_values[i])); string16 field_value_lower_case(StringToLowerASCII(field_contents)); // Phone numbers could be split in US forms, so field value could be // either prefix or suffix of the phone. bool matched_phones = false; if (type == PHONE_HOME_NUMBER && !field_value_lower_case.empty() && (profile_value_lower_case.find(field_value_lower_case) != string16::npos)) { matched_phones = true; } // Suggest variants of the profile that's already been filled in. if (matched_phones || profile_value_lower_case == field_value_lower_case) { for (size_t j = 0; j < multi_values.size(); ++j) { if (!multi_values[j].empty()) { values->push_back(multi_values[j]); guid_pairs->push_back(GUIDPair(profile->guid(), j)); } } // We've added all the values for this profile so move on to the // next. break; } } } } if (!field_is_autofilled) { AutofillProfile::CreateInferredLabels( &matched_profiles, &other_field_types, type, 1, labels); } else { // No sub-labels for previously filled fields. labels->resize(values->size()); } // No icons for profile suggestions. icons->resize(values->size()); } void PersonalDataManager::GetCreditCardSuggestions( AutofillFieldType type, const string16& field_contents, std::vector* values, std::vector* labels, std::vector* icons, std::vector* guid_pairs) { for (std::vector::const_iterator iter = credit_cards().begin(); iter != credit_cards().end(); ++iter) { CreditCard* credit_card = *iter; // The value of the stored data for this field type in the |credit_card|. string16 creditcard_field_value = credit_card->GetInfo(type, app_locale_); if (!creditcard_field_value.empty() && StartsWith(creditcard_field_value, field_contents, false)) { if (type == CREDIT_CARD_NUMBER) creditcard_field_value = credit_card->ObfuscatedNumber(); string16 label; if (credit_card->number().empty()) { // If there is no CC number, return name to show something. label = credit_card->GetInfo(CREDIT_CARD_NAME, app_locale_); } else { label = kCreditCardPrefix; label.append(credit_card->LastFourDigits()); } values->push_back(creditcard_field_value); labels->push_back(label); icons->push_back(UTF8ToUTF16(credit_card->type())); guid_pairs->push_back(GUIDPair(credit_card->guid(), 0)); } } } bool PersonalDataManager::IsAutofillEnabled() const { return components::UserPrefs::Get(browser_context_)->GetBoolean( prefs::kAutofillEnabled); } // static bool PersonalDataManager::IsValidLearnableProfile( const AutofillProfile& profile, const std::string& app_locale) { if (!IsMinimumAddress(profile, app_locale)) return false; string16 email = profile.GetRawInfo(EMAIL_ADDRESS); if (!email.empty() && !autofill::IsValidEmailAddress(email)) return false; // Reject profiles with invalid US state information. string16 state = profile.GetRawInfo(ADDRESS_HOME_STATE); if (profile.GetRawInfo(ADDRESS_HOME_COUNTRY) == ASCIIToUTF16("US") && !state.empty() && !FormGroup::IsValidState(state)) { return false; } // Reject profiles with invalid US zip information. string16 zip = profile.GetRawInfo(ADDRESS_HOME_ZIP); if (profile.GetRawInfo(ADDRESS_HOME_COUNTRY) == ASCIIToUTF16("US") && !zip.empty() && !autofill::IsValidZip(zip)) return false; return true; } // static bool PersonalDataManager::MergeProfile( const AutofillProfile& profile, const std::vector& existing_profiles, const std::string& app_locale, std::vector* merged_profiles) { merged_profiles->clear(); // Set to true if |profile| is merged into |existing_profiles|. bool merged = false; // If we have already saved this address, merge in any missing values. // Only merge with the first match. for (std::vector::const_iterator iter = existing_profiles.begin(); iter != existing_profiles.end(); ++iter) { if (!merged) { if (!profile.PrimaryValue().empty() && StringToLowerASCII((*iter)->PrimaryValue()) == StringToLowerASCII(profile.PrimaryValue())) { merged = true; (*iter)->OverwriteWithOrAddTo(profile, app_locale); } } merged_profiles->push_back(**iter); } // If the new profile was not merged with an existing one, add it to the list. if (!merged) merged_profiles->push_back(profile); return merged; } void PersonalDataManager::SetProfiles(std::vector* profiles) { if (browser_context_->IsOffTheRecord()) return; // Remove empty profiles from input. for (std::vector::iterator it = profiles->begin(); it != profiles->end();) { if (it->IsEmpty(app_locale_)) profiles->erase(it); else it++; } // Ensure that profile labels are up to date. Currently, sync relies on // labels to identify a profile. // TODO(dhollowa): We need to deprecate labels and update the way sync // identifies profiles. std::vector profile_pointers(profiles->size()); std::transform(profiles->begin(), profiles->end(), profile_pointers.begin(), address_of); AutofillProfile::AdjustInferredLabels(&profile_pointers); scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) return; // Any profiles that are not in the new profile list should be removed from // the web database. for (std::vector::const_iterator iter = web_profiles_.begin(); iter != web_profiles_.end(); ++iter) { if (!FindByGUID(*profiles, (*iter)->guid())) autofill_data->RemoveAutofillProfile((*iter)->guid()); } // Update the web database with the existing profiles. for (std::vector::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { if (FindByGUID(web_profiles_, iter->guid())) autofill_data->UpdateAutofillProfile(*iter); } // Add the new profiles to the web database. Don't add a duplicate. for (std::vector::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { if (!FindByGUID(web_profiles_, iter->guid()) && !FindByContents(web_profiles_, *iter)) autofill_data->AddAutofillProfile(*iter); } // Copy in the new profiles. web_profiles_.clear(); for (std::vector::iterator iter = profiles->begin(); iter != profiles->end(); ++iter) { web_profiles_.push_back(new AutofillProfile(*iter)); } // Refresh our local cache and send notifications to observers. Refresh(); } void PersonalDataManager::SetCreditCards( std::vector* credit_cards) { if (browser_context_->IsOffTheRecord()) return; // Remove empty credit cards from input. for (std::vector::iterator it = credit_cards->begin(); it != credit_cards->end();) { if (it->IsEmpty(app_locale_)) credit_cards->erase(it); else it++; } scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) return; // Any credit cards that are not in the new credit card list should be // removed. for (std::vector::const_iterator iter = credit_cards_.begin(); iter != credit_cards_.end(); ++iter) { if (!FindByGUID(*credit_cards, (*iter)->guid())) autofill_data->RemoveCreditCard((*iter)->guid()); } // Update the web database with the existing credit cards. for (std::vector::iterator iter = credit_cards->begin(); iter != credit_cards->end(); ++iter) { if (FindByGUID(credit_cards_, iter->guid())) autofill_data->UpdateCreditCard(*iter); } // Add the new credit cards to the web database. Don't add a duplicate. for (std::vector::iterator iter = credit_cards->begin(); iter != credit_cards->end(); ++iter) { if (!FindByGUID(credit_cards_, iter->guid()) && !FindByContents(credit_cards_, *iter)) autofill_data->AddCreditCard(*iter); } // Copy in the new credit cards. credit_cards_.clear(); for (std::vector::iterator iter = credit_cards->begin(); iter != credit_cards->end(); ++iter) { credit_cards_.push_back(new CreditCard(*iter)); } // Refresh our local cache and send notifications to observers. Refresh(); } void PersonalDataManager::LoadProfiles() { scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) { NOTREACHED(); return; } CancelPendingQuery(&pending_profiles_query_); pending_profiles_query_ = autofill_data->GetAutofillProfiles(this); } // Win and Linux implementations do nothing. Mac and Android implementations // fill in the contents of |auxiliary_profiles_|. #if !defined(OS_MACOSX) && !defined(OS_ANDROID) void PersonalDataManager::LoadAuxiliaryProfiles() { } #endif void PersonalDataManager::LoadCreditCards() { scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) { NOTREACHED(); return; } CancelPendingQuery(&pending_creditcards_query_); pending_creditcards_query_ = autofill_data->GetCreditCards(this); } void PersonalDataManager::ReceiveLoadedProfiles(WebDataServiceBase::Handle h, const WDTypedResult* result) { DCHECK_EQ(pending_profiles_query_, h); pending_profiles_query_ = 0; web_profiles_.clear(); const WDResult >* r = static_cast >*>(result); std::vector profiles = r->GetValue(); for (std::vector::iterator iter = profiles.begin(); iter != profiles.end(); ++iter) { web_profiles_.push_back(*iter); } LogProfileCount(); } void PersonalDataManager::ReceiveLoadedCreditCards( WebDataServiceBase::Handle h, const WDTypedResult* result) { DCHECK_EQ(pending_creditcards_query_, h); pending_creditcards_query_ = 0; credit_cards_.clear(); const WDResult >* r = static_cast >*>(result); std::vector credit_cards = r->GetValue(); for (std::vector::iterator iter = credit_cards.begin(); iter != credit_cards.end(); ++iter) { credit_cards_.push_back(*iter); } } void PersonalDataManager::CancelPendingQuery( WebDataServiceBase::Handle* handle) { if (*handle) { scoped_refptr autofill_data( AutofillWebDataService::FromBrowserContext(browser_context_)); if (!autofill_data.get()) { NOTREACHED(); return; } autofill_data->CancelRequest(*handle); } *handle = 0; } void PersonalDataManager::SaveImportedProfile( const AutofillProfile& imported_profile) { if (browser_context_->IsOffTheRecord()) { // The |IsOffTheRecord| check should happen earlier in the import process, // upon form submission. NOTREACHED(); return; } // Don't save a web profile if the data in the profile is a subset of an // auxiliary profile. for (std::vector::const_iterator iter = auxiliary_profiles_.begin(); iter != auxiliary_profiles_.end(); ++iter) { if (imported_profile.IsSubsetOf(**iter, app_locale_)) return; } std::vector profiles; MergeProfile(imported_profile, web_profiles_.get(), app_locale_, &profiles); SetProfiles(&profiles); } void PersonalDataManager::SaveImportedCreditCard( const CreditCard& imported_card) { DCHECK(!imported_card.number().empty()); if (browser_context_->IsOffTheRecord()) { // The |IsOffTheRecord| check should happen earlier in the import process, // upon form submission. NOTREACHED(); return; } // Set to true if |imported_card| is merged into the credit card list. bool merged = false; std::vector credit_cards; for (std::vector::const_iterator card = credit_cards_.begin(); card != credit_cards_.end(); ++card) { // If |imported_card| has not yet been merged, check whether it should be // with the current |card|. if (!merged && (*card)->UpdateFromImportedCard(imported_card, app_locale_)) merged = true; credit_cards.push_back(**card); } if (!merged) credit_cards.push_back(imported_card); SetCreditCards(&credit_cards); } void PersonalDataManager::LogProfileCount() const { if (!has_logged_profile_count_) { metric_logger_->LogStoredProfileCount(web_profiles_.size()); has_logged_profile_count_ = true; } } const AutofillMetrics* PersonalDataManager::metric_logger() const { return metric_logger_.get(); } void PersonalDataManager::set_metric_logger( const AutofillMetrics* metric_logger) { metric_logger_.reset(metric_logger); } void PersonalDataManager::set_browser_context( content::BrowserContext* context) { browser_context_ = context; }