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

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

Issue 22566004: [rAc Android dialog] Stubs for Autofill dialog integration. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed Ted's suggestions. Created 7 years, 4 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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 "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/strings/utf_string_conversions.h"
15 #include "chrome/browser/autofill/personal_data_manager_factory.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/prefs/scoped_user_pref_update.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/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"
47
48 namespace autofill {
49
50 namespace {
51
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";
58
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>();
64
65 return scoped_ptr<DataModelWrapper>(
66 new FullWalletBillingWrapper(full_wallet));
67 }
68 if (section == SECTION_SHIPPING) {
69 if (!full_wallet->shipping_address())
70 return scoped_ptr<DataModelWrapper>();
71
72 return scoped_ptr<DataModelWrapper>(
73 new FullWalletShippingWrapper(full_wallet));
74 }
75 NOTREACHED();
76 return scoped_ptr<DataModelWrapper>();
77 }
78
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
85 // Email is hidden while using Wallet, special case it.
86 if (section == SECTION_EMAIL) {
87 AutofillProfile profile;
88 profile.SetRawInfo(EMAIL_ADDRESS, email_address);
89 AutofillProfileWrapper profile_wrapper(&profile, 0);
90 profile_wrapper.FillFormStructure(inputs, compare, &form_structure);
91 return;
92 }
93
94 scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section, full_wallet);
95 if (wrapper)
96 wrapper->FillFormStructure(inputs, compare, &form_structure);
97 }
98
99 void FillOutputForSection(
100 DialogSection section,
101 FormStructure& form_structure,
102 wallet::FullWallet* full_wallet,
103 const base::string16& email_address) {
104 DetailInputs inputs;
105 common::BuildInputsForSection(section, &inputs);
106
107 FillOutputForSectionWithComparator(
108 section, inputs,
109 base::Bind(common::DetailInputMatchesField, section),
110 form_structure, full_wallet, email_address);
111 }
112
113 } // namespace
114
115
116 // static
117 base::WeakPtr<AutofillDialogController> AutofillDialogControllerAndroid::Create(
118 content::WebContents* contents,
119 const FormData& form_structure,
120 const GURL& source_url,
121 const DialogType dialog_type,
122 const base::Callback<void(const FormStructure*,
123 const std::string&)>& callback) {
124 // AutofillDialogControllerAndroid owns itself.
125 AutofillDialogControllerAndroid* autofill_dialog_controller =
126 new AutofillDialogControllerAndroid(contents,
127 form_structure,
128 source_url,
129 dialog_type,
130 callback);
131 return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
132 }
133
134 // static
135 void AutofillDialogControllerAndroid::RegisterProfilePrefs(
136 user_prefs::PrefRegistrySyncable* registry) {
137 registry->RegisterDictionaryPref(
138 ::prefs::kAutofillDialogDefaults,
139 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
140 }
141
142 // static
143 base::WeakPtr<AutofillDialogController>
144 AutofillDialogController::Create(
145 content::WebContents* contents,
146 const FormData& form_structure,
147 const GURL& source_url,
148 const DialogType dialog_type,
149 const base::Callback<void(const FormStructure*,
150 const std::string&)>& callback) {
151 return AutofillDialogControllerAndroid::Create(contents,
152 form_structure,
153 source_url,
154 dialog_type,
155 callback);
156 }
157
158 // static
159 void AutofillDialogController::RegisterProfilePrefs(
160 user_prefs::PrefRegistrySyncable* registry) {
161 AutofillDialogControllerAndroid::RegisterProfilePrefs(registry);
162 }
163
164 AutofillDialogControllerAndroid::~AutofillDialogControllerAndroid() {
165 JNIEnv* env = base::android::AttachCurrentThread();
166 Java_AutofillDialogControllerAndroid_onDestroy(env, java_object_.obj());
167 }
168
169 void AutofillDialogControllerAndroid::Show() {
170 dialog_shown_timestamp_ = base::Time::Now();
171
172 content::NavigationEntry* entry = contents_->GetController().GetActiveEntry();
173 const GURL& active_url = entry ? entry->GetURL() : contents_->GetURL();
174 invoked_from_same_origin_ = active_url.GetOrigin() == source_url_.GetOrigin();
175
176 // Log any relevant UI metrics and security exceptions.
177 GetMetricLogger().LogDialogUiEvent(
178 GetDialogType(), AutofillMetrics::DIALOG_UI_SHOWN);
179
180 GetMetricLogger().LogDialogSecurityMetric(
181 GetDialogType(), AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN);
182
183 if (RequestingCreditCardInfo() && !TransmissionWillBeSecure()) {
184 GetMetricLogger().LogDialogSecurityMetric(
185 GetDialogType(),
186 AutofillMetrics::SECURITY_METRIC_CREDIT_CARD_OVER_HTTP);
187 }
188
189 if (!invoked_from_same_origin_) {
190 GetMetricLogger().LogDialogSecurityMetric(
191 GetDialogType(),
192 AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME);
193 }
194
195 // Determine what field types should be included in the dialog.
196 bool has_types = false;
197 bool has_sections = false;
198 form_structure_.ParseFieldTypesFromAutocompleteAttributes(
199 &has_types, &has_sections);
200
201 // Fail if the author didn't specify autocomplete types.
202 if (!has_types) {
203 callback_.Run(NULL, std::string());
204 delete this;
205 return;
206 }
207
208 bool request_full_billing_address = true;
209 bool request_shipping_address = false;
210 bool request_phone_numbers = false;
211
212 for (size_t i = 0; i < form_structure_.field_count(); ++i) {
213 const ServerFieldType type =
214 form_structure_.field(i)->Type().GetStorableType();
215 if (type == PHONE_HOME_WHOLE_NUMBER || type == PHONE_BILLING_WHOLE_NUMBER) {
216 request_phone_numbers = true;
217 }
218 if (type == NAME_FULL ||
219 type == ADDRESS_HOME_LINE1 || type == ADDRESS_HOME_LINE2 ||
220 type == ADDRESS_HOME_CITY || type == ADDRESS_HOME_STATE ||
221 type == ADDRESS_HOME_ZIP || type == ADDRESS_HOME_COUNTRY ||
222 type == PHONE_HOME_WHOLE_NUMBER) {
223 request_shipping_address = true;
224 }
225 if (type == ADDRESS_BILLING_LINE1 || type == ADDRESS_BILLING_LINE2 ||
226 type == ADDRESS_BILLING_CITY || type == ADDRESS_BILLING_STATE ||
227 type == PHONE_BILLING_WHOLE_NUMBER) {
228 request_full_billing_address = true;
229 }
230 }
231
232 if (request_shipping_address)
233 request_full_billing_address = true;
234
235 const bool incognito_mode = profile_->IsOffTheRecord();
236
237 bool last_used_choice_is_autofill = false;
238 base::string16 last_used_account_name;
239 std::string last_used_billing;
240 std::string last_used_shipping;
241 std::string last_used_credit_card;
242 {
243 const base::DictionaryValue* defaults =
244 profile_->GetPrefs()->GetDictionary(::prefs::kAutofillDialogDefaults);
245 if (defaults) {
246 defaults->GetString(kLastUsedAccountName, &last_used_account_name);
247 defaults->GetBoolean(kLastUsedChoiceIsAutofill,
248 &last_used_choice_is_autofill);
249 defaults->GetString(kLastUsedBillingAddressGuid, &last_used_billing);
250 defaults->GetString(kLastUsedShippingAddressGuid, &last_used_shipping);
251 defaults->GetString(kLastUsedCreditCardGuid, &last_used_credit_card);
252 } else {
253 DLOG(ERROR) << "Failed to read AutofillDialog preferences";
254 }
255 }
256
257 if (contents_->GetBrowserContext()->IsOffTheRecord())
258 last_used_choice_is_autofill = true;
259
260 JNIEnv* env = base::android::AttachCurrentThread();
261 ScopedJavaLocalRef<jstring> jlast_used_account_name =
262 base::android::ConvertUTF16ToJavaString(
263 env, last_used_account_name);
264 ScopedJavaLocalRef<jstring> jlast_used_billing =
265 base::android::ConvertUTF8ToJavaString(
266 env, last_used_billing);
267 ScopedJavaLocalRef<jstring> jlast_used_shipping =
268 base::android::ConvertUTF8ToJavaString(
269 env, last_used_shipping);
270 ScopedJavaLocalRef<jstring> jlast_used_card =
271 base::android::ConvertUTF8ToJavaString(
272 env, last_used_credit_card);
273 ScopedJavaLocalRef<jstring> jmerchant_domain =
274 base::android::ConvertUTF8ToJavaString(
275 env, source_url_.GetOrigin().spec());
276 java_object_.Reset(Java_AutofillDialogControllerAndroid_create(
277 env,
278 reinterpret_cast<jint>(this),
279 WindowAndroidHelper::FromWebContents(contents_)->
280 GetWindowAndroid()->GetJavaObject().obj(),
281 request_full_billing_address, request_shipping_address,
282 request_phone_numbers, incognito_mode,
283 last_used_choice_is_autofill, jlast_used_account_name.obj(),
284 jlast_used_billing.obj(), jlast_used_shipping.obj(),
285 jlast_used_card.obj(),
286 jmerchant_domain.obj()));
287 }
288
289 void AutofillDialogControllerAndroid::Hide() {
290 // TODO(aruslan): http://crbug.com/177373 Autocheckout.
291 NOTIMPLEMENTED();
292 }
293
294 void AutofillDialogControllerAndroid::TabActivated() {}
295
296 void AutofillDialogControllerAndroid::AddAutocheckoutStep(
297 AutocheckoutStepType step_type) {
298 // TODO(aruslan): http://crbug.com/177373 Autocheckout.
299 NOTIMPLEMENTED() << " step_type = " << step_type;
300 }
301
302 void AutofillDialogControllerAndroid::UpdateAutocheckoutStep(
303 AutocheckoutStepType step_type,
304 AutocheckoutStepStatus step_status) {
305 // TODO(aruslan): http://crbug.com/177373 Autocheckout.
306 NOTIMPLEMENTED() << " step_type=" << step_type
307 << " step_status=" << step_status;
308 }
309
310 void AutofillDialogControllerAndroid::OnAutocheckoutError() {
311 // TODO(aruslan): http://crbug.com/177373 Autocheckout.
312 NOTIMPLEMENTED();
313 DCHECK_EQ(AUTOCHECKOUT_IN_PROGRESS, autocheckout_state_);
314 GetMetricLogger().LogAutocheckoutDuration(
315 base::Time::Now() - autocheckout_started_timestamp_,
316 AutofillMetrics::AUTOCHECKOUT_FAILED);
317 SetAutocheckoutState(AUTOCHECKOUT_ERROR);
318 autocheckout_started_timestamp_ = base::Time();
319 }
320
321 void AutofillDialogControllerAndroid::OnAutocheckoutSuccess() {
322 // TODO(aruslan): http://crbug.com/177373 Autocheckout.
323 NOTIMPLEMENTED();
324 DCHECK_EQ(AUTOCHECKOUT_IN_PROGRESS, autocheckout_state_);
325 GetMetricLogger().LogAutocheckoutDuration(
326 base::Time::Now() - autocheckout_started_timestamp_,
327 AutofillMetrics::AUTOCHECKOUT_SUCCEEDED);
328 SetAutocheckoutState(AUTOCHECKOUT_SUCCESS);
329 autocheckout_started_timestamp_ = base::Time();
330 }
331
332 DialogType AutofillDialogControllerAndroid::GetDialogType() const {
333 return dialog_type_;
334 }
335
336 // static
337 bool AutofillDialogControllerAndroid::
338 RegisterAutofillDialogControllerAndroid(JNIEnv* env) {
339 return RegisterNativesImpl(env);
340 }
341
342 void AutofillDialogControllerAndroid::DialogCancel(JNIEnv* env,
343 jobject obj) {
344 if (autocheckout_state_ == AUTOCHECKOUT_NOT_STARTED)
345 LogOnCancelMetrics();
346
347 if (autocheckout_state_ == AUTOCHECKOUT_IN_PROGRESS) {
348 GetMetricLogger().LogAutocheckoutDuration(
349 base::Time::Now() - autocheckout_started_timestamp_,
350 AutofillMetrics::AUTOCHECKOUT_CANCELLED);
351 }
352
353 callback_.Run(NULL, std::string());
354 }
355
356 void AutofillDialogControllerAndroid::DialogContinue(
357 JNIEnv* env,
358 jobject obj,
359 jobject wallet,
360 jboolean jlast_used_choice_is_autofill,
361 jstring jlast_used_account_name,
362 jstring jlast_used_billing,
363 jstring jlast_used_shipping,
364 jstring jlast_used_card) {
365 const string16 email = AutofillDialogResult::GetWalletEmail(env, wallet);
366 const std::string google_transaction_id =
367 AutofillDialogResult::GetWalletGoogleTransactionId(env, wallet);
368
369 const string16 last_used_account_name =
370 base::android::ConvertJavaStringToUTF16(env, jlast_used_account_name);
371 const std::string last_used_billing =
372 base::android::ConvertJavaStringToUTF8(env, jlast_used_billing);
373 const std::string last_used_shipping =
374 base::android::ConvertJavaStringToUTF8(env, jlast_used_shipping);
375 const std::string last_used_card =
376 base::android::ConvertJavaStringToUTF8(env, jlast_used_card);
377
378 scoped_ptr<wallet::FullWallet> full_wallet =
379 AutofillDialogResult::ConvertFromJava(env, wallet);
380 FillOutputForSection(
381 SECTION_EMAIL, form_structure_, full_wallet.get(), email);
382 FillOutputForSection(
383 SECTION_CC_BILLING, form_structure_, full_wallet.get(), email);
384 FillOutputForSection(
385 SECTION_SHIPPING, form_structure_, full_wallet.get(), email);
386
387 {
388 DictionaryPrefUpdate updater(profile_->GetPrefs(),
389 ::prefs::kAutofillDialogDefaults);
390 base::DictionaryValue* defaults = updater.Get();
391 if (defaults) {
392 const bool last_used_choice_is_autofill = !!jlast_used_choice_is_autofill;
393 defaults->SetString(kLastUsedAccountName, last_used_account_name);
394 defaults->SetBoolean(kLastUsedChoiceIsAutofill,
395 last_used_choice_is_autofill);
396 if (!last_used_billing.empty())
397 defaults->SetString(kLastUsedBillingAddressGuid, last_used_billing);
398 if (!last_used_shipping.empty())
399 defaults->SetString(kLastUsedShippingAddressGuid, last_used_shipping);
400 if (!last_used_card.empty())
401 defaults->SetString(kLastUsedCreditCardGuid, last_used_card);
402 } else {
403 LOG(ERROR) << "Failed to save AutofillDialog preferences";
404 }
405 }
406
407 if (GetDialogType() == DIALOG_TYPE_AUTOCHECKOUT) {
408 autocheckout_started_timestamp_ = base::Time::Now();
409 SetAutocheckoutState(AUTOCHECKOUT_IN_PROGRESS);
410 }
411
412 LogOnFinishSubmitMetrics();
413
414 // Callback should be called as late as possible.
415 callback_.Run(&form_structure_, google_transaction_id);
416
417 // This might delete us.
418 if (GetDialogType() == DIALOG_TYPE_REQUEST_AUTOCOMPLETE)
419 Hide();
420 }
421
422 AutofillDialogControllerAndroid::AutofillDialogControllerAndroid(
423 content::WebContents* contents,
424 const FormData& form_structure,
425 const GURL& source_url,
426 const DialogType dialog_type,
427 const base::Callback<void(const FormStructure*,
428 const std::string&)>& callback)
429 : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
430 contents_(contents),
431 initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
432 dialog_type_(dialog_type),
433 form_structure_(form_structure, std::string()),
434 invoked_from_same_origin_(true),
435 source_url_(source_url),
436 callback_(callback),
437 cares_about_shipping_(true),
438 weak_ptr_factory_(this),
439 autocheckout_state_(AUTOCHECKOUT_NOT_STARTED),
440 was_ui_latency_logged_(false) {
441 DCHECK(!callback_.is_null());
442 }
443
444 bool AutofillDialogControllerAndroid::RequestingCreditCardInfo() const {
445 DCHECK_GT(form_structure_.field_count(), 0U);
446
447 for (size_t i = 0; i < form_structure_.field_count(); ++i) {
448 AutofillType type = form_structure_.field(i)->Type();
449 if (common::IsCreditCardType(type.GetStorableType()))
450 return true;
451 }
452
453 return false;
454 }
455
456 bool AutofillDialogControllerAndroid::TransmissionWillBeSecure() const {
457 return source_url_.SchemeIs(chrome::kHttpsScheme);
458 }
459
460 void AutofillDialogControllerAndroid::SetAutocheckoutState(
461 AutocheckoutState autocheckout_state) {
462 if (autocheckout_state_ == autocheckout_state)
463 return;
464
465 autocheckout_state_ = autocheckout_state;
466 }
467
468 void AutofillDialogControllerAndroid::LogOnFinishSubmitMetrics() {
469 GetMetricLogger().LogDialogUiDuration(
470 base::Time::Now() - dialog_shown_timestamp_,
471 GetDialogType(),
472 AutofillMetrics::DIALOG_ACCEPTED);
473
474 GetMetricLogger().LogDialogUiEvent(
475 GetDialogType(), AutofillMetrics::DIALOG_UI_ACCEPTED);
476 }
477
478 void AutofillDialogControllerAndroid::LogOnCancelMetrics() {
479 GetMetricLogger().LogDialogUiDuration(
480 base::Time::Now() - dialog_shown_timestamp_,
481 GetDialogType(),
482 AutofillMetrics::DIALOG_CANCELED);
483
484 GetMetricLogger().LogDialogUiEvent(
485 GetDialogType(), AutofillMetrics::DIALOG_UI_CANCELED);
486 }
487
488 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698