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