NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / ui / android / autofill / autofill_dialog_controller_android.cc
blob97ea58911e996f66d8f86ac96a4b3bc0a35bd0e8
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"
45 #include "url/gurl.h"
47 namespace autofill {
49 namespace {
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())) {
73 return;
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,
83 compare,
84 get_info,
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) {
93 DetailInputs inputs;
94 common::BuildInputsForSection(section, "US", &inputs);
96 FillOutputForSectionWithComparator(
97 section, inputs,
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))
118 return true;
120 return false;
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)) {
131 return true;
134 return false;
137 } // namespace
140 // static
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,
149 form_structure,
150 source_url,
151 callback);
152 return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
155 #if defined(ENABLE_AUTOFILL_DIALOG)
156 // static
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,
164 form_structure,
165 source_url,
166 callback);
169 // static
170 void AutofillDialogController::RegisterPrefs(PrefRegistrySimple* registry) {}
172 // static
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())
183 return;
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.
205 if (!has_types ||
206 !Java_AutofillDialogControllerAndroid_isDialogAllowed(
207 env,
208 invoked_from_same_origin_)) {
209 callback_.Run(NULL);
210 delete this;
211 return;
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(
234 SECTION_BILLING,
235 full_billing_is_necessary_if,
236 arraysize(full_billing_is_necessary_if),
237 form_structure_);
238 const bool request_phone_numbers =
239 IsSectionInputUsedInFormStructure(
240 SECTION_BILLING,
241 PHONE_BILLING_WHOLE_NUMBER,
242 form_structure_) ||
243 IsSectionInputUsedInFormStructure(
244 SECTION_SHIPPING,
245 PHONE_HOME_WHOLE_NUMBER,
246 form_structure_);
248 bool request_shipping_address = false;
250 DetailInputs inputs;
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);
269 if (defaults) {
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);
276 } else {
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(
300 env,
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() {
313 delete this;
316 void AutofillDialogControllerAndroid::TabActivated() {}
318 // static
319 bool AutofillDialogControllerAndroid::
320 RegisterAutofillDialogControllerAndroid(JNIEnv* env) {
321 return RegisterNativesImpl(env);
324 void AutofillDialogControllerAndroid::DialogCancel(JNIEnv* env,
325 jobject obj) {
326 LogOnCancelMetrics();
327 callback_.Run(NULL);
330 void AutofillDialogControllerAndroid::DialogContinue(
331 JNIEnv* env,
332 jobject obj,
333 jobject wallet,
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();
364 if (defaults) {
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);
375 } else {
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.
386 Hide();
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())),
395 contents_(contents),
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),
400 callback_(callback),
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