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