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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/android/autofill/autofill_dialog_controller_android.cc
diff --git a/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.cc b/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.cc
new file mode 100644
index 0000000000000000000000000000000000000000..655edd956d070b93242ddc495586b460e3496e8e
--- /dev/null
+++ b/chrome/browser/ui/android/autofill/autofill_dialog_controller_android.cc
@@ -0,0 +1,488 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/android/autofill/autofill_dialog_controller_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/scoped_user_pref_update.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/android/autofill/autofill_dialog_result.h"
+#include "chrome/browser/ui/android/window_android_helper.h"
+#include "chrome/browser/ui/autofill/autofill_dialog_common.h"
+#include "chrome/browser/ui/autofill/data_model_wrapper.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "components/autofill/content/browser/wallet/full_wallet.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/common/form_data.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/web_contents.h"
+#include "grit/generated_resources.h"
+#include "jni/AutofillDialogControllerAndroid_jni.h"
+#include "ui/android/window_android.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/combobox_model.h"
+#include "ui/base/models/menu_model.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/rect.h"
+#include "url/gurl.h"
+
+namespace autofill {
+
+namespace {
+
+// Keys in kAutofillDialogDefaults pref dictionary (do not change these values).
+const char kLastUsedAccountName[] = "last_used_account_name";
+const char kLastUsedChoiceIsAutofill[] = "last_used_choice_is_autofill";
+const char kLastUsedBillingAddressGuid[] = "last_used_billing";
+const char kLastUsedShippingAddressGuid[] = "last_used_shipping";
+const char kLastUsedCreditCardGuid[] = "last_used_card";
+
+scoped_ptr<DataModelWrapper> CreateWrapper(
+ DialogSection section, wallet::FullWallet* full_wallet) {
+ if (section == SECTION_CC_BILLING) {
+ if (!full_wallet->billing_address())
+ return scoped_ptr<DataModelWrapper>();
+
+ return scoped_ptr<DataModelWrapper>(
+ new FullWalletBillingWrapper(full_wallet));
+ }
+ if (section == SECTION_SHIPPING) {
+ if (!full_wallet->shipping_address())
+ return scoped_ptr<DataModelWrapper>();
+
+ return scoped_ptr<DataModelWrapper>(
+ new FullWalletShippingWrapper(full_wallet));
+ }
+ NOTREACHED();
+ return scoped_ptr<DataModelWrapper>();
+}
+
+void FillOutputForSectionWithComparator(
+ DialogSection section, const DetailInputs& inputs,
+ const InputFieldComparator& compare,
+ FormStructure& form_structure, wallet::FullWallet* full_wallet,
+ const base::string16& email_address) {
+
+ // Email is hidden while using Wallet, special case it.
+ if (section == SECTION_EMAIL) {
+ AutofillProfile profile;
+ profile.SetRawInfo(EMAIL_ADDRESS, email_address);
+ AutofillProfileWrapper profile_wrapper(&profile, 0);
+ profile_wrapper.FillFormStructure(inputs, compare, &form_structure);
+ return;
+ }
+
+ scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section, full_wallet);
+ if (wrapper)
+ wrapper->FillFormStructure(inputs, compare, &form_structure);
+}
+
+void FillOutputForSection(
+ DialogSection section,
+ FormStructure& form_structure,
+ wallet::FullWallet* full_wallet,
+ const base::string16& email_address) {
+ DetailInputs inputs;
+ common::BuildInputsForSection(section, &inputs);
+
+ FillOutputForSectionWithComparator(
+ section, inputs,
+ base::Bind(common::DetailInputMatchesField, section),
+ form_structure, full_wallet, email_address);
+}
+
+} // namespace
+
+
+// static
+base::WeakPtr<AutofillDialogController> AutofillDialogControllerAndroid::Create(
+ content::WebContents* contents,
+ const FormData& form_structure,
+ const GURL& source_url,
+ const DialogType dialog_type,
+ const base::Callback<void(const FormStructure*,
+ const std::string&)>& callback) {
+ // AutofillDialogControllerAndroid owns itself.
+ AutofillDialogControllerAndroid* autofill_dialog_controller =
+ new AutofillDialogControllerAndroid(contents,
+ form_structure,
+ source_url,
+ dialog_type,
+ callback);
+ return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
+}
+
+// static
+void AutofillDialogControllerAndroid::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterDictionaryPref(
+ ::prefs::kAutofillDialogDefaults,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+}
+
+// static
+base::WeakPtr<AutofillDialogController>
+AutofillDialogController::Create(
+ content::WebContents* contents,
+ const FormData& form_structure,
+ const GURL& source_url,
+ const DialogType dialog_type,
+ const base::Callback<void(const FormStructure*,
+ const std::string&)>& callback) {
+ return AutofillDialogControllerAndroid::Create(contents,
+ form_structure,
+ source_url,
+ dialog_type,
+ callback);
+}
+
+// static
+void AutofillDialogController::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ AutofillDialogControllerAndroid::RegisterProfilePrefs(registry);
+}
+
+AutofillDialogControllerAndroid::~AutofillDialogControllerAndroid() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_AutofillDialogControllerAndroid_onDestroy(env, java_object_.obj());
+}
+
+void AutofillDialogControllerAndroid::Show() {
+ dialog_shown_timestamp_ = base::Time::Now();
+
+ content::NavigationEntry* entry = contents_->GetController().GetActiveEntry();
+ const GURL& active_url = entry ? entry->GetURL() : contents_->GetURL();
+ invoked_from_same_origin_ = active_url.GetOrigin() == source_url_.GetOrigin();
+
+ // Log any relevant UI metrics and security exceptions.
+ GetMetricLogger().LogDialogUiEvent(
+ GetDialogType(), AutofillMetrics::DIALOG_UI_SHOWN);
+
+ GetMetricLogger().LogDialogSecurityMetric(
+ GetDialogType(), AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN);
+
+ if (RequestingCreditCardInfo() && !TransmissionWillBeSecure()) {
+ GetMetricLogger().LogDialogSecurityMetric(
+ GetDialogType(),
+ AutofillMetrics::SECURITY_METRIC_CREDIT_CARD_OVER_HTTP);
+ }
+
+ if (!invoked_from_same_origin_) {
+ GetMetricLogger().LogDialogSecurityMetric(
+ GetDialogType(),
+ AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME);
+ }
+
+ // Determine what field types should be included in the dialog.
+ bool has_types = false;
+ bool has_sections = false;
+ form_structure_.ParseFieldTypesFromAutocompleteAttributes(
+ &has_types, &has_sections);
+
+ // Fail if the author didn't specify autocomplete types.
+ if (!has_types) {
+ callback_.Run(NULL, std::string());
+ delete this;
+ return;
+ }
+
+ bool request_full_billing_address = true;
+ bool request_shipping_address = false;
+ bool request_phone_numbers = false;
+
+ for (size_t i = 0; i < form_structure_.field_count(); ++i) {
+ const ServerFieldType type =
+ form_structure_.field(i)->Type().GetStorableType();
+ if (type == PHONE_HOME_WHOLE_NUMBER || type == PHONE_BILLING_WHOLE_NUMBER) {
+ request_phone_numbers = true;
+ }
+ if (type == NAME_FULL ||
+ type == ADDRESS_HOME_LINE1 || type == ADDRESS_HOME_LINE2 ||
+ type == ADDRESS_HOME_CITY || type == ADDRESS_HOME_STATE ||
+ type == ADDRESS_HOME_ZIP || type == ADDRESS_HOME_COUNTRY ||
+ type == PHONE_HOME_WHOLE_NUMBER) {
+ request_shipping_address = true;
+ }
+ if (type == ADDRESS_BILLING_LINE1 || type == ADDRESS_BILLING_LINE2 ||
+ type == ADDRESS_BILLING_CITY || type == ADDRESS_BILLING_STATE ||
+ type == PHONE_BILLING_WHOLE_NUMBER) {
+ request_full_billing_address = true;
+ }
+ }
+
+ if (request_shipping_address)
+ request_full_billing_address = true;
+
+ const bool incognito_mode = profile_->IsOffTheRecord();
+
+ bool last_used_choice_is_autofill = false;
+ base::string16 last_used_account_name;
+ std::string last_used_billing;
+ std::string last_used_shipping;
+ std::string last_used_credit_card;
+ {
+ const base::DictionaryValue* defaults =
+ profile_->GetPrefs()->GetDictionary(::prefs::kAutofillDialogDefaults);
+ if (defaults) {
+ defaults->GetString(kLastUsedAccountName, &last_used_account_name);
+ defaults->GetBoolean(kLastUsedChoiceIsAutofill,
+ &last_used_choice_is_autofill);
+ defaults->GetString(kLastUsedBillingAddressGuid, &last_used_billing);
+ defaults->GetString(kLastUsedShippingAddressGuid, &last_used_shipping);
+ defaults->GetString(kLastUsedCreditCardGuid, &last_used_credit_card);
+ } else {
+ DLOG(ERROR) << "Failed to read AutofillDialog preferences";
+ }
+ }
+
+ if (contents_->GetBrowserContext()->IsOffTheRecord())
+ last_used_choice_is_autofill = true;
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> jlast_used_account_name =
+ base::android::ConvertUTF16ToJavaString(
+ env, last_used_account_name);
+ ScopedJavaLocalRef<jstring> jlast_used_billing =
+ base::android::ConvertUTF8ToJavaString(
+ env, last_used_billing);
+ ScopedJavaLocalRef<jstring> jlast_used_shipping =
+ base::android::ConvertUTF8ToJavaString(
+ env, last_used_shipping);
+ ScopedJavaLocalRef<jstring> jlast_used_card =
+ base::android::ConvertUTF8ToJavaString(
+ env, last_used_credit_card);
+ ScopedJavaLocalRef<jstring> jmerchant_domain =
+ base::android::ConvertUTF8ToJavaString(
+ env, source_url_.GetOrigin().spec());
+ java_object_.Reset(Java_AutofillDialogControllerAndroid_create(
+ env,
+ reinterpret_cast<jint>(this),
+ WindowAndroidHelper::FromWebContents(contents_)->
+ GetWindowAndroid()->GetJavaObject().obj(),
+ request_full_billing_address, request_shipping_address,
+ request_phone_numbers, incognito_mode,
+ last_used_choice_is_autofill, jlast_used_account_name.obj(),
+ jlast_used_billing.obj(), jlast_used_shipping.obj(),
+ jlast_used_card.obj(),
+ jmerchant_domain.obj()));
+}
+
+void AutofillDialogControllerAndroid::Hide() {
+ // TODO(aruslan): http://crbug.com/177373 Autocheckout.
+ NOTIMPLEMENTED();
+}
+
+void AutofillDialogControllerAndroid::TabActivated() {}
+
+void AutofillDialogControllerAndroid::AddAutocheckoutStep(
+ AutocheckoutStepType step_type) {
+ // TODO(aruslan): http://crbug.com/177373 Autocheckout.
+ NOTIMPLEMENTED() << " step_type = " << step_type;
+}
+
+void AutofillDialogControllerAndroid::UpdateAutocheckoutStep(
+ AutocheckoutStepType step_type,
+ AutocheckoutStepStatus step_status) {
+ // TODO(aruslan): http://crbug.com/177373 Autocheckout.
+ NOTIMPLEMENTED() << " step_type=" << step_type
+ << " step_status=" << step_status;
+}
+
+void AutofillDialogControllerAndroid::OnAutocheckoutError() {
+ // TODO(aruslan): http://crbug.com/177373 Autocheckout.
+ NOTIMPLEMENTED();
+ DCHECK_EQ(AUTOCHECKOUT_IN_PROGRESS, autocheckout_state_);
+ GetMetricLogger().LogAutocheckoutDuration(
+ base::Time::Now() - autocheckout_started_timestamp_,
+ AutofillMetrics::AUTOCHECKOUT_FAILED);
+ SetAutocheckoutState(AUTOCHECKOUT_ERROR);
+ autocheckout_started_timestamp_ = base::Time();
+}
+
+void AutofillDialogControllerAndroid::OnAutocheckoutSuccess() {
+ // TODO(aruslan): http://crbug.com/177373 Autocheckout.
+ NOTIMPLEMENTED();
+ DCHECK_EQ(AUTOCHECKOUT_IN_PROGRESS, autocheckout_state_);
+ GetMetricLogger().LogAutocheckoutDuration(
+ base::Time::Now() - autocheckout_started_timestamp_,
+ AutofillMetrics::AUTOCHECKOUT_SUCCEEDED);
+ SetAutocheckoutState(AUTOCHECKOUT_SUCCESS);
+ autocheckout_started_timestamp_ = base::Time();
+}
+
+DialogType AutofillDialogControllerAndroid::GetDialogType() const {
+ return dialog_type_;
+}
+
+// static
+bool AutofillDialogControllerAndroid::
+ RegisterAutofillDialogControllerAndroid(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+void AutofillDialogControllerAndroid::DialogCancel(JNIEnv* env,
+ jobject obj) {
+ if (autocheckout_state_ == AUTOCHECKOUT_NOT_STARTED)
+ LogOnCancelMetrics();
+
+ if (autocheckout_state_ == AUTOCHECKOUT_IN_PROGRESS) {
+ GetMetricLogger().LogAutocheckoutDuration(
+ base::Time::Now() - autocheckout_started_timestamp_,
+ AutofillMetrics::AUTOCHECKOUT_CANCELLED);
+ }
+
+ callback_.Run(NULL, std::string());
+}
+
+void AutofillDialogControllerAndroid::DialogContinue(
+ JNIEnv* env,
+ jobject obj,
+ jobject wallet,
+ jboolean jlast_used_choice_is_autofill,
+ jstring jlast_used_account_name,
+ jstring jlast_used_billing,
+ jstring jlast_used_shipping,
+ jstring jlast_used_card) {
+ const string16 email = AutofillDialogResult::GetWalletEmail(env, wallet);
+ const std::string google_transaction_id =
+ AutofillDialogResult::GetWalletGoogleTransactionId(env, wallet);
+
+ const string16 last_used_account_name =
+ base::android::ConvertJavaStringToUTF16(env, jlast_used_account_name);
+ const std::string last_used_billing =
+ base::android::ConvertJavaStringToUTF8(env, jlast_used_billing);
+ const std::string last_used_shipping =
+ base::android::ConvertJavaStringToUTF8(env, jlast_used_shipping);
+ const std::string last_used_card =
+ base::android::ConvertJavaStringToUTF8(env, jlast_used_card);
+
+ scoped_ptr<wallet::FullWallet> full_wallet =
+ AutofillDialogResult::ConvertFromJava(env, wallet);
+ FillOutputForSection(
+ SECTION_EMAIL, form_structure_, full_wallet.get(), email);
+ FillOutputForSection(
+ SECTION_CC_BILLING, form_structure_, full_wallet.get(), email);
+ FillOutputForSection(
+ SECTION_SHIPPING, form_structure_, full_wallet.get(), email);
+
+ {
+ DictionaryPrefUpdate updater(profile_->GetPrefs(),
+ ::prefs::kAutofillDialogDefaults);
+ base::DictionaryValue* defaults = updater.Get();
+ if (defaults) {
+ const bool last_used_choice_is_autofill = !!jlast_used_choice_is_autofill;
+ defaults->SetString(kLastUsedAccountName, last_used_account_name);
+ defaults->SetBoolean(kLastUsedChoiceIsAutofill,
+ last_used_choice_is_autofill);
+ if (!last_used_billing.empty())
+ defaults->SetString(kLastUsedBillingAddressGuid, last_used_billing);
+ if (!last_used_shipping.empty())
+ defaults->SetString(kLastUsedShippingAddressGuid, last_used_shipping);
+ if (!last_used_card.empty())
+ defaults->SetString(kLastUsedCreditCardGuid, last_used_card);
+ } else {
+ LOG(ERROR) << "Failed to save AutofillDialog preferences";
+ }
+ }
+
+ if (GetDialogType() == DIALOG_TYPE_AUTOCHECKOUT) {
+ autocheckout_started_timestamp_ = base::Time::Now();
+ SetAutocheckoutState(AUTOCHECKOUT_IN_PROGRESS);
+ }
+
+ LogOnFinishSubmitMetrics();
+
+ // Callback should be called as late as possible.
+ callback_.Run(&form_structure_, google_transaction_id);
+
+ // This might delete us.
+ if (GetDialogType() == DIALOG_TYPE_REQUEST_AUTOCOMPLETE)
+ Hide();
+}
+
+AutofillDialogControllerAndroid::AutofillDialogControllerAndroid(
+ content::WebContents* contents,
+ const FormData& form_structure,
+ const GURL& source_url,
+ const DialogType dialog_type,
+ const base::Callback<void(const FormStructure*,
+ const std::string&)>& callback)
+ : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
+ contents_(contents),
+ initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
+ dialog_type_(dialog_type),
+ form_structure_(form_structure, std::string()),
+ invoked_from_same_origin_(true),
+ source_url_(source_url),
+ callback_(callback),
+ cares_about_shipping_(true),
+ weak_ptr_factory_(this),
+ autocheckout_state_(AUTOCHECKOUT_NOT_STARTED),
+ was_ui_latency_logged_(false) {
+ DCHECK(!callback_.is_null());
+}
+
+bool AutofillDialogControllerAndroid::RequestingCreditCardInfo() const {
+ DCHECK_GT(form_structure_.field_count(), 0U);
+
+ for (size_t i = 0; i < form_structure_.field_count(); ++i) {
+ AutofillType type = form_structure_.field(i)->Type();
+ if (common::IsCreditCardType(type.GetStorableType()))
+ return true;
+ }
+
+ return false;
+}
+
+bool AutofillDialogControllerAndroid::TransmissionWillBeSecure() const {
+ return source_url_.SchemeIs(chrome::kHttpsScheme);
+}
+
+void AutofillDialogControllerAndroid::SetAutocheckoutState(
+ AutocheckoutState autocheckout_state) {
+ if (autocheckout_state_ == autocheckout_state)
+ return;
+
+ autocheckout_state_ = autocheckout_state;
+}
+
+void AutofillDialogControllerAndroid::LogOnFinishSubmitMetrics() {
+ GetMetricLogger().LogDialogUiDuration(
+ base::Time::Now() - dialog_shown_timestamp_,
+ GetDialogType(),
+ AutofillMetrics::DIALOG_ACCEPTED);
+
+ GetMetricLogger().LogDialogUiEvent(
+ GetDialogType(), AutofillMetrics::DIALOG_UI_ACCEPTED);
+}
+
+void AutofillDialogControllerAndroid::LogOnCancelMetrics() {
+ GetMetricLogger().LogDialogUiDuration(
+ base::Time::Now() - dialog_shown_timestamp_,
+ GetDialogType(),
+ AutofillMetrics::DIALOG_CANCELED);
+
+ GetMetricLogger().LogDialogUiEvent(
+ GetDialogType(), AutofillMetrics::DIALOG_UI_CANCELED);
+}
+
+} // namespace autofill

Powered by Google App Engine
This is Rietveld 408576698