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

Side by Side Diff: chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc

Issue 1138653003: Move card unmask interfaces and controller into the autofill component. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix missing override declaration Created 5 years, 7 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 unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h"
6
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/profiles/profile.h"
13 #include "chrome/browser/ui/autofill/card_unmask_prompt_view.h"
14 #include "chrome/grit/generated_resources.h"
15 #include "components/autofill/core/browser/autofill_experiments.h"
16 #include "components/autofill/core/browser/autofill_metrics.h"
17 #include "components/autofill/core/common/autofill_pref_names.h"
18 #include "grit/theme_resources.h"
19 #include "ui/base/l10n/l10n_util.h"
20
21 namespace autofill {
22
23 CardUnmaskPromptControllerImpl::CardUnmaskPromptControllerImpl(
24 content::WebContents* web_contents,
25 const RiskDataCallback& risk_data_callback,
26 PrefService* pref_service,
27 bool is_off_the_record)
28 : web_contents_(web_contents),
29 risk_data_callback_(risk_data_callback),
30 pref_service_(pref_service),
31 new_card_link_clicked_(false),
32 is_off_the_record_(is_off_the_record),
33 card_unmask_view_(nullptr),
34 unmasking_result_(AutofillClient::NONE),
35 unmasking_initial_should_store_pan_(false),
36 unmasking_number_of_attempts_(0),
37 weak_pointer_factory_(this) {
38 }
39
40 CardUnmaskPromptControllerImpl::~CardUnmaskPromptControllerImpl() {
41 if (card_unmask_view_)
42 card_unmask_view_->ControllerGone();
43 }
44
45 void CardUnmaskPromptControllerImpl::ShowPrompt(
46 const CreditCard& card,
47 base::WeakPtr<CardUnmaskDelegate> delegate) {
48 if (card_unmask_view_)
49 card_unmask_view_->ControllerGone();
50
51 shown_timestamp_ = base::Time::Now();
52 pending_response_ = CardUnmaskDelegate::UnmaskResponse();
53 LoadRiskFingerprint();
54 card_ = card;
55 delegate_ = delegate;
56 card_unmask_view_ = CreateAndShowView();
57 unmasking_result_ = AutofillClient::NONE;
58 unmasking_number_of_attempts_ = 0;
59 unmasking_initial_should_store_pan_ = GetStoreLocallyStartState();
60 AutofillMetrics::LogUnmaskPromptEvent(AutofillMetrics::UNMASK_PROMPT_SHOWN);
61 }
62
63 bool CardUnmaskPromptControllerImpl::AllowsRetry(
64 AutofillClient::GetRealPanResult result) {
65 if (result == AutofillClient::NETWORK_ERROR ||
66 result == AutofillClient::PERMANENT_FAILURE) {
67 return false;
68 }
69 return true;
70 }
71
72 void CardUnmaskPromptControllerImpl::OnVerificationResult(
73 AutofillClient::GetRealPanResult result) {
74 if (!card_unmask_view_)
75 return;
76
77 base::string16 error_message;
78 switch (result) {
79 case AutofillClient::SUCCESS:
80 break;
81
82 case AutofillClient::TRY_AGAIN_FAILURE: {
83 error_message = l10n_util::GetStringUTF16(
84 IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_TRY_AGAIN);
85 break;
86 }
87
88 case AutofillClient::PERMANENT_FAILURE: {
89 error_message = l10n_util::GetStringUTF16(
90 IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_PERMANENT);
91 break;
92 }
93
94 case AutofillClient::NETWORK_ERROR: {
95 error_message = l10n_util::GetStringUTF16(
96 IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_NETWORK);
97 break;
98 }
99
100 case AutofillClient::NONE:
101 NOTREACHED();
102 return;
103 }
104
105 unmasking_result_ = result;
106 AutofillMetrics::LogRealPanResult(result);
107 AutofillMetrics::LogUnmaskingDuration(base::Time::Now() - verify_timestamp_,
108 result);
109 card_unmask_view_->GotVerificationResult(error_message,
110 AllowsRetry(result));
111 }
112
113 void CardUnmaskPromptControllerImpl::OnUnmaskDialogClosed() {
114 card_unmask_view_ = nullptr;
115 LogOnCloseEvents();
116 if (delegate_.get())
117 delegate_->OnUnmaskPromptClosed();
118 }
119
120 void CardUnmaskPromptControllerImpl::LogOnCloseEvents() {
121 AutofillMetrics::UnmaskPromptEvent close_reason_event = GetCloseReasonEvent();
122 AutofillMetrics::LogUnmaskPromptEvent(close_reason_event);
123 AutofillMetrics::LogUnmaskPromptEventDuration(
124 base::Time::Now() - shown_timestamp_, close_reason_event);
125
126 if (close_reason_event == AutofillMetrics::UNMASK_PROMPT_CLOSED_NO_ATTEMPTS)
127 return;
128
129 if (close_reason_event ==
130 AutofillMetrics::UNMASK_PROMPT_CLOSED_ABANDON_UNMASKING) {
131 AutofillMetrics::LogTimeBeforeAbandonUnmasking(base::Time::Now() -
132 verify_timestamp_);
133 }
134
135 bool final_should_store_pan = pending_response_.should_store_pan;
136 if (unmasking_result_ == AutofillClient::SUCCESS && final_should_store_pan) {
137 AutofillMetrics::LogUnmaskPromptEvent(
138 AutofillMetrics::UNMASK_PROMPT_SAVED_CARD_LOCALLY);
139 }
140
141 if (CanStoreLocally()) {
142 // Tracking changes in local save preference.
143 AutofillMetrics::UnmaskPromptEvent event;
144 if (unmasking_initial_should_store_pan_ && final_should_store_pan) {
145 event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_OUT;
146 } else if (!unmasking_initial_should_store_pan_ &&
147 !final_should_store_pan) {
148 event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_IN;
149 } else if (unmasking_initial_should_store_pan_ && !final_should_store_pan) {
150 event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_OUT;
151 } else {
152 event = AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_IN;
153 }
154 AutofillMetrics::LogUnmaskPromptEvent(event);
155 }
156 }
157
158 AutofillMetrics::UnmaskPromptEvent
159 CardUnmaskPromptControllerImpl::GetCloseReasonEvent() {
160 if (unmasking_number_of_attempts_ == 0)
161 return AutofillMetrics::UNMASK_PROMPT_CLOSED_NO_ATTEMPTS;
162
163 // If NONE and we have a pending request, we have a pending GetRealPan
164 // request.
165 if (unmasking_result_ == AutofillClient::NONE)
166 return AutofillMetrics::UNMASK_PROMPT_CLOSED_ABANDON_UNMASKING;
167
168 if (unmasking_result_ == AutofillClient::SUCCESS) {
169 return unmasking_number_of_attempts_ == 1
170 ? AutofillMetrics::UNMASK_PROMPT_UNMASKED_CARD_FIRST_ATTEMPT
171 : AutofillMetrics::
172 UNMASK_PROMPT_UNMASKED_CARD_AFTER_FAILED_ATTEMPTS;
173 } else {
174 return AllowsRetry(unmasking_result_)
175 ? AutofillMetrics::
176 UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_RETRIABLE_FAILURE
177 : AutofillMetrics::
178 UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_NON_RETRIABLE_FAILURE ;
179 }
180 }
181
182 void CardUnmaskPromptControllerImpl::OnUnmaskResponse(
183 const base::string16& cvc,
184 const base::string16& exp_month,
185 const base::string16& exp_year,
186 bool should_store_pan) {
187 verify_timestamp_ = base::Time::Now();
188 unmasking_number_of_attempts_++;
189 unmasking_result_ = AutofillClient::NONE;
190 card_unmask_view_->DisableAndWaitForVerification();
191
192 DCHECK(InputCvcIsValid(cvc));
193 base::TrimWhitespace(cvc, base::TRIM_ALL, &pending_response_.cvc);
194 if (ShouldRequestExpirationDate()) {
195 DCHECK(InputExpirationIsValid(exp_month, exp_year));
196 pending_response_.exp_month = exp_month;
197 pending_response_.exp_year = exp_year;
198 }
199 if (CanStoreLocally()) {
200 pending_response_.should_store_pan = should_store_pan;
201 // Remember the last choice the user made (on this device).
202 pref_service_->SetBoolean(
203 prefs::kAutofillWalletImportStorageCheckboxState, should_store_pan);
204 } else {
205 DCHECK(!should_store_pan);
206 pending_response_.should_store_pan = false;
207 }
208
209 if (!pending_response_.risk_data.empty())
210 delegate_->OnUnmaskResponse(pending_response_);
211 }
212
213 void CardUnmaskPromptControllerImpl::NewCardLinkClicked() {
214 new_card_link_clicked_ = true;
215 }
216
217 content::WebContents* CardUnmaskPromptControllerImpl::GetWebContents() {
218 return web_contents_;
219 }
220
221 base::string16 CardUnmaskPromptControllerImpl::GetWindowTitle() const {
222 int ids = ShouldRequestExpirationDate()
223 ? IDS_AUTOFILL_CARD_UNMASK_PROMPT_UPDATE_TITLE
224 : IDS_AUTOFILL_CARD_UNMASK_PROMPT_TITLE;
225 return l10n_util::GetStringFUTF16(ids, card_.TypeAndLastFourDigits());
226 }
227
228 base::string16 CardUnmaskPromptControllerImpl::GetInstructionsMessage() const {
229 if (ShouldRequestExpirationDate()) {
230 return l10n_util::GetStringUTF16(
231 card_.type() == kAmericanExpressCard
232 ? IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_EXPIRED_AMEX
233 : IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_EXPIRED);
234 }
235
236 return l10n_util::GetStringUTF16(
237 card_.type() == kAmericanExpressCard
238 ? IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS_AMEX
239 : IDS_AUTOFILL_CARD_UNMASK_PROMPT_INSTRUCTIONS);
240 }
241
242 int CardUnmaskPromptControllerImpl::GetCvcImageRid() const {
243 return card_.type() == kAmericanExpressCard ? IDR_CREDIT_CARD_CVC_HINT_AMEX
244 : IDR_CREDIT_CARD_CVC_HINT;
245 }
246
247 bool CardUnmaskPromptControllerImpl::ShouldRequestExpirationDate() const {
248 return card_.GetServerStatus() == CreditCard::EXPIRED ||
249 new_card_link_clicked_;
250 }
251
252 bool CardUnmaskPromptControllerImpl::CanStoreLocally() const {
253 // Never offer to save for incognito.
254 if (is_off_the_record_)
255 return false;
256 return autofill::OfferStoreUnmaskedCards();
257 }
258
259 bool CardUnmaskPromptControllerImpl::GetStoreLocallyStartState() const {
260 return pref_service_->GetBoolean(
261 prefs::kAutofillWalletImportStorageCheckboxState);
262 }
263
264 bool CardUnmaskPromptControllerImpl::InputCvcIsValid(
265 const base::string16& input_text) const {
266 base::string16 trimmed_text;
267 base::TrimWhitespace(input_text, base::TRIM_ALL, &trimmed_text);
268 size_t input_size = card_.type() == kAmericanExpressCard ? 4 : 3;
269 return trimmed_text.size() == input_size &&
270 base::ContainsOnlyChars(trimmed_text,
271 base::ASCIIToUTF16("0123456789"));
272 }
273
274 bool CardUnmaskPromptControllerImpl::InputExpirationIsValid(
275 const base::string16& month,
276 const base::string16& year) const {
277 if ((month.size() != 2U && month.size() != 1U) ||
278 (year.size() != 4U && year.size() != 2U)) {
279 return false;
280 }
281
282 int month_value = 0, year_value = 0;
283 if (!base::StringToInt(month, &month_value) ||
284 !base::StringToInt(year, &year_value)) {
285 return false;
286 }
287
288 if (month_value < 1 || month_value > 12)
289 return false;
290
291 base::Time::Exploded now;
292 base::Time::Now().LocalExplode(&now);
293
294 // Convert 2 digit year to 4 digit year.
295 if (year_value < 100)
296 year_value += (now.year / 100) * 100;
297
298 if (year_value < now.year)
299 return false;
300
301 if (year_value > now.year)
302 return true;
303
304 return month_value >= now.month;
305 }
306
307 base::TimeDelta CardUnmaskPromptControllerImpl::GetSuccessMessageDuration()
308 const {
309 return base::TimeDelta::FromMilliseconds(500);
310 }
311
312 CardUnmaskPromptView* CardUnmaskPromptControllerImpl::CreateAndShowView() {
313 return CardUnmaskPromptView::CreateAndShow(this);
314 }
315
316 void CardUnmaskPromptControllerImpl::LoadRiskFingerprint() {
317 risk_data_callback_.Run(
318 base::Bind(&CardUnmaskPromptControllerImpl::OnDidLoadRiskFingerprint,
319 weak_pointer_factory_.GetWeakPtr()));
320 }
321
322 void CardUnmaskPromptControllerImpl::OnDidLoadRiskFingerprint(
323 const std::string& risk_data) {
324 pending_response_.risk_data = risk_data;
325 if (!pending_response_.cvc.empty())
326 delegate_->OnUnmaskResponse(pending_response_);
327 }
328
329 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698