1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
6
7#include <algorithm>
8#include <map>
9#include <string>
10
11#include "base/base64.h"
12#include "base/bind.h"
13#include "base/bind_helpers.h"
14#include "base/i18n/case_conversion.h"
15#include "base/i18n/rtl.h"
16#include "base/logging.h"
17#include "base/prefs/pref_registry_simple.h"
18#include "base/prefs/pref_service.h"
19#include "base/prefs/scoped_user_pref_update.h"
20#include "base/rand_util.h"
21#include "base/strings/string_number_conversions.h"
22#include "base/strings/string_split.h"
23#include "base/strings/utf_string_conversions.h"
24#include "base/time/time.h"
25#include "chrome/browser/apps/app_window_registry_util.h"
26#include "chrome/browser/autofill/personal_data_manager_factory.h"
27#include "chrome/browser/autofill/validation_rules_storage_factory.h"
28#include "chrome/browser/browser_process.h"
29#include "chrome/browser/profiles/profile.h"
30#include "chrome/browser/ui/autofill/autofill_dialog_common.h"
31#include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h"
32#include "chrome/browser/ui/autofill/autofill_dialog_view.h"
33#include "chrome/browser/ui/autofill/data_model_wrapper.h"
34#include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
35#include "chrome/browser/ui/autofill/new_credit_card_bubble_controller.h"
36#include "chrome/browser/ui/browser.h"
37#include "chrome/browser/ui/browser_finder.h"
38#include "chrome/browser/ui/browser_navigator.h"
39#include "chrome/browser/ui/browser_window.h"
40#include "chrome/common/chrome_content_client.h"
41#include "chrome/common/chrome_version_info.h"
42#include "chrome/common/pref_names.h"
43#include "chrome/common/render_messages.h"
44#include "chrome/common/url_constants.h"
45#include "chrome/grit/chromium_strings.h"
46#include "chrome/grit/generated_resources.h"
47#include "components/autofill/content/browser/risk/fingerprint.h"
48#include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
49#include "components/autofill/content/browser/wallet/form_field_error.h"
50#include "components/autofill/content/browser/wallet/full_wallet.h"
51#include "components/autofill/content/browser/wallet/gaia_account.h"
52#include "components/autofill/content/browser/wallet/instrument.h"
53#include "components/autofill/content/browser/wallet/wallet_address.h"
54#include "components/autofill/content/browser/wallet/wallet_items.h"
55#include "components/autofill/content/browser/wallet/wallet_service_url.h"
56#include "components/autofill/content/browser/wallet/wallet_signin_helper.h"
57#include "components/autofill/core/browser/address_i18n.h"
58#include "components/autofill/core/browser/autofill_country.h"
59#include "components/autofill/core/browser/autofill_data_model.h"
60#include "components/autofill/core/browser/autofill_manager.h"
61#include "components/autofill/core/browser/autofill_type.h"
62#include "components/autofill/core/browser/personal_data_manager.h"
63#include "components/autofill/core/browser/phone_number_i18n.h"
64#include "components/autofill/core/browser/validation.h"
65#include "components/autofill/core/common/autofill_pref_names.h"
66#include "components/autofill/core/common/form_data.h"
67#include "components/metrics/metrics_service.h"
68#include "components/pref_registry/pref_registry_syncable.h"
69#include "content/public/browser/browser_thread.h"
70#include "content/public/browser/geolocation_provider.h"
71#include "content/public/browser/navigation_controller.h"
72#include "content/public/browser/navigation_details.h"
73#include "content/public/browser/navigation_entry.h"
74#include "content/public/browser/notification_service.h"
75#include "content/public/browser/notification_types.h"
76#include "content/public/browser/render_view_host.h"
77#include "content/public/browser/web_contents.h"
78#include "content/public/common/url_constants.h"
79#include "extensions/browser/app_window/app_window.h"
80#include "extensions/browser/app_window/native_app_window.h"
81#include "grit/components_scaled_resources.h"
82#include "grit/components_strings.h"
83#include "grit/platform_locale_settings.h"
84#include "grit/theme_resources.h"
85#include "net/cert/cert_status_flags.h"
86#include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
87#include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
88#include "third_party/libaddressinput/messages.h"
89#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
90#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h"
91#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_problem.h"
92#include "third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h"
93#include "ui/base/base_window.h"
94#include "ui/base/l10n/l10n_util.h"
95#include "ui/base/models/combobox_model.h"
96#include "ui/base/resource/resource_bundle.h"
97#include "ui/gfx/canvas.h"
98#include "ui/gfx/image/image_skia_operations.h"
99#include "ui/gfx/skia_util.h"
100
101using ::i18n::addressinput::AddressData;
102using ::i18n::addressinput::AddressField;
103using ::i18n::addressinput::AddressProblem;
104using ::i18n::addressinput::ADMIN_AREA;
105using ::i18n::addressinput::DEPENDENT_LOCALITY;
106using ::i18n::addressinput::FieldProblemMap;
107using ::i18n::addressinput::Localization;
108using ::i18n::addressinput::MISSING_REQUIRED_FIELD;
109
110namespace autofill {
111
112namespace {
113
114const char kAddNewItemKey[] = "add-new-item";
115const char kManageItemsKey[] = "manage-items";
116const char kSameAsBillingKey[] = "same-as-billing";
117
118// URLs for Wallet error messages.
119const char kBuyerLegalAddressStatusUrl[] =
120    "https://wallet.google.com/manage/settings";
121const char kKnowYourCustomerStatusUrl[] = "https://wallet.google.com/kyc";
122
123// Keys for the kAutofillDialogAutofillDefault pref dictionary (do not change
124// these values).
125const char kGuidPrefKey[] = "guid";
126
127// This string is stored along with saved addresses and credit cards in the
128// WebDB, and hence should not be modified, so that it remains consistent over
129// time.
130const char kAutofillDialogOrigin[] = "Chrome Autofill dialog";
131
132// HSL shift to gray out an image.
133const color_utils::HSL kGrayImageShift = {-1, 0, 0.8};
134
135// Limit Wallet items refresh rate to at most once per minute.
136const int64 kWalletItemsRefreshRateSeconds = 60;
137
138// The number of milliseconds to delay enabling the submit button after showing
139// the dialog. This delay prevents users from accidentally clicking the submit
140// button on startup.
141const int kSubmitButtonDelayMs = 1000;
142
143// A helper class to make sure an AutofillDialogView knows when a series of
144// updates is incoming.
145class ScopedViewUpdates {
146 public:
147  explicit ScopedViewUpdates(AutofillDialogView* view) : view_(view) {
148    if (view_)
149      view_->UpdatesStarted();
150  }
151
152  ~ScopedViewUpdates() {
153    if (view_)
154      view_->UpdatesFinished();
155  }
156
157 private:
158  AutofillDialogView* view_;
159
160  DISALLOW_COPY_AND_ASSIGN(ScopedViewUpdates);
161};
162
163base::string16 NullGetInfo(const AutofillType& type) {
164  return base::string16();
165}
166
167// Extract |type| from |inputs| using |section| to determine whether the info
168// should be billing or shipping specific (for sections with address info).
169base::string16 GetInfoFromInputs(const FieldValueMap& inputs,
170                                 DialogSection section,
171                                 const AutofillType& type) {
172  ServerFieldType field_type = type.GetStorableType();
173  if (section != SECTION_SHIPPING)
174    field_type = AutofillType::GetEquivalentBillingFieldType(field_type);
175
176  base::string16 info;
177  FieldValueMap::const_iterator it = inputs.find(field_type);
178  if (it != inputs.end())
179    info = it->second;
180
181  if (!info.empty() && type.html_type() == HTML_TYPE_COUNTRY_CODE) {
182    info = base::ASCIIToUTF16(AutofillCountry::GetCountryCode(
183        info, g_browser_process->GetApplicationLocale()));
184  }
185
186  return info;
187}
188
189// Returns true if |input| should be used to fill a site-requested |field| which
190// is notated with a "shipping" tag, for use when the user has decided to use
191// the billing address as the shipping address.
192bool ServerTypeMatchesShippingField(ServerFieldType type,
193                                    const AutofillField& field) {
194  // Equivalent billing field type is used to support UseBillingAsShipping
195  // usecase.
196  return common::ServerTypeEncompassesFieldType(
197      type,
198      AutofillType(AutofillType::GetEquivalentBillingFieldType(
199          field.Type().GetStorableType())));
200}
201
202// Initializes |form_group| from user-entered data.
203void FillFormGroupFromOutputs(const FieldValueMap& detail_outputs,
204                              FormGroup* form_group) {
205  for (FieldValueMap::const_iterator iter = detail_outputs.begin();
206       iter != detail_outputs.end(); ++iter) {
207    ServerFieldType type = iter->first;
208    if (!iter->second.empty()) {
209      form_group->SetInfo(AutofillType(type),
210                          iter->second,
211                          g_browser_process->GetApplicationLocale());
212    }
213  }
214}
215
216// Get billing info from |output| and put it into |card|, |cvc|, and |profile|.
217// These outparams are required because |card|/|profile| accept different types
218// of raw info, and CreditCard doesn't save CVCs.
219void GetBillingInfoFromOutputs(const FieldValueMap& output,
220                               CreditCard* card,
221                               base::string16* cvc,
222                               AutofillProfile* profile) {
223  for (FieldValueMap::const_iterator it = output.begin();
224       it != output.end(); ++it) {
225    const ServerFieldType type = it->first;
226    base::string16 trimmed;
227    base::TrimWhitespace(it->second, base::TRIM_ALL, &trimmed);
228
229    // Special case CVC as CreditCard just swallows it.
230    if (type == CREDIT_CARD_VERIFICATION_CODE) {
231      if (cvc)
232        cvc->assign(trimmed);
233    } else if (common::IsCreditCardType(type)) {
234      card->SetRawInfo(type, trimmed);
235    } else {
236      // Copy the credit card name to |profile| in addition to |card| as
237      // wallet::Instrument requires a recipient name for its billing address.
238      if (card && type == NAME_FULL)
239        card->SetRawInfo(CREDIT_CARD_NAME, trimmed);
240
241      if (profile) {
242        profile->SetInfo(AutofillType(AutofillType(type).GetStorableType()),
243                         trimmed,
244                         g_browser_process->GetApplicationLocale());
245      }
246    }
247  }
248}
249
250// Returns the containing window for the given |web_contents|. The containing
251// window might be a browser window for a Chrome tab, or it might be an app
252// window for a platform app.
253ui::BaseWindow* GetBaseWindowForWebContents(
254    content::WebContents* web_contents) {
255  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
256  if (browser)
257    return browser->window();
258
259  gfx::NativeWindow native_window = web_contents->GetTopLevelNativeWindow();
260  extensions::AppWindow* app_window =
261      AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile(
262          native_window);
263  return app_window->GetBaseWindow();
264}
265
266// Returns a string descriptor for a DialogSection, for use with prefs (do not
267// change these values).
268std::string SectionToPrefString(DialogSection section) {
269  switch (section) {
270    case SECTION_CC:
271      return "cc";
272
273    case SECTION_BILLING:
274      return "billing";
275
276    case SECTION_CC_BILLING:
277      // The SECTION_CC_BILLING section isn't active when using Autofill.
278      NOTREACHED();
279      return std::string();
280
281    case SECTION_SHIPPING:
282      return "shipping";
283  }
284
285  NOTREACHED();
286  return std::string();
287}
288
289// Check if a given MaskedInstrument is allowed for the purchase.
290bool IsInstrumentAllowed(
291    const wallet::WalletItems::MaskedInstrument& instrument) {
292  switch (instrument.status()) {
293    case wallet::WalletItems::MaskedInstrument::VALID:
294    case wallet::WalletItems::MaskedInstrument::PENDING:
295    case wallet::WalletItems::MaskedInstrument::EXPIRED:
296    case wallet::WalletItems::MaskedInstrument::BILLING_INCOMPLETE:
297      return true;
298    default:
299      return false;
300  }
301}
302
303// Loops through |addresses_| comparing to |address| ignoring ID. If a match
304// is not found, NULL is returned.
305const wallet::Address* FindDuplicateAddress(
306    const std::vector<wallet::Address*>& addresses,
307    const wallet::Address& address) {
308  for (size_t i = 0; i < addresses.size(); ++i) {
309    if (addresses[i]->EqualsIgnoreID(address))
310      return addresses[i];
311  }
312  return NULL;
313}
314
315bool IsCardHolderNameValidForWallet(const base::string16& name) {
316  base::string16 whitespace_collapsed_name =
317      base::CollapseWhitespace(name, true);
318  std::vector<base::string16> split_name;
319  base::SplitString(whitespace_collapsed_name, ' ', &split_name);
320  return split_name.size() >= 2;
321}
322
323DialogSection SectionFromLocation(wallet::FormFieldError::Location location) {
324  switch (location) {
325    case wallet::FormFieldError::PAYMENT_INSTRUMENT:
326    case wallet::FormFieldError::LEGAL_ADDRESS:
327      return SECTION_CC_BILLING;
328
329    case wallet::FormFieldError::SHIPPING_ADDRESS:
330      return SECTION_SHIPPING;
331
332    case wallet::FormFieldError::UNKNOWN_LOCATION:
333      NOTREACHED();
334      return SECTION_MAX;
335  }
336
337  NOTREACHED();
338  return SECTION_MAX;
339}
340
341scoped_ptr<DialogNotification> GetWalletError(
342    wallet::WalletClient::ErrorType error_type) {
343  base::string16 text;
344  GURL url;
345
346  switch (error_type) {
347    case wallet::WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
348      text = l10n_util::GetStringUTF16(
349          IDS_AUTOFILL_WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS);
350      url = GURL(kKnowYourCustomerStatusUrl);
351      break;
352
353    case wallet::WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
354      text = l10n_util::GetStringUTF16(
355          IDS_AUTOFILL_WALLET_BUYER_COUNTRY_NOT_SUPPORTED);
356      url = GURL(kBuyerLegalAddressStatusUrl);
357      break;
358
359    default:
360      // The notification will not have a link; it's handled in the next
361      // switch statement.
362      break;
363  }
364
365  if (!text.empty()) {
366    scoped_ptr<DialogNotification> notification(new DialogNotification(
367        DialogNotification::WALLET_ERROR,
368        text));
369    notification->set_link_url(url);
370    return notification.Pass();
371  }
372
373  int error_ids = 0;
374  int error_code = 0;
375
376  switch (error_type) {
377    case wallet::WalletClient::UNSUPPORTED_MERCHANT:
378      error_ids = IDS_AUTOFILL_WALLET_UNSUPPORTED_MERCHANT;
379      break;
380
381    case wallet::WalletClient::BAD_REQUEST:
382      error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR;
383      error_code = 71;
384      break;
385
386    case wallet::WalletClient::INVALID_PARAMS:
387      error_ids = IDS_AUTOFILL_WALLET_BAD_TRANSACTION_AMOUNT;
388      error_code = 76;
389      break;
390
391    case wallet::WalletClient::BUYER_ACCOUNT_ERROR:
392      error_ids = IDS_AUTOFILL_WALLET_BUYER_ACCOUNT_ERROR;
393      error_code = 12;
394      break;
395
396    case wallet::WalletClient::UNSUPPORTED_API_VERSION:
397      error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR;
398      error_code = 43;
399      break;
400
401    case wallet::WalletClient::SERVICE_UNAVAILABLE:
402      error_ids = IDS_AUTOFILL_WALLET_SERVICE_UNAVAILABLE_ERROR;
403      error_code = 61;
404      break;
405
406    case wallet::WalletClient::INTERNAL_ERROR:
407      error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR;
408      error_code = 62;
409      break;
410
411    case wallet::WalletClient::MALFORMED_RESPONSE:
412      error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
413      error_code = 72;
414      break;
415
416    case wallet::WalletClient::NETWORK_ERROR:
417      error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
418      error_code = 73;
419      break;
420
421    case wallet::WalletClient::UNKNOWN_ERROR:
422      error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
423      error_code = 74;
424      break;
425
426    case wallet::WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
427      error_ids = IDS_AUTOFILL_WALLET_UNSUPPORTED_AGENT_OR_API_KEY;
428      error_code = 75;
429      break;
430
431    case wallet::WalletClient::SPENDING_LIMIT_EXCEEDED:
432      error_ids = IDS_AUTOFILL_WALLET_BAD_TRANSACTION_AMOUNT;
433      break;
434
435    // Handled in the prior switch().
436    case wallet::WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
437    case wallet::WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
438      NOTREACHED();
439      break;
440  }
441
442  DCHECK_NE(0, error_ids);
443
444  // The other error types are strings of the form "XXX. You can pay without
445  // wallet."
446  scoped_ptr<DialogNotification> notification(new DialogNotification(
447      DialogNotification::WALLET_ERROR,
448      l10n_util::GetStringFUTF16(IDS_AUTOFILL_DIALOG_COMPLETE_WITHOUT_WALLET,
449                                 l10n_util::GetStringUTF16(error_ids))));
450
451  if (error_code) {
452    notification->set_tooltip_text(
453        l10n_util::GetStringFUTF16(IDS_AUTOFILL_WALLET_ERROR_CODE_TOOLTIP,
454                                   base::IntToString16(error_code)));
455  }
456
457  return notification.Pass();
458}
459
460// Returns the ID of the address or instrument that should be selected in the
461// UI, given that the |default_id| is currently the default ID on the Wallet
462// server, |previous_default_id| was the default ID prior to re-fetching the
463// Wallet data, and |previously_selected_id| was the ID of the item selected in
464// the dialog prior to re-fetching the Wallet data.
465std::string GetIdToSelect(const std::string& default_id,
466                          const std::string& previous_default_id,
467                          const std::string& previously_selected_id) {
468  // If the default ID changed since the last fetch of the Wallet data, select
469  // it rather than the previously selected item, as the user's intention in
470  // changing the default was probably to use it.
471  if (default_id != previous_default_id)
472    return default_id;
473
474  // Otherwise, prefer the previously selected item, if there was one.
475  return !previously_selected_id.empty() ? previously_selected_id : default_id;
476}
477
478// Generate a random card number in a user displayable format.
479base::string16 GenerateRandomCardNumber() {
480  std::string card_number;
481  for (size_t i = 0; i < 4; ++i) {
482    int part = base::RandInt(0, 10000);
483    base::StringAppendF(&card_number, "%04d ", part);
484  }
485  return base::ASCIIToUTF16(card_number);
486}
487
488gfx::Image CreditCardIconForType(const std::string& credit_card_type) {
489  const int input_card_idr = CreditCard::IconResourceId(credit_card_type);
490  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
491  gfx::Image result = rb.GetImageNamed(input_card_idr);
492  if (input_card_idr == IDR_AUTOFILL_CC_GENERIC) {
493    // When the credit card type is unknown, no image should be shown. However,
494    // to simplify the view code on Mac, save space for the credit card image by
495    // returning a transparent image of the appropriate size. Not all credit
496    // card images are the same size, but none is larger than the Visa icon.
497    result = gfx::Image(gfx::ImageSkiaOperations::CreateTransparentImage(
498        rb.GetImageNamed(IDR_AUTOFILL_CC_VISA).AsImageSkia(), 0));
499  }
500  return result;
501}
502
503gfx::Image CvcIconForCreditCardType(const base::string16& credit_card_type) {
504  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
505  if (credit_card_type == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX))
506    return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT_AMEX);
507
508  return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT);
509}
510
511ServerFieldType CountryTypeForSection(DialogSection section) {
512  return section == SECTION_SHIPPING ? ADDRESS_HOME_COUNTRY :
513                                       ADDRESS_BILLING_COUNTRY;
514}
515
516// Attempts to canonicalize the administrative area name in |profile| using the
517// rules in |validator|.
518void CanonicalizeState(const AddressValidator* validator,
519                       AutofillProfile* profile) {
520  base::string16 administrative_area;
521  scoped_ptr<AddressData> address_data =
522      i18n::CreateAddressDataFromAutofillProfile(
523          *profile, g_browser_process->GetApplicationLocale());
524
525  validator->CanonicalizeAdministrativeArea(address_data.get());
526  administrative_area = base::UTF8ToUTF16(address_data->administrative_area);
527
528  profile->SetInfo(AutofillType(ADDRESS_HOME_STATE),
529                   administrative_area,
530                   g_browser_process->GetApplicationLocale());
531}
532
533ValidityMessage GetPhoneValidityMessage(const base::string16& country_name,
534                                        const base::string16& number) {
535  std::string region = AutofillCountry::GetCountryCode(
536      country_name,
537      g_browser_process->GetApplicationLocale());
538  i18n::PhoneObject phone_object(number, region);
539  ValidityMessage phone_message(base::string16(), true);
540
541  // Check if the phone number is invalid. Allow valid international
542  // numbers that don't match the address's country only if they have an
543  // international calling code.
544  if (!phone_object.IsValidNumber() ||
545      (phone_object.country_code().empty() &&
546       phone_object.region() != region)) {
547    phone_message.text = l10n_util::GetStringUTF16(
548        IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_PHONE_NUMBER);
549  }
550
551  return phone_message;
552}
553
554// Constructs |inputs| from template data for a given |dialog_section|.
555// |country_country| specifies the country code that the inputs should be built
556// for. Sets the |language_code| to be used for address formatting, if
557// internationalized address input is enabled. The |language_code| parameter can
558// be NULL.
559void BuildInputsForSection(DialogSection dialog_section,
560                           const std::string& country_code,
561                           DetailInputs* inputs,
562                           std::string* language_code) {
563  using l10n_util::GetStringUTF16;
564
565  const DetailInput kCCInputs[] = {
566    { DetailInput::LONG,
567      CREDIT_CARD_NUMBER,
568      GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CARD_NUMBER) },
569    { DetailInput::SHORT,
570      CREDIT_CARD_EXP_MONTH,
571      GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_MONTH) },
572    { DetailInput::SHORT,
573      CREDIT_CARD_EXP_4_DIGIT_YEAR,
574      GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_YEAR) },
575    { DetailInput::SHORT_EOL,
576      CREDIT_CARD_VERIFICATION_CODE,
577      GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC),
578      1.5 },
579  };
580
581  const DetailInput kBillingPhoneInputs[] = {
582    { DetailInput::LONG,
583      PHONE_BILLING_WHOLE_NUMBER,
584      GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_PHONE_NUMBER) },
585  };
586
587  const DetailInput kEmailInputs[] = {
588    { DetailInput::LONG,
589      EMAIL_ADDRESS,
590      GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EMAIL) },
591  };
592
593  const DetailInput kShippingPhoneInputs[] = {
594    { DetailInput::LONG,
595      PHONE_HOME_WHOLE_NUMBER,
596      GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_PHONE_NUMBER) },
597  };
598
599  switch (dialog_section) {
600    case SECTION_CC: {
601      common::BuildInputs(kCCInputs, arraysize(kCCInputs), inputs);
602      break;
603    }
604
605    case SECTION_BILLING: {
606      i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_BILLING,
607                                    country_code, inputs, language_code);
608      common::BuildInputs(kBillingPhoneInputs, arraysize(kBillingPhoneInputs),
609                          inputs);
610      common::BuildInputs(kEmailInputs, arraysize(kEmailInputs), inputs);
611      break;
612    }
613
614    case SECTION_CC_BILLING: {
615      common::BuildInputs(kCCInputs, arraysize(kCCInputs), inputs);
616
617      // Wallet only supports US billing addresses.
618      const std::string hardcoded_country_code = "US";
619      i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_BILLING,
620                                    hardcoded_country_code,
621                                    inputs,
622                                    language_code);
623      DCHECK_EQ(inputs->back().type, ADDRESS_BILLING_COUNTRY);
624      inputs->back().length = DetailInput::NONE;
625      const std::string& app_locale =
626          g_browser_process->GetApplicationLocale();
627      inputs->back().initial_value =
628          AutofillCountry(hardcoded_country_code, app_locale).name();
629
630      common::BuildInputs(kBillingPhoneInputs, arraysize(kBillingPhoneInputs),
631                          inputs);
632      break;
633    }
634
635    case SECTION_SHIPPING: {
636      i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_SHIPPING,
637                                    country_code, inputs, language_code);
638      common::BuildInputs(kShippingPhoneInputs, arraysize(kShippingPhoneInputs),
639                          inputs);
640      break;
641    }
642  }
643}
644
645}  // namespace
646
647AutofillDialogViewDelegate::~AutofillDialogViewDelegate() {}
648
649AutofillDialogControllerImpl::~AutofillDialogControllerImpl() {
650  if (popup_controller_)
651    popup_controller_->Hide();
652
653  GetMetricLogger().LogDialogInitialUserState(initial_user_state_);
654}
655
656// Checks the country code against the values the form structure enumerates.
657bool AutofillCountryFilter(
658    const std::set<base::string16>& form_structure_values,
659    const std::string& country_code) {
660  if (!form_structure_values.empty() &&
661      !form_structure_values.count(base::ASCIIToUTF16(country_code))) {
662    return false;
663  }
664
665  return true;
666}
667
668// Checks the country code against the values the form structure enumerates and
669// against the ones Wallet allows.
670bool WalletCountryFilter(
671    const std::set<base::string16>& form_structure_values,
672    const std::set<std::string>& wallet_allowed_values,
673    const std::string& country_code) {
674  if ((!form_structure_values.empty() &&
675       !form_structure_values.count(base::ASCIIToUTF16(country_code))) ||
676      (!wallet_allowed_values.empty() &&
677       !wallet_allowed_values.count(country_code))) {
678    return false;
679  }
680
681  return true;
682}
683
684// static
685base::WeakPtr<AutofillDialogControllerImpl>
686AutofillDialogControllerImpl::Create(
687    content::WebContents* contents,
688    const FormData& form_structure,
689    const GURL& source_url,
690    const AutofillClient::ResultCallback& callback) {
691  // AutofillDialogControllerImpl owns itself.
692  AutofillDialogControllerImpl* autofill_dialog_controller =
693      new AutofillDialogControllerImpl(contents,
694                                       form_structure,
695                                       source_url,
696                                       callback);
697  return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
698}
699
700// static
701void AutofillDialogController::RegisterPrefs(PrefRegistrySimple* registry) {
702  registry->RegisterListPref(::prefs::kAutofillDialogWalletLocationAcceptance);
703}
704
705// static
706void AutofillDialogController::RegisterProfilePrefs(
707    user_prefs::PrefRegistrySyncable* registry) {
708  registry->RegisterBooleanPref(
709      ::prefs::kAutofillDialogPayWithoutWallet,
710      false,
711      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
712  registry->RegisterDictionaryPref(
713      ::prefs::kAutofillDialogAutofillDefault,
714      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
715  registry->RegisterBooleanPref(
716      ::prefs::kAutofillDialogSaveData,
717      true,
718      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
719  registry->RegisterBooleanPref(
720      ::prefs::kAutofillDialogWalletShippingSameAsBilling,
721      false,
722      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
723}
724
725// static
726base::WeakPtr<AutofillDialogController> AutofillDialogController::Create(
727    content::WebContents* contents,
728    const FormData& form_structure,
729    const GURL& source_url,
730    const AutofillClient::ResultCallback& callback) {
731  return AutofillDialogControllerImpl::Create(contents,
732                                              form_structure,
733                                              source_url,
734                                              callback);
735}
736
737void AutofillDialogControllerImpl::Show() {
738  dialog_shown_timestamp_ = base::Time::Now();
739
740  // Determine what field types should be included in the dialog.
741  bool has_types = false;
742  bool has_sections = false;
743  form_structure_.ParseFieldTypesFromAutocompleteAttributes(
744      &has_types, &has_sections);
745
746  // Fail if the author didn't specify autocomplete types.
747  if (!has_types) {
748    callback_.Run(
749        AutofillClient::AutocompleteResultErrorDisabled,
750        base::ASCIIToUTF16("Form is missing autocomplete attributes."),
751        NULL);
752    delete this;
753    return;
754  }
755
756  // Fail if the author didn't ask for at least some kind of credit card
757  // information.
758  bool has_credit_card_field = false;
759  for (size_t i = 0; i < form_structure_.field_count(); ++i) {
760    AutofillType type = form_structure_.field(i)->Type();
761    if (type.html_type() != HTML_TYPE_UNKNOWN && type.group() == CREDIT_CARD) {
762      has_credit_card_field = true;
763      break;
764    }
765  }
766
767  if (!has_credit_card_field) {
768    callback_.Run(AutofillClient::AutocompleteResultErrorDisabled,
769                  base::ASCIIToUTF16(
770                      "Form is not a payment form (must contain "
771                      "some autocomplete=\"cc-*\" fields). "),
772                  NULL);
773    delete this;
774    return;
775  }
776
777  billing_country_combobox_model_.reset(new CountryComboboxModel());
778  billing_country_combobox_model_->SetCountries(
779      *GetManager(),
780      base::Bind(AutofillCountryFilter,
781                 form_structure_.PossibleValues(ADDRESS_BILLING_COUNTRY)));
782  shipping_country_combobox_model_.reset(new CountryComboboxModel());
783  acceptable_shipping_countries_ =
784      form_structure_.PossibleValues(ADDRESS_HOME_COUNTRY);
785  shipping_country_combobox_model_->SetCountries(
786      *GetManager(),
787      base::Bind(AutofillCountryFilter,
788                 base::ConstRef(acceptable_shipping_countries_)));
789
790  // If the form has a country <select> but none of the options are valid, bail.
791  if (billing_country_combobox_model_->GetItemCount() == 0 ||
792      shipping_country_combobox_model_->GetItemCount() == 0) {
793    callback_.Run(AutofillClient::AutocompleteResultErrorDisabled,
794                  base::ASCIIToUTF16("No valid/supported country options"
795                                     " found."),
796                  NULL);
797    delete this;
798    return;
799  }
800
801  // Log any relevant UI metrics and security exceptions.
802  GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_SHOWN);
803
804  GetMetricLogger().LogDialogSecurityMetric(
805      AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN);
806
807  // The Autofill dialog is shown in response to a message from the renderer and
808  // as such, it can only be made in the context of the current document. A call
809  // to GetActiveEntry would return a pending entry, if there was one, which
810  // would be a security bug. Therefore, we use the last committed URL for the
811  // access checks.
812  const GURL& current_url = web_contents()->GetLastCommittedURL();
813  invoked_from_same_origin_ =
814      current_url.GetOrigin() == source_url_.GetOrigin();
815
816  if (!invoked_from_same_origin_) {
817    GetMetricLogger().LogDialogSecurityMetric(
818        AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME);
819  }
820
821  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
822    DialogSection section = static_cast<DialogSection>(i);
823
824    std::string country_code;
825    CountryComboboxModel* model = CountryComboboxModelForSection(section);
826    if (model)
827      country_code = model->GetDefaultCountryCode();
828
829    DetailInputs* inputs = MutableRequestedFieldsForSection(section);
830    BuildInputsForSection(
831        section, country_code, inputs,
832        MutableAddressLanguageCodeForSection(section));
833  }
834
835  // Test whether we need to show the shipping section. If filling that section
836  // would be a no-op, don't show it.
837  cares_about_shipping_ = form_structure_.FillFields(
838      RequestedTypesForSection(SECTION_SHIPPING),
839      base::Bind(common::ServerTypeMatchesField, SECTION_SHIPPING),
840      base::Bind(NullGetInfo),
841      std::string(),
842      g_browser_process->GetApplicationLocale());
843
844  transaction_amount_ = form_structure_.GetUniqueValue(
845      HTML_TYPE_TRANSACTION_AMOUNT);
846  transaction_currency_ = form_structure_.GetUniqueValue(
847      HTML_TYPE_TRANSACTION_CURRENCY);
848
849  account_chooser_model_.reset(
850      new AccountChooserModel(this,
851                              profile_,
852                              !ShouldShowAccountChooser(),
853                              metric_logger_));
854
855  acceptable_cc_types_ = form_structure_.PossibleValues(CREDIT_CARD_TYPE);
856  // Wallet generates MC virtual cards, so we have to disable it if MC is not
857  // allowed.
858  if (ShouldDisallowCcType(CreditCard::TypeForDisplay(kMasterCard)))
859    DisableWallet(wallet::WalletClient::UNSUPPORTED_MERCHANT);
860
861  if (account_chooser_model_->WalletIsSelected())
862    FetchWalletCookie();
863
864  validator_.reset(new AddressValidator(
865      scoped_ptr< ::i18n::addressinput::Source>(
866          new autofill::ChromeMetadataSource(I18N_ADDRESS_VALIDATION_DATA_URL,
867                                             profile_->GetRequestContext())),
868      ValidationRulesStorageFactory::CreateStorage(),
869      this));
870
871  SuggestionsUpdated();
872  SubmitButtonDelayBegin();
873  view_.reset(CreateView());
874  view_->Show();
875  GetManager()->AddObserver(this);
876
877  if (!account_chooser_model_->WalletIsSelected())
878    LogDialogLatencyToShow();
879}
880
881void AutofillDialogControllerImpl::Hide() {
882  if (view_)
883    view_->Hide();
884}
885
886void AutofillDialogControllerImpl::TabActivated() {
887  // If the user switched away from this tab and then switched back, reload the
888  // Wallet items, in case they've changed.
889  int64 seconds_elapsed_since_last_refresh =
890      (base::TimeTicks::Now() - last_wallet_items_fetch_timestamp_).InSeconds();
891  if (IsPayingWithWallet() && wallet_items_ &&
892      seconds_elapsed_since_last_refresh >= kWalletItemsRefreshRateSeconds) {
893    GetWalletItems();
894  }
895}
896
897////////////////////////////////////////////////////////////////////////////////
898// AutofillDialogViewDelegate implementation.
899
900base::string16 AutofillDialogControllerImpl::DialogTitle() const {
901  if (ShouldShowSpinner())
902    return base::string16();
903
904  return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TITLE);
905}
906
907base::string16 AutofillDialogControllerImpl::AccountChooserText() const {
908  if (!account_chooser_model_->WalletIsSelected())
909    return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PAYING_WITHOUT_WALLET);
910
911  if (SignedInState() == SIGNED_IN)
912    return account_chooser_model_->GetActiveWalletAccountName();
913
914  // In this case, the account chooser should be showing the signin link.
915  return base::string16();
916}
917
918base::string16 AutofillDialogControllerImpl::SignInLinkText() const {
919  int ids = SignedInState() == NOT_CHECKED ?
920      IDS_AUTOFILL_DIALOG_USE_WALLET_LINK :
921      ShouldShowSignInWebView() ? IDS_AUTOFILL_DIALOG_CANCEL_SIGN_IN :
922                                  IDS_AUTOFILL_DIALOG_SIGN_IN;
923
924  return l10n_util::GetStringUTF16(ids);
925}
926
927base::string16 AutofillDialogControllerImpl::SpinnerText() const {
928  return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_LOADING);
929}
930
931base::string16 AutofillDialogControllerImpl::EditSuggestionText() const {
932  return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EDIT);
933}
934
935base::string16 AutofillDialogControllerImpl::CancelButtonText() const {
936  return l10n_util::GetStringUTF16(IDS_CANCEL);
937}
938
939base::string16 AutofillDialogControllerImpl::ConfirmButtonText() const {
940  return l10n_util::GetStringUTF16(IsSubmitPausedOn(wallet::VERIFY_CVV) ?
941      IDS_AUTOFILL_DIALOG_VERIFY_BUTTON : IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON);
942}
943
944base::string16 AutofillDialogControllerImpl::SaveLocallyText() const {
945  return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX);
946}
947
948base::string16 AutofillDialogControllerImpl::SaveLocallyTooltip() const {
949  return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_TOOLTIP);
950}
951
952base::string16 AutofillDialogControllerImpl::LegalDocumentsText() {
953  if (!IsPayingWithWallet() || ShouldShowSignInWebView())
954    return base::string16();
955
956  return legal_documents_text_;
957}
958
959bool AutofillDialogControllerImpl::ShouldShowSpinner() const {
960  return SignedInState() == REQUIRES_RESPONSE ||
961         SignedInState() == REQUIRES_PASSIVE_SIGN_IN;
962}
963
964bool AutofillDialogControllerImpl::ShouldShowAccountChooser() const {
965  return !ShouldShowSpinner() && GetManager()->IsCountryOfInterest("US");
966}
967
968bool AutofillDialogControllerImpl::ShouldShowSignInWebView() const {
969  return !signin_registrar_.IsEmpty();
970}
971
972GURL AutofillDialogControllerImpl::SignInUrl() const {
973  return wallet::GetSignInUrl();
974}
975
976bool AutofillDialogControllerImpl::ShouldOfferToSaveInChrome() const {
977  return IsAutofillEnabled() &&
978      !IsPayingWithWallet() &&
979      !profile_->IsOffTheRecord() &&
980      IsManuallyEditingAnySection() &&
981      !ShouldShowSpinner();
982}
983
984bool AutofillDialogControllerImpl::ShouldSaveInChrome() const {
985  return profile_->GetPrefs()->GetBoolean(::prefs::kAutofillDialogSaveData);
986}
987
988int AutofillDialogControllerImpl::GetDialogButtons() const {
989  if (waiting_for_explicit_sign_in_response_)
990    return ui::DIALOG_BUTTON_NONE;
991
992  if (ShouldShowSpinner() && !handling_use_wallet_link_click_)
993    return ui::DIALOG_BUTTON_CANCEL;
994
995  return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
996}
997
998bool AutofillDialogControllerImpl::IsDialogButtonEnabled(
999    ui::DialogButton button) const {
1000  if (button == ui::DIALOG_BUTTON_OK) {
1001    if (IsSubmitPausedOn(wallet::VERIFY_CVV))
1002      return true;
1003
1004    if (ShouldShowSpinner() || is_submitting_)
1005      return false;
1006
1007    if (submit_button_delay_timer_.IsRunning())
1008      return false;
1009
1010    return true;
1011  }
1012
1013  DCHECK_EQ(ui::DIALOG_BUTTON_CANCEL, button);
1014  return !is_submitting_ || IsSubmitPausedOn(wallet::VERIFY_CVV);
1015}
1016
1017DialogOverlayState AutofillDialogControllerImpl::GetDialogOverlay() {
1018  bool show_wallet_interstitial = IsPayingWithWallet() && is_submitting_ &&
1019      !(full_wallet_ && !full_wallet_->required_actions().empty());
1020  if (!show_wallet_interstitial) {
1021    card_scrambling_delay_.Stop();
1022    card_scrambling_refresher_.Stop();
1023    return DialogOverlayState();
1024  }
1025
1026  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1027  DialogOverlayState state;
1028  state.string.font_list = rb->GetFontList(ui::ResourceBundle::MediumFont);
1029
1030  const SkColor start_top_color = SkColorSetRGB(0xD6, 0xD6, 0xD6);
1031  const SkColor start_bottom_color = SkColorSetRGB(0x98, 0x98, 0x98);
1032  const SkColor final_top_color = SkColorSetRGB(0x52, 0x9F, 0xF8);
1033  const SkColor final_bottom_color = SkColorSetRGB(0x22, 0x75, 0xE5);
1034
1035  if (full_wallet_ && full_wallet_->required_actions().empty()) {
1036    card_scrambling_delay_.Stop();
1037    card_scrambling_refresher_.Stop();
1038
1039    base::string16 cc_number = base::ASCIIToUTF16(full_wallet_->GetPan());
1040    DCHECK_GE(cc_number.size(), 4U);
1041    state.image = GetGeneratedCardImage(
1042        base::ASCIIToUTF16("XXXX XXXX XXXX ") +
1043            cc_number.substr(cc_number.size() - 4),
1044        full_wallet_->billing_address()->recipient_name(),
1045        color_utils::AlphaBlend(
1046            final_top_color,
1047            start_top_color,
1048            255 * card_generated_animation_.GetCurrentValue()),
1049        color_utils::AlphaBlend(
1050            final_bottom_color,
1051            start_bottom_color,
1052            255 * card_generated_animation_.GetCurrentValue()));
1053
1054    state.string.text = l10n_util::GetStringUTF16(
1055        IDS_AUTOFILL_DIALOG_CARD_GENERATION_DONE);
1056  } else {
1057    // Start the refresher if it isn't running. Wait one second before pumping
1058    // updates to the view.
1059    if (!card_scrambling_delay_.IsRunning() &&
1060        !card_scrambling_refresher_.IsRunning()) {
1061      scrambled_card_number_ = GenerateRandomCardNumber();
1062      card_scrambling_delay_.Start(
1063          FROM_HERE,
1064          base::TimeDelta::FromSeconds(1),
1065          this,
1066          &AutofillDialogControllerImpl::StartCardScramblingRefresher);
1067    }
1068
1069    DCHECK(!scrambled_card_number_.empty());
1070    state.image = GetGeneratedCardImage(
1071        scrambled_card_number_,
1072        submitted_cardholder_name_,
1073        start_top_color,
1074        start_bottom_color);
1075
1076    // "Submitting" waiting page.
1077    state.string.text = l10n_util::GetStringUTF16(
1078        IDS_AUTOFILL_DIALOG_CARD_GENERATION_IN_PROGRESS);
1079  }
1080
1081  return state;
1082}
1083
1084const std::vector<gfx::Range>& AutofillDialogControllerImpl::
1085    LegalDocumentLinks() {
1086  return legal_document_link_ranges_;
1087}
1088
1089bool AutofillDialogControllerImpl::SectionIsActive(DialogSection section)
1090    const {
1091  if (IsSubmitPausedOn(wallet::VERIFY_CVV))
1092    return section == SECTION_CC_BILLING;
1093
1094  if (!FormStructureCaresAboutSection(section))
1095    return false;
1096
1097  if (IsPayingWithWallet())
1098    return section == SECTION_CC_BILLING || section == SECTION_SHIPPING;
1099
1100  return section != SECTION_CC_BILLING;
1101}
1102
1103void AutofillDialogControllerImpl::GetWalletItems() {
1104  ScopedViewUpdates updates(view_.get());
1105
1106  wallet_items_requested_ = true;
1107  wallet::WalletClient* wallet_client = GetWalletClient();
1108  wallet_client->CancelRequest();
1109
1110  previously_selected_instrument_id_.clear();
1111  previously_selected_shipping_address_id_.clear();
1112  if (wallet_items_) {
1113    previous_default_instrument_id_ = wallet_items_->default_instrument_id();
1114    previous_default_shipping_address_id_ = wallet_items_->default_address_id();
1115
1116    const wallet::WalletItems::MaskedInstrument* instrument =
1117        ActiveInstrument();
1118    if (instrument)
1119      previously_selected_instrument_id_ = instrument->object_id();
1120
1121    const wallet::Address* address = ActiveShippingAddress();
1122    if (address)
1123      previously_selected_shipping_address_id_ = address->object_id();
1124  }
1125
1126  last_wallet_items_fetch_timestamp_ = base::TimeTicks::Now();
1127  passive_failed_ = false;
1128  wallet_items_.reset();
1129
1130  // The "Loading..." page should be showing now, which should cause the
1131  // account chooser to hide.
1132  view_->UpdateAccountChooser();
1133  wallet_client->GetWalletItems(transaction_amount_, transaction_currency_);
1134}
1135
1136void AutofillDialogControllerImpl::HideSignIn() {
1137  ScopedViewUpdates updates(view_.get());
1138  signin_registrar_.RemoveAll();
1139  view_->HideSignIn();
1140  view_->UpdateAccountChooser();
1141}
1142
1143AutofillDialogControllerImpl::DialogSignedInState
1144    AutofillDialogControllerImpl::SignedInState() const {
1145  if (wallet_error_notification_)
1146    return SIGN_IN_DISABLED;
1147
1148  if (signin_helper_ || (wallet_items_requested_ && !wallet_items_))
1149    return REQUIRES_RESPONSE;
1150
1151  if (!wallet_items_requested_)
1152    return NOT_CHECKED;
1153
1154  if (wallet_items_->HasRequiredAction(wallet::GAIA_AUTH) ||
1155      passive_failed_) {
1156    return REQUIRES_SIGN_IN;
1157  }
1158
1159  if (wallet_items_->HasRequiredAction(wallet::PASSIVE_GAIA_AUTH))
1160    return REQUIRES_PASSIVE_SIGN_IN;
1161
1162  return SIGNED_IN;
1163}
1164
1165void AutofillDialogControllerImpl::SignedInStateUpdated() {
1166  if (!ShouldShowSpinner())
1167    waiting_for_explicit_sign_in_response_ = false;
1168
1169  switch (SignedInState()) {
1170    case SIGNED_IN:
1171      LogDialogLatencyToShow();
1172      break;
1173
1174    case REQUIRES_SIGN_IN:
1175      if (handling_use_wallet_link_click_)
1176        SignInLinkClicked();
1177      // Fall through.
1178    case SIGN_IN_DISABLED:
1179      // Switch to the local account and refresh the dialog.
1180      signin_helper_.reset();
1181      OnWalletSigninError();
1182      handling_use_wallet_link_click_ = false;
1183      break;
1184
1185    case REQUIRES_PASSIVE_SIGN_IN:
1186      // Attempt to passively sign in the user.
1187      DCHECK(!signin_helper_);
1188      signin_helper_.reset(new wallet::WalletSigninHelper(
1189          this,
1190          profile_->GetRequestContext()));
1191      signin_helper_->StartPassiveSignin(GetWalletClient()->user_index());
1192      break;
1193
1194    case NOT_CHECKED:
1195    case REQUIRES_RESPONSE:
1196      break;
1197  }
1198}
1199
1200void AutofillDialogControllerImpl::OnWalletOrSigninUpdate() {
1201  ScopedViewUpdates updates(view_.get());
1202  SignedInStateUpdated();
1203  SuggestionsUpdated();
1204  UpdateAccountChooserView();
1205
1206  if (view_) {
1207    view_->UpdateButtonStrip();
1208    view_->UpdateOverlay();
1209  }
1210
1211  // On the first successful response, compute the initial user state metric.
1212  if (initial_user_state_ == AutofillMetrics::DIALOG_USER_STATE_UNKNOWN)
1213    initial_user_state_ = GetInitialUserState();
1214}
1215
1216void AutofillDialogControllerImpl::OnWalletFormFieldError(
1217    const std::vector<wallet::FormFieldError>& form_field_errors) {
1218  if (form_field_errors.empty())
1219    return;
1220
1221  for (std::vector<wallet::FormFieldError>::const_iterator it =
1222           form_field_errors.begin();
1223       it != form_field_errors.end(); ++it) {
1224    if (it->error_type() == wallet::FormFieldError::UNKNOWN_ERROR ||
1225        it->GetAutofillType() == MAX_VALID_FIELD_TYPE ||
1226        it->location() == wallet::FormFieldError::UNKNOWN_LOCATION) {
1227      wallet_server_validation_recoverable_ = false;
1228      break;
1229    }
1230    DialogSection section = SectionFromLocation(it->location());
1231    wallet_errors_[section][it->GetAutofillType()] =
1232        std::make_pair(it->GetErrorMessage(),
1233                       GetValueFromSection(section, it->GetAutofillType()));
1234  }
1235
1236  // Unrecoverable validation errors.
1237  if (!wallet_server_validation_recoverable_)
1238    DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
1239
1240  UpdateForErrors();
1241}
1242
1243void AutofillDialogControllerImpl::ConstructLegalDocumentsText() {
1244  legal_documents_text_.clear();
1245  legal_document_link_ranges_.clear();
1246
1247  if (!wallet_items_)
1248    return;
1249
1250  PrefService* local_state = g_browser_process->local_state();
1251  // List of users who have accepted location sharing for fraud protection
1252  // on this device.
1253  const base::ListValue* accepted =
1254      local_state->GetList(::prefs::kAutofillDialogWalletLocationAcceptance);
1255  bool has_accepted_location_sharing =
1256      accepted->Find(base::StringValue(
1257          account_chooser_model_->GetActiveWalletAccountName())) !=
1258      accepted->end();
1259
1260  if (wallet_items_->legal_documents().empty()) {
1261    if (!has_accepted_location_sharing) {
1262      legal_documents_text_ = l10n_util::GetStringUTF16(
1263          IDS_AUTOFILL_DIALOG_LOCATION_DISCLOSURE);
1264    }
1265
1266    return;
1267  }
1268
1269  const std::vector<wallet::WalletItems::LegalDocument*>& documents =
1270      wallet_items_->legal_documents();
1271  // There should never be just one document because the privacy policy doc gets
1272  // tacked on the end of other documents.
1273  DCHECK_GE(documents.size(), 2U);
1274
1275  std::vector<base::string16> link_names;
1276  for (size_t i = 0; i < documents.size(); ++i) {
1277    link_names.push_back(documents[i]->display_name());
1278  }
1279
1280  int resource_id = 0;
1281  switch (documents.size()) {
1282    case 2U:
1283      resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_2;
1284      break;
1285    case 3U:
1286      resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_3;
1287      break;
1288    case 4U:
1289      resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_4;
1290      break;
1291    case 5U:
1292      resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_5;
1293      break;
1294    case 6U:
1295      resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_6;
1296      break;
1297    default:
1298      // We can only handle so many documents. For lack of a better way of
1299      // handling document overflow, just error out if there are too many.
1300      DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
1301      return;
1302  }
1303
1304  std::vector<size_t> offsets;
1305  base::string16 text =
1306      l10n_util::GetStringFUTF16(resource_id, link_names,&offsets);
1307
1308  // Tack on the location string if need be.
1309  size_t base_offset = 0;
1310  if (!has_accepted_location_sharing) {
1311    text = l10n_util::GetStringFUTF16(
1312        IDS_AUTOFILL_DIALOG_LOCATION_DISCLOSURE_WITH_LEGAL_DOCS,
1313        text,
1314        &base_offset);
1315  }
1316
1317  for (size_t i = 0; i < documents.size(); ++i) {
1318    size_t link_start = offsets[i] + base_offset;
1319    legal_document_link_ranges_.push_back(gfx::Range(
1320        link_start, link_start + documents[i]->display_name().size()));
1321  }
1322  legal_documents_text_ = text;
1323}
1324
1325void AutofillDialogControllerImpl::ResetSectionInput(DialogSection section) {
1326  SetEditingExistingData(section, false);
1327  needs_validation_.erase(section);
1328
1329  CountryComboboxModel* model = CountryComboboxModelForSection(section);
1330  if (model) {
1331    base::string16 country = model->GetItemAt(model->GetDefaultIndex());
1332    RebuildInputsForCountry(section, country, false);
1333  }
1334
1335  DetailInputs* inputs = MutableRequestedFieldsForSection(section);
1336  for (DetailInputs::iterator it = inputs->begin();
1337       it != inputs->end(); ++it) {
1338    if (it->length != DetailInput::NONE) {
1339      it->initial_value.clear();
1340    } else if (!it->initial_value.empty() &&
1341               (it->type == ADDRESS_BILLING_COUNTRY ||
1342                it->type == ADDRESS_HOME_COUNTRY)) {
1343      GetValidator()->LoadRules(AutofillCountry::GetCountryCode(
1344          it->initial_value, g_browser_process->GetApplicationLocale()));
1345    }
1346  }
1347}
1348
1349void AutofillDialogControllerImpl::ShowEditUiIfBadSuggestion(
1350    DialogSection section) {
1351  // |CreateWrapper()| returns an empty wrapper if |IsEditingExistingData()|, so
1352  // get the wrapper before this potentially happens below.
1353  scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
1354
1355  // If the chosen item in |model| yields an empty suggestion text, it is
1356  // invalid. In this case, show the edit UI and highlight invalid fields.
1357  SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1358  base::string16 unused, unused2;
1359  if (IsASuggestionItemKey(model->GetItemKeyForCheckedItem()) &&
1360      !SuggestionTextForSection(section, &unused, &unused2)) {
1361    SetEditingExistingData(section, true);
1362  }
1363
1364  if (wrapper && IsEditingExistingData(section)) {
1365    base::string16 country =
1366        wrapper->GetInfo(AutofillType(CountryTypeForSection(section)));
1367    if (!country.empty()) {
1368      // There's no user input to restore here as this is only called after
1369      // resetting all section input.
1370      if (RebuildInputsForCountry(section, country, false))
1371        UpdateSection(section);
1372    }
1373    wrapper->FillInputs(MutableRequestedFieldsForSection(section));
1374  }
1375}
1376
1377bool AutofillDialogControllerImpl::InputWasEdited(ServerFieldType type,
1378                                                  const base::string16& value) {
1379  if (value.empty())
1380    return false;
1381
1382  // If this is a combobox at the default value, don't preserve it.
1383  ui::ComboboxModel* model = ComboboxModelForAutofillType(type);
1384  if (model && model->GetItemAt(model->GetDefaultIndex()) == value)
1385    return false;
1386
1387  return true;
1388}
1389
1390FieldValueMap AutofillDialogControllerImpl::TakeUserInputSnapshot() {
1391  FieldValueMap snapshot;
1392  if (!view_)
1393    return snapshot;
1394
1395  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
1396    DialogSection section = static_cast<DialogSection>(i);
1397    SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1398    if (model->GetItemKeyForCheckedItem() != kAddNewItemKey)
1399      continue;
1400
1401    FieldValueMap outputs;
1402    view_->GetUserInput(section, &outputs);
1403    // Remove fields that are empty, at their default values, or invalid.
1404    for (FieldValueMap::iterator it = outputs.begin(); it != outputs.end();
1405         ++it) {
1406      if (InputWasEdited(it->first, it->second) &&
1407          InputValidityMessage(section, it->first, it->second).empty()) {
1408        snapshot.insert(std::make_pair(it->first, it->second));
1409      }
1410    }
1411  }
1412
1413  return snapshot;
1414}
1415
1416void AutofillDialogControllerImpl::RestoreUserInputFromSnapshot(
1417    const FieldValueMap& snapshot) {
1418  if (snapshot.empty())
1419    return;
1420
1421  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
1422    DialogSection section = static_cast<DialogSection>(i);
1423    if (!SectionIsActive(section))
1424      continue;
1425
1426    DetailInputs* inputs = MutableRequestedFieldsForSection(section);
1427    for (size_t i = 0; i < inputs->size(); ++i) {
1428      DetailInput* input = &(*inputs)[i];
1429      if (input->length != DetailInput::NONE) {
1430        input->initial_value =
1431            GetInfoFromInputs(snapshot, section, AutofillType(input->type));
1432      }
1433      if (InputWasEdited(input->type, input->initial_value))
1434        SuggestionsMenuModelForSection(section)->SetCheckedItem(kAddNewItemKey);
1435    }
1436  }
1437}
1438
1439void AutofillDialogControllerImpl::UpdateSection(DialogSection section) {
1440  if (view_)
1441    view_->UpdateSection(section);
1442}
1443
1444void AutofillDialogControllerImpl::UpdateForErrors() {
1445  if (!view_)
1446    return;
1447
1448  // Currently, the view should only need to be updated if there are
1449  // |wallet_errors_| or validating a suggestion that's based on existing data.
1450  bool should_update = !wallet_errors_.empty();
1451  if (!should_update) {
1452    for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
1453      if (IsEditingExistingData(static_cast<DialogSection>(i))) {
1454        should_update = true;
1455        break;
1456      }
1457    }
1458  }
1459
1460  if (should_update)
1461    view_->UpdateForErrors();
1462}
1463
1464gfx::Image AutofillDialogControllerImpl::GetGeneratedCardImage(
1465    const base::string16& card_number,
1466    const base::string16& name,
1467    const SkColor& gradient_top,
1468    const SkColor& gradient_bottom) {
1469  const int kCardWidthPx = 300;
1470  const int kCardHeightPx = 190;
1471  const gfx::Size size(kCardWidthPx, kCardHeightPx);
1472  float scale_factor = ui::GetScaleFactorForNativeView(
1473      web_contents()->GetNativeView());
1474  gfx::Canvas canvas(size, scale_factor, false);
1475
1476  gfx::Rect display_rect(size);
1477
1478  skia::RefPtr<SkShader> shader = gfx::CreateGradientShader(
1479      0, size.height(), gradient_top, gradient_bottom);
1480  SkPaint paint;
1481  paint.setShader(shader.get());
1482  canvas.DrawRoundRect(display_rect, 8, paint);
1483
1484  display_rect.Inset(20, 0, 0, 0);
1485  gfx::Font font(l10n_util::GetStringUTF8(IDS_FIXED_FONT_FAMILY), 18);
1486  gfx::FontList font_list(font);
1487  gfx::ShadowValues shadows;
1488  shadows.push_back(gfx::ShadowValue(gfx::Point(0, 1), 1.0, SK_ColorBLACK));
1489  canvas.DrawStringRectWithShadows(
1490      card_number,
1491      font_list,
1492      SK_ColorWHITE,
1493      display_rect, 0, 0, shadows);
1494
1495  base::string16 capitalized_name = base::i18n::ToUpper(name);
1496  display_rect.Inset(0, size.height() / 2, 0, 0);
1497  canvas.DrawStringRectWithShadows(
1498      capitalized_name,
1499      font_list,
1500      SK_ColorWHITE,
1501      display_rect, 0, 0, shadows);
1502
1503  gfx::ImageSkia skia(canvas.ExtractImageRep());
1504  return gfx::Image(skia);
1505}
1506
1507void AutofillDialogControllerImpl::StartCardScramblingRefresher() {
1508  RefreshCardScramblingOverlay();
1509  card_scrambling_refresher_.Start(
1510      FROM_HERE,
1511      base::TimeDelta::FromMilliseconds(75),
1512      this,
1513      &AutofillDialogControllerImpl::RefreshCardScramblingOverlay);
1514}
1515
1516void AutofillDialogControllerImpl::RefreshCardScramblingOverlay() {
1517  scrambled_card_number_ = GenerateRandomCardNumber();
1518  PushOverlayUpdate();
1519}
1520
1521void AutofillDialogControllerImpl::PushOverlayUpdate() {
1522  if (view_) {
1523    ScopedViewUpdates updates(view_.get());
1524    view_->UpdateOverlay();
1525  }
1526}
1527
1528const DetailInputs& AutofillDialogControllerImpl::RequestedFieldsForSection(
1529    DialogSection section) const {
1530  switch (section) {
1531    case SECTION_CC:
1532      return requested_cc_fields_;
1533    case SECTION_BILLING:
1534      return requested_billing_fields_;
1535    case SECTION_CC_BILLING:
1536      return requested_cc_billing_fields_;
1537    case SECTION_SHIPPING:
1538      return requested_shipping_fields_;
1539  }
1540
1541  NOTREACHED();
1542  return requested_billing_fields_;
1543}
1544
1545ui::ComboboxModel* AutofillDialogControllerImpl::ComboboxModelForAutofillType(
1546    ServerFieldType type) {
1547  switch (type) {
1548    case CREDIT_CARD_EXP_MONTH:
1549      return &cc_exp_month_combobox_model_;
1550
1551    case CREDIT_CARD_EXP_4_DIGIT_YEAR:
1552      return &cc_exp_year_combobox_model_;
1553
1554    case ADDRESS_BILLING_COUNTRY:
1555      return billing_country_combobox_model_.get();
1556
1557    case ADDRESS_HOME_COUNTRY:
1558      return shipping_country_combobox_model_.get();
1559
1560    default:
1561      return NULL;
1562  }
1563}
1564
1565ui::MenuModel* AutofillDialogControllerImpl::MenuModelForSection(
1566    DialogSection section) {
1567  SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1568  // The shipping section menu is special. It will always show because there is
1569  // a choice between "Use billing" and "enter new".
1570  if (section == SECTION_SHIPPING)
1571    return model;
1572
1573  // For other sections, only show a menu if there's at least one suggestion.
1574  for (int i = 0; i < model->GetItemCount(); ++i) {
1575    if (IsASuggestionItemKey(model->GetItemKeyAt(i)))
1576      return model;
1577  }
1578
1579  return NULL;
1580}
1581
1582ui::MenuModel* AutofillDialogControllerImpl::MenuModelForAccountChooser() {
1583  // If there were unrecoverable Wallet errors, or if there are choices other
1584  // than "Pay without the wallet", show the full menu.
1585  // TODO(estade): this can present a braindead menu (only 1 option) when
1586  // there's a wallet error.
1587  if (wallet_error_notification_ ||
1588      (SignedInState() == SIGNED_IN &&
1589       account_chooser_model_->HasAccountsToChoose() &&
1590       !ShouldShowSignInWebView())) {
1591    return account_chooser_model_.get();
1592  }
1593
1594  // Otherwise, there is no menu, just a sign in link.
1595  return NULL;
1596}
1597
1598gfx::Image AutofillDialogControllerImpl::AccountChooserImage() {
1599  if (!MenuModelForAccountChooser() && !ShouldShowSignInWebView()) {
1600    return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1601        IDR_WALLET_ICON);
1602  }
1603
1604  return gfx::Image();
1605}
1606
1607gfx::Image AutofillDialogControllerImpl::ButtonStripImage() const {
1608  if (IsPayingWithWallet()) {
1609    return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1610        IDR_WALLET_LOGO);
1611  }
1612
1613  return gfx::Image();
1614}
1615
1616base::string16 AutofillDialogControllerImpl::LabelForSection(
1617    DialogSection section) const {
1618  switch (section) {
1619    case SECTION_CC:
1620      return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_CC);
1621    case SECTION_BILLING:
1622    case SECTION_CC_BILLING:
1623      return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_BILLING);
1624    case SECTION_SHIPPING:
1625      return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_SHIPPING);
1626  }
1627  NOTREACHED();
1628  return base::string16();
1629}
1630
1631SuggestionState AutofillDialogControllerImpl::SuggestionStateForSection(
1632    DialogSection section) {
1633  base::string16 vertically_compact, horizontally_compact;
1634  bool show_suggestion = SuggestionTextForSection(section,
1635                                                  &vertically_compact,
1636                                                  &horizontally_compact);
1637  return SuggestionState(show_suggestion,
1638                         vertically_compact,
1639                         horizontally_compact,
1640                         SuggestionIconForSection(section),
1641                         ExtraSuggestionTextForSection(section),
1642                         ExtraSuggestionIconForSection(section));
1643}
1644
1645bool AutofillDialogControllerImpl::SuggestionTextForSection(
1646    DialogSection section,
1647    base::string16* vertically_compact,
1648    base::string16* horizontally_compact) {
1649  base::string16 action_text = RequiredActionTextForSection(section);
1650  if (!action_text.empty()) {
1651    *vertically_compact = *horizontally_compact = action_text;
1652    return true;
1653  }
1654
1655  // When the user has clicked 'edit' or a suggestion is somehow invalid (e.g. a
1656  // user selects a credit card that has expired), don't show a suggestion (even
1657  // though there is a profile selected in the model).
1658  if (IsEditingExistingData(section))
1659    return false;
1660
1661  SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1662  std::string item_key = model->GetItemKeyForCheckedItem();
1663  if (item_key == kSameAsBillingKey) {
1664    *vertically_compact = *horizontally_compact = l10n_util::GetStringUTF16(
1665        IDS_AUTOFILL_DIALOG_USING_BILLING_FOR_SHIPPING);
1666    return true;
1667  }
1668
1669  if (!IsASuggestionItemKey(item_key))
1670    return false;
1671
1672  if (!IsPayingWithWallet() &&
1673      (section == SECTION_BILLING || section == SECTION_SHIPPING)) {
1674    // Also check if the address is invalid (rules may have loaded since
1675    // the dialog was shown).
1676    if (HasInvalidAddress(*GetManager()->GetProfileByGUID(item_key)))
1677      return false;
1678  }
1679
1680  scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
1681  return wrapper->GetDisplayText(vertically_compact, horizontally_compact);
1682}
1683
1684base::string16 AutofillDialogControllerImpl::RequiredActionTextForSection(
1685    DialogSection section) const {
1686  if (section == SECTION_CC_BILLING && IsSubmitPausedOn(wallet::VERIFY_CVV)) {
1687    const wallet::WalletItems::MaskedInstrument* current_instrument =
1688        wallet_items_->GetInstrumentById(active_instrument_id_);
1689    if (current_instrument)
1690      return current_instrument->TypeAndLastFourDigits();
1691
1692    FieldValueMap output;
1693    view_->GetUserInput(section, &output);
1694    CreditCard card;
1695    GetBillingInfoFromOutputs(output, &card, NULL, NULL);
1696    return card.TypeAndLastFourDigits();
1697  }
1698
1699  return base::string16();
1700}
1701
1702base::string16 AutofillDialogControllerImpl::ExtraSuggestionTextForSection(
1703    DialogSection section) const {
1704  if (section == SECTION_CC ||
1705      (section == SECTION_CC_BILLING && IsSubmitPausedOn(wallet::VERIFY_CVV))) {
1706    return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC);
1707  }
1708
1709  return base::string16();
1710}
1711
1712const wallet::WalletItems::MaskedInstrument* AutofillDialogControllerImpl::
1713    ActiveInstrument() const {
1714  if (!IsPayingWithWallet())
1715    return NULL;
1716
1717  const SuggestionsMenuModel* model =
1718      SuggestionsMenuModelForSection(SECTION_CC_BILLING);
1719  const std::string item_key = model->GetItemKeyForCheckedItem();
1720  if (!IsASuggestionItemKey(item_key))
1721    return NULL;
1722
1723  int index;
1724  if (!base::StringToInt(item_key, &index) || index < 0 ||
1725      static_cast<size_t>(index) >= wallet_items_->instruments().size()) {
1726    NOTREACHED();
1727    return NULL;
1728  }
1729
1730  return wallet_items_->instruments()[index];
1731}
1732
1733const wallet::Address* AutofillDialogControllerImpl::
1734    ActiveShippingAddress() const {
1735  if (!IsPayingWithWallet() || !IsShippingAddressRequired())
1736    return NULL;
1737
1738  const SuggestionsMenuModel* model =
1739      SuggestionsMenuModelForSection(SECTION_SHIPPING);
1740  const std::string item_key = model->GetItemKeyForCheckedItem();
1741  if (!IsASuggestionItemKey(item_key))
1742    return NULL;
1743
1744  int index;
1745  if (!base::StringToInt(item_key, &index) || index < 0 ||
1746      static_cast<size_t>(index) >= wallet_items_->addresses().size()) {
1747    NOTREACHED();
1748    return NULL;
1749  }
1750
1751  return wallet_items_->addresses()[index];
1752}
1753
1754scoped_ptr<DataModelWrapper> AutofillDialogControllerImpl::CreateWrapper(
1755    DialogSection section) {
1756  if (IsPayingWithWallet() && full_wallet_ &&
1757      full_wallet_->required_actions().empty()) {
1758    if (section == SECTION_CC_BILLING) {
1759      return scoped_ptr<DataModelWrapper>(
1760          new FullWalletBillingWrapper(full_wallet_.get()));
1761    }
1762    if (section == SECTION_SHIPPING) {
1763      return scoped_ptr<DataModelWrapper>(
1764          new FullWalletShippingWrapper(full_wallet_.get()));
1765    }
1766  }
1767
1768  SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1769  std::string item_key = model->GetItemKeyForCheckedItem();
1770  if (!IsASuggestionItemKey(item_key) || IsManuallyEditingSection(section))
1771    return scoped_ptr<DataModelWrapper>();
1772
1773  if (IsPayingWithWallet()) {
1774    if (section == SECTION_CC_BILLING) {
1775      return scoped_ptr<DataModelWrapper>(
1776          new WalletInstrumentWrapper(ActiveInstrument()));
1777    }
1778
1779    if (section == SECTION_SHIPPING) {
1780      return scoped_ptr<DataModelWrapper>(
1781          new WalletAddressWrapper(ActiveShippingAddress()));
1782    }
1783
1784    return scoped_ptr<DataModelWrapper>();
1785  }
1786
1787  if (section == SECTION_CC) {
1788    CreditCard* card = GetManager()->GetCreditCardByGUID(item_key);
1789    DCHECK(card);
1790    return scoped_ptr<DataModelWrapper>(new AutofillCreditCardWrapper(card));
1791  }
1792
1793  AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
1794  DCHECK(profile);
1795  if (section == SECTION_SHIPPING) {
1796    return scoped_ptr<DataModelWrapper>(
1797        new AutofillShippingAddressWrapper(profile));
1798  }
1799  DCHECK_EQ(SECTION_BILLING, section);
1800  return scoped_ptr<DataModelWrapper>(
1801      new AutofillProfileWrapper(profile));
1802}
1803
1804gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection(
1805    DialogSection section) {
1806  scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
1807  if (!model.get())
1808    return gfx::Image();
1809
1810  return model->GetIcon();
1811}
1812
1813gfx::Image AutofillDialogControllerImpl::ExtraSuggestionIconForSection(
1814    DialogSection section) {
1815  if (section != SECTION_CC && section != SECTION_CC_BILLING)
1816    return gfx::Image();
1817
1818  scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
1819  if (!model.get())
1820    return gfx::Image();
1821
1822  return CvcIconForCreditCardType(
1823      model->GetInfo(AutofillType(CREDIT_CARD_TYPE)));
1824}
1825
1826FieldIconMap AutofillDialogControllerImpl::IconsForFields(
1827    const FieldValueMap& user_inputs) const {
1828  FieldIconMap result;
1829  base::string16 credit_card_type;
1830
1831  FieldValueMap::const_iterator credit_card_iter =
1832      user_inputs.find(CREDIT_CARD_NUMBER);
1833  if (credit_card_iter != user_inputs.end()) {
1834    const base::string16& number = credit_card_iter->second;
1835    const std::string type = CreditCard::GetCreditCardType(number);
1836    credit_card_type = CreditCard::TypeForDisplay(type);
1837    result[CREDIT_CARD_NUMBER] = CreditCardIconForType(type);
1838  }
1839
1840  if (!user_inputs.count(CREDIT_CARD_VERIFICATION_CODE))
1841    return result;
1842
1843  result[CREDIT_CARD_VERIFICATION_CODE] =
1844      CvcIconForCreditCardType(credit_card_type);
1845
1846  return result;
1847}
1848
1849bool AutofillDialogControllerImpl::FieldControlsIcons(
1850    ServerFieldType type) const {
1851  return type == CREDIT_CARD_NUMBER;
1852}
1853
1854base::string16 AutofillDialogControllerImpl::TooltipForField(
1855    ServerFieldType type) const {
1856  if (type == PHONE_HOME_WHOLE_NUMBER || type == PHONE_BILLING_WHOLE_NUMBER)
1857    return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TOOLTIP_PHONE_NUMBER);
1858
1859  return base::string16();
1860}
1861
1862bool AutofillDialogControllerImpl::InputIsEditable(
1863    const DetailInput& input,
1864    DialogSection section) {
1865  if (section != SECTION_CC_BILLING || !IsPayingWithWallet())
1866    return true;
1867
1868  if (input.type == CREDIT_CARD_NUMBER)
1869    return !IsEditingExistingData(section);
1870
1871  // For CVC, only require (allow) input if the user has edited some other
1872  // aspect of the card.
1873  if (input.type == CREDIT_CARD_VERIFICATION_CODE &&
1874      IsEditingExistingData(section)) {
1875    FieldValueMap output;
1876    view_->GetUserInput(section, &output);
1877    WalletInstrumentWrapper wrapper(ActiveInstrument());
1878
1879    for (FieldValueMap::iterator iter = output.begin(); iter != output.end();
1880         ++iter) {
1881      if (iter->first == input.type)
1882        continue;
1883
1884      AutofillType type(iter->first);
1885      if (type.group() == CREDIT_CARD &&
1886          iter->second != wrapper.GetInfo(type)) {
1887        return true;
1888      }
1889    }
1890
1891    return false;
1892  }
1893
1894  return true;
1895}
1896
1897// TODO(groby): Add more tests.
1898base::string16 AutofillDialogControllerImpl::InputValidityMessage(
1899    DialogSection section,
1900    ServerFieldType type,
1901    const base::string16& value) {
1902  // If the field is edited, clear any Wallet errors.
1903  if (IsPayingWithWallet()) {
1904    WalletValidationErrors::iterator it = wallet_errors_.find(section);
1905    if (it != wallet_errors_.end()) {
1906      TypeErrorInputMap::const_iterator iter = it->second.find(type);
1907      if (iter != it->second.end()) {
1908        if (iter->second.second == value)
1909          return iter->second.first;
1910        it->second.erase(type);
1911      }
1912    }
1913  }
1914
1915  AutofillType autofill_type(type);
1916  if (autofill_type.group() == ADDRESS_HOME ||
1917      autofill_type.group() == ADDRESS_BILLING) {
1918    return base::string16();
1919  }
1920
1921  switch (autofill_type.GetStorableType()) {
1922    case EMAIL_ADDRESS:
1923      if (!value.empty() && !IsValidEmailAddress(value)) {
1924        return l10n_util::GetStringUTF16(
1925            IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_EMAIL_ADDRESS);
1926      }
1927      break;
1928
1929    case CREDIT_CARD_NUMBER: {
1930      if (!value.empty()) {
1931        base::string16 message = CreditCardNumberValidityMessage(value);
1932        if (!message.empty())
1933          return message;
1934      }
1935      break;
1936    }
1937
1938    case CREDIT_CARD_EXP_MONTH:
1939      if (!InputWasEdited(CREDIT_CARD_EXP_MONTH, value)) {
1940        return l10n_util::GetStringUTF16(
1941            IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD);
1942      }
1943      break;
1944
1945    case CREDIT_CARD_EXP_4_DIGIT_YEAR:
1946      if (!InputWasEdited(CREDIT_CARD_EXP_4_DIGIT_YEAR, value)) {
1947        return l10n_util::GetStringUTF16(
1948            IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD);
1949      }
1950      break;
1951
1952    case CREDIT_CARD_VERIFICATION_CODE:
1953      if (!value.empty() && !autofill::IsValidCreditCardSecurityCode(value)) {
1954        return l10n_util::GetStringUTF16(
1955            IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_SECURITY_CODE);
1956      }
1957      break;
1958
1959    case NAME_FULL:
1960      // Wallet requires a first and last billing name.
1961      if (IsPayingWithWallet() && !value.empty() &&
1962          !IsCardHolderNameValidForWallet(value)) {
1963        return l10n_util::GetStringUTF16(
1964            IDS_AUTOFILL_DIALOG_VALIDATION_WALLET_REQUIRES_TWO_NAMES);
1965      }
1966      break;
1967
1968    case PHONE_HOME_WHOLE_NUMBER:  // Used in shipping section.
1969      break;
1970
1971    case PHONE_BILLING_WHOLE_NUMBER:  // Used in billing section.
1972      break;
1973
1974    default:
1975      NOTREACHED();  // Trying to validate unknown field.
1976      break;
1977  }
1978
1979  return value.empty() ? l10n_util::GetStringUTF16(
1980                             IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD) :
1981                         base::string16();
1982}
1983
1984// TODO(groby): Also add tests.
1985ValidityMessages AutofillDialogControllerImpl::InputsAreValid(
1986    DialogSection section,
1987    const FieldValueMap& inputs) {
1988  ValidityMessages messages;
1989  if (inputs.empty())
1990    return messages;
1991
1992  AddressValidator::Status status = AddressValidator::SUCCESS;
1993  if (section != SECTION_CC) {
1994    AutofillProfile profile;
1995    FillFormGroupFromOutputs(inputs, &profile);
1996    scoped_ptr<AddressData> address_data =
1997        i18n::CreateAddressDataFromAutofillProfile(
1998            profile, g_browser_process->GetApplicationLocale());
1999    address_data->language_code = AddressLanguageCodeForSection(section);
2000
2001    Localization localization;
2002    localization.SetGetter(l10n_util::GetStringUTF8);
2003    FieldProblemMap problems;
2004    status = GetValidator()->ValidateAddress(*address_data, NULL, &problems);
2005    bool billing = section != SECTION_SHIPPING;
2006
2007    for (FieldProblemMap::const_iterator iter = problems.begin();
2008         iter != problems.end(); ++iter) {
2009      bool sure = iter->second != MISSING_REQUIRED_FIELD;
2010      base::string16 text = base::UTF8ToUTF16(localization.GetErrorMessage(
2011          *address_data, iter->first, iter->second, true, false));
2012      messages.Set(i18n::TypeForField(iter->first, billing),
2013                   ValidityMessage(text, sure));
2014    }
2015  }
2016
2017  for (FieldValueMap::const_iterator iter = inputs.begin();
2018       iter != inputs.end(); ++iter) {
2019    const ServerFieldType type = iter->first;
2020    base::string16 text = InputValidityMessage(section, type, iter->second);
2021
2022    // Skip empty/unchanged fields in edit mode. If the individual field does
2023    // not have validation errors, assume it to be valid unless later proven
2024    // otherwise.
2025    bool sure = InputWasEdited(type, iter->second);
2026
2027    if (sure && status == AddressValidator::RULES_NOT_READY &&
2028        !ComboboxModelForAutofillType(type) &&
2029        (AutofillType(type).group() == ADDRESS_HOME ||
2030         AutofillType(type).group() == ADDRESS_BILLING)) {
2031      DCHECK(text.empty());
2032      text = l10n_util::GetStringUTF16(
2033          IDS_AUTOFILL_DIALOG_VALIDATION_WAITING_FOR_RULES);
2034      sure = false;
2035      needs_validation_.insert(section);
2036    }
2037
2038    messages.Set(type, ValidityMessage(text, sure));
2039  }
2040
2041  // For the convenience of using operator[].
2042  FieldValueMap& field_values = const_cast<FieldValueMap&>(inputs);
2043  // Validate the date formed by month and year field. (Autofill dialog is
2044  // never supposed to have 2-digit years, so not checked).
2045  if (field_values.count(CREDIT_CARD_EXP_4_DIGIT_YEAR) &&
2046      field_values.count(CREDIT_CARD_EXP_MONTH) &&
2047      InputWasEdited(CREDIT_CARD_EXP_4_DIGIT_YEAR,
2048                     field_values[CREDIT_CARD_EXP_4_DIGIT_YEAR]) &&
2049      InputWasEdited(CREDIT_CARD_EXP_MONTH,
2050                     field_values[CREDIT_CARD_EXP_MONTH])) {
2051    ValidityMessage year_message(base::string16(), true);
2052    ValidityMessage month_message(base::string16(), true);
2053    if (!IsCreditCardExpirationValid(field_values[CREDIT_CARD_EXP_4_DIGIT_YEAR],
2054                                     field_values[CREDIT_CARD_EXP_MONTH])) {
2055      // The dialog shows the same error message for the month and year fields.
2056      year_message.text = l10n_util::GetStringUTF16(
2057          IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_DATE);
2058      month_message.text = l10n_util::GetStringUTF16(
2059          IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_DATE);
2060    }
2061    messages.Set(CREDIT_CARD_EXP_4_DIGIT_YEAR, year_message);
2062    messages.Set(CREDIT_CARD_EXP_MONTH, month_message);
2063  }
2064
2065  // If there is a credit card number and a CVC, validate them together.
2066  if (field_values.count(CREDIT_CARD_NUMBER) &&
2067      field_values.count(CREDIT_CARD_VERIFICATION_CODE)) {
2068    ValidityMessage ccv_message(base::string16(), true);
2069    if (!autofill::IsValidCreditCardSecurityCode(
2070            field_values[CREDIT_CARD_VERIFICATION_CODE],
2071            field_values[CREDIT_CARD_NUMBER])) {
2072      ccv_message.text = l10n_util::GetStringUTF16(
2073          IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_SECURITY_CODE);
2074    }
2075    messages.Set(CREDIT_CARD_VERIFICATION_CODE, ccv_message);
2076  }
2077
2078  // Validate the shipping phone number against the country code of the address.
2079  if (field_values.count(ADDRESS_HOME_COUNTRY) &&
2080      field_values.count(PHONE_HOME_WHOLE_NUMBER)) {
2081    messages.Set(
2082        PHONE_HOME_WHOLE_NUMBER,
2083        GetPhoneValidityMessage(field_values[ADDRESS_HOME_COUNTRY],
2084                                field_values[PHONE_HOME_WHOLE_NUMBER]));
2085  }
2086
2087  // Validate the billing phone number against the country code of the address.
2088  if (field_values.count(ADDRESS_BILLING_COUNTRY) &&
2089      field_values.count(PHONE_BILLING_WHOLE_NUMBER)) {
2090    messages.Set(
2091        PHONE_BILLING_WHOLE_NUMBER,
2092        GetPhoneValidityMessage(field_values[ADDRESS_BILLING_COUNTRY],
2093                                field_values[PHONE_BILLING_WHOLE_NUMBER]));
2094  }
2095
2096  return messages;
2097}
2098
2099void AutofillDialogControllerImpl::UserEditedOrActivatedInput(
2100    DialogSection section,
2101    ServerFieldType type,
2102    gfx::NativeView parent_view,
2103    const gfx::Rect& content_bounds,
2104    const base::string16& field_contents,
2105    bool was_edit) {
2106  ScopedViewUpdates updates(view_.get());
2107
2108  if (type == ADDRESS_BILLING_COUNTRY || type == ADDRESS_HOME_COUNTRY) {
2109    const FieldValueMap& snapshot = TakeUserInputSnapshot();
2110
2111    // Clobber the inputs because the view's already been updated.
2112    RebuildInputsForCountry(section, field_contents, true);
2113    RestoreUserInputFromSnapshot(snapshot);
2114    UpdateSection(section);
2115  }
2116
2117  // The rest of this method applies only to textfields while Autofill is
2118  // enabled. If a combobox or Autofill is disabled, bail.
2119  if (ComboboxModelForAutofillType(type) || !IsAutofillEnabled())
2120    return;
2121
2122  // If the field is edited down to empty, don't show a popup.
2123  if (was_edit && field_contents.empty()) {
2124    HidePopup();
2125    return;
2126  }
2127
2128  // If the user clicks while the popup is already showing, be sure to hide
2129  // it.
2130  if (!was_edit && popup_controller_.get()) {
2131    HidePopup();
2132    return;
2133  }
2134
2135  std::vector<base::string16> popup_values, popup_labels, popup_icons;
2136  if (common::IsCreditCardType(type)) {
2137    GetManager()->GetCreditCardSuggestions(AutofillType(type),
2138                                           field_contents,
2139                                           &popup_values,
2140                                           &popup_labels,
2141                                           &popup_icons,
2142                                           &popup_guids_);
2143  } else {
2144    GetManager()->GetProfileSuggestions(
2145        AutofillType(type),
2146        field_contents,
2147        false,
2148        RequestedTypesForSection(section),
2149        base::Bind(&AutofillDialogControllerImpl::ShouldSuggestProfile,
2150                   base::Unretained(this), section),
2151        &popup_values,
2152        &popup_labels,
2153        &popup_icons,
2154        &popup_guids_);
2155
2156    GetI18nValidatorSuggestions(section, type, &popup_values, &popup_labels,
2157                                &popup_icons);
2158  }
2159
2160  if (popup_values.empty()) {
2161    HidePopup();
2162    return;
2163  }
2164
2165  // |popup_input_type_| must be set before calling |Show()|.
2166  popup_input_type_ = type;
2167  popup_section_ = section;
2168
2169  // TODO(estade): do we need separators and control rows like 'Clear
2170  // Form'?
2171  std::vector<int> popup_ids;
2172  for (size_t i = 0; i < popup_values.size(); ++i) {
2173    popup_ids.push_back(i);
2174  }
2175
2176  popup_controller_ = AutofillPopupControllerImpl::GetOrCreate(
2177      popup_controller_,
2178      weak_ptr_factory_.GetWeakPtr(),
2179      NULL,
2180      parent_view,
2181      content_bounds,
2182      base::i18n::IsRTL() ?
2183          base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT);
2184  popup_controller_->Show(popup_values,
2185                          popup_labels,
2186                          popup_icons,
2187                          popup_ids);
2188}
2189
2190void AutofillDialogControllerImpl::FocusMoved() {
2191  HidePopup();
2192}
2193
2194bool AutofillDialogControllerImpl::ShouldShowErrorBubble() const {
2195  return popup_input_type_ == UNKNOWN_TYPE;
2196}
2197
2198void AutofillDialogControllerImpl::ViewClosed() {
2199  GetManager()->RemoveObserver(this);
2200
2201  // Called from here rather than in ~AutofillDialogControllerImpl as this
2202  // relies on virtual methods that change to their base class in the dtor.
2203  MaybeShowCreditCardBubble();
2204
2205  delete this;
2206}
2207
2208std::vector<DialogNotification> AutofillDialogControllerImpl::
2209    CurrentNotifications() {
2210  std::vector<DialogNotification> notifications;
2211
2212  // TODO(dbeam): figure out a way to dismiss this error after a while.
2213  if (wallet_error_notification_)
2214    notifications.push_back(*wallet_error_notification_);
2215
2216  if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
2217    notifications.push_back(DialogNotification(
2218        DialogNotification::REQUIRED_ACTION,
2219        l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_VERIFY_CVV)));
2220  }
2221
2222  if (!wallet_server_validation_recoverable_) {
2223    notifications.push_back(DialogNotification(
2224        DialogNotification::REQUIRED_ACTION,
2225        l10n_util::GetStringUTF16(
2226            IDS_AUTOFILL_DIALOG_FAILED_TO_SAVE_WALLET_DATA)));
2227  }
2228
2229  if (choose_another_instrument_or_address_) {
2230    notifications.push_back(DialogNotification(
2231        DialogNotification::REQUIRED_ACTION,
2232        l10n_util::GetStringUTF16(
2233            IDS_AUTOFILL_DIALOG_CHOOSE_DIFFERENT_WALLET_INSTRUMENT)));
2234  }
2235
2236  if (notifications.empty() && MenuModelForAccountChooser()) {
2237    base::string16 text = l10n_util::GetStringUTF16(
2238        IsManuallyEditingAnySection() ?
2239            IDS_AUTOFILL_DIALOG_SAVE_DETAILS_IN_WALLET :
2240            IDS_AUTOFILL_DIALOG_USE_WALLET);
2241    DialogNotification notification(
2242        DialogNotification::WALLET_USAGE_CONFIRMATION,
2243        text);
2244    notification.set_tooltip_text(
2245        l10n_util::GetStringUTF16(
2246            IDS_AUTOFILL_DIALOG_SAVE_IN_WALLET_TOOLTIP));
2247    notification.set_checked(IsPayingWithWallet());
2248    notifications.push_back(notification);
2249  }
2250
2251  if (IsPayingWithWallet() && !wallet::IsUsingProd()) {
2252    notifications.push_back(DialogNotification(
2253        DialogNotification::DEVELOPER_WARNING,
2254        l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_NOT_PROD_WARNING)));
2255  }
2256
2257  if (!invoked_from_same_origin_) {
2258    notifications.push_back(DialogNotification(
2259        DialogNotification::SECURITY_WARNING,
2260        l10n_util::GetStringFUTF16(IDS_AUTOFILL_DIALOG_SITE_WARNING,
2261                                   base::UTF8ToUTF16(source_url_.host()))));
2262  }
2263
2264  return notifications;
2265}
2266
2267void AutofillDialogControllerImpl::LinkClicked(const GURL& url) {
2268  OpenTabWithUrl(url);
2269}
2270
2271void AutofillDialogControllerImpl::SignInLinkClicked() {
2272  ScopedViewUpdates updates(view_.get());
2273
2274  if (SignedInState() == NOT_CHECKED) {
2275    handling_use_wallet_link_click_ = true;
2276    account_chooser_model_->SelectWalletAccount(0);
2277    FetchWalletCookie();
2278  } else if (signin_registrar_.IsEmpty()) {
2279    // Start sign in.
2280    waiting_for_explicit_sign_in_response_ = true;
2281    content::Source<content::NavigationController> source(view_->ShowSignIn());
2282    signin_registrar_.Add(
2283        this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source);
2284
2285    GetMetricLogger().LogDialogUiEvent(
2286        AutofillMetrics::DIALOG_UI_SIGNIN_SHOWN);
2287  } else {
2288    waiting_for_explicit_sign_in_response_ = false;
2289    HideSignIn();
2290  }
2291
2292  view_->UpdateAccountChooser();
2293  view_->UpdateButtonStrip();
2294}
2295
2296void AutofillDialogControllerImpl::NotificationCheckboxStateChanged(
2297    DialogNotification::Type type, bool checked) {
2298  if (type == DialogNotification::WALLET_USAGE_CONFIRMATION) {
2299    if (checked) {
2300      account_chooser_model_->SelectWalletAccount(
2301          GetWalletClient()->user_index());
2302    } else {
2303      account_chooser_model_->SelectUseAutofill();
2304    }
2305
2306    AccountChoiceChanged();
2307  }
2308}
2309
2310void AutofillDialogControllerImpl::LegalDocumentLinkClicked(
2311    const gfx::Range& range) {
2312  for (size_t i = 0; i < legal_document_link_ranges_.size(); ++i) {
2313    if (legal_document_link_ranges_[i] == range) {
2314      OpenTabWithUrl(wallet_items_->legal_documents()[i]->url());
2315      return;
2316    }
2317  }
2318
2319  NOTREACHED();
2320}
2321
2322bool AutofillDialogControllerImpl::OnCancel() {
2323  HidePopup();
2324  if (!is_submitting_)
2325    LogOnCancelMetrics();
2326  callback_.Run(
2327      AutofillClient::AutocompleteResultErrorCancel, base::string16(), NULL);
2328  return true;
2329}
2330
2331bool AutofillDialogControllerImpl::OnAccept() {
2332  ScopedViewUpdates updates(view_.get());
2333  choose_another_instrument_or_address_ = false;
2334  wallet_server_validation_recoverable_ = true;
2335  HidePopup();
2336
2337  // This must come before SetIsSubmitting().
2338  if (IsPayingWithWallet()) {
2339    // In the VERIFY_CVV case, hold onto the previously submitted cardholder
2340    // name.
2341    if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
2342      submitted_cardholder_name_ =
2343          GetValueFromSection(SECTION_CC_BILLING, NAME_BILLING_FULL);
2344
2345      // Snag the last four digits of the backing card now as it could be wiped
2346      // out if a CVC challenge happens.
2347      if (ActiveInstrument()) {
2348        backing_card_last_four_ = ActiveInstrument()->TypeAndLastFourDigits();
2349      } else {
2350        FieldValueMap output;
2351        view_->GetUserInput(SECTION_CC_BILLING, &output);
2352        CreditCard card;
2353        GetBillingInfoFromOutputs(output, &card, NULL, NULL);
2354        backing_card_last_four_ = card.TypeAndLastFourDigits();
2355      }
2356    }
2357    DCHECK(!submitted_cardholder_name_.empty());
2358    DCHECK(!backing_card_last_four_.empty());
2359  }
2360
2361  SetIsSubmitting(true);
2362
2363  if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
2364    DCHECK(!active_instrument_id_.empty());
2365    full_wallet_.reset();
2366    GetWalletClient()->AuthenticateInstrument(
2367        active_instrument_id_,
2368        base::UTF16ToUTF8(view_->GetCvc()));
2369    view_->UpdateOverlay();
2370  } else if (IsPayingWithWallet()) {
2371    AcceptLegalTerms();
2372  } else {
2373    FinishSubmit();
2374  }
2375
2376  return false;
2377}
2378
2379Profile* AutofillDialogControllerImpl::profile() {
2380  return profile_;
2381}
2382
2383content::WebContents* AutofillDialogControllerImpl::GetWebContents() {
2384  return web_contents();
2385}
2386
2387////////////////////////////////////////////////////////////////////////////////
2388// AutofillPopupDelegate implementation.
2389
2390void AutofillDialogControllerImpl::OnPopupShown() {
2391  ScopedViewUpdates update(view_.get());
2392  view_->UpdateErrorBubble();
2393
2394  GetMetricLogger().LogDialogPopupEvent(AutofillMetrics::DIALOG_POPUP_SHOWN);
2395}
2396
2397void AutofillDialogControllerImpl::OnPopupHidden() {}
2398
2399void AutofillDialogControllerImpl::DidSelectSuggestion(
2400    const base::string16& value,
2401    int identifier) {
2402  // TODO(estade): implement.
2403}
2404
2405void AutofillDialogControllerImpl::DidAcceptSuggestion(
2406    const base::string16& value,
2407    int identifier) {
2408  DCHECK_NE(UNKNOWN_TYPE, popup_input_type_);
2409  // Because |HidePopup()| can be called from |UpdateSection()|, remember the
2410  // type of the input for later here.
2411  const ServerFieldType popup_input_type = popup_input_type_;
2412
2413  ScopedViewUpdates updates(view_.get());
2414  scoped_ptr<DataModelWrapper> wrapper;
2415
2416  if (static_cast<size_t>(identifier) < popup_guids_.size()) {
2417    const PersonalDataManager::GUIDPair& pair = popup_guids_[identifier];
2418    if (common::IsCreditCardType(popup_input_type)) {
2419      wrapper.reset(new AutofillCreditCardWrapper(
2420          GetManager()->GetCreditCardByGUID(pair.first)));
2421    } else {
2422      wrapper.reset(new AutofillProfileWrapper(
2423          GetManager()->GetProfileByGUID(pair.first),
2424          AutofillType(popup_input_type),
2425          pair.second));
2426    }
2427  } else {
2428    wrapper.reset(new I18nAddressDataWrapper(
2429        &i18n_validator_suggestions_[identifier - popup_guids_.size()]));
2430  }
2431
2432  // If the user hasn't switched away from the default country and |wrapper|'s
2433  // country differs from the |view_|'s, rebuild inputs and restore user data.
2434  const FieldValueMap snapshot = TakeUserInputSnapshot();
2435  bool billing_rebuilt = false, shipping_rebuilt = false;
2436
2437  base::string16 billing_country =
2438      wrapper->GetInfo(AutofillType(ADDRESS_BILLING_COUNTRY));
2439  if (popup_section_ == ActiveBillingSection() &&
2440      !snapshot.count(ADDRESS_BILLING_COUNTRY) &&
2441      !billing_country.empty()) {
2442    billing_rebuilt = RebuildInputsForCountry(
2443        ActiveBillingSection(), billing_country, false);
2444  }
2445
2446  base::string16 shipping_country =
2447      wrapper->GetInfo(AutofillType(ADDRESS_HOME_COUNTRY));
2448  if (popup_section_ == SECTION_SHIPPING &&
2449      !snapshot.count(ADDRESS_HOME_COUNTRY) &&
2450      !shipping_country.empty()) {
2451    shipping_rebuilt = RebuildInputsForCountry(
2452        SECTION_SHIPPING, shipping_country, false);
2453  }
2454
2455  if (billing_rebuilt || shipping_rebuilt) {
2456    RestoreUserInputFromSnapshot(snapshot);
2457    if (billing_rebuilt)
2458      UpdateSection(ActiveBillingSection());
2459    if (shipping_rebuilt)
2460      UpdateSection(SECTION_SHIPPING);
2461  }
2462
2463  DCHECK(SectionIsActive(popup_section_));
2464  wrapper->FillInputs(MutableRequestedFieldsForSection(popup_section_));
2465  view_->FillSection(popup_section_, popup_input_type);
2466
2467  GetMetricLogger().LogDialogPopupEvent(
2468      AutofillMetrics::DIALOG_POPUP_FORM_FILLED);
2469
2470  // TODO(estade): not sure why it's necessary to do this explicitly.
2471  HidePopup();
2472}
2473
2474void AutofillDialogControllerImpl::RemoveSuggestion(
2475    const base::string16& value,
2476    int identifier) {
2477  // TODO(estade): implement.
2478}
2479
2480void AutofillDialogControllerImpl::ClearPreviewedForm() {
2481  // TODO(estade): implement.
2482}
2483
2484////////////////////////////////////////////////////////////////////////////////
2485// content::NotificationObserver implementation.
2486
2487void AutofillDialogControllerImpl::Observe(
2488    int type,
2489    const content::NotificationSource& source,
2490    const content::NotificationDetails& details) {
2491  DCHECK_EQ(type, content::NOTIFICATION_NAV_ENTRY_COMMITTED);
2492  content::LoadCommittedDetails* load_details =
2493      content::Details<content::LoadCommittedDetails>(details).ptr();
2494  size_t user_index = 0;
2495  if (IsSignInContinueUrl(load_details->entry->GetVirtualURL(), &user_index)) {
2496    GetWalletClient()->SetUserIndex(user_index);
2497    FetchWalletCookie();
2498
2499    // NOTE: |HideSignIn()| may delete the WebContents which doesn't expect to
2500    // be deleted while committing a nav entry. Just call |HideSignIn()| later.
2501    base::MessageLoop::current()->PostTask(FROM_HERE,
2502        base::Bind(&AutofillDialogControllerImpl::HideSignIn,
2503                   base::Unretained(this)));
2504  }
2505}
2506
2507////////////////////////////////////////////////////////////////////////////////
2508// SuggestionsMenuModelDelegate implementation.
2509
2510void AutofillDialogControllerImpl::SuggestionItemSelected(
2511    SuggestionsMenuModel* model,
2512    size_t index) {
2513  ScopedViewUpdates updates(view_.get());
2514
2515  if (model->GetItemKeyAt(index) == kManageItemsKey) {
2516    GURL url;
2517    if (!IsPayingWithWallet()) {
2518      DCHECK(IsAutofillEnabled());
2519      GURL settings_url(chrome::kChromeUISettingsURL);
2520      url = settings_url.Resolve(chrome::kAutofillSubPage);
2521    } else {
2522      // Reset |last_wallet_items_fetch_timestamp_| to ensure that the Wallet
2523      // data is refreshed as soon as the user switches back to this tab after
2524      // potentially editing his data.
2525      last_wallet_items_fetch_timestamp_ = base::TimeTicks();
2526      size_t user_index = GetWalletClient()->user_index();
2527      url = SectionForSuggestionsMenuModel(*model) == SECTION_SHIPPING ?
2528          wallet::GetManageAddressesUrl(user_index) :
2529          wallet::GetManageInstrumentsUrl(user_index);
2530    }
2531
2532    OpenTabWithUrl(url);
2533    return;
2534  }
2535
2536  model->SetCheckedIndex(index);
2537  DialogSection section = SectionForSuggestionsMenuModel(*model);
2538
2539  ResetSectionInput(section);
2540  ShowEditUiIfBadSuggestion(section);
2541  UpdateSection(section);
2542  view_->UpdateNotificationArea();
2543  UpdateForErrors();
2544
2545  LogSuggestionItemSelectedMetric(*model);
2546}
2547
2548////////////////////////////////////////////////////////////////////////////////
2549// wallet::WalletClientDelegate implementation.
2550
2551const AutofillMetrics& AutofillDialogControllerImpl::GetMetricLogger() const {
2552  return metric_logger_;
2553}
2554
2555std::string AutofillDialogControllerImpl::GetRiskData() const {
2556  DCHECK(!risk_data_.empty());
2557  return risk_data_;
2558}
2559
2560std::string AutofillDialogControllerImpl::GetWalletCookieValue() const {
2561  return wallet_cookie_value_;
2562}
2563
2564bool AutofillDialogControllerImpl::IsShippingAddressRequired() const {
2565  return cares_about_shipping_;
2566}
2567
2568void AutofillDialogControllerImpl::OnDidAcceptLegalDocuments() {
2569  DCHECK(is_submitting_ && IsPayingWithWallet());
2570  has_accepted_legal_documents_ = true;
2571  LoadRiskFingerprintData();
2572}
2573
2574void AutofillDialogControllerImpl::OnDidAuthenticateInstrument(bool success) {
2575  DCHECK(is_submitting_ && IsPayingWithWallet());
2576
2577  // TODO(dbeam): use the returned full wallet. http://crbug.com/224992
2578  if (success) {
2579    GetFullWallet();
2580  } else {
2581    DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
2582    SuggestionsUpdated();
2583  }
2584}
2585
2586void AutofillDialogControllerImpl::OnDidGetFullWallet(
2587    scoped_ptr<wallet::FullWallet> full_wallet) {
2588  DCHECK(is_submitting_ && IsPayingWithWallet());
2589  ScopedViewUpdates updates(view_.get());
2590
2591  full_wallet_ = full_wallet.Pass();
2592
2593  if (full_wallet_->required_actions().empty()) {
2594    FinishSubmit();
2595    return;
2596  }
2597
2598  switch (full_wallet_->required_actions()[0]) {
2599    case wallet::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
2600      choose_another_instrument_or_address_ = true;
2601      SetIsSubmitting(false);
2602      GetWalletItems();
2603      break;
2604
2605    case wallet::VERIFY_CVV:
2606      SuggestionsUpdated();
2607      break;
2608
2609    default:
2610      DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
2611      return;
2612  }
2613
2614  view_->UpdateNotificationArea();
2615  view_->UpdateButtonStrip();
2616  view_->UpdateOverlay();
2617}
2618
2619void AutofillDialogControllerImpl::OnPassiveSigninSuccess() {
2620  FetchWalletCookie();
2621}
2622
2623void AutofillDialogControllerImpl::OnPassiveSigninFailure(
2624    const GoogleServiceAuthError& error) {
2625  signin_helper_.reset();
2626  passive_failed_ = true;
2627
2628  if (handling_use_wallet_link_click_ ||
2629      GetWalletClient()->user_index() != 0) {
2630    // TODO(estade): When a secondary account is selected and fails passive
2631    // auth, we show a sign in page. Currently we show the generic add account
2632    // page, but we should instead show sign in for the selected account.
2633    // http://crbug.com/323327
2634    SignInLinkClicked();
2635    handling_use_wallet_link_click_ = false;
2636  }
2637
2638  OnWalletSigninError();
2639}
2640
2641void AutofillDialogControllerImpl::OnDidFetchWalletCookieValue(
2642    const std::string& cookie_value) {
2643  wallet_cookie_value_ = cookie_value;
2644  signin_helper_.reset();
2645  GetWalletItems();
2646}
2647
2648void AutofillDialogControllerImpl::OnDidGetWalletItems(
2649    scoped_ptr<wallet::WalletItems> wallet_items) {
2650  legal_documents_text_.clear();
2651  legal_document_link_ranges_.clear();
2652  has_accepted_legal_documents_ = false;
2653
2654  wallet_items_ = wallet_items.Pass();
2655
2656  if (wallet_items_ && !wallet_items_->ObfuscatedGaiaId().empty()) {
2657    // Making sure the user index is in sync shouldn't be necessary, but is an
2658    // extra precaution. But if there is no active account (such as in the
2659    // PASSIVE_AUTH case), stick with the old active account.
2660    GetWalletClient()->SetUserIndex(wallet_items_->active_account_index());
2661
2662    std::vector<std::string> usernames;
2663    for (size_t i = 0; i < wallet_items_->gaia_accounts().size(); ++i) {
2664      usernames.push_back(wallet_items_->gaia_accounts()[i]->email_address());
2665    }
2666    account_chooser_model_->SetWalletAccounts(
2667        usernames, wallet_items_->active_account_index());
2668  }
2669
2670  if (wallet_items_) {
2671    shipping_country_combobox_model_->SetCountries(
2672        *GetManager(),
2673        base::Bind(WalletCountryFilter,
2674                   acceptable_shipping_countries_,
2675                   wallet_items_->allowed_shipping_countries()));
2676
2677    // If the site doesn't ship to any of the countries Wallet allows shipping
2678    // to, the merchant is not supported. (Note we generally shouldn't get here
2679    // as such a merchant wouldn't make it onto the Wallet whitelist.)
2680    if (shipping_country_combobox_model_->GetItemCount() == 0)
2681      DisableWallet(wallet::WalletClient::UNSUPPORTED_MERCHANT);
2682  }
2683
2684  ConstructLegalDocumentsText();
2685  OnWalletOrSigninUpdate();
2686}
2687
2688void AutofillDialogControllerImpl::OnDidSaveToWallet(
2689    const std::string& instrument_id,
2690    const std::string& address_id,
2691    const std::vector<wallet::RequiredAction>& required_actions,
2692    const std::vector<wallet::FormFieldError>& form_field_errors) {
2693  DCHECK(is_submitting_ && IsPayingWithWallet());
2694
2695  if (required_actions.empty()) {
2696    if (!address_id.empty())
2697      active_address_id_ = address_id;
2698    if (!instrument_id.empty())
2699      active_instrument_id_ = instrument_id;
2700    GetFullWallet();
2701  } else {
2702    OnWalletFormFieldError(form_field_errors);
2703    HandleSaveOrUpdateRequiredActions(required_actions);
2704  }
2705}
2706
2707void AutofillDialogControllerImpl::OnWalletError(
2708    wallet::WalletClient::ErrorType error_type) {
2709  DisableWallet(error_type);
2710}
2711
2712////////////////////////////////////////////////////////////////////////////////
2713// PersonalDataManagerObserver implementation.
2714
2715void AutofillDialogControllerImpl::OnPersonalDataChanged() {
2716  if (is_submitting_)
2717    return;
2718
2719  SuggestionsUpdated();
2720}
2721
2722////////////////////////////////////////////////////////////////////////////////
2723// AccountChooserModelDelegate implementation.
2724
2725void AutofillDialogControllerImpl::AccountChoiceChanged() {
2726  ScopedViewUpdates updates(view_.get());
2727  wallet::WalletClient* client = GetWalletClient();
2728
2729  if (is_submitting_)
2730    client->CancelRequest();
2731
2732  SetIsSubmitting(false);
2733
2734  size_t selected_user_index =
2735      account_chooser_model_->GetActiveWalletAccountIndex();
2736  if (account_chooser_model_->WalletIsSelected() &&
2737      client->user_index() != selected_user_index) {
2738    client->SetUserIndex(selected_user_index);
2739    // Clear |wallet_items_| so we don't try to restore the selected instrument
2740    // and address.
2741    wallet_items_.reset();
2742    GetWalletItems();
2743  } else {
2744    SuggestionsUpdated();
2745    UpdateAccountChooserView();
2746  }
2747}
2748
2749void AutofillDialogControllerImpl::AddAccount() {
2750  SignInLinkClicked();
2751}
2752
2753void AutofillDialogControllerImpl::UpdateAccountChooserView() {
2754  if (view_) {
2755    ScopedViewUpdates updates(view_.get());
2756    view_->UpdateAccountChooser();
2757    view_->UpdateNotificationArea();
2758  }
2759}
2760
2761////////////////////////////////////////////////////////////////////////////////
2762
2763bool AutofillDialogControllerImpl::HandleKeyPressEventInInput(
2764    const content::NativeWebKeyboardEvent& event) {
2765  if (popup_controller_.get())
2766    return popup_controller_->HandleKeyPressEvent(event);
2767
2768  return false;
2769}
2770
2771bool AutofillDialogControllerImpl::IsSubmitPausedOn(
2772    wallet::RequiredAction required_action) const {
2773  return full_wallet_ && full_wallet_->HasRequiredAction(required_action);
2774}
2775
2776void AutofillDialogControllerImpl::ShowNewCreditCardBubble(
2777    scoped_ptr<CreditCard> new_card,
2778    scoped_ptr<AutofillProfile> billing_profile) {
2779  NewCreditCardBubbleController::Show(web_contents(),
2780                                      new_card.Pass(),
2781                                      billing_profile.Pass());
2782}
2783
2784void AutofillDialogControllerImpl::SubmitButtonDelayBegin() {
2785  submit_button_delay_timer_.Start(
2786      FROM_HERE,
2787      base::TimeDelta::FromMilliseconds(kSubmitButtonDelayMs),
2788      this,
2789      &AutofillDialogControllerImpl::OnSubmitButtonDelayEnd);
2790}
2791
2792void AutofillDialogControllerImpl::SubmitButtonDelayEndForTesting() {
2793  DCHECK(submit_button_delay_timer_.IsRunning());
2794  submit_button_delay_timer_.user_task().Run();
2795  submit_button_delay_timer_.Stop();
2796}
2797
2798void AutofillDialogControllerImpl::
2799    ClearLastWalletItemsFetchTimestampForTesting() {
2800  last_wallet_items_fetch_timestamp_ = base::TimeTicks();
2801}
2802
2803AccountChooserModel* AutofillDialogControllerImpl::
2804    AccountChooserModelForTesting() {
2805  return account_chooser_model_.get();
2806}
2807
2808bool AutofillDialogControllerImpl::IsSignInContinueUrl(
2809    const GURL& url,
2810    size_t* user_index) const {
2811  return wallet::IsSignInContinueUrl(url, user_index);
2812}
2813
2814AutofillDialogControllerImpl::AutofillDialogControllerImpl(
2815    content::WebContents* contents,
2816    const FormData& form_structure,
2817    const GURL& source_url,
2818    const AutofillClient::ResultCallback& callback)
2819    : WebContentsObserver(contents),
2820      profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
2821      initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
2822      form_structure_(form_structure),
2823      invoked_from_same_origin_(true),
2824      source_url_(source_url),
2825      callback_(callback),
2826      wallet_client_(profile_->GetRequestContext(), this, source_url),
2827      wallet_items_requested_(false),
2828      handling_use_wallet_link_click_(false),
2829      passive_failed_(false),
2830      suggested_cc_(this),
2831      suggested_billing_(this),
2832      suggested_cc_billing_(this),
2833      suggested_shipping_(this),
2834      cares_about_shipping_(true),
2835      popup_input_type_(UNKNOWN_TYPE),
2836      popup_section_(SECTION_MIN),
2837      waiting_for_explicit_sign_in_response_(false),
2838      has_accepted_legal_documents_(false),
2839      is_submitting_(false),
2840      choose_another_instrument_or_address_(false),
2841      wallet_server_validation_recoverable_(true),
2842      data_was_passed_back_(false),
2843      was_ui_latency_logged_(false),
2844      card_generated_animation_(2000, 60, this),
2845      weak_ptr_factory_(this) {
2846  DCHECK(!callback_.is_null());
2847}
2848
2849AutofillDialogView* AutofillDialogControllerImpl::CreateView() {
2850  return AutofillDialogView::Create(this);
2851}
2852
2853PersonalDataManager* AutofillDialogControllerImpl::GetManager() const {
2854  return PersonalDataManagerFactory::GetForProfile(profile_);
2855}
2856
2857AddressValidator* AutofillDialogControllerImpl::GetValidator() {
2858  return validator_.get();
2859}
2860
2861const wallet::WalletClient* AutofillDialogControllerImpl::GetWalletClient()
2862    const {
2863  return const_cast<AutofillDialogControllerImpl*>(this)->GetWalletClient();
2864}
2865
2866wallet::WalletClient* AutofillDialogControllerImpl::GetWalletClient() {
2867  return &wallet_client_;
2868}
2869
2870bool AutofillDialogControllerImpl::IsPayingWithWallet() const {
2871  return account_chooser_model_->WalletIsSelected() &&
2872         SignedInState() == SIGNED_IN;
2873}
2874
2875void AutofillDialogControllerImpl::LoadRiskFingerprintData() {
2876  risk_data_.clear();
2877
2878  uint64 obfuscated_gaia_id = 0;
2879  bool success = base::StringToUint64(wallet_items_->ObfuscatedGaiaId(),
2880                                      &obfuscated_gaia_id);
2881  DCHECK(success);
2882
2883  gfx::Rect window_bounds;
2884  window_bounds = GetBaseWindowForWebContents(web_contents())->GetBounds();
2885
2886  PrefService* user_prefs = profile_->GetPrefs();
2887  std::string charset = user_prefs->GetString(::prefs::kDefaultCharset);
2888  std::string accept_languages =
2889      user_prefs->GetString(::prefs::kAcceptLanguages);
2890  base::Time install_time = base::Time::FromTimeT(
2891      g_browser_process->metrics_service()->GetInstallDate());
2892
2893  risk::GetFingerprint(
2894      obfuscated_gaia_id, window_bounds, web_contents(),
2895      chrome::VersionInfo().Version(), charset, accept_languages, install_time,
2896      g_browser_process->GetApplicationLocale(), GetUserAgent(),
2897      base::Bind(&AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData,
2898                 weak_ptr_factory_.GetWeakPtr()));
2899}
2900
2901void AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData(
2902    scoped_ptr<risk::Fingerprint> fingerprint) {
2903  DCHECK(AreLegalDocumentsCurrent());
2904
2905  std::string proto_data;
2906  fingerprint->SerializeToString(&proto_data);
2907  base::Base64Encode(proto_data, &risk_data_);
2908
2909  SubmitWithWallet();
2910}
2911
2912void AutofillDialogControllerImpl::OpenTabWithUrl(const GURL& url) {
2913  chrome::NavigateParams params(
2914      chrome::FindBrowserWithWebContents(web_contents()),
2915      url,
2916      ui::PAGE_TRANSITION_LINK);
2917  params.disposition = NEW_FOREGROUND_TAB;
2918  chrome::Navigate(&params);
2919}
2920
2921DialogSection AutofillDialogControllerImpl::ActiveBillingSection() const {
2922  return IsPayingWithWallet() ? SECTION_CC_BILLING : SECTION_BILLING;
2923}
2924
2925bool AutofillDialogControllerImpl::IsEditingExistingData(
2926    DialogSection section) const {
2927  return section_editing_state_.count(section) > 0;
2928}
2929
2930bool AutofillDialogControllerImpl::IsManuallyEditingSection(
2931    DialogSection section) const {
2932  return IsEditingExistingData(section) ||
2933         SuggestionsMenuModelForSection(section)->
2934             GetItemKeyForCheckedItem() == kAddNewItemKey;
2935}
2936
2937void AutofillDialogControllerImpl::OnWalletSigninError() {
2938  account_chooser_model_->SetHadWalletSigninError();
2939  GetWalletClient()->CancelRequest();
2940  LogDialogLatencyToShow();
2941}
2942
2943void AutofillDialogControllerImpl::DisableWallet(
2944    wallet::WalletClient::ErrorType error_type) {
2945  signin_helper_.reset();
2946  wallet_items_.reset();
2947  wallet_errors_.clear();
2948  GetWalletClient()->CancelRequest();
2949  SetIsSubmitting(false);
2950  wallet_error_notification_ = GetWalletError(error_type);
2951  account_chooser_model_->SetHadWalletError();
2952}
2953
2954void AutofillDialogControllerImpl::SuggestionsUpdated() {
2955  ScopedViewUpdates updates(view_.get());
2956
2957  const FieldValueMap snapshot = TakeUserInputSnapshot();
2958
2959  suggested_cc_.Reset();
2960  suggested_billing_.Reset();
2961  suggested_cc_billing_.Reset();
2962  suggested_shipping_.Reset();
2963  HidePopup();
2964
2965  suggested_shipping_.AddKeyedItem(
2966      kSameAsBillingKey,
2967      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_USE_BILLING_FOR_SHIPPING));
2968
2969  if (IsPayingWithWallet()) {
2970    const std::vector<wallet::Address*>& addresses =
2971        wallet_items_->addresses();
2972
2973    bool shipping_same_as_billing = profile_->GetPrefs()->GetBoolean(
2974        ::prefs::kAutofillDialogWalletShippingSameAsBilling);
2975
2976    if (shipping_same_as_billing)
2977      suggested_shipping_.SetCheckedItem(kSameAsBillingKey);
2978
2979    for (size_t i = 0; i < addresses.size(); ++i) {
2980      std::string key = base::IntToString(i);
2981      suggested_shipping_.AddKeyedItemWithMinorText(
2982          key,
2983          addresses[i]->DisplayName(),
2984          addresses[i]->DisplayNameDetail());
2985      suggested_shipping_.SetEnabled(
2986          key,
2987          CanAcceptCountry(SECTION_SHIPPING,
2988                           addresses[i]->country_name_code()));
2989
2990      // TODO(scr): Move this assignment outside the loop or comment why it
2991      // can't be there.
2992      const std::string default_shipping_address_id =
2993          GetIdToSelect(wallet_items_->default_address_id(),
2994                        previous_default_shipping_address_id_,
2995                        previously_selected_shipping_address_id_);
2996
2997      if (!shipping_same_as_billing &&
2998          addresses[i]->object_id() == default_shipping_address_id) {
2999        suggested_shipping_.SetCheckedItem(key);
3000      }
3001    }
3002
3003    if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
3004      const std::vector<wallet::WalletItems::MaskedInstrument*>& instruments =
3005          wallet_items_->instruments();
3006      std::string first_active_instrument_key;
3007      std::string default_instrument_key;
3008      for (size_t i = 0; i < instruments.size(); ++i) {
3009        bool allowed = IsInstrumentAllowed(*instruments[i]) &&
3010            CanAcceptCountry(SECTION_BILLING,
3011                             instruments[i]->address().country_name_code());
3012        gfx::Image icon = instruments[i]->CardIcon();
3013        if (!allowed && !icon.IsEmpty()) {
3014          // Create a grayed disabled icon.
3015          SkBitmap disabled_bitmap = SkBitmapOperations::CreateHSLShiftedBitmap(
3016              *icon.ToSkBitmap(), kGrayImageShift);
3017          icon = gfx::Image(
3018              gfx::ImageSkia::CreateFrom1xBitmap(disabled_bitmap));
3019        }
3020        std::string key = base::IntToString(i);
3021        suggested_cc_billing_.AddKeyedItemWithMinorTextAndIcon(
3022            key,
3023            instruments[i]->DisplayName(),
3024            instruments[i]->DisplayNameDetail(),
3025            icon);
3026        suggested_cc_billing_.SetEnabled(key, allowed);
3027
3028        if (allowed) {
3029          if (first_active_instrument_key.empty())
3030            first_active_instrument_key = key;
3031
3032          const std::string default_instrument_id =
3033              GetIdToSelect(wallet_items_->default_instrument_id(),
3034                            previous_default_instrument_id_,
3035                            previously_selected_instrument_id_);
3036          if (instruments[i]->object_id() == default_instrument_id)
3037            default_instrument_key = key;
3038        }
3039      }
3040
3041      suggested_cc_billing_.AddKeyedItem(
3042          kAddNewItemKey,
3043          l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_BILLING_DETAILS));
3044      if (!wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)) {
3045        suggested_cc_billing_.AddKeyedItemWithMinorText(
3046            kManageItemsKey,
3047            l10n_util::GetStringUTF16(
3048                IDS_AUTOFILL_DIALOG_MANAGE_BILLING_DETAILS),
3049                base::UTF8ToUTF16(wallet::GetManageInstrumentsUrl(0U).host()));
3050      }
3051
3052      // Determine which instrument item should be selected.
3053      if (!default_instrument_key.empty())
3054        suggested_cc_billing_.SetCheckedItem(default_instrument_key);
3055      else if (!first_active_instrument_key.empty())
3056        suggested_cc_billing_.SetCheckedItem(first_active_instrument_key);
3057      else
3058        suggested_cc_billing_.SetCheckedItem(kAddNewItemKey);
3059    }
3060  } else {
3061    shipping_country_combobox_model_->SetCountries(
3062        *GetManager(),
3063        base::Bind(AutofillCountryFilter, acceptable_shipping_countries_));
3064
3065    if (IsAutofillEnabled()) {
3066      PersonalDataManager* manager = GetManager();
3067      const std::vector<CreditCard*>& cards = manager->GetCreditCards();
3068      ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
3069      for (size_t i = 0; i < cards.size(); ++i) {
3070        if (!i18ninput::CardHasCompleteAndVerifiedData(*cards[i]))
3071          continue;
3072
3073        suggested_cc_.AddKeyedItemWithIcon(
3074            cards[i]->guid(),
3075            cards[i]->Label(),
3076            rb.GetImageNamed(CreditCard::IconResourceId(cards[i]->type())));
3077        suggested_cc_.SetEnabled(
3078            cards[i]->guid(),
3079            !ShouldDisallowCcType(cards[i]->TypeForDisplay()));
3080      }
3081
3082      const std::vector<AutofillProfile*>& profiles = manager->GetProfiles();
3083      std::vector<base::string16> labels;
3084      AutofillProfile::CreateDifferentiatingLabels(
3085          profiles,
3086          g_browser_process->GetApplicationLocale(),
3087          &labels);
3088      DCHECK_EQ(labels.size(), profiles.size());
3089      for (size_t i = 0; i < profiles.size(); ++i) {
3090        const AutofillProfile& profile = *profiles[i];
3091        if (!i18ninput::AddressHasCompleteAndVerifiedData(
3092                profile, g_browser_process->GetApplicationLocale())) {
3093          continue;
3094        }
3095
3096        // Don't add variants for addresses: name is part of credit card and
3097        // we'll just ignore email and phone number variants.
3098        suggested_shipping_.AddKeyedItem(profile.guid(), labels[i]);
3099        suggested_shipping_.SetEnabled(
3100            profile.guid(),
3101            CanAcceptCountry(
3102                SECTION_SHIPPING,
3103                base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))));
3104        if (!profile.GetRawInfo(EMAIL_ADDRESS).empty() &&
3105            !profile.IsPresentButInvalid(EMAIL_ADDRESS)) {
3106          suggested_billing_.AddKeyedItem(profile.guid(), labels[i]);
3107          suggested_billing_.SetEnabled(
3108              profile.guid(),
3109              CanAcceptCountry(
3110                  SECTION_BILLING,
3111                  base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))));
3112        }
3113      }
3114    }
3115
3116    suggested_cc_.AddKeyedItem(
3117        kAddNewItemKey,
3118        l10n_util::GetStringUTF16(IsAutofillEnabled() ?
3119            IDS_AUTOFILL_DIALOG_ADD_CREDIT_CARD :
3120            IDS_AUTOFILL_DIALOG_ENTER_CREDIT_CARD));
3121    suggested_cc_.AddKeyedItem(
3122        kManageItemsKey,
3123        l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_CREDIT_CARD));
3124    suggested_billing_.AddKeyedItem(
3125        kAddNewItemKey,
3126        l10n_util::GetStringUTF16(IsAutofillEnabled() ?
3127            IDS_AUTOFILL_DIALOG_ADD_BILLING_ADDRESS :
3128            IDS_AUTOFILL_DIALOG_ENTER_BILLING_DETAILS));
3129    suggested_billing_.AddKeyedItem(
3130        kManageItemsKey,
3131        l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_BILLING_ADDRESS));
3132  }
3133
3134  suggested_shipping_.AddKeyedItem(
3135      kAddNewItemKey,
3136      l10n_util::GetStringUTF16(IsPayingWithWallet() || IsAutofillEnabled() ?
3137          IDS_AUTOFILL_DIALOG_ADD_SHIPPING_ADDRESS :
3138          IDS_AUTOFILL_DIALOG_USE_DIFFERENT_SHIPPING_ADDRESS));
3139
3140  if (!IsPayingWithWallet()) {
3141    if (IsAutofillEnabled()) {
3142      suggested_shipping_.AddKeyedItem(
3143          kManageItemsKey,
3144          l10n_util::GetStringUTF16(
3145              IDS_AUTOFILL_DIALOG_MANAGE_SHIPPING_ADDRESS));
3146    }
3147  } else if (!wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)) {
3148    suggested_shipping_.AddKeyedItemWithMinorText(
3149        kManageItemsKey,
3150        l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_SHIPPING_ADDRESS),
3151        base::UTF8ToUTF16(wallet::GetManageAddressesUrl(0U).host()));
3152  }
3153
3154  if (!IsPayingWithWallet() && IsAutofillEnabled()) {
3155    for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3156      DialogSection section = static_cast<DialogSection>(i);
3157      if (!SectionIsActive(section))
3158        continue;
3159
3160      // Set the starting choice for the menu. First set to the default in case
3161      // the GUID saved in prefs refers to a profile that no longer exists.
3162      std::string guid;
3163      GetDefaultAutofillChoice(section, &guid);
3164      SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
3165      model->SetCheckedItem(guid);
3166      if (GetAutofillChoice(section, &guid))
3167        model->SetCheckedItem(guid);
3168    }
3169  }
3170
3171  if (view_)
3172    view_->ModelChanged();
3173
3174  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3175    ResetSectionInput(static_cast<DialogSection>(i));
3176  }
3177
3178  FieldValueMap::const_iterator billing_it =
3179      snapshot.find(ADDRESS_BILLING_COUNTRY);
3180  if (billing_it != snapshot.end())
3181    RebuildInputsForCountry(ActiveBillingSection(), billing_it->second, true);
3182
3183  FieldValueMap::const_iterator shipping_it =
3184      snapshot.find(ADDRESS_HOME_COUNTRY);
3185  if (shipping_it != snapshot.end())
3186    RebuildInputsForCountry(SECTION_SHIPPING, shipping_it->second, true);
3187
3188  RestoreUserInputFromSnapshot(snapshot);
3189
3190  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3191    DialogSection section = static_cast<DialogSection>(i);
3192    if (!SectionIsActive(section))
3193      continue;
3194
3195    ShowEditUiIfBadSuggestion(section);
3196    UpdateSection(section);
3197  }
3198
3199  UpdateForErrors();
3200}
3201
3202void AutofillDialogControllerImpl::FillOutputForSectionWithComparator(
3203    DialogSection section,
3204    const FormStructure::InputFieldComparator& compare) {
3205  if (!SectionIsActive(section))
3206    return;
3207
3208  DetailInputs inputs;
3209  std::string country_code = CountryCodeForSection(section);
3210  BuildInputsForSection(section, country_code, &inputs,
3211                        MutableAddressLanguageCodeForSection(section));
3212  std::vector<ServerFieldType> types = common::TypesFromInputs(inputs);
3213
3214  scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
3215  if (wrapper) {
3216    // Only fill in data that is associated with this section.
3217    wrapper->FillFormStructure(types, compare, &form_structure_);
3218
3219    // CVC needs special-casing because the CreditCard class doesn't store or
3220    // handle them. This isn't necessary when filling the combined CC and
3221    // billing section as CVC comes from |full_wallet_| in this case.
3222    if (section == SECTION_CC)
3223      SetOutputForFieldsOfType(CREDIT_CARD_VERIFICATION_CODE, view_->GetCvc());
3224
3225    // When filling from Wallet data, use the email address associated with the
3226    // account. There is no other email address stored as part of a Wallet
3227    // address.
3228    if (section == SECTION_CC_BILLING) {
3229      SetOutputForFieldsOfType(
3230          EMAIL_ADDRESS, account_chooser_model_->GetActiveWalletAccountName());
3231    }
3232  } else {
3233    // The user manually input data. If using Autofill, save the info as new or
3234    // edited data. Always fill local data into |form_structure_|.
3235    FieldValueMap output;
3236    view_->GetUserInput(section, &output);
3237
3238    if (section == SECTION_CC) {
3239      CreditCard card;
3240      FillFormGroupFromOutputs(output, &card);
3241
3242      // The card holder name comes from the billing address section.
3243      card.SetRawInfo(CREDIT_CARD_NAME,
3244                      GetValueFromSection(SECTION_BILLING, NAME_BILLING_FULL));
3245
3246      if (ShouldSaveDetailsLocally()) {
3247        card.set_origin(kAutofillDialogOrigin);
3248
3249        std::string guid = GetManager()->SaveImportedCreditCard(card);
3250        newly_saved_data_model_guids_[section] = guid;
3251        DCHECK(!profile()->IsOffTheRecord());
3252        newly_saved_card_.reset(new CreditCard(card));
3253      }
3254
3255      AutofillCreditCardWrapper card_wrapper(&card);
3256      card_wrapper.FillFormStructure(types, compare, &form_structure_);
3257
3258      // Again, CVC needs special-casing. Fill it in directly from |output|.
3259      SetOutputForFieldsOfType(
3260          CREDIT_CARD_VERIFICATION_CODE,
3261          output[CREDIT_CARD_VERIFICATION_CODE]);
3262    } else {
3263      AutofillProfile profile;
3264      FillFormGroupFromOutputs(output, &profile);
3265      profile.set_language_code(AddressLanguageCodeForSection(section));
3266
3267      if (ShouldSaveDetailsLocally()) {
3268        profile.set_origin(RulesAreLoaded(section) ?
3269            kAutofillDialogOrigin : source_url_.GetOrigin().spec());
3270
3271        std::string guid = GetManager()->SaveImportedProfile(profile);
3272        newly_saved_data_model_guids_[section] = guid;
3273      }
3274
3275      AutofillProfileWrapper profile_wrapper(&profile);
3276      profile_wrapper.FillFormStructure(types, compare, &form_structure_);
3277    }
3278  }
3279}
3280
3281void AutofillDialogControllerImpl::FillOutputForSection(DialogSection section) {
3282  FillOutputForSectionWithComparator(
3283      section, base::Bind(common::ServerTypeMatchesField, section));
3284}
3285
3286bool AutofillDialogControllerImpl::FormStructureCaresAboutSection(
3287    DialogSection section) const {
3288  // For now, only SECTION_SHIPPING may be omitted due to a site not asking for
3289  // any of the fields.
3290  if (section == SECTION_SHIPPING)
3291    return cares_about_shipping_;
3292
3293  return true;
3294}
3295
3296void AutofillDialogControllerImpl::SetOutputForFieldsOfType(
3297    ServerFieldType type,
3298    const base::string16& output) {
3299  for (size_t i = 0; i < form_structure_.field_count(); ++i) {
3300    AutofillField* field = form_structure_.field(i);
3301    if (field->Type().GetStorableType() == type)
3302      field->value = output;
3303  }
3304}
3305
3306base::string16 AutofillDialogControllerImpl::GetValueFromSection(
3307    DialogSection section,
3308    ServerFieldType type) {
3309  DCHECK(SectionIsActive(section));
3310
3311  scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
3312  if (wrapper)
3313    return wrapper->GetInfo(AutofillType(type));
3314
3315  FieldValueMap output;
3316  view_->GetUserInput(section, &output);
3317  return output[type];
3318}
3319
3320bool AutofillDialogControllerImpl::CanAcceptCountry(
3321    DialogSection section,
3322    const std::string& country_code) {
3323  DCHECK_EQ(2U, country_code.size());
3324
3325  if (section == SECTION_CC_BILLING)
3326    return LowerCaseEqualsASCII(country_code, "us");
3327
3328  CountryComboboxModel* model = CountryComboboxModelForSection(section);
3329  const std::vector<AutofillCountry*>& countries = model->countries();
3330  for (size_t i = 0; i < countries.size(); ++i) {
3331    if (countries[i] && countries[i]->country_code() == country_code)
3332      return true;
3333  }
3334
3335  return false;
3336}
3337
3338bool AutofillDialogControllerImpl::ShouldSuggestProfile(
3339    DialogSection section,
3340    const AutofillProfile& profile) {
3341  std::string country_code =
3342      base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
3343  return country_code.empty() || CanAcceptCountry(section, country_code);
3344}
3345
3346SuggestionsMenuModel* AutofillDialogControllerImpl::
3347    SuggestionsMenuModelForSection(DialogSection section) {
3348  switch (section) {
3349    case SECTION_CC:
3350      return &suggested_cc_;
3351    case SECTION_BILLING:
3352      return &suggested_billing_;
3353    case SECTION_SHIPPING:
3354      return &suggested_shipping_;
3355    case SECTION_CC_BILLING:
3356      return &suggested_cc_billing_;
3357  }
3358
3359  NOTREACHED();
3360  return NULL;
3361}
3362
3363const SuggestionsMenuModel* AutofillDialogControllerImpl::
3364    SuggestionsMenuModelForSection(DialogSection section) const {
3365  return const_cast<AutofillDialogControllerImpl*>(this)->
3366      SuggestionsMenuModelForSection(section);
3367}
3368
3369DialogSection AutofillDialogControllerImpl::SectionForSuggestionsMenuModel(
3370    const SuggestionsMenuModel& model) {
3371  if (&model == &suggested_cc_)
3372    return SECTION_CC;
3373
3374  if (&model == &suggested_billing_)
3375    return SECTION_BILLING;
3376
3377  if (&model == &suggested_cc_billing_)
3378    return SECTION_CC_BILLING;
3379
3380  DCHECK_EQ(&model, &suggested_shipping_);
3381  return SECTION_SHIPPING;
3382}
3383
3384CountryComboboxModel* AutofillDialogControllerImpl::
3385    CountryComboboxModelForSection(DialogSection section) {
3386  if (section == SECTION_BILLING)
3387    return billing_country_combobox_model_.get();
3388
3389  if (section == SECTION_SHIPPING)
3390    return shipping_country_combobox_model_.get();
3391
3392  return NULL;
3393}
3394
3395void AutofillDialogControllerImpl::GetI18nValidatorSuggestions(
3396    DialogSection section,
3397    ServerFieldType type,
3398    std::vector<base::string16>* popup_values,
3399    std::vector<base::string16>* popup_labels,
3400    std::vector<base::string16>* popup_icons) {
3401  AddressField focused_field;
3402  if (!i18n::FieldForType(type, &focused_field))
3403    return;
3404
3405  FieldValueMap inputs;
3406  view_->GetUserInput(section, &inputs);
3407
3408  AutofillProfile profile;
3409  FillFormGroupFromOutputs(inputs, &profile);
3410
3411  scoped_ptr<AddressData> user_input =
3412      i18n::CreateAddressDataFromAutofillProfile(
3413          profile, g_browser_process->GetApplicationLocale());
3414  user_input->language_code = AddressLanguageCodeForSection(section);
3415
3416  static const size_t kSuggestionsLimit = 10;
3417  AddressValidator::Status status = GetValidator()->GetSuggestions(
3418      *user_input, focused_field, kSuggestionsLimit,
3419      &i18n_validator_suggestions_);
3420
3421  if (status != AddressValidator::SUCCESS)
3422    return;
3423
3424  for (size_t i = 0; i < i18n_validator_suggestions_.size(); ++i) {
3425    popup_values->push_back(base::UTF8ToUTF16(
3426        i18n_validator_suggestions_[i].GetFieldValue(focused_field)));
3427
3428    // Disambiguate the suggestion by showing the smallest administrative
3429    // region of the suggested address:
3430    //    ADMIN_AREA > LOCALITY > DEPENDENT_LOCALITY
3431    popup_labels->push_back(base::string16());
3432    for (int field = DEPENDENT_LOCALITY; field >= ADMIN_AREA; --field) {
3433      const std::string& field_value =
3434          i18n_validator_suggestions_[i].GetFieldValue(
3435              static_cast<AddressField>(field));
3436      if (focused_field != field && !field_value.empty()) {
3437        popup_labels->back().assign(base::UTF8ToUTF16(field_value));
3438        break;
3439      }
3440    }
3441  }
3442  popup_icons->resize(popup_values->size());
3443}
3444
3445DetailInputs* AutofillDialogControllerImpl::MutableRequestedFieldsForSection(
3446    DialogSection section) {
3447  return const_cast<DetailInputs*>(&RequestedFieldsForSection(section));
3448}
3449
3450std::string* AutofillDialogControllerImpl::MutableAddressLanguageCodeForSection(
3451    DialogSection section) {
3452  switch (section) {
3453    case SECTION_BILLING:
3454    case SECTION_CC_BILLING:
3455      return &billing_address_language_code_;
3456    case SECTION_SHIPPING:
3457      return &shipping_address_language_code_;
3458    case SECTION_CC:
3459      return NULL;
3460  }
3461  NOTREACHED();
3462  return NULL;
3463}
3464
3465std::string AutofillDialogControllerImpl::AddressLanguageCodeForSection(
3466    DialogSection section) {
3467  std::string* language_code = MutableAddressLanguageCodeForSection(section);
3468  return language_code != NULL ? *language_code : std::string();
3469}
3470
3471std::vector<ServerFieldType> AutofillDialogControllerImpl::
3472    RequestedTypesForSection(DialogSection section) const {
3473  return common::TypesFromInputs(RequestedFieldsForSection(section));
3474}
3475
3476std::string AutofillDialogControllerImpl::CountryCodeForSection(
3477    DialogSection section) {
3478  base::string16 country;
3479
3480  scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
3481  if (wrapper) {
3482    country = wrapper->GetInfo(AutofillType(CountryTypeForSection(section)));
3483  } else {
3484    FieldValueMap outputs;
3485    view_->GetUserInput(section, &outputs);
3486    country = outputs[CountryTypeForSection(section)];
3487  }
3488
3489  return AutofillCountry::GetCountryCode(
3490      country, g_browser_process->GetApplicationLocale());
3491}
3492
3493bool AutofillDialogControllerImpl::RebuildInputsForCountry(
3494    DialogSection section,
3495    const base::string16& country_name,
3496    bool should_clobber) {
3497  CountryComboboxModel* model = CountryComboboxModelForSection(section);
3498  if (!model)
3499    return false;
3500
3501  std::string country_code = AutofillCountry::GetCountryCode(
3502      country_name, g_browser_process->GetApplicationLocale());
3503  DCHECK(CanAcceptCountry(section, country_code));
3504
3505  if (view_ && !should_clobber) {
3506    FieldValueMap outputs;
3507    view_->GetUserInput(section, &outputs);
3508
3509    // If |country_name| is the same as the view, no-op and let the caller know.
3510    if (outputs[CountryTypeForSection(section)] == country_name)
3511      return false;
3512  }
3513
3514  DetailInputs* inputs = MutableRequestedFieldsForSection(section);
3515  inputs->clear();
3516  BuildInputsForSection(section, country_code, inputs,
3517                        MutableAddressLanguageCodeForSection(section));
3518
3519  if (!country_code.empty()) {
3520    GetValidator()->LoadRules(AutofillCountry::GetCountryCode(
3521        country_name, g_browser_process->GetApplicationLocale()));
3522  }
3523
3524  return true;
3525}
3526
3527void AutofillDialogControllerImpl::HidePopup() {
3528  if (popup_controller_)
3529    popup_controller_->Hide();
3530  popup_input_type_ = UNKNOWN_TYPE;
3531}
3532
3533void AutofillDialogControllerImpl::SetEditingExistingData(
3534    DialogSection section, bool editing) {
3535  if (editing)
3536    section_editing_state_.insert(section);
3537  else
3538    section_editing_state_.erase(section);
3539}
3540
3541bool AutofillDialogControllerImpl::IsASuggestionItemKey(
3542    const std::string& key) const {
3543  return !key.empty() &&
3544      key != kAddNewItemKey &&
3545      key != kManageItemsKey &&
3546      key != kSameAsBillingKey;
3547}
3548
3549bool AutofillDialogControllerImpl::IsAutofillEnabled() const {
3550  return profile_->GetPrefs()->GetBoolean(prefs::kAutofillEnabled);
3551}
3552
3553bool AutofillDialogControllerImpl::IsManuallyEditingAnySection() const {
3554  for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
3555    if (IsManuallyEditingSection(static_cast<DialogSection>(section)))
3556      return true;
3557  }
3558  return false;
3559}
3560
3561base::string16 AutofillDialogControllerImpl::CreditCardNumberValidityMessage(
3562    const base::string16& number) const {
3563  if (!number.empty() && !autofill::IsValidCreditCardNumber(number)) {
3564    return l10n_util::GetStringUTF16(
3565        IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_NUMBER);
3566  }
3567
3568  if (!IsPayingWithWallet() &&
3569      ShouldDisallowCcType(CreditCard::TypeForDisplay(
3570          CreditCard::GetCreditCardType(number)))) {
3571    int ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_GENERIC_CARD;
3572    const char* const type = CreditCard::GetCreditCardType(number);
3573    if (type == kAmericanExpressCard)
3574      ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_AMEX;
3575    else if (type == kDiscoverCard)
3576      ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_DISCOVER;
3577    else if (type == kMasterCard)
3578      ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_MASTERCARD;
3579    else if (type == kVisaCard)
3580      ids = IDS_AUTOFILL_DIALOG_VALIDATION_UNACCEPTED_VISA;
3581
3582    return l10n_util::GetStringUTF16(ids);
3583  }
3584
3585  base::string16 message;
3586  if (IsPayingWithWallet() && !wallet_items_->SupportsCard(number, &message))
3587    return message;
3588
3589  // Card number is good and supported.
3590  return base::string16();
3591}
3592
3593bool AutofillDialogControllerImpl::AllSectionsAreValid() {
3594  for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
3595    if (!SectionIsValid(static_cast<DialogSection>(section)))
3596      return false;
3597  }
3598  return true;
3599}
3600
3601bool AutofillDialogControllerImpl::SectionIsValid(
3602    DialogSection section) {
3603  if (!IsManuallyEditingSection(section))
3604    return true;
3605
3606  FieldValueMap detail_outputs;
3607  view_->GetUserInput(section, &detail_outputs);
3608  return !InputsAreValid(section, detail_outputs).HasSureErrors();
3609}
3610
3611bool AutofillDialogControllerImpl::RulesAreLoaded(DialogSection section) {
3612  AddressData address_data;
3613  address_data.region_code = CountryCodeForSection(section);
3614  AddressValidator::Status status = GetValidator()->ValidateAddress(
3615      address_data, NULL, NULL);
3616  return status == AddressValidator::SUCCESS;
3617}
3618
3619bool AutofillDialogControllerImpl::IsCreditCardExpirationValid(
3620    const base::string16& year,
3621    const base::string16& month) const {
3622  // If the expiration is in the past as per the local clock, it's invalid.
3623  base::Time now = base::Time::Now();
3624  if (!autofill::IsValidCreditCardExpirationDate(year, month, now))
3625    return false;
3626
3627  const wallet::WalletItems::MaskedInstrument* instrument =
3628      ActiveInstrument();
3629  if (instrument) {
3630    const std::string& locale = g_browser_process->GetApplicationLocale();
3631    int month_int;
3632    if (base::StringToInt(month, &month_int) &&
3633        instrument->status() ==
3634            wallet::WalletItems::MaskedInstrument::EXPIRED &&
3635        year ==
3636            instrument->GetInfo(
3637                AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), locale) &&
3638        month_int == instrument->expiration_month()) {
3639      // Otherwise, if the user is editing an instrument that's deemed expired
3640      // by the Online Wallet server, mark it invalid on selection.
3641      return false;
3642    }
3643  }
3644
3645  return true;
3646}
3647
3648bool AutofillDialogControllerImpl::ShouldDisallowCcType(
3649    const base::string16& type) const {
3650  if (acceptable_cc_types_.empty())
3651    return false;
3652
3653  if (acceptable_cc_types_.find(base::i18n::ToUpper(type)) ==
3654          acceptable_cc_types_.end()) {
3655    return true;
3656  }
3657
3658  return false;
3659}
3660
3661bool AutofillDialogControllerImpl::HasInvalidAddress(
3662    const AutofillProfile& profile) {
3663  scoped_ptr<AddressData> address_data =
3664      i18n::CreateAddressDataFromAutofillProfile(
3665          profile, g_browser_process->GetApplicationLocale());
3666
3667  FieldProblemMap problems;
3668  GetValidator()->ValidateAddress(*address_data, NULL, &problems);
3669  return !problems.empty();
3670}
3671
3672bool AutofillDialogControllerImpl::ShouldUseBillingForShipping() {
3673  return SectionIsActive(SECTION_SHIPPING) &&
3674      suggested_shipping_.GetItemKeyForCheckedItem() == kSameAsBillingKey;
3675}
3676
3677bool AutofillDialogControllerImpl::ShouldSaveDetailsLocally() {
3678  // It's possible that the user checked [X] Save details locally before
3679  // switching payment methods, so only ask the view whether to save details
3680  // locally if that checkbox is showing (currently if not paying with wallet).
3681  // Also, if the user isn't editing any sections, there's no data to save
3682  // locally.
3683  return ShouldOfferToSaveInChrome() && view_->SaveDetailsLocally();
3684}
3685
3686void AutofillDialogControllerImpl::SetIsSubmitting(bool submitting) {
3687  is_submitting_ = submitting;
3688
3689  if (!submitting)
3690    full_wallet_.reset();
3691
3692  if (view_) {
3693    ScopedViewUpdates updates(view_.get());
3694    view_->UpdateButtonStrip();
3695    view_->UpdateOverlay();
3696    view_->UpdateNotificationArea();
3697  }
3698}
3699
3700bool AutofillDialogControllerImpl::AreLegalDocumentsCurrent() const {
3701  return has_accepted_legal_documents_ ||
3702      (wallet_items_ && wallet_items_->legal_documents().empty());
3703}
3704
3705void AutofillDialogControllerImpl::AcceptLegalTerms() {
3706  content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices();
3707  PrefService* local_state = g_browser_process->local_state();
3708  ListPrefUpdate accepted(
3709      local_state, ::prefs::kAutofillDialogWalletLocationAcceptance);
3710  accepted->AppendIfNotPresent(new base::StringValue(
3711      account_chooser_model_->GetActiveWalletAccountName()));
3712
3713  if (AreLegalDocumentsCurrent()) {
3714    LoadRiskFingerprintData();
3715  } else {
3716    GetWalletClient()->AcceptLegalDocuments(
3717        wallet_items_->legal_documents(),
3718        wallet_items_->google_transaction_id());
3719  }
3720}
3721
3722void AutofillDialogControllerImpl::SubmitWithWallet() {
3723  active_instrument_id_.clear();
3724  active_address_id_.clear();
3725  full_wallet_.reset();
3726
3727  const wallet::WalletItems::MaskedInstrument* active_instrument =
3728      ActiveInstrument();
3729  if (!IsManuallyEditingSection(SECTION_CC_BILLING)) {
3730    active_instrument_id_ = active_instrument->object_id();
3731    DCHECK(!active_instrument_id_.empty());
3732  }
3733
3734  const wallet::Address* active_address = ActiveShippingAddress();
3735  if (!IsManuallyEditingSection(SECTION_SHIPPING) &&
3736      !ShouldUseBillingForShipping() &&
3737      IsShippingAddressRequired()) {
3738    active_address_id_ = active_address->object_id();
3739    DCHECK(!active_address_id_.empty());
3740  }
3741
3742  scoped_ptr<wallet::Instrument> inputted_instrument =
3743      CreateTransientInstrument();
3744
3745  scoped_ptr<wallet::Address> inputted_address;
3746  if (active_address_id_.empty() && IsShippingAddressRequired()) {
3747    if (ShouldUseBillingForShipping()) {
3748      const wallet::Address& address = inputted_instrument ?
3749          *inputted_instrument->address() : active_instrument->address();
3750      // Try to find an exact matched shipping address and use it for shipping,
3751      // otherwise save it as a new shipping address. http://crbug.com/225442
3752      const wallet::Address* duplicated_address =
3753          FindDuplicateAddress(wallet_items_->addresses(), address);
3754      if (duplicated_address) {
3755        active_address_id_ = duplicated_address->object_id();
3756        DCHECK(!active_address_id_.empty());
3757      } else {
3758        inputted_address.reset(new wallet::Address(address));
3759        DCHECK(inputted_address->object_id().empty());
3760      }
3761    } else {
3762      inputted_address = CreateTransientAddress();
3763    }
3764  }
3765
3766  // If there's neither an address nor instrument to save, |GetFullWallet()|
3767  // is called when the risk fingerprint is loaded.
3768  if (!active_instrument_id_.empty() &&
3769      (!active_address_id_.empty() || !IsShippingAddressRequired())) {
3770    GetFullWallet();
3771    return;
3772  }
3773
3774  GetWalletClient()->SaveToWallet(
3775      inputted_instrument.Pass(),
3776      inputted_address.Pass(),
3777      IsEditingExistingData(SECTION_CC_BILLING) ? active_instrument : NULL,
3778      IsEditingExistingData(SECTION_SHIPPING) ? active_address : NULL);
3779}
3780
3781scoped_ptr<wallet::Instrument> AutofillDialogControllerImpl::
3782    CreateTransientInstrument() {
3783  if (!active_instrument_id_.empty())
3784    return scoped_ptr<wallet::Instrument>();
3785
3786  FieldValueMap output;
3787  view_->GetUserInput(SECTION_CC_BILLING, &output);
3788
3789  CreditCard card;
3790  AutofillProfile profile;
3791  base::string16 cvc;
3792  GetBillingInfoFromOutputs(output, &card, &cvc, &profile);
3793  CanonicalizeState(validator_.get(), &profile);
3794
3795  return scoped_ptr<wallet::Instrument>(
3796      new wallet::Instrument(card, cvc, profile));
3797}
3798
3799scoped_ptr<wallet::Address>AutofillDialogControllerImpl::
3800    CreateTransientAddress() {
3801  // If not using billing for shipping, just scrape the view.
3802  FieldValueMap output;
3803  view_->GetUserInput(SECTION_SHIPPING, &output);
3804
3805  AutofillProfile profile;
3806  FillFormGroupFromOutputs(output, &profile);
3807  profile.set_language_code(shipping_address_language_code_);
3808  CanonicalizeState(validator_.get(), &profile);
3809
3810  return scoped_ptr<wallet::Address>(new wallet::Address(profile));
3811}
3812
3813void AutofillDialogControllerImpl::GetFullWallet() {
3814  DCHECK(is_submitting_);
3815  DCHECK(IsPayingWithWallet());
3816  DCHECK(wallet_items_);
3817  DCHECK(!active_instrument_id_.empty());
3818  DCHECK(!active_address_id_.empty() || !IsShippingAddressRequired());
3819
3820  std::vector<wallet::WalletClient::RiskCapability> capabilities;
3821  capabilities.push_back(wallet::WalletClient::VERIFY_CVC);
3822
3823  GetWalletClient()->GetFullWallet(wallet::WalletClient::FullWalletRequest(
3824      active_instrument_id_,
3825      active_address_id_,
3826      wallet_items_->google_transaction_id(),
3827      capabilities,
3828      wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)));
3829}
3830
3831void AutofillDialogControllerImpl::HandleSaveOrUpdateRequiredActions(
3832    const std::vector<wallet::RequiredAction>& required_actions) {
3833  DCHECK(!required_actions.empty());
3834
3835  // TODO(ahutter): Investigate if we need to support more generic actions on
3836  // this call such as GAIA_AUTH. See crbug.com/243457.
3837  for (std::vector<wallet::RequiredAction>::const_iterator iter =
3838           required_actions.begin();
3839       iter != required_actions.end(); ++iter) {
3840    if (*iter != wallet::INVALID_FORM_FIELD) {
3841      // TODO(dbeam): handle this more gracefully.
3842      DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
3843    }
3844  }
3845  SetIsSubmitting(false);
3846}
3847
3848void AutofillDialogControllerImpl::FinishSubmit() {
3849  if (IsPayingWithWallet()) {
3850    ScopedViewUpdates updates(view_.get());
3851    view_->UpdateOverlay();
3852
3853    card_generated_animation_.Start();
3854    return;
3855  }
3856  DoFinishSubmit();
3857}
3858
3859void AutofillDialogControllerImpl::AnimationProgressed(
3860    const gfx::Animation* animation) {
3861  DCHECK_EQ(animation, &card_generated_animation_);
3862  PushOverlayUpdate();
3863}
3864
3865void AutofillDialogControllerImpl::AnimationEnded(
3866    const gfx::Animation* animation) {
3867  DCHECK_EQ(animation, &card_generated_animation_);
3868  DoFinishSubmit();
3869}
3870
3871void AutofillDialogControllerImpl::OnAddressValidationRulesLoaded(
3872    const std::string& country_code,
3873    bool success) {
3874  // Rules may load instantly (during initialization, before the view is
3875  // even ready). We'll validate when the view is created.
3876  if (!view_)
3877    return;
3878
3879  ScopedViewUpdates updates(view_.get());
3880
3881  // TODO(dbeam): should we retry on failure?
3882  for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3883    DialogSection section = static_cast<DialogSection>(i);
3884    if (!SectionIsActive(section) ||
3885        CountryCodeForSection(section) != country_code) {
3886      continue;
3887    }
3888
3889    if (IsManuallyEditingSection(section) &&
3890        needs_validation_.count(section)) {
3891      view_->ValidateSection(section);
3892      needs_validation_.erase(section);
3893    } else if (success) {
3894      ShowEditUiIfBadSuggestion(section);
3895      UpdateSection(section);
3896    }
3897  }
3898}
3899
3900void AutofillDialogControllerImpl::DoFinishSubmit() {
3901  FillOutputForSection(SECTION_CC);
3902  FillOutputForSection(SECTION_BILLING);
3903  FillOutputForSection(SECTION_CC_BILLING);
3904
3905  if (ShouldUseBillingForShipping()) {
3906    FillOutputForSectionWithComparator(
3907        SECTION_BILLING,
3908        base::Bind(ServerTypeMatchesShippingField));
3909    FillOutputForSectionWithComparator(
3910        SECTION_CC,
3911        base::Bind(ServerTypeMatchesShippingField));
3912    FillOutputForSectionWithComparator(
3913        SECTION_CC_BILLING,
3914        base::Bind(ServerTypeMatchesShippingField));
3915  } else {
3916    FillOutputForSection(SECTION_SHIPPING);
3917  }
3918
3919  if (IsPayingWithWallet()) {
3920    if (SectionIsActive(SECTION_SHIPPING)) {
3921      profile_->GetPrefs()->SetBoolean(
3922          ::prefs::kAutofillDialogWalletShippingSameAsBilling,
3923          suggested_shipping_.GetItemKeyForCheckedItem() == kSameAsBillingKey);
3924    }
3925  } else if (ShouldOfferToSaveInChrome()) {
3926    for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3927      DialogSection section = static_cast<DialogSection>(i);
3928      if (!SectionIsActive(section))
3929        continue;
3930
3931      SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
3932      std::string item_key = model->GetItemKeyForCheckedItem();
3933      if (IsASuggestionItemKey(item_key) || item_key == kSameAsBillingKey) {
3934        PersistAutofillChoice(section, item_key);
3935      } else if (item_key == kAddNewItemKey && ShouldSaveDetailsLocally()) {
3936        DCHECK(newly_saved_data_model_guids_.count(section));
3937        PersistAutofillChoice(section, newly_saved_data_model_guids_[section]);
3938      }
3939    }
3940
3941    profile_->GetPrefs()->SetBoolean(::prefs::kAutofillDialogSaveData,
3942                                     view_->SaveDetailsLocally());
3943  }
3944
3945  // On a successful submit, if the user manually selected "pay without wallet",
3946  // stop trying to pay with Wallet on future runs of the dialog. On the other
3947  // hand, if there was an error that prevented the user from having the choice
3948  // of using Wallet, leave the pref alone.
3949  if (!wallet_error_notification_ &&
3950      account_chooser_model_->HasAccountsToChoose()) {
3951    profile_->GetPrefs()->SetBoolean(
3952        ::prefs::kAutofillDialogPayWithoutWallet,
3953        !account_chooser_model_->WalletIsSelected());
3954  }
3955
3956  LogOnFinishSubmitMetrics();
3957
3958  // Callback should be called as late as possible.
3959  callback_.Run(AutofillClient::AutocompleteResultSuccess,
3960                base::string16(),
3961                &form_structure_);
3962  data_was_passed_back_ = true;
3963
3964  // This might delete us.
3965  Hide();
3966}
3967
3968void AutofillDialogControllerImpl::PersistAutofillChoice(
3969    DialogSection section,
3970    const std::string& guid) {
3971  DCHECK(!IsPayingWithWallet() && ShouldOfferToSaveInChrome());
3972  scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
3973  value->SetString(kGuidPrefKey, guid);
3974
3975  DictionaryPrefUpdate updater(profile()->GetPrefs(),
3976                               ::prefs::kAutofillDialogAutofillDefault);
3977  base::DictionaryValue* autofill_choice = updater.Get();
3978  autofill_choice->Set(SectionToPrefString(section), value.release());
3979}
3980
3981void AutofillDialogControllerImpl::GetDefaultAutofillChoice(
3982    DialogSection section,
3983    std::string* guid) {
3984  DCHECK(!IsPayingWithWallet() && IsAutofillEnabled());
3985  // The default choice is the first thing in the menu that is a suggestion
3986  // item.
3987  SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
3988  for (int i = 0; i < model->GetItemCount(); ++i) {
3989    // Try the first suggestion item that is enabled.
3990    if (IsASuggestionItemKey(model->GetItemKeyAt(i)) && model->IsEnabledAt(i)) {
3991      *guid = model->GetItemKeyAt(i);
3992      return;
3993    // Fall back to the first non-suggestion key.
3994    } else if (!IsASuggestionItemKey(model->GetItemKeyAt(i)) && guid->empty()) {
3995      *guid = model->GetItemKeyAt(i);
3996    }
3997  }
3998}
3999
4000bool AutofillDialogControllerImpl::GetAutofillChoice(DialogSection section,
4001                                                     std::string* guid) {
4002  DCHECK(!IsPayingWithWallet() && IsAutofillEnabled());
4003  const base::DictionaryValue* choices = profile()->GetPrefs()->GetDictionary(
4004      ::prefs::kAutofillDialogAutofillDefault);
4005  if (!choices)
4006    return false;
4007
4008  const base::DictionaryValue* choice = NULL;
4009  if (!choices->GetDictionary(SectionToPrefString(section), &choice))
4010    return false;
4011
4012  choice->GetString(kGuidPrefKey, guid);
4013  return true;
4014}
4015
4016void AutofillDialogControllerImpl::LogOnFinishSubmitMetrics() {
4017  GetMetricLogger().LogDialogUiDuration(
4018      base::Time::Now() - dialog_shown_timestamp_,
4019      AutofillMetrics::DIALOG_ACCEPTED);
4020
4021  GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_ACCEPTED);
4022
4023  AutofillMetrics::DialogDismissalState dismissal_state;
4024  if (!IsManuallyEditingAnySection()) {
4025    dismissal_state = IsPayingWithWallet() ?
4026        AutofillMetrics::DIALOG_ACCEPTED_EXISTING_WALLET_DATA :
4027        AutofillMetrics::DIALOG_ACCEPTED_EXISTING_AUTOFILL_DATA;
4028  } else if (IsPayingWithWallet()) {
4029    dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_SAVE_TO_WALLET;
4030  } else if (ShouldSaveDetailsLocally()) {
4031    dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_SAVE_TO_AUTOFILL;
4032  } else {
4033    dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_NO_SAVE;
4034  }
4035
4036  GetMetricLogger().LogDialogDismissalState(dismissal_state);
4037}
4038
4039void AutofillDialogControllerImpl::LogOnCancelMetrics() {
4040  GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_CANCELED);
4041
4042  AutofillMetrics::DialogDismissalState dismissal_state;
4043  if (ShouldShowSignInWebView())
4044    dismissal_state = AutofillMetrics::DIALOG_CANCELED_DURING_SIGNIN;
4045  else if (!IsManuallyEditingAnySection())
4046    dismissal_state = AutofillMetrics::DIALOG_CANCELED_NO_EDITS;
4047  else if (AllSectionsAreValid())
4048    dismissal_state = AutofillMetrics::DIALOG_CANCELED_NO_INVALID_FIELDS;
4049  else
4050    dismissal_state = AutofillMetrics::DIALOG_CANCELED_WITH_INVALID_FIELDS;
4051
4052  GetMetricLogger().LogDialogDismissalState(dismissal_state);
4053
4054  GetMetricLogger().LogDialogUiDuration(
4055      base::Time::Now() - dialog_shown_timestamp_,
4056      AutofillMetrics::DIALOG_CANCELED);
4057}
4058
4059void AutofillDialogControllerImpl::LogSuggestionItemSelectedMetric(
4060    const SuggestionsMenuModel& model) {
4061  DialogSection section = SectionForSuggestionsMenuModel(model);
4062
4063  AutofillMetrics::DialogUiEvent dialog_ui_event;
4064  if (model.GetItemKeyForCheckedItem() == kAddNewItemKey) {
4065    // Selected to add a new item.
4066    dialog_ui_event = common::DialogSectionToUiItemAddedEvent(section);
4067  } else if (IsASuggestionItemKey(model.GetItemKeyForCheckedItem())) {
4068    // Selected an existing item.
4069    dialog_ui_event = common::DialogSectionToUiSelectionChangedEvent(section);
4070  } else {
4071    // TODO(estade): add logging for "Manage items" or "Use billing for
4072    // shipping"?
4073    return;
4074  }
4075
4076  GetMetricLogger().LogDialogUiEvent(dialog_ui_event);
4077}
4078
4079void AutofillDialogControllerImpl::LogDialogLatencyToShow() {
4080  if (was_ui_latency_logged_)
4081    return;
4082
4083  GetMetricLogger().LogDialogLatencyToShow(
4084      base::Time::Now() - dialog_shown_timestamp_);
4085  was_ui_latency_logged_ = true;
4086}
4087
4088AutofillMetrics::DialogInitialUserStateMetric
4089    AutofillDialogControllerImpl::GetInitialUserState() const {
4090  // Consider a user to be an Autofill user if the user has any credit cards
4091  // or addresses saved. Check that the item count is greater than 2 because
4092  // an "empty" menu still has the "add new" menu item and "manage" menu item.
4093  const bool has_autofill_profiles =
4094      suggested_cc_.GetItemCount() > 2 ||
4095      suggested_billing_.GetItemCount() > 2;
4096
4097  if (SignedInState() != SIGNED_IN) {
4098    // Not signed in.
4099    return has_autofill_profiles ?
4100        AutofillMetrics::DIALOG_USER_NOT_SIGNED_IN_HAS_AUTOFILL :
4101        AutofillMetrics::DIALOG_USER_NOT_SIGNED_IN_NO_AUTOFILL;
4102  }
4103
4104  // Signed in.
4105  if (wallet_items_->instruments().empty()) {
4106    // No Wallet items.
4107    return has_autofill_profiles ?
4108        AutofillMetrics::DIALOG_USER_SIGNED_IN_NO_WALLET_HAS_AUTOFILL :
4109        AutofillMetrics::DIALOG_USER_SIGNED_IN_NO_WALLET_NO_AUTOFILL;
4110  }
4111
4112  // Has Wallet items.
4113  return has_autofill_profiles ?
4114      AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_HAS_AUTOFILL :
4115      AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_NO_AUTOFILL;
4116}
4117
4118void AutofillDialogControllerImpl::MaybeShowCreditCardBubble() {
4119  if (!data_was_passed_back_)
4120    return;
4121
4122  if (newly_saved_card_) {
4123    scoped_ptr<AutofillProfile> billing_profile;
4124    if (IsManuallyEditingSection(SECTION_BILLING)) {
4125      // Scrape the view as the user's entering or updating information.
4126      FieldValueMap outputs;
4127      view_->GetUserInput(SECTION_BILLING, &outputs);
4128      billing_profile.reset(new AutofillProfile);
4129      FillFormGroupFromOutputs(outputs, billing_profile.get());
4130      billing_profile->set_language_code(billing_address_language_code_);
4131    } else {
4132      // Just snag the currently suggested profile.
4133      std::string item_key = SuggestionsMenuModelForSection(SECTION_BILLING)->
4134          GetItemKeyForCheckedItem();
4135      AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
4136      billing_profile.reset(new AutofillProfile(*profile));
4137    }
4138
4139    ShowNewCreditCardBubble(newly_saved_card_.Pass(),
4140                            billing_profile.Pass());
4141    return;
4142  }
4143
4144  if (!full_wallet_ || !full_wallet_->billing_address())
4145    return;
4146
4147  GeneratedCreditCardBubbleController::Show(
4148      web_contents(),
4149      full_wallet_->TypeAndLastFourDigits(),
4150      backing_card_last_four_);
4151}
4152
4153void AutofillDialogControllerImpl::OnSubmitButtonDelayEnd() {
4154  if (!view_)
4155    return;
4156  ScopedViewUpdates updates(view_.get());
4157  view_->UpdateButtonStrip();
4158}
4159
4160void AutofillDialogControllerImpl::FetchWalletCookie() {
4161  net::URLRequestContextGetter* request_context = profile_->GetRequestContext();
4162  signin_helper_.reset(new wallet::WalletSigninHelper(this, request_context));
4163  signin_helper_->StartWalletCookieValueFetch();
4164}
4165
4166}  // namespace autofill
4167