OLD | NEW |
(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 |
OLD | NEW |