Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / android / autofill / autofill_dialog_controller_android.cc
blobb60e1fb3715a30bb4def4901c701c0569af5b27d
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.
5 #include "chrome/browser/ui/android/autofill/autofill_dialog_controller_android.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/android/scoped_java_ref.h"
11 #include "base/bind.h"
12 #include "base/logging.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/autofill/personal_data_manager_factory.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/ui/android/autofill/autofill_dialog_result.h"
21 #include "chrome/browser/ui/android/window_android_helper.h"
22 #include "chrome/browser/ui/autofill/autofill_dialog_common.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/common/url_constants.h"
25 #include "components/autofill/content/browser/wallet/full_wallet.h"
26 #include "components/autofill/core/browser/autofill_metrics.h"
27 #include "components/autofill/core/browser/autofill_profile.h"
28 #include "components/autofill/core/browser/autofill_type.h"
29 #include "components/autofill/core/browser/credit_card.h"
30 #include "components/autofill/core/browser/detail_input.h"
31 #include "components/autofill/core/browser/dialog_section.h"
32 #include "components/autofill/core/browser/field_types.h"
33 #include "components/autofill/core/browser/personal_data_manager.h"
34 #include "components/autofill/core/browser/server_field_types_util.h"
35 #include "components/autofill/core/common/form_data.h"
36 #include "components/pref_registry/pref_registry_syncable.h"
37 #include "content/public/browser/navigation_controller.h"
38 #include "content/public/browser/navigation_details.h"
39 #include "content/public/browser/navigation_entry.h"
40 #include "content/public/browser/web_contents.h"
41 #include "jni/AutofillDialogControllerAndroid_jni.h"
42 #include "ui/android/window_android.h"
43 #include "ui/base/models/combobox_model.h"
44 #include "ui/base/models/menu_model.h"
45 #include "ui/gfx/android/java_bitmap.h"
46 #include "ui/gfx/geometry/rect.h"
47 #include "url/gurl.h"
49 namespace autofill {
51 namespace {
53 using wallet::FullWallet;
55 // Keys in kAutofillDialogDefaults pref dictionary (do not change these values).
56 const char kLastUsedAccountName[] = "last_used_account_name";
57 const char kLastUsedChoiceIsAutofill[] = "last_used_choice_is_autofill";
58 const char kLastUsedBillingAddressGuid[] = "last_used_billing";
59 const char kLastUsedShippingAddressGuid[] = "last_used_shipping";
60 const char kLastUsedCreditCardGuid[] = "last_used_card";
62 // Constructs |inputs| for the SECTION_CC_BILLING section.
63 void BuildCcBillingInputs(DetailInputs* inputs) {
64 const DetailInput kCcBillingInputs[] = {
65 { DetailInput::LONG, NAME_BILLING_FULL },
66 { DetailInput::LONG, ADDRESS_BILLING_STREET_ADDRESS },
67 { DetailInput::LONG, ADDRESS_BILLING_CITY },
68 { DetailInput::LONG, ADDRESS_BILLING_DEPENDENT_LOCALITY },
69 { DetailInput::LONG, ADDRESS_BILLING_STATE },
70 { DetailInput::LONG, ADDRESS_BILLING_ZIP },
71 { DetailInput::LONG, ADDRESS_BILLING_SORTING_CODE },
72 { DetailInput::LONG, ADDRESS_BILLING_COUNTRY },
73 { DetailInput::LONG, PHONE_BILLING_WHOLE_NUMBER },
74 { DetailInput::LONG, CREDIT_CARD_NUMBER },
75 { DetailInput::LONG, CREDIT_CARD_EXP_MONTH },
76 { DetailInput::LONG, CREDIT_CARD_EXP_4_DIGIT_YEAR },
77 { DetailInput::LONG, CREDIT_CARD_VERIFICATION_CODE },
79 BuildInputs(kCcBillingInputs, arraysize(kCcBillingInputs), inputs);
82 // Constructs |inputs| for the SECTION_SHIPPING section.
83 void BuildShippingInputs(DetailInputs* inputs) {
84 const DetailInput kShippingInputs[] = {
85 { DetailInput::LONG, NAME_FULL },
86 { DetailInput::LONG, ADDRESS_HOME_STREET_ADDRESS },
87 { DetailInput::LONG, ADDRESS_HOME_CITY },
88 { DetailInput::LONG, ADDRESS_HOME_DEPENDENT_LOCALITY },
89 { DetailInput::LONG, ADDRESS_HOME_STATE },
90 { DetailInput::LONG, ADDRESS_HOME_ZIP },
91 { DetailInput::LONG, ADDRESS_HOME_SORTING_CODE },
92 { DetailInput::LONG, ADDRESS_HOME_COUNTRY },
93 { DetailInput::LONG, PHONE_HOME_WHOLE_NUMBER },
95 BuildInputs(kShippingInputs, arraysize(kShippingInputs), inputs);
98 base::string16 NullGetInfo(const AutofillType& type) {
99 return base::string16();
102 void FillOutputForSectionWithComparator(
103 DialogSection section,
104 const DetailInputs& inputs,
105 const FormStructure::InputFieldComparator& compare,
106 FormStructure& form_structure,
107 FullWallet* full_wallet,
108 const base::string16& email_address) {
109 if ((section == SECTION_CC_BILLING && !full_wallet->billing_address()) ||
110 (section == SECTION_SHIPPING && !full_wallet->shipping_address())) {
111 return;
114 base::Callback<base::string16(const AutofillType&)> get_info =
115 base::Bind(&FullWallet::GetInfo,
116 base::Unretained(full_wallet),
117 g_browser_process->GetApplicationLocale());
119 std::vector<ServerFieldType> types = TypesFromInputs(inputs);
120 form_structure.FillFields(
121 types,
122 compare,
123 get_info,
124 section == SECTION_CC_BILLING
125 ? full_wallet->billing_address()->language_code()
126 : full_wallet->shipping_address()->language_code(),
127 g_browser_process->GetApplicationLocale());
130 void FillOutputForSection(
131 DialogSection section,
132 FormStructure& form_structure,
133 FullWallet* full_wallet,
134 const base::string16& email_address) {
135 DCHECK(section == SECTION_CC_BILLING || section == SECTION_SHIPPING);
136 DetailInputs inputs;
137 if (section == SECTION_CC_BILLING)
138 BuildCcBillingInputs(&inputs);
139 else
140 BuildShippingInputs(&inputs);
142 FillOutputForSectionWithComparator(
143 section, inputs, base::Bind(ServerTypeMatchesField, section),
144 form_structure, full_wallet, email_address);
146 if (section == SECTION_CC_BILLING) {
147 // Email is hidden while using Wallet, special case it.
148 for (size_t i = 0; i < form_structure.field_count(); ++i) {
149 AutofillField* field = form_structure.field(i);
150 if (field->Type().GetStorableType() == EMAIL_ADDRESS)
151 field->value = email_address;
156 // Returns true if |input_type| in |section| is needed for |form_structure|.
157 bool IsSectionInputUsedInFormStructure(DialogSection section,
158 ServerFieldType input_type,
159 const FormStructure& form_structure) {
160 for (size_t i = 0; i < form_structure.field_count(); ++i) {
161 const AutofillField* field = form_structure.field(i);
162 if (field && ServerTypeMatchesField(section, input_type, *field))
163 return true;
165 return false;
168 // Returns true if one of |inputs| in |section| is needed for |form_structure|.
169 bool IsSectionInputsUsedInFormStructure(DialogSection section,
170 const ServerFieldType* input_types,
171 const size_t input_types_size,
172 const FormStructure& form_structure) {
173 for (size_t i = 0; i < input_types_size; ++i) {
174 if (IsSectionInputUsedInFormStructure(
175 section, input_types[i], form_structure)) {
176 return true;
179 return false;
182 } // namespace
185 // static
186 base::WeakPtr<AutofillDialogController> AutofillDialogControllerAndroid::Create(
187 content::WebContents* contents,
188 const FormData& form_structure,
189 const GURL& source_url,
190 const AutofillClient::ResultCallback& callback) {
191 // AutofillDialogControllerAndroid owns itself.
192 AutofillDialogControllerAndroid* autofill_dialog_controller =
193 new AutofillDialogControllerAndroid(contents,
194 form_structure,
195 source_url,
196 callback);
197 return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
200 #if defined(ENABLE_AUTOFILL_DIALOG)
201 // static
202 base::WeakPtr<AutofillDialogController>
203 AutofillDialogController::Create(
204 content::WebContents* contents,
205 const FormData& form_structure,
206 const GURL& source_url,
207 const AutofillClient::ResultCallback& callback) {
208 return AutofillDialogControllerAndroid::Create(contents,
209 form_structure,
210 source_url,
211 callback);
214 // static
215 void AutofillDialogController::RegisterPrefs(PrefRegistrySimple* registry) {}
217 // static
218 void AutofillDialogController::RegisterProfilePrefs(
219 user_prefs::PrefRegistrySyncable* registry) {
220 registry->RegisterDictionaryPref(
221 ::prefs::kAutofillDialogDefaults,
222 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
224 #endif // defined(ENABLE_AUTOFILL_DIALOG)
226 AutofillDialogControllerAndroid::~AutofillDialogControllerAndroid() {
227 if (java_object_.is_null())
228 return;
230 JNIEnv* env = base::android::AttachCurrentThread();
231 Java_AutofillDialogControllerAndroid_onDestroy(env, java_object_.obj());
234 void AutofillDialogControllerAndroid::Show() {
235 JNIEnv* env = base::android::AttachCurrentThread();
236 dialog_shown_timestamp_ = base::Time::Now();
238 // The Autofill dialog is shown in response to a message from the renderer and
239 // as such, it can only be made in the context of the current document. A call
240 // to GetActiveEntry would return a pending entry, if there was one, which
241 // would be a security bug. Therefore, we use the last committed URL for the
242 // access checks.
243 const GURL& current_url = contents_->GetLastCommittedURL();
244 invoked_from_same_origin_ =
245 current_url.GetOrigin() == source_url_.GetOrigin();
247 // Fail if the dialog factory (e.g. SDK) doesn't support cross-origin calls.
248 if (!Java_AutofillDialogControllerAndroid_isDialogAllowed(
249 env,
250 invoked_from_same_origin_)) {
251 callback_.Run(
252 AutofillClient::AutocompleteResultErrorDisabled,
253 base::ASCIIToUTF16("Cross-origin form invocations are not supported."),
254 NULL);
255 delete this;
256 return;
259 // Determine what field types should be included in the dialog.
260 bool has_types = false;
261 bool has_sections = false;
262 form_structure_.ParseFieldTypesFromAutocompleteAttributes(
263 &has_types, &has_sections);
265 // Fail if the author didn't specify autocomplete types, or
266 // if the dialog shouldn't be shown in a given circumstances.
267 if (!has_types) {
268 callback_.Run(
269 AutofillClient::AutocompleteResultErrorDisabled,
270 base::ASCIIToUTF16("Form is missing autocomplete attributes."),
271 NULL);
272 delete this;
273 return;
276 // Fail if the author didn't ask for at least some kind of credit card
277 // information.
278 bool has_credit_card_field = false;
279 for (size_t i = 0; i < form_structure_.field_count(); ++i) {
280 AutofillType type = form_structure_.field(i)->Type();
281 if (type.html_type() != HTML_TYPE_UNKNOWN && type.group() == CREDIT_CARD) {
282 has_credit_card_field = true;
283 break;
287 if (!has_credit_card_field) {
288 callback_.Run(
289 AutofillClient::AutocompleteResultErrorDisabled,
290 base::ASCIIToUTF16("Form is not a payment form (must contain "
291 "some autocomplete=\"cc-*\" fields). "),
292 NULL);
293 delete this;
294 return;
297 // Log any relevant UI metrics and security exceptions.
298 AutofillMetrics::LogDialogUiEvent(AutofillMetrics::DIALOG_UI_SHOWN);
300 AutofillMetrics::LogDialogSecurityMetric(
301 AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN);
303 if (!invoked_from_same_origin_) {
304 AutofillMetrics::LogDialogSecurityMetric(
305 AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME);
308 const ServerFieldType full_billing_is_necessary_if[] = {
309 ADDRESS_BILLING_LINE1,
310 ADDRESS_BILLING_LINE2,
311 ADDRESS_BILLING_APT_NUM,
312 ADDRESS_BILLING_CITY,
313 ADDRESS_BILLING_STATE,
314 // ADDRESS_BILLING_ZIP, // Postal code alone is a short form.
315 ADDRESS_BILLING_COUNTRY,
316 ADDRESS_BILLING_STREET_ADDRESS,
317 ADDRESS_BILLING_DEPENDENT_LOCALITY,
318 ADDRESS_BILLING_SORTING_CODE,
319 PHONE_BILLING_WHOLE_NUMBER
321 const ServerFieldType billing_phone_number_is_necessary_if[] = {
322 PHONE_BILLING_WHOLE_NUMBER
324 const ServerFieldType shipping_phone_number_is_necessary_if[] = {
325 PHONE_HOME_WHOLE_NUMBER
327 const bool request_full_billing_address =
328 IsSectionInputsUsedInFormStructure(
329 SECTION_BILLING,
330 full_billing_is_necessary_if,
331 arraysize(full_billing_is_necessary_if),
332 form_structure_);
333 const bool request_phone_numbers =
334 IsSectionInputsUsedInFormStructure(
335 SECTION_BILLING,
336 billing_phone_number_is_necessary_if,
337 arraysize(billing_phone_number_is_necessary_if),
338 form_structure_) ||
339 IsSectionInputsUsedInFormStructure(
340 SECTION_SHIPPING,
341 shipping_phone_number_is_necessary_if,
342 arraysize(shipping_phone_number_is_necessary_if),
343 form_structure_);
345 bool request_shipping_address = false;
347 DetailInputs inputs;
348 BuildShippingInputs(&inputs);
349 request_shipping_address = form_structure_.FillFields(
350 TypesFromInputs(inputs),
351 base::Bind(ServerTypeMatchesField, SECTION_SHIPPING),
352 base::Bind(NullGetInfo), std::string(),
353 g_browser_process->GetApplicationLocale());
356 bool last_used_choice_is_autofill = false;
357 base::string16 last_used_account_name;
358 std::string last_used_billing;
359 std::string last_used_shipping;
360 std::string last_used_credit_card;
362 const base::DictionaryValue* defaults =
363 profile_->GetPrefs()->GetDictionary(::prefs::kAutofillDialogDefaults);
364 if (defaults) {
365 defaults->GetString(kLastUsedAccountName, &last_used_account_name);
366 defaults->GetBoolean(kLastUsedChoiceIsAutofill,
367 &last_used_choice_is_autofill);
368 defaults->GetString(kLastUsedBillingAddressGuid, &last_used_billing);
369 defaults->GetString(kLastUsedShippingAddressGuid, &last_used_shipping);
370 defaults->GetString(kLastUsedCreditCardGuid, &last_used_credit_card);
371 } else {
372 DLOG(ERROR) << "Failed to read AutofillDialog preferences";
376 const bool incognito_mode = profile_->IsOffTheRecord();
377 if (incognito_mode)
378 last_used_choice_is_autofill = true;
380 ScopedJavaLocalRef<jstring> jlast_used_account_name =
381 base::android::ConvertUTF16ToJavaString(
382 env, last_used_account_name);
383 ScopedJavaLocalRef<jstring> jlast_used_billing =
384 base::android::ConvertUTF8ToJavaString(
385 env, last_used_billing);
386 ScopedJavaLocalRef<jstring> jlast_used_shipping =
387 base::android::ConvertUTF8ToJavaString(
388 env, last_used_shipping);
389 ScopedJavaLocalRef<jstring> jlast_used_card =
390 base::android::ConvertUTF8ToJavaString(
391 env, last_used_credit_card);
392 ScopedJavaLocalRef<jstring> jmerchant_domain =
393 base::android::ConvertUTF8ToJavaString(
394 env, source_url_.GetOrigin().spec());
395 const std::set<base::string16> available_shipping_countries =
396 form_structure_.PossibleValues(ADDRESS_HOME_COUNTRY);
397 ScopedJavaLocalRef<jobjectArray> jshipping_countries =
398 base::android::ToJavaArrayOfStrings(
399 env,
400 std::vector<base::string16>(available_shipping_countries.begin(),
401 available_shipping_countries.end()));
402 const std::set<base::string16> available_credit_card_types =
403 form_structure_.PossibleValues(CREDIT_CARD_TYPE);
404 ScopedJavaLocalRef<jobjectArray> jcredit_card_types =
405 base::android::ToJavaArrayOfStrings(
406 env,
407 std::vector<base::string16>(available_credit_card_types.begin(),
408 available_credit_card_types.end()));
410 java_object_.Reset(Java_AutofillDialogControllerAndroid_create(
411 env,
412 reinterpret_cast<intptr_t>(this),
413 WindowAndroidHelper::FromWebContents(contents_)->
414 GetWindowAndroid()->GetJavaObject().obj(),
415 request_full_billing_address, request_shipping_address,
416 request_phone_numbers, incognito_mode,
417 last_used_choice_is_autofill, jlast_used_account_name.obj(),
418 jlast_used_billing.obj(), jlast_used_shipping.obj(),
419 jlast_used_card.obj(),
420 jmerchant_domain.obj(),
421 jshipping_countries.obj(),
422 jcredit_card_types.obj()));
425 void AutofillDialogControllerAndroid::Hide() {
426 delete this;
429 void AutofillDialogControllerAndroid::TabActivated() {}
431 // static
432 bool AutofillDialogControllerAndroid::
433 RegisterAutofillDialogControllerAndroid(JNIEnv* env) {
434 return RegisterNativesImpl(env);
437 void AutofillDialogControllerAndroid::DialogCancel(JNIEnv* env,
438 jobject obj) {
439 LogOnCancelMetrics();
440 callback_.Run(AutofillClient::AutocompleteResultErrorCancel,
441 base::string16(),
442 NULL);
445 void AutofillDialogControllerAndroid::DialogContinue(
446 JNIEnv* env,
447 jobject obj,
448 jobject wallet,
449 jboolean jlast_used_choice_is_autofill,
450 jstring jlast_used_account_name,
451 jstring jlast_used_billing,
452 jstring jlast_used_shipping,
453 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);
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);
468 scoped_ptr<FullWallet> full_wallet =
469 AutofillDialogResult::ConvertFromJava(env, wallet);
470 FillOutputForSection(
471 SECTION_CC_BILLING, form_structure_, full_wallet.get(), email);
472 FillOutputForSection(
473 SECTION_SHIPPING, form_structure_, full_wallet.get(), email);
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";
495 LogOnFinishSubmitMetrics();
497 // Callback should be called as late as possible.
498 callback_.Run(AutofillClient::AutocompleteResultSuccess,
499 base::string16(),
500 &form_structure_);
502 // This might delete us.
503 Hide();
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());
524 void AutofillDialogControllerAndroid::LogOnFinishSubmitMetrics() {
525 AutofillMetrics::LogDialogUiDuration(
526 base::Time::Now() - dialog_shown_timestamp_,
527 AutofillMetrics::DIALOG_ACCEPTED);
529 AutofillMetrics::LogDialogUiEvent(AutofillMetrics::DIALOG_UI_ACCEPTED);
532 void AutofillDialogControllerAndroid::LogOnCancelMetrics() {
533 AutofillMetrics::LogDialogUiDuration(
534 base::Time::Now() - dialog_shown_timestamp_,
535 AutofillMetrics::DIALOG_CANCELED);
537 AutofillMetrics::LogDialogUiEvent(AutofillMetrics::DIALOG_UI_CANCELED);
540 } // namespace autofill