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

Side by Side Diff: chrome/browser/ui/android/autofill/autofill_dialog_controller_android.cc

Issue 1931043002: Remove requestAutocomplete (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 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 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/android/autofill/autofill_dialog_controller_android. h"
6
7 #include <stddef.h>
8
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_array.h"
11 #include "base/android/jni_string.h"
12 #include "base/android/scoped_java_ref.h"
13 #include "base/bind.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/autofill/personal_data_manager_factory.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/ui/android/autofill/autofill_dialog_result.h"
22 #include "chrome/browser/ui/android/view_android_helper.h"
23 #include "chrome/browser/ui/autofill/autofill_dialog_common.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/common/url_constants.h"
26 #include "components/autofill/content/browser/wallet/full_wallet.h"
27 #include "components/autofill/core/browser/autofill_metrics.h"
28 #include "components/autofill/core/browser/autofill_profile.h"
29 #include "components/autofill/core/browser/autofill_type.h"
30 #include "components/autofill/core/browser/credit_card.h"
31 #include "components/autofill/core/browser/detail_input.h"
32 #include "components/autofill/core/browser/dialog_section.h"
33 #include "components/autofill/core/browser/field_types.h"
34 #include "components/autofill/core/browser/personal_data_manager.h"
35 #include "components/autofill/core/browser/server_field_types_util.h"
36 #include "components/autofill/core/common/form_data.h"
37 #include "components/pref_registry/pref_registry_syncable.h"
38 #include "components/prefs/pref_service.h"
39 #include "components/prefs/scoped_user_pref_update.h"
40 #include "content/public/browser/navigation_controller.h"
41 #include "content/public/browser/navigation_details.h"
42 #include "content/public/browser/navigation_entry.h"
43 #include "content/public/browser/web_contents.h"
44 #include "jni/AutofillDialogControllerAndroid_jni.h"
45 #include "ui/android/view_android.h"
46 #include "ui/android/window_android.h"
47 #include "ui/base/models/combobox_model.h"
48 #include "ui/base/models/menu_model.h"
49 #include "ui/gfx/android/java_bitmap.h"
50 #include "ui/gfx/geometry/rect.h"
51 #include "url/gurl.h"
52
53 namespace autofill {
54
55 namespace {
56
57 using wallet::FullWallet;
58
59 // Keys in kAutofillDialogDefaults pref dictionary (do not change these values).
60 const char kLastUsedAccountName[] = "last_used_account_name";
61 const char kLastUsedChoiceIsAutofill[] = "last_used_choice_is_autofill";
62 const char kLastUsedBillingAddressGuid[] = "last_used_billing";
63 const char kLastUsedShippingAddressGuid[] = "last_used_shipping";
64 const char kLastUsedCreditCardGuid[] = "last_used_card";
65
66 // Constructs |inputs| for the SECTION_BILLING section.
67 void BuildCcBillingInputs(DetailInputs* inputs) {
68 const DetailInput kCcBillingInputs[] = {
69 { DetailInput::LONG, NAME_BILLING_FULL },
70 { DetailInput::LONG, ADDRESS_BILLING_STREET_ADDRESS },
71 { DetailInput::LONG, ADDRESS_BILLING_CITY },
72 { DetailInput::LONG, ADDRESS_BILLING_DEPENDENT_LOCALITY },
73 { DetailInput::LONG, ADDRESS_BILLING_STATE },
74 { DetailInput::LONG, ADDRESS_BILLING_ZIP },
75 { DetailInput::LONG, ADDRESS_BILLING_SORTING_CODE },
76 { DetailInput::LONG, ADDRESS_BILLING_COUNTRY },
77 { DetailInput::LONG, PHONE_BILLING_WHOLE_NUMBER },
78 { DetailInput::LONG, CREDIT_CARD_NUMBER },
79 { DetailInput::LONG, CREDIT_CARD_EXP_MONTH },
80 { DetailInput::LONG, CREDIT_CARD_EXP_4_DIGIT_YEAR },
81 { DetailInput::LONG, CREDIT_CARD_VERIFICATION_CODE },
82 };
83 BuildInputs(kCcBillingInputs, arraysize(kCcBillingInputs), inputs);
84 }
85
86 // Constructs |inputs| for the SECTION_SHIPPING section.
87 void BuildShippingInputs(DetailInputs* inputs) {
88 const DetailInput kShippingInputs[] = {
89 { DetailInput::LONG, NAME_FULL },
90 { DetailInput::LONG, ADDRESS_HOME_STREET_ADDRESS },
91 { DetailInput::LONG, ADDRESS_HOME_CITY },
92 { DetailInput::LONG, ADDRESS_HOME_DEPENDENT_LOCALITY },
93 { DetailInput::LONG, ADDRESS_HOME_STATE },
94 { DetailInput::LONG, ADDRESS_HOME_ZIP },
95 { DetailInput::LONG, ADDRESS_HOME_SORTING_CODE },
96 { DetailInput::LONG, ADDRESS_HOME_COUNTRY },
97 { DetailInput::LONG, PHONE_HOME_WHOLE_NUMBER },
98 };
99 BuildInputs(kShippingInputs, arraysize(kShippingInputs), inputs);
100 }
101
102 base::string16 NullGetInfo(const AutofillType& type) {
103 return base::string16();
104 }
105
106 void FillOutputForSectionWithComparator(
107 DialogSection section,
108 const DetailInputs& inputs,
109 const FormStructure::InputFieldComparator& compare,
110 FormStructure& form_structure,
111 FullWallet* full_wallet,
112 const base::string16& email_address) {
113 if ((section == SECTION_BILLING && !full_wallet->billing_address()) ||
114 (section == SECTION_SHIPPING && !full_wallet->shipping_address())) {
115 return;
116 }
117
118 base::Callback<base::string16(const AutofillType&)> get_info =
119 base::Bind(&FullWallet::GetInfo,
120 base::Unretained(full_wallet),
121 g_browser_process->GetApplicationLocale());
122
123 std::vector<ServerFieldType> types = TypesFromInputs(inputs);
124 form_structure.FillFields(
125 types, compare, get_info,
126 section == SECTION_BILLING
127 ? full_wallet->billing_address()->language_code()
128 : full_wallet->shipping_address()->language_code(),
129 g_browser_process->GetApplicationLocale());
130 }
131
132 void FillOutputForSection(
133 DialogSection section,
134 FormStructure& form_structure,
135 FullWallet* full_wallet,
136 const base::string16& email_address) {
137 DetailInputs inputs;
138 if (section == SECTION_BILLING)
139 BuildCcBillingInputs(&inputs);
140 else
141 BuildShippingInputs(&inputs);
142
143 FillOutputForSectionWithComparator(
144 section, inputs, base::Bind(ServerTypeMatchesField, section),
145 form_structure, full_wallet, email_address);
146
147 if (section == SECTION_BILLING) {
148 // Email is hidden while using Wallet, special case it.
149 for (size_t i = 0; i < form_structure.field_count(); ++i) {
150 AutofillField* field = form_structure.field(i);
151 if (field->Type().GetStorableType() == EMAIL_ADDRESS)
152 field->value = email_address;
153 }
154 }
155 }
156
157 // Returns true if |input_type| in |section| is needed for |form_structure|.
158 bool IsSectionInputUsedInFormStructure(DialogSection section,
159 ServerFieldType input_type,
160 const FormStructure& form_structure) {
161 for (size_t i = 0; i < form_structure.field_count(); ++i) {
162 const AutofillField* field = form_structure.field(i);
163 if (field && ServerTypeMatchesField(section, input_type, *field))
164 return true;
165 }
166 return false;
167 }
168
169 // Returns true if one of |inputs| in |section| is needed for |form_structure|.
170 bool IsSectionInputsUsedInFormStructure(DialogSection section,
171 const ServerFieldType* input_types,
172 const size_t input_types_size,
173 const FormStructure& form_structure) {
174 for (size_t i = 0; i < input_types_size; ++i) {
175 if (IsSectionInputUsedInFormStructure(
176 section, input_types[i], form_structure)) {
177 return true;
178 }
179 }
180 return false;
181 }
182
183 } // namespace
184
185
186 // static
187 base::WeakPtr<AutofillDialogController> AutofillDialogControllerAndroid::Create(
188 content::WebContents* contents,
189 const FormData& form_structure,
190 const GURL& source_url,
191 const AutofillClient::ResultCallback& callback) {
192 // AutofillDialogControllerAndroid owns itself.
193 AutofillDialogControllerAndroid* autofill_dialog_controller =
194 new AutofillDialogControllerAndroid(contents,
195 form_structure,
196 source_url,
197 callback);
198 return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
199 }
200
201 #if defined(ENABLE_AUTOFILL_DIALOG)
202 // static
203 base::WeakPtr<AutofillDialogController>
204 AutofillDialogController::Create(
205 content::WebContents* contents,
206 const FormData& form_structure,
207 const GURL& source_url,
208 const AutofillClient::ResultCallback& callback) {
209 return AutofillDialogControllerAndroid::Create(contents,
210 form_structure,
211 source_url,
212 callback);
213 }
214
215 // static
216 void AutofillDialogController::RegisterPrefs(PrefRegistrySimple* registry) {}
217
218 // static
219 void AutofillDialogController::RegisterProfilePrefs(
220 user_prefs::PrefRegistrySyncable* registry) {
221 registry->RegisterDictionaryPref(
222 ::prefs::kAutofillDialogDefaults,
223 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
224 }
225 #endif // defined(ENABLE_AUTOFILL_DIALOG)
226
227 AutofillDialogControllerAndroid::~AutofillDialogControllerAndroid() {
228 if (java_object_.is_null())
229 return;
230
231 JNIEnv* env = base::android::AttachCurrentThread();
232 Java_AutofillDialogControllerAndroid_onDestroy(env, java_object_.obj());
233 }
234
235 void AutofillDialogControllerAndroid::Show() {
236 JNIEnv* env = base::android::AttachCurrentThread();
237 dialog_shown_timestamp_ = base::Time::Now();
238
239 // The Autofill dialog is shown in response to a message from the renderer and
240 // as such, it can only be made in the context of the current document. A call
241 // to GetActiveEntry would return a pending entry, if there was one, which
242 // would be a security bug. Therefore, we use the last committed URL for the
243 // access checks.
244 const GURL& current_url = contents_->GetLastCommittedURL();
245 invoked_from_same_origin_ =
246 current_url.GetOrigin() == source_url_.GetOrigin();
247
248 // Fail if the dialog factory (e.g. SDK) doesn't support cross-origin calls.
249 if (!Java_AutofillDialogControllerAndroid_isDialogAllowed(
250 env,
251 invoked_from_same_origin_)) {
252 callback_.Run(
253 AutofillClient::AutocompleteResultErrorDisabled,
254 base::ASCIIToUTF16("Cross-origin form invocations are not supported."),
255 NULL);
256 delete this;
257 return;
258 }
259
260 // Determine what field types should be included in the dialog.
261 form_structure_.ParseFieldTypesFromAutocompleteAttributes();
262
263 // Fail if the author didn't specify autocomplete types, or
264 // if the dialog shouldn't be shown in a given circumstances.
265 if (!form_structure_.has_author_specified_types()) {
266 callback_.Run(
267 AutofillClient::AutocompleteResultErrorDisabled,
268 base::ASCIIToUTF16("Form is missing autocomplete attributes."),
269 NULL);
270 delete this;
271 return;
272 }
273
274 // Fail if the author didn't ask for at least some kind of credit card
275 // information.
276 bool has_credit_card_field = false;
277 for (size_t i = 0; i < form_structure_.field_count(); ++i) {
278 AutofillType type = form_structure_.field(i)->Type();
279 if (type.html_type() != HTML_TYPE_UNSPECIFIED &&
280 type.group() == CREDIT_CARD) {
281 has_credit_card_field = true;
282 break;
283 }
284 }
285
286 if (!has_credit_card_field) {
287 callback_.Run(
288 AutofillClient::AutocompleteResultErrorDisabled,
289 base::ASCIIToUTF16("Form is not a payment form (must contain "
290 "some autocomplete=\"cc-*\" fields). "),
291 NULL);
292 delete this;
293 return;
294 }
295
296 // Log any relevant UI metrics and security exceptions.
297 AutofillMetrics::LogDialogUiEvent(AutofillMetrics::DIALOG_UI_SHOWN);
298
299 AutofillMetrics::LogDialogSecurityMetric(
300 AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN);
301
302 if (!invoked_from_same_origin_) {
303 AutofillMetrics::LogDialogSecurityMetric(
304 AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME);
305 }
306
307 const ServerFieldType full_billing_is_necessary_if[] = {
308 ADDRESS_BILLING_LINE1,
309 ADDRESS_BILLING_LINE2,
310 ADDRESS_BILLING_APT_NUM,
311 ADDRESS_BILLING_CITY,
312 ADDRESS_BILLING_STATE,
313 // ADDRESS_BILLING_ZIP, // Postal code alone is a short form.
314 ADDRESS_BILLING_COUNTRY,
315 ADDRESS_BILLING_STREET_ADDRESS,
316 ADDRESS_BILLING_DEPENDENT_LOCALITY,
317 ADDRESS_BILLING_SORTING_CODE,
318 PHONE_BILLING_WHOLE_NUMBER
319 };
320 const ServerFieldType billing_phone_number_is_necessary_if[] = {
321 PHONE_BILLING_WHOLE_NUMBER
322 };
323 const ServerFieldType shipping_phone_number_is_necessary_if[] = {
324 PHONE_HOME_WHOLE_NUMBER
325 };
326 const bool request_full_billing_address =
327 IsSectionInputsUsedInFormStructure(
328 SECTION_BILLING,
329 full_billing_is_necessary_if,
330 arraysize(full_billing_is_necessary_if),
331 form_structure_);
332 const bool request_phone_numbers =
333 IsSectionInputsUsedInFormStructure(
334 SECTION_BILLING,
335 billing_phone_number_is_necessary_if,
336 arraysize(billing_phone_number_is_necessary_if),
337 form_structure_) ||
338 IsSectionInputsUsedInFormStructure(
339 SECTION_SHIPPING,
340 shipping_phone_number_is_necessary_if,
341 arraysize(shipping_phone_number_is_necessary_if),
342 form_structure_);
343
344 bool request_shipping_address = false;
345 {
346 DetailInputs inputs;
347 BuildShippingInputs(&inputs);
348 request_shipping_address = form_structure_.FillFields(
349 TypesFromInputs(inputs),
350 base::Bind(ServerTypeMatchesField, SECTION_SHIPPING),
351 base::Bind(NullGetInfo), std::string(),
352 g_browser_process->GetApplicationLocale());
353 }
354
355 bool last_used_choice_is_autofill = false;
356 base::string16 last_used_account_name;
357 std::string last_used_billing;
358 std::string last_used_shipping;
359 std::string last_used_credit_card;
360 {
361 const base::DictionaryValue* defaults =
362 profile_->GetPrefs()->GetDictionary(::prefs::kAutofillDialogDefaults);
363 if (defaults) {
364 defaults->GetString(kLastUsedAccountName, &last_used_account_name);
365 defaults->GetBoolean(kLastUsedChoiceIsAutofill,
366 &last_used_choice_is_autofill);
367 defaults->GetString(kLastUsedBillingAddressGuid, &last_used_billing);
368 defaults->GetString(kLastUsedShippingAddressGuid, &last_used_shipping);
369 defaults->GetString(kLastUsedCreditCardGuid, &last_used_credit_card);
370 } else {
371 DLOG(ERROR) << "Failed to read AutofillDialog preferences";
372 }
373 }
374
375 const bool incognito_mode = profile_->IsOffTheRecord();
376 if (incognito_mode)
377 last_used_choice_is_autofill = true;
378
379 ScopedJavaLocalRef<jstring> jlast_used_account_name =
380 base::android::ConvertUTF16ToJavaString(
381 env, last_used_account_name);
382 ScopedJavaLocalRef<jstring> jlast_used_billing =
383 base::android::ConvertUTF8ToJavaString(
384 env, last_used_billing);
385 ScopedJavaLocalRef<jstring> jlast_used_shipping =
386 base::android::ConvertUTF8ToJavaString(
387 env, last_used_shipping);
388 ScopedJavaLocalRef<jstring> jlast_used_card =
389 base::android::ConvertUTF8ToJavaString(
390 env, last_used_credit_card);
391 ScopedJavaLocalRef<jstring> jmerchant_domain =
392 base::android::ConvertUTF8ToJavaString(
393 env, source_url_.GetOrigin().spec());
394 const std::set<base::string16> available_shipping_countries =
395 form_structure_.PossibleValues(ADDRESS_HOME_COUNTRY);
396 ScopedJavaLocalRef<jobjectArray> jshipping_countries =
397 base::android::ToJavaArrayOfStrings(
398 env,
399 std::vector<base::string16>(available_shipping_countries.begin(),
400 available_shipping_countries.end()));
401 const std::set<base::string16> available_credit_card_types =
402 form_structure_.PossibleValues(CREDIT_CARD_TYPE);
403 ScopedJavaLocalRef<jobjectArray> jcredit_card_types =
404 base::android::ToJavaArrayOfStrings(
405 env,
406 std::vector<base::string16>(available_credit_card_types.begin(),
407 available_credit_card_types.end()));
408
409 java_object_.Reset(Java_AutofillDialogControllerAndroid_create(
410 env,
411 reinterpret_cast<intptr_t>(this),
412 ViewAndroidHelper::FromWebContents(contents_)->
413 GetViewAndroid()->GetWindowAndroid()->GetJavaObject().obj(),
414 request_full_billing_address, request_shipping_address,
415 request_phone_numbers, incognito_mode,
416 last_used_choice_is_autofill, jlast_used_account_name.obj(),
417 jlast_used_billing.obj(), jlast_used_shipping.obj(),
418 jlast_used_card.obj(),
419 jmerchant_domain.obj(),
420 jshipping_countries.obj(),
421 jcredit_card_types.obj()));
422 }
423
424 void AutofillDialogControllerAndroid::Hide() {
425 delete this;
426 }
427
428 void AutofillDialogControllerAndroid::TabActivated() {}
429
430 // static
431 bool AutofillDialogControllerAndroid::
432 RegisterAutofillDialogControllerAndroid(JNIEnv* env) {
433 return RegisterNativesImpl(env);
434 }
435
436 void AutofillDialogControllerAndroid::DialogCancel(
437 JNIEnv* env,
438 const JavaParamRef<jobject>& obj) {
439 LogOnCancelMetrics();
440 callback_.Run(AutofillClient::AutocompleteResultErrorCancel,
441 base::string16(),
442 NULL);
443 }
444
445 void AutofillDialogControllerAndroid::DialogContinue(
446 JNIEnv* env,
447 const JavaParamRef<jobject>& obj,
448 const JavaParamRef<jobject>& wallet,
449 jboolean jlast_used_choice_is_autofill,
450 const JavaParamRef<jstring>& jlast_used_account_name,
451 const JavaParamRef<jstring>& jlast_used_billing,
452 const JavaParamRef<jstring>& jlast_used_shipping,
453 const JavaParamRef<jstring>& jlast_used_card) {
454 const base::string16 email =
455 AutofillDialogResult::GetWalletEmail(env, wallet);
456 const std::string google_transaction_id =
457 AutofillDialogResult::GetWalletGoogleTransactionId(env, wallet);
458
459 const base::string16 last_used_account_name =
460 base::android::ConvertJavaStringToUTF16(env, jlast_used_account_name);
461 const std::string last_used_billing =
462 base::android::ConvertJavaStringToUTF8(env, jlast_used_billing);
463 const std::string last_used_shipping =
464 base::android::ConvertJavaStringToUTF8(env, jlast_used_shipping);
465 const std::string last_used_card =
466 base::android::ConvertJavaStringToUTF8(env, jlast_used_card);
467
468 std::unique_ptr<FullWallet> full_wallet =
469 AutofillDialogResult::ConvertFromJava(env, wallet);
470 FillOutputForSection(SECTION_BILLING, form_structure_, full_wallet.get(),
471 email);
472 FillOutputForSection(
473 SECTION_SHIPPING, form_structure_, full_wallet.get(), email);
474
475 {
476 DictionaryPrefUpdate updater(profile_->GetPrefs(),
477 ::prefs::kAutofillDialogDefaults);
478 base::DictionaryValue* defaults = updater.Get();
479 if (defaults) {
480 const bool last_used_choice_is_autofill = !!jlast_used_choice_is_autofill;
481 defaults->SetString(kLastUsedAccountName, last_used_account_name);
482 defaults->SetBoolean(kLastUsedChoiceIsAutofill,
483 last_used_choice_is_autofill);
484 if (!last_used_billing.empty())
485 defaults->SetString(kLastUsedBillingAddressGuid, last_used_billing);
486 if (!last_used_shipping.empty())
487 defaults->SetString(kLastUsedShippingAddressGuid, last_used_shipping);
488 if (!last_used_card.empty())
489 defaults->SetString(kLastUsedCreditCardGuid, last_used_card);
490 } else {
491 DLOG(ERROR) << "Failed to save AutofillDialog preferences";
492 }
493 }
494
495 LogOnFinishSubmitMetrics();
496
497 // Callback should be called as late as possible.
498 callback_.Run(AutofillClient::AutocompleteResultSuccess,
499 base::string16(),
500 &form_structure_);
501
502 // This might delete us.
503 Hide();
504 }
505
506 AutofillDialogControllerAndroid::AutofillDialogControllerAndroid(
507 content::WebContents* contents,
508 const FormData& form_structure,
509 const GURL& source_url,
510 const AutofillClient::ResultCallback& callback)
511 : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
512 contents_(contents),
513 initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
514 form_structure_(form_structure),
515 invoked_from_same_origin_(true),
516 source_url_(source_url),
517 callback_(callback),
518 cares_about_shipping_(true),
519 was_ui_latency_logged_(false),
520 weak_ptr_factory_(this) {
521 DCHECK(!callback_.is_null());
522 }
523
524 void AutofillDialogControllerAndroid::LogOnFinishSubmitMetrics() {
525 AutofillMetrics::LogDialogUiDuration(
526 base::Time::Now() - dialog_shown_timestamp_,
527 AutofillMetrics::DIALOG_ACCEPTED);
528
529 AutofillMetrics::LogDialogUiEvent(AutofillMetrics::DIALOG_UI_ACCEPTED);
530 }
531
532 void AutofillDialogControllerAndroid::LogOnCancelMetrics() {
533 AutofillMetrics::LogDialogUiDuration(
534 base::Time::Now() - dialog_shown_timestamp_,
535 AutofillMetrics::DIALOG_CANCELED);
536
537 AutofillMetrics::LogDialogUiEvent(AutofillMetrics::DIALOG_UI_CANCELED);
538 }
539
540 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698