Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(223)

Unified Diff: chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc

Issue 12893007: Implementing VERIFY_CVV required action. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index 96548f6c0bbec147c932e2d284c31169ff24011e..6d9b7df20fff02a5ce42856ebdc402f8608630e4 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -172,17 +172,20 @@ void GetBillingInfoFromOutputs(const DetailOutputMap& output,
// Special case CVC as CreditCard just swallows it.
if (it->first->type == CREDIT_CARD_VERIFICATION_CODE) {
- cvc->assign(trimmed);
+ if (cvc)
+ cvc->assign(trimmed);
} else {
// Copy the credit card name to |profile| in addition to |card| as
// wallet::Instrument requires a recipient name for its billing address.
- if (it->first->type == CREDIT_CARD_NAME)
+ if (profile && it->first->type == CREDIT_CARD_NAME)
profile->SetRawInfo(NAME_FULL, trimmed);
- if (IsCreditCardType(it->first->type))
- card->SetRawInfo(it->first->type, trimmed);
- else
+ if (IsCreditCardType(it->first->type)) {
+ if (card)
+ card->SetRawInfo(it->first->type, trimmed);
+ } else if (profile) {
profile->SetRawInfo(it->first->type, trimmed);
+ }
}
}
}
@@ -249,7 +252,7 @@ AutofillDialogControllerImpl::AutofillDialogControllerImpl(
metric_logger_(metric_logger),
initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
dialog_type_(dialog_type),
- did_submit_(false),
+ is_submitting_(false),
autocheckout_is_running_(false),
had_autocheckout_error_(false) {
// TODO(estade): remove duplicates from |form|?
@@ -428,7 +431,8 @@ string16 AutofillDialogControllerImpl::CancelButtonText() const {
}
string16 AutofillDialogControllerImpl::ConfirmButtonText() const {
- return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON);
+ return l10n_util::GetStringUTF16(IsSubmitPausedOn(wallet::VERIFY_CVV) ?
+ IDS_AUTOFILL_DIALOG_VERIFY_BUTTON : IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON);
}
string16 AutofillDialogControllerImpl::CancelSignInText() const {
@@ -471,7 +475,6 @@ string16 AutofillDialogControllerImpl::AccountChooserText() const {
if (!IsPayingWithWallet())
return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PAY_WITHOUT_WALLET);
- // TODO(dbeam): real strings and l10n.
if (SignedInState() == SIGNED_IN)
return ASCIIToUTF16(current_username_);
@@ -498,12 +501,18 @@ bool AutofillDialogControllerImpl::HadAutocheckoutError() const {
bool AutofillDialogControllerImpl::IsDialogButtonEnabled(
ui::DialogButton button) const {
+ const bool is_submit_going = is_submitting_ &&
+ !IsSubmitPausedOn(wallet::VERIFY_CVV);
if (button == ui::DIALOG_BUTTON_OK)
- return !did_submit_;
+ return !is_submit_going;
+
DCHECK_EQ(ui::DIALOG_BUTTON_CANCEL, button);
+ if (dialog_type_ == DIALOG_TYPE_REQUEST_AUTOCOMPLETE)
+ return true;
Ilya Sherman 2013/03/31 06:04:37 It doesn't seem like you should need this check at
Dan Beam 2013/04/01 22:17:23 Done.
+
// TODO(ahutter): Make it possible for the user to cancel out of the dialog
// while Autocheckout is in progress.
- return had_autocheckout_error_ || !did_submit_;
+ return had_autocheckout_error_ || !is_submit_going;
Ilya Sherman 2013/03/31 06:04:37 I think what you want to check is !callback_.is_nu
Dan Beam 2013/04/01 22:17:23 Done.
}
const std::vector<ui::Range>& AutofillDialogControllerImpl::
@@ -514,6 +523,9 @@ const std::vector<ui::Range>& AutofillDialogControllerImpl::
bool AutofillDialogControllerImpl::SectionIsActive(DialogSection section)
const {
+ if (IsSubmitPausedOn(wallet::VERIFY_CVV))
+ return section == SECTION_CC_BILLING;
+
if (IsPayingWithWallet())
return section != SECTION_BILLING && section != SECTION_CC;
@@ -526,6 +538,11 @@ bool AutofillDialogControllerImpl::HasCompleteWallet() const {
!wallet_items_->addresses().empty();
}
+bool AutofillDialogControllerImpl::IsSubmitPausedOn(
+ wallet::RequiredAction required_action) const {
+ return full_wallet_ && full_wallet_->HasRequiredAction(required_action);
+}
+
void AutofillDialogControllerImpl::StartFetchingWalletItems() {
DCHECK(IsPayingWithWallet());
// TODO(dbeam): Add Risk capabilites once the UI supports risk challenges.
@@ -699,8 +716,21 @@ string16 AutofillDialogControllerImpl::LabelForSection(DialogSection section)
}
}
+SuggestionState AutofillDialogControllerImpl::SuggestionStateForSection(
+ DialogSection section) {
+ return SuggestionState(SuggestionTextForSection(section),
+ SuggestionIconForSection(section),
+ ExtraSuggestionTextForSection(section),
+ ExtraSuggestionIconForSection(section),
+ EditEnabledForSection(section));
+}
+
string16 AutofillDialogControllerImpl::SuggestionTextForSection(
DialogSection section) {
+ string16 action_text = RequiredActionTextForSection(section);
+ if (!action_text.empty())
+ return action_text;
+
// When the user has clicked 'edit', don't show a suggestion (even though
// there is a profile selected in the model).
if (section_editing_state_[section])
@@ -718,9 +748,38 @@ string16 AutofillDialogControllerImpl::SuggestionTextForSection(
return wrapper->GetDisplayText();
}
+string16 AutofillDialogControllerImpl::RequiredActionTextForSection(
+ DialogSection section) const {
+ if (section == SECTION_CC_BILLING && IsSubmitPausedOn(wallet::VERIFY_CVV)) {
+ const wallet::WalletItems::MaskedInstrument* current_instrument =
+ wallet_items_->GetInstrumentById(active_instrument_id_);
+ if (current_instrument)
+ return current_instrument->TypeAndLastFourDigits();
+
+ DetailOutputMap output;
+ view_->GetUserInput(section, &output);
+ CreditCard card;
+ GetBillingInfoFromOutputs(output, &card, NULL, NULL);
+ return card.TypeAndLastFourDigits();
+ }
+
+ return string16();
+}
+
+string16 AutofillDialogControllerImpl::ExtraSuggestionTextForSection(
+ DialogSection section) const {
+ if (section == SECTION_CC ||
+ (section == SECTION_CC_BILLING && IsSubmitPausedOn(wallet::VERIFY_CVV))) {
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC);
+ }
+
+ return string16();
+}
+
scoped_ptr<DataModelWrapper> AutofillDialogControllerImpl::CreateWrapper(
DialogSection section) {
- if (IsPayingWithWallet() && full_wallet_) {
+ if (IsPayingWithWallet() && full_wallet_ &&
+ !IsSubmitPausedOn(wallet::VERIFY_CVV)) {
if (section == SECTION_CC_BILLING) {
return scoped_ptr<DataModelWrapper>(
new FullWalletBillingWrapper(full_wallet_.get()));
@@ -781,6 +840,19 @@ gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection(
return model->GetIcon();
}
+gfx::Image AutofillDialogControllerImpl::ExtraSuggestionIconForSection(
+ DialogSection section) const {
+ if (section == SECTION_CC || section == SECTION_CC_BILLING)
+ return IconForField(CREDIT_CARD_VERIFICATION_CODE, string16());
+
+ return gfx::Image();
+}
+
+bool AutofillDialogControllerImpl::EditEnabledForSection(
+ DialogSection section) const {
+ return section != SECTION_CC_BILLING || !IsSubmitPausedOn(wallet::VERIFY_CVV);
+}
+
void AutofillDialogControllerImpl::EditClickedForSection(
DialogSection section) {
DetailInputs* inputs = MutableRequestedFieldsForSection(section);
@@ -1043,49 +1115,48 @@ std::vector<DialogNotification>
// On first run with a complete wallet profile, show a notification
// explaining where this data came from.
if (IsFirstRun() && HasCompleteWallet()) {
- notifications.push_back(
- DialogNotification(
- DialogNotification::EXPLANATORY_MESSAGE,
- l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_DETAILS_FROM_WALLET)));
+ notifications.push_back(DialogNotification(
+ DialogNotification::EXPLANATORY_MESSAGE,
+ l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_DIALOG_DETAILS_FROM_WALLET)));
} else {
- notifications.push_back(
- DialogNotification(
- DialogNotification::WALLET_PROMO,
- l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_SAVE_DETAILS_IN_WALLET)));
+ notifications.push_back(DialogNotification(
+ DialogNotification::WALLET_PROMO,
+ l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_DIALOG_SAVE_DETAILS_IN_WALLET)));
}
} else if (IsFirstRun()) {
// If the user is not signed in, show an upsell notification on first run.
- notifications.push_back(
- DialogNotification(
- DialogNotification::WALLET_PROMO,
- l10n_util::GetStringUTF16(
- IDS_AUTOFILL_DIALOG_SIGN_IN_AND_SAVE_DETAILS)));
+ notifications.push_back(DialogNotification(
+ DialogNotification::WALLET_PROMO,
+ l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_DIALOG_SIGN_IN_AND_SAVE_DETAILS)));
}
}
if (RequestingCreditCardInfo() && !TransmissionWillBeSecure()) {
- notifications.push_back(
- DialogNotification(
- DialogNotification::SECURITY_WARNING,
- l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECURITY_WARNING)));
+ notifications.push_back(DialogNotification(
+ DialogNotification::SECURITY_WARNING,
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECURITY_WARNING)));
}
if (!invoked_from_same_origin_) {
- notifications.push_back(
- DialogNotification(
- DialogNotification::SECURITY_WARNING,
- l10n_util::GetStringFUTF16(
- IDS_AUTOFILL_DIALOG_SITE_WARNING,
- UTF8ToUTF16(source_url_.host()))));
+ notifications.push_back(DialogNotification(
+ DialogNotification::SECURITY_WARNING,
+ l10n_util::GetStringFUTF16(IDS_AUTOFILL_DIALOG_SITE_WARNING,
+ UTF8ToUTF16(source_url_.host()))));
+ }
+
+ if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
+ notifications.push_back(DialogNotification(
+ DialogNotification::REQUIRED_ACTION,
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_VERIFY_CVV)));
}
if (had_autocheckout_error_) {
- notifications.push_back(
- DialogNotification(
- DialogNotification::AUTOCHECKOUT_ERROR,
- l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_AUTOCHECKOUT_ERROR)));
+ notifications.push_back(DialogNotification(
+ DialogNotification::AUTOCHECKOUT_ERROR,
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_AUTOCHECKOUT_ERROR)));
}
if (account_chooser_model_.had_wallet_error()) {
@@ -1136,42 +1207,38 @@ void AutofillDialogControllerImpl::LegalDocumentLinkClicked(
}
void AutofillDialogControllerImpl::OnCancel() {
- if (!did_submit_) {
- metric_logger_.LogDialogUiDuration(
- base::Time::Now() - dialog_shown_timestamp_,
- dialog_type_,
- AutofillMetrics::DIALOG_CANCELED);
- }
-
- // If Autocheckout has an error, it's possible that the dialog will be
- // submitted to start the flow and then cancelled to close the dialog after
- // the error.
- if (!callback_.is_null()) {
- callback_.Run(NULL);
- callback_ = base::Callback<void(const FormStructure*)>();
- }
-}
+ // If the submit was successful, |callback_| will have already been |.Run()|
+ // and nullified. If this is the case, no further actions are required. If
+ // Autocheckout has an error, it's possible that the dialog will be submitted
+ // to start the flow and then cancelled to close the dialog after the error.
+ if (callback_.is_null())
+ return;
-void AutofillDialogControllerImpl::OnSubmit() {
- did_submit_ = true;
metric_logger_.LogDialogUiDuration(
base::Time::Now() - dialog_shown_timestamp_,
dialog_type_,
- AutofillMetrics::DIALOG_ACCEPTED);
+ AutofillMetrics::DIALOG_CANCELED);
- if (dialog_type_ == DIALOG_TYPE_AUTOCHECKOUT) {
- // Stop observing PersonalDataManager to avoid the dialog redrawing while
- // in an Autocheckout flow.
- GetManager()->RemoveObserver(this);
- autocheckout_is_running_ = true;
- autocheckout_started_timestamp_ = base::Time::Now();
- view_->UpdateButtonStrip();
- }
+ callback_.Run(NULL);
+ callback_ = base::Callback<void(const FormStructure*)>();
+}
- if (IsPayingWithWallet())
+void AutofillDialogControllerImpl::OnAccept() {
+ is_submitting_ = true;
+ view_->UpdateButtonStrip();
+
+ if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
+ DCHECK(!active_instrument_id_.empty());
+ GetWalletClient()->AuthenticateInstrument(
+ active_instrument_id_,
+ UTF16ToUTF8(view_->GetCvc()),
+ wallet_items_->obfuscated_gaia_id());
+ } else if (IsPayingWithWallet()) {
+ // TODO(dbeam): disallow switching payment methods while submitting.
SubmitWithWallet();
- else
+ } else {
FinishSubmit();
+ }
}
Profile* AutofillDialogControllerImpl::profile() {
@@ -1286,13 +1353,17 @@ void AutofillDialogControllerImpl::OnDidAuthenticateInstrument(bool success) {
void AutofillDialogControllerImpl::OnDidGetFullWallet(
scoped_ptr<wallet::FullWallet> full_wallet) {
- // TODO(dbeam): handle more required actions.
full_wallet_ = full_wallet.Pass();
- if (full_wallet_->HasRequiredAction(wallet::VERIFY_CVV))
- DisableWallet();
- else
+ if (full_wallet_->required_actions().empty()) {
FinishSubmit();
+ return;
+ }
+
+ GenerateSuggestionsModels();
+ view_->ModelChanged();
+ view_->UpdateNotificationArea();
+ view_->UpdateButtonStrip();
}
void AutofillDialogControllerImpl::OnPassiveSigninSuccess(
@@ -1476,10 +1547,15 @@ bool AutofillDialogControllerImpl::IsPayingWithWallet() const {
}
void AutofillDialogControllerImpl::DisableWallet() {
+ is_submitting_ = false;
+ if (view_)
+ view_->UpdateButtonStrip();
+
signin_helper_.reset();
current_username_.clear();
account_chooser_model_.SetHadWalletError();
GetWalletClient()->CancelPendingRequests();
+ full_wallet_.reset();
}
void AutofillDialogControllerImpl::OnWalletSigninError() {
@@ -1502,7 +1578,7 @@ void AutofillDialogControllerImpl::GenerateSuggestionsModels() {
suggested_shipping_.Reset();
if (IsPayingWithWallet()) {
- if (wallet_items_.get()) {
+ if (wallet_items_) {
// TODO(estade): seems we need to hardcode the email address.
const std::vector<wallet::Address*>& addresses =
@@ -1515,21 +1591,25 @@ void AutofillDialogControllerImpl::GenerateSuggestionsModels() {
addresses[i]->DisplayNameDetail());
}
- const std::vector<wallet::WalletItems::MaskedInstrument*>& instruments =
- wallet_items_->instruments();
- for (size_t i = 0; i < instruments.size(); ++i) {
- // TODO(dbeam): respect wallet_items_->default_address_id().
- suggested_cc_billing_.AddKeyedItemWithSublabelAndIcon(
- base::IntToString(i),
- instruments[i]->DisplayName(),
- instruments[i]->DisplayNameDetail(),
- instruments[i]->CardIcon());
+ if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
+ const std::vector<wallet::WalletItems::MaskedInstrument*>& instruments =
+ wallet_items_->instruments();
+ for (size_t i = 0; i < instruments.size(); ++i) {
+ // TODO(dbeam): respect wallet_items_->default_address_id().
+ suggested_cc_billing_.AddKeyedItemWithSublabelAndIcon(
+ base::IntToString(i),
+ instruments[i]->DisplayName(),
+ instruments[i]->DisplayNameDetail(),
+ instruments[i]->CardIcon());
+ }
}
}
- suggested_cc_billing_.AddKeyedItem(
- std::string(),
- l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_BILLING_DETAILS));
+ if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
+ suggested_cc_billing_.AddKeyedItem(
+ std::string(),
+ l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_BILLING_DETAILS));
+ }
} else {
PersonalDataManager* manager = GetManager();
const std::vector<CreditCard*>& cards = manager->credit_cards();
@@ -1863,7 +1943,7 @@ void AutofillDialogControllerImpl::SubmitWithWallet() {
}
void AutofillDialogControllerImpl::GetFullWallet() {
- DCHECK(did_submit_);
+ DCHECK(is_submitting_);
DCHECK(IsPayingWithWallet());
DCHECK(wallet_items_);
DCHECK(!active_instrument_id_.empty());
@@ -1883,6 +1963,7 @@ void AutofillDialogControllerImpl::FinishSubmit() {
FillOutputForSection(SECTION_CC);
FillOutputForSection(SECTION_BILLING);
FillOutputForSection(SECTION_CC_BILLING);
+
if (ShouldUseBillingForShipping()) {
FillOutputForSectionWithComparator(
SECTION_BILLING,
@@ -1893,12 +1974,29 @@ void AutofillDialogControllerImpl::FinishSubmit() {
} else {
FillOutputForSection(SECTION_SHIPPING);
}
+
callback_.Run(&form_structure_);
callback_ = base::Callback<void(const FormStructure*)>();
- if (dialog_type_ == DIALOG_TYPE_REQUEST_AUTOCOMPLETE) {
- // This may delete us.
- Hide();
+ metric_logger_.LogDialogUiDuration(
+ base::Time::Now() - dialog_shown_timestamp_,
+ dialog_type_,
+ AutofillMetrics::DIALOG_ACCEPTED);
+
+ switch (dialog_type_) {
+ case DIALOG_TYPE_AUTOCHECKOUT:
+ // Stop observing PersonalDataManager to avoid the dialog redrawing while
+ // in an Autocheckout flow.
+ GetManager()->RemoveObserver(this);
+ autocheckout_is_running_ = true;
+ autocheckout_started_timestamp_ = base::Time::Now();
+ view_->UpdateButtonStrip();
+ break;
+
+ case DIALOG_TYPE_REQUEST_AUTOCOMPLETE:
+ // This may delete us.
+ Hide();
+ break;
}
}

Powered by Google App Engine
This is Rietveld 408576698