// Copyright 2013 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 "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h" #include #include #include #include "apps/app_window.h" #include "apps/app_window_registry.h" #include "apps/ui/native_app_window.h" #include "base/base64.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/i18n/case_conversion.h" #include "base/i18n/rtl.h" #include "base/logging.h" #include "base/prefs/pref_registry_simple.h" #include "base/prefs/pref_service.h" #include "base/prefs/scoped_user_pref_update.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/autofill/validation_rules_storage_factory.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/autofill/autofill_dialog_common.h" #include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h" #include "chrome/browser/ui/autofill/autofill_dialog_view.h" #include "chrome/browser/ui/autofill/data_model_wrapper.h" #include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h" #include "chrome/browser/ui/autofill/new_credit_card_bubble_controller.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/common/chrome_content_client.h" #include "chrome/common/chrome_version_info.h" #include "chrome/common/pref_names.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "components/autofill/content/browser/risk/fingerprint.h" #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h" #include "components/autofill/content/browser/wallet/form_field_error.h" #include "components/autofill/content/browser/wallet/full_wallet.h" #include "components/autofill/content/browser/wallet/gaia_account.h" #include "components/autofill/content/browser/wallet/instrument.h" #include "components/autofill/content/browser/wallet/wallet_address.h" #include "components/autofill/content/browser/wallet/wallet_items.h" #include "components/autofill/content/browser/wallet/wallet_service_url.h" #include "components/autofill/content/browser/wallet/wallet_signin_helper.h" #include "components/autofill/core/browser/address_i18n.h" #include "components/autofill/core/browser/autofill_country.h" #include "components/autofill/core/browser/autofill_data_model.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/phone_number_i18n.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_pref_names.h" #include "components/autofill/core/common/form_data.h" #include "components/metrics/metrics_service.h" #include "components/pref_registry/pref_registry_syncable.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/geolocation_provider.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" #include "grit/chromium_strings.h" #include "grit/component_scaled_resources.h" #include "grit/components_strings.h" #include "grit/generated_resources.h" #include "grit/platform_locale_settings.h" #include "grit/theme_resources.h" #include "net/cert/cert_status_flags.h" #include "third_party/libaddressinput/chromium/chrome_downloader_impl.h" #include "third_party/libaddressinput/chromium/chrome_storage_impl.h" #include "third_party/libaddressinput/messages.h" #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h" #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h" #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h" #include "third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h" #include "ui/base/base_window.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/models/combobox_model.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/skia_util.h" using ::i18n::addressinput::AddressData; using ::i18n::addressinput::AddressField; using ::i18n::addressinput::AddressProblem; using ::i18n::addressinput::ADMIN_AREA; using ::i18n::addressinput::DEPENDENT_LOCALITY; using ::i18n::addressinput::Downloader; using ::i18n::addressinput::FieldProblemMap; using ::i18n::addressinput::Localization; using ::i18n::addressinput::MISSING_REQUIRED_FIELD; namespace autofill { namespace { const char kAddNewItemKey[] = "add-new-item"; const char kManageItemsKey[] = "manage-items"; const char kSameAsBillingKey[] = "same-as-billing"; // URLs for Wallet error messages. const char kBuyerLegalAddressStatusUrl[] = "https://wallet.google.com/manage/settings"; const char kKnowYourCustomerStatusUrl[] = "https://wallet.google.com/kyc"; // Keys for the kAutofillDialogAutofillDefault pref dictionary (do not change // these values). const char kGuidPrefKey[] = "guid"; // This string is stored along with saved addresses and credit cards in the // WebDB, and hence should not be modified, so that it remains consistent over // time. const char kAutofillDialogOrigin[] = "Chrome Autofill dialog"; // HSL shift to gray out an image. const color_utils::HSL kGrayImageShift = {-1, 0, 0.8}; // Limit Wallet items refresh rate to at most once per minute. const int64 kWalletItemsRefreshRateSeconds = 60; // The number of milliseconds to delay enabling the submit button after showing // the dialog. This delay prevents users from accidentally clicking the submit // button on startup. const int kSubmitButtonDelayMs = 1000; // A helper class to make sure an AutofillDialogView knows when a series of // updates is incoming. class ScopedViewUpdates { public: explicit ScopedViewUpdates(AutofillDialogView* view) : view_(view) { if (view_) view_->UpdatesStarted(); } ~ScopedViewUpdates() { if (view_) view_->UpdatesFinished(); } private: AutofillDialogView* view_; DISALLOW_COPY_AND_ASSIGN(ScopedViewUpdates); }; base::string16 NullGetInfo(const AutofillType& type) { return base::string16(); } // Extract |type| from |inputs| using |section| to determine whether the info // should be billing or shipping specific (for sections with address info). base::string16 GetInfoFromInputs(const FieldValueMap& inputs, DialogSection section, const AutofillType& type) { ServerFieldType field_type = type.GetStorableType(); if (section != SECTION_SHIPPING) field_type = AutofillType::GetEquivalentBillingFieldType(field_type); base::string16 info; FieldValueMap::const_iterator it = inputs.find(field_type); if (it != inputs.end()) info = it->second; if (!info.empty() && type.html_type() == HTML_TYPE_COUNTRY_CODE) { info = base::ASCIIToUTF16(AutofillCountry::GetCountryCode( info, g_browser_process->GetApplicationLocale())); } return info; } // Returns true if |input| should be used to fill a site-requested |field| which // is notated with a "shipping" tag, for use when the user has decided to use // the billing address as the shipping address. bool ServerTypeMatchesShippingField(ServerFieldType type, const AutofillField& field) { // Equivalent billing field type is used to support UseBillingAsShipping // usecase. return common::ServerTypeEncompassesFieldType( type, AutofillType(AutofillType::GetEquivalentBillingFieldType( field.Type().GetStorableType()))); } // Initializes |form_group| from user-entered data. void FillFormGroupFromOutputs(const FieldValueMap& detail_outputs, FormGroup* form_group) { for (FieldValueMap::const_iterator iter = detail_outputs.begin(); iter != detail_outputs.end(); ++iter) { ServerFieldType type = iter->first; if (!iter->second.empty()) { form_group->SetInfo(AutofillType(type), iter->second, g_browser_process->GetApplicationLocale()); } } } // Get billing info from |output| and put it into |card|, |cvc|, and |profile|. // These outparams are required because |card|/|profile| accept different types // of raw info, and CreditCard doesn't save CVCs. void GetBillingInfoFromOutputs(const FieldValueMap& output, CreditCard* card, base::string16* cvc, AutofillProfile* profile) { for (FieldValueMap::const_iterator it = output.begin(); it != output.end(); ++it) { const ServerFieldType type = it->first; base::string16 trimmed; base::TrimWhitespace(it->second, base::TRIM_ALL, &trimmed); // Special case CVC as CreditCard just swallows it. if (type == CREDIT_CARD_VERIFICATION_CODE) { if (cvc) cvc->assign(trimmed); } else if (common::IsCreditCardType(type)) { card->SetRawInfo(type, trimmed); } else { // Copy the credit card name to |profile| in addition to |card| as // wallet::Instrument requires a recipient name for its billing address. if (card && type == NAME_FULL) card->SetRawInfo(CREDIT_CARD_NAME, trimmed); if (profile) { profile->SetInfo(AutofillType(AutofillType(type).GetStorableType()), trimmed, g_browser_process->GetApplicationLocale()); } } } } // Returns the containing window for the given |web_contents|. The containing // window might be a browser window for a Chrome tab, or it might be an app // window for a platform app. ui::BaseWindow* GetBaseWindowForWebContents( content::WebContents* web_contents) { Browser* browser = chrome::FindBrowserWithWebContents(web_contents); if (browser) return browser->window(); gfx::NativeWindow native_window = web_contents->GetTopLevelNativeWindow(); apps::AppWindow* app_window = apps::AppWindowRegistry::GetAppWindowForNativeWindowAnyProfile( native_window); return app_window->GetBaseWindow(); } // Returns a string descriptor for a DialogSection, for use with prefs (do not // change these values). std::string SectionToPrefString(DialogSection section) { switch (section) { case SECTION_CC: return "cc"; case SECTION_BILLING: return "billing"; case SECTION_CC_BILLING: // The SECTION_CC_BILLING section isn't active when using Autofill. NOTREACHED(); return std::string(); case SECTION_SHIPPING: return "shipping"; } NOTREACHED(); return std::string(); } // Check if a given MaskedInstrument is allowed for the purchase. bool IsInstrumentAllowed( const wallet::WalletItems::MaskedInstrument& instrument) { switch (instrument.status()) { case wallet::WalletItems::MaskedInstrument::VALID: case wallet::WalletItems::MaskedInstrument::PENDING: case wallet::WalletItems::MaskedInstrument::EXPIRED: case wallet::WalletItems::MaskedInstrument::BILLING_INCOMPLETE: return true; default: return false; } } // Loops through |addresses_| comparing to |address| ignoring ID. If a match // is not found, NULL is returned. const wallet::Address* FindDuplicateAddress( const std::vector& addresses, const wallet::Address& address) { for (size_t i = 0; i < addresses.size(); ++i) { if (addresses[i]->EqualsIgnoreID(address)) return addresses[i]; } return NULL; } bool IsCardHolderNameValidForWallet(const base::string16& name) { base::string16 whitespace_collapsed_name = base::CollapseWhitespace(name, true); std::vector split_name; base::SplitString(whitespace_collapsed_name, ' ', &split_name); return split_name.size() >= 2; } DialogSection SectionFromLocation(wallet::FormFieldError::Location location) { switch (location) { case wallet::FormFieldError::PAYMENT_INSTRUMENT: case wallet::FormFieldError::LEGAL_ADDRESS: return SECTION_CC_BILLING; case wallet::FormFieldError::SHIPPING_ADDRESS: return SECTION_SHIPPING; case wallet::FormFieldError::UNKNOWN_LOCATION: NOTREACHED(); return SECTION_MAX; } NOTREACHED(); return SECTION_MAX; } scoped_ptr GetWalletError( wallet::WalletClient::ErrorType error_type) { base::string16 text; GURL url; switch (error_type) { case wallet::WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS: text = l10n_util::GetStringUTF16( IDS_AUTOFILL_WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS); url = GURL(kKnowYourCustomerStatusUrl); break; case wallet::WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED: text = l10n_util::GetStringUTF16( IDS_AUTOFILL_WALLET_BUYER_COUNTRY_NOT_SUPPORTED); url = GURL(kBuyerLegalAddressStatusUrl); break; default: // The notification will not have a link; it's handled in the next // switch statement. break; } if (!text.empty()) { scoped_ptr notification(new DialogNotification( DialogNotification::WALLET_ERROR, text)); notification->set_link_url(url); return notification.Pass(); } int error_ids = 0; int error_code = 0; switch (error_type) { case wallet::WalletClient::UNSUPPORTED_MERCHANT: error_ids = IDS_AUTOFILL_WALLET_UNSUPPORTED_MERCHANT; break; case wallet::WalletClient::BAD_REQUEST: error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR; error_code = 71; break; case wallet::WalletClient::INVALID_PARAMS: error_ids = IDS_AUTOFILL_WALLET_BAD_TRANSACTION_AMOUNT; error_code = 76; break; case wallet::WalletClient::BUYER_ACCOUNT_ERROR: error_ids = IDS_AUTOFILL_WALLET_BUYER_ACCOUNT_ERROR; error_code = 12; break; case wallet::WalletClient::UNSUPPORTED_API_VERSION: error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR; error_code = 43; break; case wallet::WalletClient::SERVICE_UNAVAILABLE: error_ids = IDS_AUTOFILL_WALLET_SERVICE_UNAVAILABLE_ERROR; error_code = 61; break; case wallet::WalletClient::INTERNAL_ERROR: error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR; error_code = 62; break; case wallet::WalletClient::MALFORMED_RESPONSE: error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR; error_code = 72; break; case wallet::WalletClient::NETWORK_ERROR: error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR; error_code = 73; break; case wallet::WalletClient::UNKNOWN_ERROR: error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR; error_code = 74; break; case wallet::WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY: error_ids = IDS_AUTOFILL_WALLET_UNSUPPORTED_AGENT_OR_API_KEY; error_code = 75; break; case wallet::WalletClient::SPENDING_LIMIT_EXCEEDED: error_ids = IDS_AUTOFILL_WALLET_BAD_TRANSACTION_AMOUNT; break; // Handled in the prior switch(). case wallet::WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS: case wallet::WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED: NOTREACHED(); break; } DCHECK_NE(0, error_ids); // The other error types are strings of the form "XXX. You can pay without // wallet." scoped_ptr notification(new DialogNotification( DialogNotification::WALLET_ERROR, l10n_util::GetStringFUTF16(IDS_AUTOFILL_DIALOG_COMPLETE_WITHOUT_WALLET, l10n_util::GetStringUTF16(error_ids)))); if (error_code) { notification->set_tooltip_text( l10n_util::GetStringFUTF16(IDS_AUTOFILL_WALLET_ERROR_CODE_TOOLTIP, base::IntToString16(error_code))); } return notification.Pass(); } // Returns the ID of the address or instrument that should be selected in the // UI, given that the |default_id| is currently the default ID on the Wallet // server, |previous_default_id| was the default ID prior to re-fetching the // Wallet data, and |previously_selected_id| was the ID of the item selected in // the dialog prior to re-fetching the Wallet data. std::string GetIdToSelect(const std::string& default_id, const std::string& previous_default_id, const std::string& previously_selected_id) { // If the default ID changed since the last fetch of the Wallet data, select // it rather than the previously selected item, as the user's intention in // changing the default was probably to use it. if (default_id != previous_default_id) return default_id; // Otherwise, prefer the previously selected item, if there was one. return !previously_selected_id.empty() ? previously_selected_id : default_id; } // Generate a random card number in a user displayable format. base::string16 GenerateRandomCardNumber() { std::string card_number; for (size_t i = 0; i < 4; ++i) { int part = base::RandInt(0, 10000); base::StringAppendF(&card_number, "%04d ", part); } return base::ASCIIToUTF16(card_number); } gfx::Image CreditCardIconForType(const std::string& credit_card_type) { const int input_card_idr = CreditCard::IconResourceId(credit_card_type); ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); gfx::Image result = rb.GetImageNamed(input_card_idr); if (input_card_idr == IDR_AUTOFILL_CC_GENERIC) { // When the credit card type is unknown, no image should be shown. However, // to simplify the view code on Mac, save space for the credit card image by // returning a transparent image of the appropriate size. Not all credit // card images are the same size, but none is larger than the Visa icon. result = gfx::Image(gfx::ImageSkiaOperations::CreateTransparentImage( rb.GetImageNamed(IDR_AUTOFILL_CC_VISA).AsImageSkia(), 0)); } return result; } gfx::Image CvcIconForCreditCardType(const base::string16& credit_card_type) { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); if (credit_card_type == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX)) return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT_AMEX); return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT); } ServerFieldType CountryTypeForSection(DialogSection section) { return section == SECTION_SHIPPING ? ADDRESS_HOME_COUNTRY : ADDRESS_BILLING_COUNTRY; } // Attempts to canonicalize the administrative area name in |profile| using the // rules in |validator|. void CanonicalizeState(const AddressValidator* validator, AutofillProfile* profile) { base::string16 administrative_area; scoped_ptr address_data = i18n::CreateAddressDataFromAutofillProfile( *profile, g_browser_process->GetApplicationLocale()); validator->CanonicalizeAdministrativeArea(address_data.get()); administrative_area = base::UTF8ToUTF16(address_data->administrative_area); profile->SetInfo(AutofillType(ADDRESS_HOME_STATE), administrative_area, g_browser_process->GetApplicationLocale()); } ValidityMessage GetPhoneValidityMessage(const base::string16& country_name, const base::string16& number) { std::string region = AutofillCountry::GetCountryCode( country_name, g_browser_process->GetApplicationLocale()); i18n::PhoneObject phone_object(number, region); ValidityMessage phone_message(base::string16(), true); // Check if the phone number is invalid. Allow valid international // numbers that don't match the address's country only if they have an // international calling code. if (!phone_object.IsValidNumber() || (phone_object.country_code().empty() && phone_object.region() != region)) { phone_message.text = l10n_util::GetStringUTF16( IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_PHONE_NUMBER); } return phone_message; } // Constructs |inputs| from template data for a given |dialog_section|. // |country_country| specifies the country code that the inputs should be built // for. Sets the |language_code| to be used for address formatting, if // internationalized address input is enabled. The |language_code| parameter can // be NULL. void BuildInputsForSection(DialogSection dialog_section, const std::string& country_code, DetailInputs* inputs, std::string* language_code) { using l10n_util::GetStringUTF16; const DetailInput kCCInputs[] = { { DetailInput::LONG, CREDIT_CARD_NUMBER, GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CARD_NUMBER) }, { DetailInput::SHORT, CREDIT_CARD_EXP_MONTH, GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_MONTH) }, { DetailInput::SHORT, CREDIT_CARD_EXP_4_DIGIT_YEAR, GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_YEAR) }, { DetailInput::SHORT_EOL, CREDIT_CARD_VERIFICATION_CODE, GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC), 1.5 }, }; const DetailInput kBillingPhoneInputs[] = { { DetailInput::LONG, PHONE_BILLING_WHOLE_NUMBER, GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_PHONE_NUMBER) }, }; const DetailInput kEmailInputs[] = { { DetailInput::LONG, EMAIL_ADDRESS, GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EMAIL) }, }; const DetailInput kShippingPhoneInputs[] = { { DetailInput::LONG, PHONE_HOME_WHOLE_NUMBER, GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_PHONE_NUMBER) }, }; switch (dialog_section) { case SECTION_CC: { common::BuildInputs(kCCInputs, arraysize(kCCInputs), inputs); break; } case SECTION_BILLING: { i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_BILLING, country_code, inputs, language_code); common::BuildInputs(kBillingPhoneInputs, arraysize(kBillingPhoneInputs), inputs); common::BuildInputs(kEmailInputs, arraysize(kEmailInputs), inputs); break; } case SECTION_CC_BILLING: { common::BuildInputs(kCCInputs, arraysize(kCCInputs), inputs); // Wallet only supports US billing addresses. const std::string hardcoded_country_code = "US"; i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_BILLING, hardcoded_country_code, inputs, language_code); DCHECK_EQ(inputs->back().type, ADDRESS_BILLING_COUNTRY); inputs->back().length = DetailInput::NONE; const std::string& app_locale = g_browser_process->GetApplicationLocale(); inputs->back().initial_value = AutofillCountry(hardcoded_country_code, app_locale).name(); common::BuildInputs(kBillingPhoneInputs, arraysize(kBillingPhoneInputs), inputs); break; } case SECTION_SHIPPING: { i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_SHIPPING, country_code, inputs, language_code); common::BuildInputs(kShippingPhoneInputs, arraysize(kShippingPhoneInputs), inputs); break; } } } } // namespace AutofillDialogViewDelegate::~AutofillDialogViewDelegate() {} AutofillDialogControllerImpl::~AutofillDialogControllerImpl() { if (popup_controller_) popup_controller_->Hide(); GetMetricLogger().LogDialogInitialUserState(initial_user_state_); } // Checks the country code against the values the form structure enumerates. bool AutofillCountryFilter( const std::set& form_structure_values, const std::string& country_code) { if (!form_structure_values.empty() && !form_structure_values.count(base::ASCIIToUTF16(country_code))) { return false; } return true; } // Checks the country code against the values the form structure enumerates and // against the ones Wallet allows. bool WalletCountryFilter( const std::set& form_structure_values, const std::set& wallet_allowed_values, const std::string& country_code) { if ((!form_structure_values.empty() && !form_structure_values.count(base::ASCIIToUTF16(country_code))) || (!wallet_allowed_values.empty() && !wallet_allowed_values.count(country_code))) { return false; } return true; } // static base::WeakPtr AutofillDialogControllerImpl::Create( content::WebContents* contents, const FormData& form_structure, const GURL& source_url, const AutofillClient::ResultCallback& callback) { // AutofillDialogControllerImpl owns itself. AutofillDialogControllerImpl* autofill_dialog_controller = new AutofillDialogControllerImpl(contents, form_structure, source_url, callback); return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr(); } // static void AutofillDialogController::RegisterPrefs(PrefRegistrySimple* registry) { registry->RegisterListPref(::prefs::kAutofillDialogWalletLocationAcceptance); } // static void AutofillDialogController::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { registry->RegisterBooleanPref( ::prefs::kAutofillDialogPayWithoutWallet, false, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); registry->RegisterDictionaryPref( ::prefs::kAutofillDialogAutofillDefault, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); registry->RegisterBooleanPref( ::prefs::kAutofillDialogSaveData, true, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); registry->RegisterBooleanPref( ::prefs::kAutofillDialogWalletShippingSameAsBilling, false, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); } // static base::WeakPtr AutofillDialogController::Create( content::WebContents* contents, const FormData& form_structure, const GURL& source_url, const AutofillClient::ResultCallback& callback) { return AutofillDialogControllerImpl::Create(contents, form_structure, source_url, callback); } void AutofillDialogControllerImpl::Show() { dialog_shown_timestamp_ = base::Time::Now(); // Determine what field types should be included in the dialog. bool has_types = false; bool has_sections = false; form_structure_.ParseFieldTypesFromAutocompleteAttributes( &has_types, &has_sections); // Fail if the author didn't specify autocomplete types. if (!has_types) { callback_.Run( AutofillClient::AutocompleteResultErrorDisabled, base::ASCIIToUTF16("Form is missing autocomplete attributes."), NULL); delete this; return; } // Fail if the author didn't ask for at least some kind of credit card // information. bool has_credit_card_field = false; for (size_t i = 0; i < form_structure_.field_count(); ++i) { AutofillType type = form_structure_.field(i)->Type(); if (type.html_type() != HTML_TYPE_UNKNOWN && type.group() == CREDIT_CARD) { has_credit_card_field = true; break; } } if (!has_credit_card_field) { callback_.Run(AutofillClient::AutocompleteResultErrorDisabled, base::ASCIIToUTF16( "Form is not a payment form (must contain " "some autocomplete=\"cc-*\" fields). "), NULL); delete this; return; } billing_country_combobox_model_.reset(new CountryComboboxModel()); billing_country_combobox_model_->SetCountries( *GetManager(), base::Bind(AutofillCountryFilter, form_structure_.PossibleValues(ADDRESS_BILLING_COUNTRY))); shipping_country_combobox_model_.reset(new CountryComboboxModel()); acceptable_shipping_countries_ = form_structure_.PossibleValues(ADDRESS_HOME_COUNTRY); shipping_country_combobox_model_->SetCountries( *GetManager(), base::Bind(AutofillCountryFilter, base::ConstRef(acceptable_shipping_countries_))); // If the form has a country