Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / autofill / card_unmask_prompt_controller_impl.cc
blob2e58519c639cac098f133d764c4231bf7a84c042
1 // Copyright 2014 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.
5 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h"
7 #include "base/bind.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/autofill/risk_util.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/autofill/card_unmask_prompt_view.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "components/autofill/core/browser/autofill_experiments.h"
17 #include "components/autofill/core/browser/autofill_metrics.h"
18 #include "components/autofill/core/common/autofill_pref_names.h"
19 #include "components/user_prefs/user_prefs.h"
20 #include "content/public/browser/web_contents.h"
21 #include "grit/theme_resources.h"
22 #include "ui/base/l10n/l10n_util.h"
24 namespace autofill {
26 CardUnmaskPromptControllerImpl::CardUnmaskPromptControllerImpl(
27 content::WebContents* web_contents)
28 : web_contents_(web_contents),
29 card_unmask_view_(nullptr),
30 unmasking_result_(AutofillClient::NONE),
31 unmasking_initial_should_store_pan_(false),
32 unmasking_number_of_attempts_(0),
33 weak_pointer_factory_(this) {
36 CardUnmaskPromptControllerImpl::~CardUnmaskPromptControllerImpl() {
37 if (card_unmask_view_)
38 card_unmask_view_->ControllerGone();
41 void CardUnmaskPromptControllerImpl::ShowPrompt(
42 const CreditCard& card,
43 base::WeakPtr<CardUnmaskDelegate> delegate) {
44 if (card_unmask_view_)
45 card_unmask_view_->ControllerGone();
47 shown_timestamp_ = base::Time::Now();
48 pending_response_ = CardUnmaskDelegate::UnmaskResponse();
49 LoadRiskFingerprint();
50 card_ = card;
51 delegate_ = delegate;
52 card_unmask_view_ = CreateAndShowView();
53 unmasking_result_ = AutofillClient::NONE;
54 unmasking_number_of_attempts_ = 0;
55 unmasking_initial_should_store_pan_ = GetStoreLocallyStartState();
56 AutofillMetrics::LogUnmaskPromptEvent(AutofillMetrics::UNMASK_PROMPT_SHOWN);
59 bool CardUnmaskPromptControllerImpl::AllowsRetry(
60 AutofillClient::GetRealPanResult result) {
61 if (result == AutofillClient::NETWORK_ERROR ||
62 result == AutofillClient::PERMANENT_FAILURE) {
63 return false;
65 return true;
68 void CardUnmaskPromptControllerImpl::OnVerificationResult(
69 AutofillClient::GetRealPanResult result) {
70 if (!card_unmask_view_)
71 return;
73 base::string16 error_message;
74 switch (result) {
75 case AutofillClient::SUCCESS:
76 break;
78 case AutofillClient::TRY_AGAIN_FAILURE: {
79 error_message = l10n_util::GetStringUTF16(
80 IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_TRY_AGAIN);
81 break;
84 case AutofillClient::PERMANENT_FAILURE: {
85 error_message = l10n_util::GetStringUTF16(
86 IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_PERMANENT);
87 break;
90 case AutofillClient::NETWORK_ERROR: {
91 error_message = l10n_util::GetStringUTF16(
92 IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_NETWORK);
93 break;
96 case AutofillClient::NONE:
97 NOTREACHED();
98 return;
101 unmasking_result_ = result;
102 AutofillMetrics::LogRealPanResult(result);
103 AutofillMetrics::LogUnmaskingDuration(base::Time::Now() - verify_timestamp_,
104 result);
105 card_unmask_view_->GotVerificationResult(error_message,
106 AllowsRetry(result));
109 void CardUnmaskPromptControllerImpl::OnUnmaskDialogClosed() {
110 card_unmask_view_ = nullptr;
111 LogOnCloseEvents();
112 delegate_->OnUnmaskPromptClosed();
115 void CardUnmaskPromptControllerImpl::LogOnCloseEvents() {
116 AutofillMetrics::UnmaskPromptEvent close_reason_event = GetCloseReasonEvent();
117 AutofillMetrics::LogUnmaskPromptEvent(close_reason_event);
118 AutofillMetrics::LogUnmaskPromptEventDuration(
119 base::Time::Now() - shown_timestamp_, close_reason_event);
121 if (close_reason_event == AutofillMetrics::UNMASK_PROMPT_CLOSED_NO_ATTEMPTS)
122 return;
124 if (close_reason_event ==
125 AutofillMetrics::UNMASK_PROMPT_CLOSED_ABANDON_UNMASKING) {
126 AutofillMetrics::LogTimeBeforeAbandonUnmasking(base::Time::Now() -
127 verify_timestamp_);
130 bool final_should_store_pan = pending_response_.should_store_pan;
131 if (unmasking_result_ == AutofillClient::SUCCESS && final_should_store_pan) {
132 AutofillMetrics::LogUnmaskPromptEvent(
133 AutofillMetrics::UNMASK_PROMPT_SAVED_CARD_LOCALLY);
136 if (CanStoreLocally()) {
137 // Tracking changes in local save preference.
138 AutofillMetrics::UnmaskPromptEvent event;
139 if (unmasking_initial_should_store_pan_ && final_should_store_pan) {
140 event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_OUT;
141 } else if (!unmasking_initial_should_store_pan_ &&
142 !final_should_store_pan) {
143 event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_IN;
144 } else if (unmasking_initial_should_store_pan_ && !final_should_store_pan) {
145 event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_OUT;
146 } else {
147 event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_IN;
149 AutofillMetrics::LogUnmaskPromptEvent(event);
153 AutofillMetrics::UnmaskPromptEvent
154 CardUnmaskPromptControllerImpl::GetCloseReasonEvent() {
155 if (unmasking_number_of_attempts_ == 0)
156 return AutofillMetrics::UNMASK_PROMPT_CLOSED_NO_ATTEMPTS;
158 // If NONE and we have a pending request, we have a pending GetRealPan
159 // request.
160 if (unmasking_result_ == AutofillClient::NONE)
161 return AutofillMetrics::UNMASK_PROMPT_CLOSED_ABANDON_UNMASKING;
163 if (unmasking_result_ == AutofillClient::SUCCESS) {
164 return unmasking_number_of_attempts_ == 1
165 ? AutofillMetrics::UNMASK_PROMPT_UNMASKED_CARD_FIRST_ATTEMPT
166 : AutofillMetrics::
167 UNMASK_PROMPT_UNMASKED_CARD_AFTER_FAILED_ATTEMPTS;
168 } else {
169 return AllowsRetry(unmasking_result_)
170 ? AutofillMetrics::
171 UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_RETRIABLE_FAILURE
172 : AutofillMetrics::
173 UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_NON_RETRIABLE_FAILURE;
177 void CardUnmaskPromptControllerImpl::OnUnmaskResponse(
178 const base::string16& cvc,
179 const base::string16& exp_month,
180 const base::string16& exp_year,
181 bool should_store_pan) {
182 verify_timestamp_ = base::Time::Now();
183 unmasking_number_of_attempts_++;
184 unmasking_result_ = AutofillClient::NONE;
185 card_unmask_view_->DisableAndWaitForVerification();
187 DCHECK(InputCvcIsValid(cvc));
188 base::TrimWhitespace(cvc, base::TRIM_ALL, &pending_response_.cvc);
189 if (ShouldRequestExpirationDate()) {
190 DCHECK(InputExpirationIsValid(exp_month, exp_year));
191 pending_response_.exp_month = exp_month;
192 pending_response_.exp_year = exp_year;
194 if (CanStoreLocally()) {
195 pending_response_.should_store_pan = should_store_pan;
196 } else {
197 DCHECK(!should_store_pan);
198 pending_response_.should_store_pan = false;
201 // Remember the last choice the user made (on this device).
202 user_prefs::UserPrefs::Get(web_contents_->GetBrowserContext())->SetBoolean(
203 prefs::kAutofillWalletImportStorageCheckboxState, should_store_pan);
205 if (!pending_response_.risk_data.empty())
206 delegate_->OnUnmaskResponse(pending_response_);
209 content::WebContents* CardUnmaskPromptControllerImpl::GetWebContents() {
210 return web_contents_;
213 base::string16 CardUnmaskPromptControllerImpl::GetWindowTitle() const {
214 int ids = ShouldRequestExpirationDate()
215 ? IDS_AUTOFILL_CARD_UNMASK_PROMPT_UPDATE_TITLE
216 : IDS_AUTOFILL_CARD_UNMASK_PROMPT_TITLE;
217 return l10n_util::GetStringFUTF16(ids, card_.TypeAndLastFourDigits());
220 base::string16 CardUnmaskPromptControllerImpl::GetInstructionsMessage() const {
221 if (ShouldRequestExpirationDate()) {
222 return l10n_util::GetStringUTF16(
223 card_.type() == kAmericanExpressCard
224 ? IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_EXPIRED_AMEX
225 : IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_EXPIRED);
228 return l10n_util::GetStringUTF16(
229 card_.type() == kAmericanExpressCard
230 ? IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_AMEX
231 : IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS);
234 int CardUnmaskPromptControllerImpl::GetCvcImageRid() const {
235 return card_.type() == kAmericanExpressCard ? IDR_CREDIT_CARD_CVC_HINT_AMEX
236 : IDR_CREDIT_CARD_CVC_HINT;
239 bool CardUnmaskPromptControllerImpl::ShouldRequestExpirationDate() const {
240 return card_.GetServerStatus() == CreditCard::EXPIRED;
243 bool CardUnmaskPromptControllerImpl::CanStoreLocally() const {
244 // Never offer to save for incognito.
245 if (Profile::FromBrowserContext(web_contents_->GetBrowserContext())
246 ->IsOffTheRecord())
247 return false;
248 return autofill::OfferStoreUnmaskedCards();
251 bool CardUnmaskPromptControllerImpl::GetStoreLocallyStartState() const {
252 PrefService* prefs =
253 user_prefs::UserPrefs::Get(web_contents_->GetBrowserContext());
254 return prefs->GetBoolean(prefs::kAutofillWalletImportStorageCheckboxState);
257 bool CardUnmaskPromptControllerImpl::InputCvcIsValid(
258 const base::string16& input_text) const {
259 base::string16 trimmed_text;
260 base::TrimWhitespace(input_text, base::TRIM_ALL, &trimmed_text);
261 size_t input_size = card_.type() == kAmericanExpressCard ? 4 : 3;
262 return trimmed_text.size() == input_size &&
263 base::ContainsOnlyChars(trimmed_text,
264 base::ASCIIToUTF16("0123456789"));
267 bool CardUnmaskPromptControllerImpl::InputExpirationIsValid(
268 const base::string16& month,
269 const base::string16& year) const {
270 if ((month.size() != 2U && month.size() != 1U) ||
271 (year.size() != 4U && year.size() != 2U)) {
272 return false;
275 int month_value = 0, year_value = 0;
276 if (!base::StringToInt(month, &month_value) ||
277 !base::StringToInt(year, &year_value)) {
278 return false;
281 if (month_value < 1 || month_value > 12)
282 return false;
284 base::Time::Exploded now;
285 base::Time::Now().LocalExplode(&now);
287 // Convert 2 digit year to 4 digit year.
288 if (year_value < 100)
289 year_value += (now.year / 100) * 100;
291 if (year_value < now.year)
292 return false;
294 if (year_value > now.year)
295 return true;
297 return month_value >= now.month;
300 base::TimeDelta CardUnmaskPromptControllerImpl::GetSuccessMessageDuration()
301 const {
302 return base::TimeDelta::FromMilliseconds(500);
305 CardUnmaskPromptView* CardUnmaskPromptControllerImpl::CreateAndShowView() {
306 return CardUnmaskPromptView::CreateAndShow(this);
309 void CardUnmaskPromptControllerImpl::LoadRiskFingerprint() {
310 LoadRiskData(
311 0, web_contents_,
312 base::Bind(&CardUnmaskPromptControllerImpl::OnDidLoadRiskFingerprint,
313 weak_pointer_factory_.GetWeakPtr()));
316 void CardUnmaskPromptControllerImpl::OnDidLoadRiskFingerprint(
317 const std::string& risk_data) {
318 pending_response_.risk_data = risk_data;
319 if (!pending_response_.cvc.empty())
320 delegate_->OnUnmaskResponse(pending_response_);
323 } // namespace autofill