Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / android / autofill / autofill_dialog_controller_android.cc
blob2e67caba345d8d81c27acd50c04e949bb2db528a
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/browser/ui/autofill/data_model_wrapper.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/personal_data_manager.h"
32 #include "components/autofill/core/common/form_data.h"
33 #include "components/user_prefs/pref_registry_syncable.h"
34 #include "content/public/browser/navigation_controller.h"
35 #include "content/public/browser/navigation_details.h"
36 #include "content/public/browser/navigation_entry.h"
37 #include "content/public/browser/web_contents.h"
38 #include "grit/generated_resources.h"
39 #include "jni/AutofillDialogControllerAndroid_jni.h"
40 #include "ui/base/android/window_android.h"
41 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/base/models/combobox_model.h"
43 #include "ui/base/models/menu_model.h"
44 #include "ui/gfx/android/java_bitmap.h"
45 #include "ui/gfx/rect.h"
46 #include "url/gurl.h"
48 namespace autofill {
50 namespace {
52 // Keys in kAutofillDialogDefaults pref dictionary (do not change these values).
53 const char kLastUsedAccountName[] = "last_used_account_name";
54 const char kLastUsedChoiceIsAutofill[] = "last_used_choice_is_autofill";
55 const char kLastUsedBillingAddressGuid[] = "last_used_billing";
56 const char kLastUsedShippingAddressGuid[] = "last_used_shipping";
57 const char kLastUsedCreditCardGuid[] = "last_used_card";
59 scoped_ptr<DataModelWrapper> CreateWrapper(
60 DialogSection section, wallet::FullWallet* full_wallet) {
61 if (section == SECTION_CC_BILLING) {
62 if (!full_wallet->billing_address())
63 return scoped_ptr<DataModelWrapper>();
65 return scoped_ptr<DataModelWrapper>(
66 new FullWalletBillingWrapper(full_wallet));
68 if (section == SECTION_SHIPPING) {
69 if (!full_wallet->shipping_address())
70 return scoped_ptr<DataModelWrapper>();
72 return scoped_ptr<DataModelWrapper>(
73 new FullWalletShippingWrapper(full_wallet));
75 NOTREACHED();
76 return scoped_ptr<DataModelWrapper>();
79 void FillOutputForSectionWithComparator(
80 DialogSection section, const DetailInputs& inputs,
81 const InputFieldComparator& compare,
82 FormStructure& form_structure, wallet::FullWallet* full_wallet,
83 const base::string16& email_address) {
84 scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section, full_wallet);
85 if (wrapper)
86 wrapper->FillFormStructure(inputs, compare, &form_structure);
89 void FillOutputForSection(
90 DialogSection section,
91 FormStructure& form_structure,
92 wallet::FullWallet* full_wallet,
93 const base::string16& email_address) {
94 DetailInputs inputs;
95 common::BuildInputsForSection(section, "US", &inputs);
97 FillOutputForSectionWithComparator(
98 section, inputs,
99 base::Bind(common::DetailInputMatchesField, section),
100 form_structure, full_wallet, email_address);
102 if (section == SECTION_CC_BILLING) {
103 // Email is hidden while using Wallet, special case it.
104 for (size_t i = 0; i < form_structure.field_count(); ++i) {
105 AutofillField* field = form_structure.field(i);
106 if (field->Type().GetStorableType() == EMAIL_ADDRESS)
107 field->value = email_address;
112 // Returns true if |input_type| in |section| is needed for |form_structure|.
113 bool IsSectionInputUsedInFormStructure(DialogSection section,
114 ServerFieldType input_type,
115 const FormStructure& form_structure) {
116 const DetailInput input = { DetailInput::LONG, input_type };
117 for (size_t i = 0; i < form_structure.field_count(); ++i) {
118 const AutofillField* field = form_structure.field(i);
119 if (field && common::DetailInputMatchesField(section, input, *field))
120 return true;
122 return false;
125 // Returns true if one of |inputs| in |section| is needed for |form_structure|.
126 bool IsSectionInputsUsedInFormStructure(DialogSection section,
127 const ServerFieldType* input_types,
128 const size_t input_types_size,
129 const FormStructure& form_structure) {
130 for (size_t i = 0; i < input_types_size; ++i) {
131 if (IsSectionInputUsedInFormStructure(
132 section, input_types[i], form_structure)) {
133 return true;
136 return false;
139 } // namespace
142 // static
143 base::WeakPtr<AutofillDialogController> AutofillDialogControllerAndroid::Create(
144 content::WebContents* contents,
145 const FormData& form_structure,
146 const GURL& source_url,
147 const base::Callback<void(const FormStructure*)>& callback) {
148 // AutofillDialogControllerAndroid owns itself.
149 AutofillDialogControllerAndroid* autofill_dialog_controller =
150 new AutofillDialogControllerAndroid(contents,
151 form_structure,
152 source_url,
153 callback);
154 return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
157 #if defined(ENABLE_AUTOFILL_DIALOG)
158 // static
159 base::WeakPtr<AutofillDialogController>
160 AutofillDialogController::Create(
161 content::WebContents* contents,
162 const FormData& form_structure,
163 const GURL& source_url,
164 const base::Callback<void(const FormStructure*)>& callback) {
165 return AutofillDialogControllerAndroid::Create(contents,
166 form_structure,
167 source_url,
168 callback);
171 // static
172 void AutofillDialogController::RegisterPrefs(PrefRegistrySimple* registry) {}
174 // static
175 void AutofillDialogController::RegisterProfilePrefs(
176 user_prefs::PrefRegistrySyncable* registry) {
177 registry->RegisterDictionaryPref(
178 ::prefs::kAutofillDialogDefaults,
179 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
181 #endif // defined(ENABLE_AUTOFILL_DIALOG)
183 AutofillDialogControllerAndroid::~AutofillDialogControllerAndroid() {
184 if (java_object_.is_null())
185 return;
187 JNIEnv* env = base::android::AttachCurrentThread();
188 Java_AutofillDialogControllerAndroid_onDestroy(env, java_object_.obj());
191 void AutofillDialogControllerAndroid::Show() {
192 JNIEnv* env = base::android::AttachCurrentThread();
193 dialog_shown_timestamp_ = base::Time::Now();
195 const GURL& current_url = contents_->GetLastCommittedURL();
196 invoked_from_same_origin_ =
197 current_url.GetOrigin() == source_url_.GetOrigin();
199 // Determine what field types should be included in the dialog.
200 bool has_types = false;
201 bool has_sections = false;
202 form_structure_.ParseFieldTypesFromAutocompleteAttributes(
203 &has_types, &has_sections);
205 // Fail if the author didn't specify autocomplete types, or
206 // if the dialog shouldn't be shown in a given circumstances.
207 if (!has_types ||
208 !Java_AutofillDialogControllerAndroid_isDialogAllowed(
209 env,
210 invoked_from_same_origin_)) {
211 callback_.Run(NULL);
212 delete this;
213 return;
216 // Log any relevant UI metrics and security exceptions.
217 GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_SHOWN);
219 GetMetricLogger().LogDialogSecurityMetric(
220 AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN);
222 if (!invoked_from_same_origin_) {
223 GetMetricLogger().LogDialogSecurityMetric(
224 AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME);
227 const ServerFieldType full_billing_is_necessary_if[] = {
228 ADDRESS_BILLING_LINE1,
229 ADDRESS_BILLING_LINE2,
230 ADDRESS_BILLING_CITY,
231 ADDRESS_BILLING_STATE,
232 PHONE_BILLING_WHOLE_NUMBER
234 const bool request_full_billing_address =
235 IsSectionInputsUsedInFormStructure(
236 SECTION_BILLING,
237 full_billing_is_necessary_if,
238 arraysize(full_billing_is_necessary_if),
239 form_structure_);
240 const bool request_phone_numbers =
241 IsSectionInputUsedInFormStructure(
242 SECTION_BILLING,
243 PHONE_BILLING_WHOLE_NUMBER,
244 form_structure_) ||
245 IsSectionInputUsedInFormStructure(
246 SECTION_SHIPPING,
247 PHONE_HOME_WHOLE_NUMBER,
248 form_structure_);
250 bool request_shipping_address = false;
252 DetailInputs inputs;
253 common::BuildInputsForSection(SECTION_SHIPPING, "US", &inputs);
254 EmptyDataModelWrapper empty_wrapper;
255 request_shipping_address = empty_wrapper.FillFormStructure(
256 inputs,
257 base::Bind(common::DetailInputMatchesField, SECTION_SHIPPING),
258 &form_structure_);
261 const bool incognito_mode = profile_->IsOffTheRecord();
263 bool last_used_choice_is_autofill = false;
264 base::string16 last_used_account_name;
265 std::string last_used_billing;
266 std::string last_used_shipping;
267 std::string last_used_credit_card;
269 const base::DictionaryValue* defaults =
270 profile_->GetPrefs()->GetDictionary(::prefs::kAutofillDialogDefaults);
271 if (defaults) {
272 defaults->GetString(kLastUsedAccountName, &last_used_account_name);
273 defaults->GetBoolean(kLastUsedChoiceIsAutofill,
274 &last_used_choice_is_autofill);
275 defaults->GetString(kLastUsedBillingAddressGuid, &last_used_billing);
276 defaults->GetString(kLastUsedShippingAddressGuid, &last_used_shipping);
277 defaults->GetString(kLastUsedCreditCardGuid, &last_used_credit_card);
278 } else {
279 DLOG(ERROR) << "Failed to read AutofillDialog preferences";
283 if (contents_->GetBrowserContext()->IsOffTheRecord())
284 last_used_choice_is_autofill = true;
286 ScopedJavaLocalRef<jstring> jlast_used_account_name =
287 base::android::ConvertUTF16ToJavaString(
288 env, last_used_account_name);
289 ScopedJavaLocalRef<jstring> jlast_used_billing =
290 base::android::ConvertUTF8ToJavaString(
291 env, last_used_billing);
292 ScopedJavaLocalRef<jstring> jlast_used_shipping =
293 base::android::ConvertUTF8ToJavaString(
294 env, last_used_shipping);
295 ScopedJavaLocalRef<jstring> jlast_used_card =
296 base::android::ConvertUTF8ToJavaString(
297 env, last_used_credit_card);
298 ScopedJavaLocalRef<jstring> jmerchant_domain =
299 base::android::ConvertUTF8ToJavaString(
300 env, source_url_.GetOrigin().spec());
301 java_object_.Reset(Java_AutofillDialogControllerAndroid_create(
302 env,
303 reinterpret_cast<intptr_t>(this),
304 WindowAndroidHelper::FromWebContents(contents_)->
305 GetWindowAndroid()->GetJavaObject().obj(),
306 request_full_billing_address, request_shipping_address,
307 request_phone_numbers, incognito_mode,
308 last_used_choice_is_autofill, jlast_used_account_name.obj(),
309 jlast_used_billing.obj(), jlast_used_shipping.obj(),
310 jlast_used_card.obj(),
311 jmerchant_domain.obj()));
314 void AutofillDialogControllerAndroid::Hide() {
315 delete this;
318 void AutofillDialogControllerAndroid::TabActivated() {}
320 // static
321 bool AutofillDialogControllerAndroid::
322 RegisterAutofillDialogControllerAndroid(JNIEnv* env) {
323 return RegisterNativesImpl(env);
326 void AutofillDialogControllerAndroid::DialogCancel(JNIEnv* env,
327 jobject obj) {
328 LogOnCancelMetrics();
329 callback_.Run(NULL);
332 void AutofillDialogControllerAndroid::DialogContinue(
333 JNIEnv* env,
334 jobject obj,
335 jobject wallet,
336 jboolean jlast_used_choice_is_autofill,
337 jstring jlast_used_account_name,
338 jstring jlast_used_billing,
339 jstring jlast_used_shipping,
340 jstring jlast_used_card) {
341 const base::string16 email =
342 AutofillDialogResult::GetWalletEmail(env, wallet);
343 const std::string google_transaction_id =
344 AutofillDialogResult::GetWalletGoogleTransactionId(env, wallet);
346 const base::string16 last_used_account_name =
347 base::android::ConvertJavaStringToUTF16(env, jlast_used_account_name);
348 const std::string last_used_billing =
349 base::android::ConvertJavaStringToUTF8(env, jlast_used_billing);
350 const std::string last_used_shipping =
351 base::android::ConvertJavaStringToUTF8(env, jlast_used_shipping);
352 const std::string last_used_card =
353 base::android::ConvertJavaStringToUTF8(env, jlast_used_card);
355 scoped_ptr<wallet::FullWallet> full_wallet =
356 AutofillDialogResult::ConvertFromJava(env, wallet);
357 FillOutputForSection(
358 SECTION_CC_BILLING, form_structure_, full_wallet.get(), email);
359 FillOutputForSection(
360 SECTION_SHIPPING, form_structure_, full_wallet.get(), email);
363 DictionaryPrefUpdate updater(profile_->GetPrefs(),
364 ::prefs::kAutofillDialogDefaults);
365 base::DictionaryValue* defaults = updater.Get();
366 if (defaults) {
367 const bool last_used_choice_is_autofill = !!jlast_used_choice_is_autofill;
368 defaults->SetString(kLastUsedAccountName, last_used_account_name);
369 defaults->SetBoolean(kLastUsedChoiceIsAutofill,
370 last_used_choice_is_autofill);
371 if (!last_used_billing.empty())
372 defaults->SetString(kLastUsedBillingAddressGuid, last_used_billing);
373 if (!last_used_shipping.empty())
374 defaults->SetString(kLastUsedShippingAddressGuid, last_used_shipping);
375 if (!last_used_card.empty())
376 defaults->SetString(kLastUsedCreditCardGuid, last_used_card);
377 } else {
378 LOG(ERROR) << "Failed to save AutofillDialog preferences";
382 LogOnFinishSubmitMetrics();
384 // Callback should be called as late as possible.
385 callback_.Run(&form_structure_);
387 // This might delete us.
388 Hide();
391 AutofillDialogControllerAndroid::AutofillDialogControllerAndroid(
392 content::WebContents* contents,
393 const FormData& form_structure,
394 const GURL& source_url,
395 const base::Callback<void(const FormStructure*)>& callback)
396 : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
397 contents_(contents),
398 initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
399 form_structure_(form_structure),
400 invoked_from_same_origin_(true),
401 source_url_(source_url),
402 callback_(callback),
403 cares_about_shipping_(true),
404 weak_ptr_factory_(this),
405 was_ui_latency_logged_(false) {
406 DCHECK(!callback_.is_null());
409 void AutofillDialogControllerAndroid::LogOnFinishSubmitMetrics() {
410 GetMetricLogger().LogDialogUiDuration(
411 base::Time::Now() - dialog_shown_timestamp_,
412 AutofillMetrics::DIALOG_ACCEPTED);
414 GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_ACCEPTED);
417 void AutofillDialogControllerAndroid::LogOnCancelMetrics() {
418 GetMetricLogger().LogDialogUiDuration(
419 base::Time::Now() - dialog_shown_timestamp_,
420 AutofillMetrics::DIALOG_CANCELED);
422 GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_CANCELED);
425 } // namespace autofill