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