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/personal_data_manager.h"
31 #include "components/autofill/core/common/form_data.h"
32 #include "components/user_prefs/pref_registry_syncable.h"
33 #include "content/public/browser/navigation_controller.h"
34 #include "content/public/browser/navigation_details.h"
35 #include "content/public/browser/navigation_entry.h"
36 #include "content/public/browser/web_contents.h"
37 #include "grit/generated_resources.h"
38 #include "jni/AutofillDialogControllerAndroid_jni.h"
39 #include "ui/base/android/window_android.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/base/models/combobox_model.h"
42 #include "ui/base/models/menu_model.h"
43 #include "ui/gfx/android/java_bitmap.h"
44 #include "ui/gfx/rect.h"
51 using wallet::FullWallet
;
53 // Keys in kAutofillDialogDefaults pref dictionary (do not change these values).
54 const char kLastUsedAccountName
[] = "last_used_account_name";
55 const char kLastUsedChoiceIsAutofill
[] = "last_used_choice_is_autofill";
56 const char kLastUsedBillingAddressGuid
[] = "last_used_billing";
57 const char kLastUsedShippingAddressGuid
[] = "last_used_shipping";
58 const char kLastUsedCreditCardGuid
[] = "last_used_card";
60 base::string16
NullGetInfo(const AutofillType
& type
) {
61 return base::string16();
64 void FillOutputForSectionWithComparator(
65 DialogSection section
,
66 const DetailInputs
& inputs
,
67 const FormStructure::InputFieldComparator
& compare
,
68 FormStructure
& form_structure
,
69 FullWallet
* full_wallet
,
70 const base::string16
& email_address
) {
71 if ((section
== SECTION_CC_BILLING
&& !full_wallet
->billing_address()) ||
72 (section
== SECTION_SHIPPING
&& !full_wallet
->shipping_address())) {
76 base::Callback
<base::string16(const AutofillType
&)> get_info
=
77 base::Bind(&FullWallet::GetInfo
,
78 base::Unretained(full_wallet
),
79 g_browser_process
->GetApplicationLocale());
81 std::vector
<ServerFieldType
> types
= common::TypesFromInputs(inputs
);
82 form_structure
.FillFields(types
,
85 g_browser_process
->GetApplicationLocale());
88 void FillOutputForSection(
89 DialogSection section
,
90 FormStructure
& form_structure
,
91 FullWallet
* full_wallet
,
92 const base::string16
& email_address
) {
94 common::BuildInputsForSection(section
, "US", &inputs
);
96 FillOutputForSectionWithComparator(
98 base::Bind(common::ServerTypeMatchesField
, section
),
99 form_structure
, full_wallet
, email_address
);
101 if (section
== SECTION_CC_BILLING
) {
102 // Email is hidden while using Wallet, special case it.
103 for (size_t i
= 0; i
< form_structure
.field_count(); ++i
) {
104 AutofillField
* field
= form_structure
.field(i
);
105 if (field
->Type().GetStorableType() == EMAIL_ADDRESS
)
106 field
->value
= email_address
;
111 // Returns true if |input_type| in |section| is needed for |form_structure|.
112 bool IsSectionInputUsedInFormStructure(DialogSection section
,
113 ServerFieldType input_type
,
114 const FormStructure
& form_structure
) {
115 for (size_t i
= 0; i
< form_structure
.field_count(); ++i
) {
116 const AutofillField
* field
= form_structure
.field(i
);
117 if (field
&& common::ServerTypeMatchesField(section
, input_type
, *field
))
123 // Returns true if one of |inputs| in |section| is needed for |form_structure|.
124 bool IsSectionInputsUsedInFormStructure(DialogSection section
,
125 const ServerFieldType
* input_types
,
126 const size_t input_types_size
,
127 const FormStructure
& form_structure
) {
128 for (size_t i
= 0; i
< input_types_size
; ++i
) {
129 if (IsSectionInputUsedInFormStructure(
130 section
, input_types
[i
], form_structure
)) {
141 base::WeakPtr
<AutofillDialogController
> AutofillDialogControllerAndroid::Create(
142 content::WebContents
* contents
,
143 const FormData
& form_structure
,
144 const GURL
& source_url
,
145 const base::Callback
<void(const FormStructure
*)>& callback
) {
146 // AutofillDialogControllerAndroid owns itself.
147 AutofillDialogControllerAndroid
* autofill_dialog_controller
=
148 new AutofillDialogControllerAndroid(contents
,
152 return autofill_dialog_controller
->weak_ptr_factory_
.GetWeakPtr();
155 #if defined(ENABLE_AUTOFILL_DIALOG)
157 base::WeakPtr
<AutofillDialogController
>
158 AutofillDialogController::Create(
159 content::WebContents
* contents
,
160 const FormData
& form_structure
,
161 const GURL
& source_url
,
162 const base::Callback
<void(const FormStructure
*)>& callback
) {
163 return AutofillDialogControllerAndroid::Create(contents
,
170 void AutofillDialogController::RegisterPrefs(PrefRegistrySimple
* registry
) {}
173 void AutofillDialogController::RegisterProfilePrefs(
174 user_prefs::PrefRegistrySyncable
* registry
) {
175 registry
->RegisterDictionaryPref(
176 ::prefs::kAutofillDialogDefaults
,
177 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
);
179 #endif // defined(ENABLE_AUTOFILL_DIALOG)
181 AutofillDialogControllerAndroid::~AutofillDialogControllerAndroid() {
182 if (java_object_
.is_null())
185 JNIEnv
* env
= base::android::AttachCurrentThread();
186 Java_AutofillDialogControllerAndroid_onDestroy(env
, java_object_
.obj());
189 void AutofillDialogControllerAndroid::Show() {
190 JNIEnv
* env
= base::android::AttachCurrentThread();
191 dialog_shown_timestamp_
= base::Time::Now();
193 const GURL
& current_url
= contents_
->GetLastCommittedURL();
194 invoked_from_same_origin_
=
195 current_url
.GetOrigin() == source_url_
.GetOrigin();
197 // Determine what field types should be included in the dialog.
198 bool has_types
= false;
199 bool has_sections
= false;
200 form_structure_
.ParseFieldTypesFromAutocompleteAttributes(
201 &has_types
, &has_sections
);
203 // Fail if the author didn't specify autocomplete types, or
204 // if the dialog shouldn't be shown in a given circumstances.
206 !Java_AutofillDialogControllerAndroid_isDialogAllowed(
208 invoked_from_same_origin_
)) {
214 // Log any relevant UI metrics and security exceptions.
215 GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_SHOWN
);
217 GetMetricLogger().LogDialogSecurityMetric(
218 AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN
);
220 if (!invoked_from_same_origin_
) {
221 GetMetricLogger().LogDialogSecurityMetric(
222 AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME
);
225 const ServerFieldType full_billing_is_necessary_if
[] = {
226 ADDRESS_BILLING_LINE1
,
227 ADDRESS_BILLING_LINE2
,
228 ADDRESS_BILLING_CITY
,
229 ADDRESS_BILLING_STATE
,
230 PHONE_BILLING_WHOLE_NUMBER
232 const bool request_full_billing_address
=
233 IsSectionInputsUsedInFormStructure(
235 full_billing_is_necessary_if
,
236 arraysize(full_billing_is_necessary_if
),
238 const bool request_phone_numbers
=
239 IsSectionInputUsedInFormStructure(
241 PHONE_BILLING_WHOLE_NUMBER
,
243 IsSectionInputUsedInFormStructure(
245 PHONE_HOME_WHOLE_NUMBER
,
248 bool request_shipping_address
= false;
251 common::BuildInputsForSection(SECTION_SHIPPING
, "US", &inputs
);
252 request_shipping_address
= form_structure_
.FillFields(
253 common::TypesFromInputs(inputs
),
254 base::Bind(common::ServerTypeMatchesField
, SECTION_SHIPPING
),
255 base::Bind(NullGetInfo
),
256 g_browser_process
->GetApplicationLocale());
259 const bool incognito_mode
= profile_
->IsOffTheRecord();
261 bool last_used_choice_is_autofill
= false;
262 base::string16 last_used_account_name
;
263 std::string last_used_billing
;
264 std::string last_used_shipping
;
265 std::string last_used_credit_card
;
267 const base::DictionaryValue
* defaults
=
268 profile_
->GetPrefs()->GetDictionary(::prefs::kAutofillDialogDefaults
);
270 defaults
->GetString(kLastUsedAccountName
, &last_used_account_name
);
271 defaults
->GetBoolean(kLastUsedChoiceIsAutofill
,
272 &last_used_choice_is_autofill
);
273 defaults
->GetString(kLastUsedBillingAddressGuid
, &last_used_billing
);
274 defaults
->GetString(kLastUsedShippingAddressGuid
, &last_used_shipping
);
275 defaults
->GetString(kLastUsedCreditCardGuid
, &last_used_credit_card
);
277 DLOG(ERROR
) << "Failed to read AutofillDialog preferences";
281 if (contents_
->GetBrowserContext()->IsOffTheRecord())
282 last_used_choice_is_autofill
= true;
284 ScopedJavaLocalRef
<jstring
> jlast_used_account_name
=
285 base::android::ConvertUTF16ToJavaString(
286 env
, last_used_account_name
);
287 ScopedJavaLocalRef
<jstring
> jlast_used_billing
=
288 base::android::ConvertUTF8ToJavaString(
289 env
, last_used_billing
);
290 ScopedJavaLocalRef
<jstring
> jlast_used_shipping
=
291 base::android::ConvertUTF8ToJavaString(
292 env
, last_used_shipping
);
293 ScopedJavaLocalRef
<jstring
> jlast_used_card
=
294 base::android::ConvertUTF8ToJavaString(
295 env
, last_used_credit_card
);
296 ScopedJavaLocalRef
<jstring
> jmerchant_domain
=
297 base::android::ConvertUTF8ToJavaString(
298 env
, source_url_
.GetOrigin().spec());
299 java_object_
.Reset(Java_AutofillDialogControllerAndroid_create(
301 reinterpret_cast<intptr_t>(this),
302 WindowAndroidHelper::FromWebContents(contents_
)->
303 GetWindowAndroid()->GetJavaObject().obj(),
304 request_full_billing_address
, request_shipping_address
,
305 request_phone_numbers
, incognito_mode
,
306 last_used_choice_is_autofill
, jlast_used_account_name
.obj(),
307 jlast_used_billing
.obj(), jlast_used_shipping
.obj(),
308 jlast_used_card
.obj(),
309 jmerchant_domain
.obj()));
312 void AutofillDialogControllerAndroid::Hide() {
316 void AutofillDialogControllerAndroid::TabActivated() {}
319 bool AutofillDialogControllerAndroid::
320 RegisterAutofillDialogControllerAndroid(JNIEnv
* env
) {
321 return RegisterNativesImpl(env
);
324 void AutofillDialogControllerAndroid::DialogCancel(JNIEnv
* env
,
326 LogOnCancelMetrics();
330 void AutofillDialogControllerAndroid::DialogContinue(
334 jboolean jlast_used_choice_is_autofill
,
335 jstring jlast_used_account_name
,
336 jstring jlast_used_billing
,
337 jstring jlast_used_shipping
,
338 jstring jlast_used_card
) {
339 const base::string16 email
=
340 AutofillDialogResult::GetWalletEmail(env
, wallet
);
341 const std::string google_transaction_id
=
342 AutofillDialogResult::GetWalletGoogleTransactionId(env
, wallet
);
344 const base::string16 last_used_account_name
=
345 base::android::ConvertJavaStringToUTF16(env
, jlast_used_account_name
);
346 const std::string last_used_billing
=
347 base::android::ConvertJavaStringToUTF8(env
, jlast_used_billing
);
348 const std::string last_used_shipping
=
349 base::android::ConvertJavaStringToUTF8(env
, jlast_used_shipping
);
350 const std::string last_used_card
=
351 base::android::ConvertJavaStringToUTF8(env
, jlast_used_card
);
353 scoped_ptr
<FullWallet
> full_wallet
=
354 AutofillDialogResult::ConvertFromJava(env
, wallet
);
355 FillOutputForSection(
356 SECTION_CC_BILLING
, form_structure_
, full_wallet
.get(), email
);
357 FillOutputForSection(
358 SECTION_SHIPPING
, form_structure_
, full_wallet
.get(), email
);
361 DictionaryPrefUpdate
updater(profile_
->GetPrefs(),
362 ::prefs::kAutofillDialogDefaults
);
363 base::DictionaryValue
* defaults
= updater
.Get();
365 const bool last_used_choice_is_autofill
= !!jlast_used_choice_is_autofill
;
366 defaults
->SetString(kLastUsedAccountName
, last_used_account_name
);
367 defaults
->SetBoolean(kLastUsedChoiceIsAutofill
,
368 last_used_choice_is_autofill
);
369 if (!last_used_billing
.empty())
370 defaults
->SetString(kLastUsedBillingAddressGuid
, last_used_billing
);
371 if (!last_used_shipping
.empty())
372 defaults
->SetString(kLastUsedShippingAddressGuid
, last_used_shipping
);
373 if (!last_used_card
.empty())
374 defaults
->SetString(kLastUsedCreditCardGuid
, last_used_card
);
376 LOG(ERROR
) << "Failed to save AutofillDialog preferences";
380 LogOnFinishSubmitMetrics();
382 // Callback should be called as late as possible.
383 callback_
.Run(&form_structure_
);
385 // This might delete us.
389 AutofillDialogControllerAndroid::AutofillDialogControllerAndroid(
390 content::WebContents
* contents
,
391 const FormData
& form_structure
,
392 const GURL
& source_url
,
393 const base::Callback
<void(const FormStructure
*)>& callback
)
394 : profile_(Profile::FromBrowserContext(contents
->GetBrowserContext())),
396 initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN
),
397 form_structure_(form_structure
),
398 invoked_from_same_origin_(true),
399 source_url_(source_url
),
401 cares_about_shipping_(true),
402 weak_ptr_factory_(this),
403 was_ui_latency_logged_(false) {
404 DCHECK(!callback_
.is_null());
407 void AutofillDialogControllerAndroid::LogOnFinishSubmitMetrics() {
408 GetMetricLogger().LogDialogUiDuration(
409 base::Time::Now() - dialog_shown_timestamp_
,
410 AutofillMetrics::DIALOG_ACCEPTED
);
412 GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_ACCEPTED
);
415 void AutofillDialogControllerAndroid::LogOnCancelMetrics() {
416 GetMetricLogger().LogDialogUiDuration(
417 base::Time::Now() - dialog_shown_timestamp_
,
418 AutofillMetrics::DIALOG_CANCELED
);
420 GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_CANCELED
);
423 } // namespace autofill